// File: gvaumour[P]cache-simulator/src/Prefetcher.cc
// Function: SimplePrefetcher::getNextAddress(unsigned long)
vector<uint64_t>
SimplePrefetcher::getNextAddress(uint64_t current_address)
{

	uint64_t distance = INT64_MAX;
	int index = PAGE_SIZE;
	vector<uint64_t> prefetch_addresses;
	
	for(unsigned i = 0; i < m_prev_address.size() ; i++)
	{
		if( (current_address - m_prev_address[i].addr < distance) && m_prev_address[i].isValid)
		{
			index = i;
			distance = current_address - m_prev_address[i].addr;
		}
	}
	//DPRINTF("SimplePrefetcher::getNextAddress Distance %ld, index %d\n", distance , index);
	
	if( !(distance > 0 && distance < PAGE_SIZE) ) //No address within proper distances, create an entry 
	{
		//Select the older entry
		uint64_t age = INT64_MAX;
		int index_old = 0;
		bool done = false;
		for(unsigned i = 0 ; i < m_prev_address.size();i++)
		{
			if(!m_prev_address[i].isValid)
			{
				m_prev_address[i].addr = current_address;
				m_prev_address[i].isValid = true;
				m_prev_address[i].LRU_info = cpt_time;
				done = true;
			}
		}
		if(!done)
		{
		
			for(unsigned i = 0 ; i < m_prev_address.size();i++)
			{
				if(m_prev_address[i].LRU_info < age)
				{
					age = m_prev_address[i].LRU_info;
					index_old = i;
				}
			}
			m_prev_address[index_old].addr = current_address;
			m_prev_address[index_old].isValid = true;
			m_prev_address[index_old].LRU_info = cpt_time;
		}
		//DPRINTF("SimplePrefetcher::getNextAddress No Address Generated\n");
		return prefetch_addresses;
	}
	
	
	int stride = current_address - m_prev_address[index].addr;
	m_prev_address[index].addr = current_address;
	m_prev_address[index].LRU_info = cpt_time;

	if (stride != 0)
	{
		//DPRINTF("SimplePrefetcher::getNextAddress Generated prefecth For address %#lx\n", current_address);

		for(int i = 0; i < m_prefetchDegree; ++i)
		{
			 uint64_t prefetch_address = current_address + (i+1) * stride;
			 // But stay within the page if requested
			 if (!m_stop_at_page || ((prefetch_address & PAGE_MASK) == (current_address & PAGE_MASK)))
			    prefetch_addresses.push_back(prefetch_address);
			//DPRINTF("SimplePrefetcher::getNextAddress - %#lx\n",prefetch_address );
		}
		
	}

	return prefetch_addresses;
}

// Assembly:
subq $0xe8, %rsp
movq %rdi, 0x60(%rsp)
movq %rdi, %rax
movq %rax, 0x68(%rsp)
movq %rdi, 0xe0(%rsp)
movq %rsi, 0xd8(%rsp)
movq %rdx, 0xd0(%rsp)
movq 0xd8(%rsp), %rax
movq %rax, 0x70(%rsp)
movabsq $0x7fffffffffffffff, %rax # imm = 0x7FFFFFFFFFFFFFFF
movq %rax, 0xc8(%rsp)
movl $0x1000, 0xc4(%rsp) # imm = 0x1000
movb $0x0, 0xc3(%rsp)
callq 0xe8c0
movl $0x0, 0xbc(%rsp)
movq 0x70(%rsp), %rdi
movl 0xbc(%rsp), %eax
movq %rax, 0x58(%rsp)
addq $0x18, %rdi
callq 0x5c470
movq %rax, %rcx
movq 0x58(%rsp), %rax
cmpq %rcx, %rax
jae 0x5be5c
movq 0x70(%rsp), %rdi
movq 0xd0(%rsp), %rax
movq %rax, 0x50(%rsp)
addq $0x18, %rdi
movl 0xbc(%rsp), %eax
movl %eax, %esi
callq 0x5c490
movq %rax, %rcx
movq 0x50(%rsp), %rax
subq (%rcx), %rax
cmpq 0xc8(%rsp), %rax
jae 0x5be44
movq 0x70(%rsp), %rdi
addq $0x18, %rdi
movl 0xbc(%rsp), %eax
movl %eax, %esi
callq 0x5c490
testb $0x1, 0x8(%rax)
je 0x5be44
movq 0x70(%rsp), %rdi
movl 0xbc(%rsp), %eax
movl %eax, 0xc4(%rsp)
movq 0xd0(%rsp), %rax
movq %rax, 0x48(%rsp)
addq $0x18, %rdi
movl 0xbc(%rsp), %eax
movl %eax, %esi
callq 0x5c490
movq %rax, %rcx
movq 0x48(%rsp), %rax
subq (%rcx), %rax
movq %rax, 0xc8(%rsp)
jmp 0x5be46
movl 0xbc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xbc(%rsp)
jmp 0x5bd7e
cmpq $0x0, 0xc8(%rsp)
jbe 0x5be79
cmpq $0x1000, 0xc8(%rsp) # imm = 0x1000
jb 0x5c0c0
movabsq $0x7fffffffffffffff, %rax # imm = 0x7FFFFFFFFFFFFFFF
movq %rax, 0xb0(%rsp)
movl $0x0, 0xac(%rsp)
movb $0x0, 0xab(%rsp)
movl $0x0, 0xa4(%rsp)
movq 0x70(%rsp), %rdi
movl 0xa4(%rsp), %eax
movq %rax, 0x40(%rsp)
addq $0x18, %rdi
callq 0x5c470
movq %rax, %rcx
movq 0x40(%rsp), %rax
cmpq %rcx, %rax
jae 0x5bf87
movq 0x70(%rsp), %rdi
addq $0x18, %rdi
movl 0xa4(%rsp), %eax
movl %eax, %esi
callq 0x5c490
testb $0x1, 0x8(%rax)
jne 0x5bf6f
movq 0x70(%rsp), %rdi
movq 0xd0(%rsp), %rax
movq %rax, 0x30(%rsp)
addq $0x18, %rdi
movl 0xa4(%rsp), %eax
movl %eax, %esi
callq 0x5c490
movq 0x30(%rsp), %rcx
movq 0x70(%rsp), %rdi
movq %rcx, (%rax)
addq $0x18, %rdi
movl 0xa4(%rsp), %eax
movl %eax, %esi
callq 0x5c490
movq 0x70(%rsp), %rdi
movb $0x1, 0x8(%rax)
leaq 0x38074(%rip), %rax     # 0x93fb8
movq (%rax), %rax
movq %rax, 0x38(%rsp)
addq $0x18, %rdi
movl 0xa4(%rsp), %eax
movl %eax, %esi
callq 0x5c490
movq 0x38(%rsp), %rcx
movq %rcx, 0x10(%rax)
movb $0x1, 0xab(%rsp)
jmp 0x5bf71
movl 0xa4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xa4(%rsp)
jmp 0x5bea9
testb $0x1, 0xab(%rsp)
jne 0x5c0a8
movl $0x0, 0xa0(%rsp)
movq 0x70(%rsp), %rdi
movl 0xa0(%rsp), %eax
movq %rax, 0x28(%rsp)
addq $0x18, %rdi
callq 0x5c470
movq %rax, %rcx
movq 0x28(%rsp), %rax
cmpq %rcx, %rax
jae 0x5c035
movq 0x70(%rsp), %rdi
addq $0x18, %rdi
movl 0xa0(%rsp), %eax
movl %eax, %esi
callq 0x5c490
movq 0x10(%rax), %rax
cmpq 0xb0(%rsp), %rax
jae 0x5c01d
movq 0x70(%rsp), %rdi
addq $0x18, %rdi
movl 0xa0(%rsp), %eax
movl %eax, %esi
callq 0x5c490
movq 0x10(%rax), %rax
movq %rax, 0xb0(%rsp)
movl 0xa0(%rsp), %eax
movl %eax, 0xac(%rsp)
jmp 0x5c01f
movl 0xa0(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xa0(%rsp)
jmp 0x5bfa0
movq 0x70(%rsp), %rdi
movq 0xd0(%rsp), %rax
movq %rax, 0x18(%rsp)
addq $0x18, %rdi
movslq 0xac(%rsp), %rsi
callq 0x5c490
movq 0x18(%rsp), %rcx
movq 0x70(%rsp), %rdi
movq %rcx, (%rax)
addq $0x18, %rdi
movslq 0xac(%rsp), %rsi
callq 0x5c490
movq 0x70(%rsp), %rdi
movb $0x1, 0x8(%rax)
leaq 0x37f32(%rip), %rax     # 0x93fb8
movq (%rax), %rax
movq %rax, 0x20(%rsp)
addq $0x18, %rdi
movslq 0xac(%rsp), %rsi
callq 0x5c490
movq 0x20(%rsp), %rcx
movq %rcx, 0x10(%rax)
movb $0x1, 0xc3(%rsp)
movl $0x1, 0x9c(%rsp)
jmp 0x5c22f
movq 0x70(%rsp), %rdi
movq 0xd0(%rsp), %rax
movq %rax, (%rsp)
addq $0x18, %rdi
movslq 0xc4(%rsp), %rsi
callq 0x5c490
movq 0x70(%rsp), %rdi
movq %rax, %rcx
movq (%rsp), %rax
subq (%rcx), %rax
movl %eax, 0x98(%rsp)
movq 0xd0(%rsp), %rax
movq %rax, 0x8(%rsp)
addq $0x18, %rdi
movslq 0xc4(%rsp), %rsi
callq 0x5c490
movq 0x8(%rsp), %rcx
movq 0x70(%rsp), %rdi
movq %rcx, (%rax)
leaq 0x37e8e(%rip), %rax     # 0x93fb8
movq (%rax), %rax
movq %rax, 0x10(%rsp)
addq $0x18, %rdi
movslq 0xc4(%rsp), %rsi
callq 0x5c490
movq 0x10(%rsp), %rcx
movq %rcx, 0x10(%rax)
cmpl $0x0, 0x98(%rsp)
je 0x5c21c
movl $0x0, 0x94(%rsp)
movq 0x70(%rsp), %rcx
movl 0x94(%rsp), %eax
cmpl 0x8(%rcx), %eax
jge 0x5c21a
movq 0x70(%rsp), %rax
movq 0xd0(%rsp), %rcx
movl 0x94(%rsp), %edx
addl $0x1, %edx
imull 0x98(%rsp), %edx
movslq %edx, %rdx
addq %rdx, %rcx
movq %rcx, 0x88(%rsp)
testb $0x1, 0x15(%rax)
je 0x5c1cf
movq 0x88(%rsp), %rax
andq $-0x1000, %rax          # imm = 0xF000
movq 0xd0(%rsp), %rcx
andq $-0x1000, %rcx          # imm = 0xF000
cmpq %rcx, %rax
jne 0x5c202
movq 0x60(%rsp), %rdi
leaq 0x88(%rsp), %rsi
callq 0x3d940
jmp 0x5c1e3
jmp 0x5c202
movq 0x60(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x80(%rsp)
movl %eax, 0x7c(%rsp)
callq 0xf0e0
jmp 0x5c250
jmp 0x5c204
movl 0x94(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x94(%rsp)
jmp 0x5c165
jmp 0x5c21c
movb $0x1, 0xc3(%rsp)
movl $0x1, 0x9c(%rsp)
testb $0x1, 0xc3(%rsp)
jne 0x5c243
movq 0x60(%rsp), %rdi
callq 0xf0e0
movq 0x68(%rsp), %rax
addq $0xe8, %rsp
retq
movq 0x80(%rsp), %rdi
callq 0x5690
nopl (%rax)