// File: gvaumour[P]cache-simulator/src/SimplePerceptron.cc
// Function: SimplePerceptronPredictor::checkLazyMigration(CacheEntry*, unsigned long, bool, unsigned long, bool)
CacheEntry*
SimplePerceptronPredictor::checkLazyMigration(CacheEntry* current ,uint64_t set,bool inNVM, uint64_t index, bool isWrite)
{

	int yout = 0;
	for(unsigned i = 0 ; i < m_features.size() ; i++)
	{
		int hash = hashing_function1( m_features_hash[i] , current->address , current->missPC );
		int pred = m_features[i]->getCounter(hash);
		yout += pred;
	}
	
	if ( abs(yout) < simu_parameters.simple_perceptron_learningTreshold)
		return current;

	allocDecision des = yout > 0 ? ALLOCATE_IN_NVM : ALLOCATE_IN_SRAM;

	if( inNVM == false && des == ALLOCATE_IN_NVM)
	{
		//cl is SRAM , check whether we should migrate to NVM 
		if(simu_parameters.enableDatasetSpilling && m_isNVMbusy[set])
		{
			//reportSpilling(rap_current, current->address, false ,  inNVM);
			//stats_busyness_migrate_change++; //If NVM tab is busy , don't migrate
		}
		else
		{
			//Trigger Migration
			int id_assocNVM = evictPolicy(set, true);//Select LRU candidate from NVM cache
			//DPRINTF("DBAMBPredictor:: Migration Triggered from SRAM, index %ld, id_assoc %d \n" , index, id_assoc);

			CacheEntry* replaced_entry_NVM = m_tableNVM[set][id_assocNVM];
					
			/** Migration incurs one read and one extra write */ 
			replaced_entry_NVM->nbWrite++;
			current->nbRead++;
		
			/* Record the write error migration */ 
			Predictor::migrationRecording();
		
			reportMigration(current, false , isWrite);
		
			m_cache->triggerMigration(set, index , id_assocNVM , false);
			if(!m_isWarmup)
				stats_nbMigrations[true]++;


			current = replaced_entry_NVM;
		}

	}
	else if( des == ALLOCATE_IN_SRAM && inNVM == true)
	{
		//cl is in NVM , check whether we should migrate to SRAM 
			
		//If SRAM tab is busy , don't migrate
		if(simu_parameters.enableDatasetSpilling && m_isSRAMbusy[set])
		{
			//reportSpilling(rap_current, current->address, false ,  inNVM);
			//stats_busyness_migrate_change++; //If NVM tab is busy , don't migrate
		}
		else 
		{		
			int id_assocSRAM = evictPolicy(set, false);
		
			CacheEntry* replaced_entry_SRAM = m_tableSRAM[set][id_assocSRAM];

			/** Migration incurs one read and one extra write */ 
			replaced_entry_SRAM->nbWrite++;
			current->nbRead++;
			reportMigration( current, true , isWrite);
	
			m_cache->triggerMigration(set, id_assocSRAM , index , true);
		
			if(!m_isWarmup)
				stats_nbMigrations[false]++;

			current = replaced_entry_SRAM;		
		}

	}
	return current;
}

// Assembly:
subq $0xe8, %rsp
movb %r9b, %al
movq %rdi, 0xd8(%rsp)
movq %rsi, 0xd0(%rsp)
movq %rdx, 0xc8(%rsp)
andb $0x1, %cl
movb %cl, 0xc7(%rsp)
movq %r8, 0xb8(%rsp)
andb $0x1, %al
movb %al, 0xb7(%rsp)
movq 0xd8(%rsp), %rax
movq %rax, 0x20(%rsp)
movl $0x0, 0xb0(%rsp)
movl $0x0, 0xac(%rsp)
movq 0x20(%rsp), %rdi
movl 0xac(%rsp), %eax
movq %rax, 0x18(%rsp)
addq $0x270, %rdi            # imm = 0x270
callq 0x64a70
movq %rax, %rcx
movq 0x18(%rsp), %rax
cmpq %rcx, %rax
jae 0x6297a
movq 0x20(%rsp), %rdi
addq $0x288, %rdi            # imm = 0x288
movl 0xac(%rsp), %eax
movl %eax, %esi
callq 0xf860
movq %rax, %rsi
leaq 0x80(%rsp), %rdi
movq %rdi, 0x8(%rsp)
callq 0xf880
movq 0x8(%rsp), %rdi
movq 0xd0(%rsp), %rax
movq 0x8(%rax), %rsi
movq 0x20(%rax), %rdx
callq 0x2ff40
movl %eax, 0x14(%rsp)
jmp 0x628ed
leaq 0x80(%rsp), %rdi
callq 0xf7b0
movl 0x14(%rsp), %eax
movq 0x20(%rsp), %rdi
movl %eax, 0xa8(%rsp)
addq $0x270, %rdi            # imm = 0x270
movl 0xac(%rsp), %eax
movl %eax, %esi
callq 0x64a90
movq (%rax), %rdi
movl 0xa8(%rsp), %esi
callq 0x5e6e0
movl %eax, 0x70(%rsp)
movl 0x70(%rsp), %eax
addl 0xb0(%rsp), %eax
movl %eax, 0xb0(%rsp)
movl 0xac(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xac(%rsp)
jmp 0x62870
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x78(%rsp)
movl %eax, 0x74(%rsp)
leaq 0x80(%rsp), %rdi
callq 0xf7b0
jmp 0x62cd3
movl 0xb0(%rsp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
leaq 0x31661(%rip), %rcx     # 0x93ff0
cmpl 0x248(%rcx), %eax
jge 0x629ac
movq 0xd0(%rsp), %rax
movq %rax, 0xe0(%rsp)
jmp 0x62cc3
movl 0xb0(%rsp), %edx
xorl %eax, %eax
movl $0x1, %ecx
cmpl $0x0, %edx
cmovgl %ecx, %eax
movl %eax, 0x6c(%rsp)
movb 0xc7(%rsp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x62b40
cmpl $0x1, 0x6c(%rsp)
jne 0x62b40
xorl %eax, %eax
leaq 0x31603(%rip), %rcx     # 0x93ff0
testb $0x1, 0x158(%rcx)
movb %al, 0x7(%rsp)
je 0x62a2b
movq 0x20(%rsp), %rdi
addq $0x110, %rdi            # imm = 0x110
movq 0xc8(%rsp), %rsi
callq 0xfa90
movq %rax, 0x58(%rsp)
movq %rdx, 0x60(%rsp)
leaq 0x58(%rsp), %rdi
callq 0xfaf0
movb %al, 0x7(%rsp)
movb 0x7(%rsp), %al
testb $0x1, %al
jne 0x62a35
jmp 0x62a3a
jmp 0x62b3b
movq 0x20(%rsp), %rdi
movq 0xc8(%rsp), %rax
movl %eax, %esi
movq (%rdi), %rax
movl $0x1, %edx
callq *0x28(%rax)
movl %eax, %ecx
movq 0x20(%rsp), %rax
movl %ecx, 0x54(%rsp)
movq 0x10(%rax), %rdi
movq 0xc8(%rsp), %rsi
callq 0xf9a0
movq %rax, %rdi
movslq 0x54(%rsp), %rsi
callq 0xf9c0
movq 0x20(%rsp), %rdi
movq (%rax), %rax
movq %rax, 0x48(%rsp)
movq 0x48(%rsp), %rax
movl 0x11c(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x11c(%rax)
movq 0xd0(%rsp), %rax
movl 0x120(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x120(%rax)
callq 0x56e70
movq 0x20(%rsp), %rdi
movq 0xd0(%rsp), %rsi
movb 0xb7(%rsp), %al
xorl %edx, %edx
andb $0x1, %al
movzbl %al, %ecx
callq 0x63880
movq 0x20(%rsp), %rax
movq 0x70(%rax), %rdi
movq 0xc8(%rsp), %rax
movl %eax, %esi
movq 0xb8(%rsp), %rax
movl %eax, %edx
movl 0x54(%rsp), %ecx
xorl %r8d, %r8d
callq 0x3ac00
movq 0x20(%rsp), %rax
testb $0x1, 0x81(%rax)
jne 0x62b2e
movq 0x20(%rsp), %rdi
addq $0x350, %rdi            # imm = 0x350
movl $0x1, %esi
callq 0xef90
movl (%rax), %ecx
addl $0x1, %ecx
movl %ecx, (%rax)
movq 0x48(%rsp), %rax
movq %rax, 0xd0(%rsp)
jmp 0x62cb3
cmpl $0x0, 0x6c(%rsp)
jne 0x62cb1
movb 0xc7(%rsp), %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x1, %eax
jne 0x62cb1
xorl %eax, %eax
leaq 0x31487(%rip), %rcx     # 0x93ff0
testb $0x1, 0x158(%rcx)
movb %al, 0x6(%rsp)
je 0x62ba7
movq 0x20(%rsp), %rdi
addq $0xe8, %rdi
movq 0xc8(%rsp), %rsi
callq 0xfa90
movq %rax, 0x38(%rsp)
movq %rdx, 0x40(%rsp)
leaq 0x38(%rsp), %rdi
callq 0xfaf0
movb %al, 0x6(%rsp)
movb 0x6(%rsp), %al
testb $0x1, %al
jne 0x62bb1
jmp 0x62bb6
jmp 0x62caf
movq 0x20(%rsp), %rdi
movq 0xc8(%rsp), %rax
movl %eax, %esi
movq (%rdi), %rax
xorl %edx, %edx
callq *0x28(%rax)
movl %eax, %ecx
movq 0x20(%rsp), %rax
movl %ecx, 0x34(%rsp)
movq 0x8(%rax), %rdi
movq 0xc8(%rsp), %rsi
callq 0xf9a0
movq %rax, %rdi
movslq 0x34(%rsp), %rsi
callq 0xf9c0
movq 0x20(%rsp), %rdi
movq (%rax), %rax
movq %rax, 0x28(%rsp)
movq 0x28(%rsp), %rax
movl 0x11c(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x11c(%rax)
movq 0xd0(%rsp), %rax
movl 0x120(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x120(%rax)
movq 0xd0(%rsp), %rsi
movb 0xb7(%rsp), %al
movl $0x1, %edx
andb $0x1, %al
movzbl %al, %ecx
callq 0x63880
movq 0x20(%rsp), %rax
movq 0x70(%rax), %rdi
movq 0xc8(%rsp), %rax
movl %eax, %esi
movl 0x34(%rsp), %edx
movq 0xb8(%rsp), %rax
movl %eax, %ecx
movl $0x1, %r8d
callq 0x3ac00
movq 0x20(%rsp), %rax
testb $0x1, 0x81(%rax)
jne 0x62ca2
movq 0x20(%rsp), %rdi
addq $0x350, %rdi            # imm = 0x350
xorl %eax, %eax
movl %eax, %esi
callq 0xef90
movl (%rax), %ecx
addl $0x1, %ecx
movl %ecx, (%rax)
movq 0x28(%rsp), %rax
movq %rax, 0xd0(%rsp)
jmp 0x62cb1
jmp 0x62cb3
movq 0xd0(%rsp), %rax
movq %rax, 0xe0(%rsp)
movq 0xe0(%rsp), %rax
addq $0xe8, %rsp
retq
movq 0x78(%rsp), %rdi
callq 0x5690
nopl (%rax)