// File: gvaumour[P]cache-simulator/src/PHC.cc
// Function: PHCPredictor::evictPolicy(int, bool)
int PHCPredictor::evictPolicy(int set, bool inNVM)
{
	int assoc_victim = -1;
	assert(m_replacementPolicyNVM_ptr != NULL);
	assert(m_replacementPolicySRAM_ptr != NULL);

	CacheEntry* entry = NULL;
	if(inNVM)
	{	
		assoc_victim = m_replacementPolicyNVM_ptr->evictPolicy(set);
		entry = m_tableNVM[set][assoc_victim];
	}
	else
	{
		assoc_victim = m_replacementPolicySRAM_ptr->evictPolicy(set);
		entry = m_tableSRAM[set][assoc_victim];		
	}

	if(entry->isValid )
	{
		/*
		string alloc = inNVM ? "NVM" : "SRAM";
		cout << "Eviction Block 0x" << std::hex << entry->address << std::dec << " from " << alloc << " Cost Value = " << entry->cost_value << endl;
		*/
		if(simu_parameters.perceptron_drawFeatureMaps)
		{
			bool global_error = false;
			allocDecision des = entry->cost_value > simu_parameters.PHC_cost_threshold ? ALLOCATE_IN_SRAM : ALLOCATE_IN_NVM;
			//cout << "\t Evaluated allocation = " << str_allocDecision[des] << " , cost Value = " << entry->cost_value << endl;
			if(( des == ALLOCATE_IN_SRAM && inNVM ) || \
				( des == ALLOCATE_IN_NVM && !inNVM ))
				global_error = true;
			if(global_error)
			{
				int hash1 = m_features_hash[0](entry->address , entry->m_pc);
				int hash2 = (m_features.size() > 1) ? m_features_hash[1](entry->address , entry->m_pc) : 0;
				stats_global_error[hash1][hash2]++;
				//cout << "\tGlobal Error Detected features[" << hash1 << "][" << hash2 << "]" << endl; 

			}
		
			for(unsigned i = 0; i < m_features.size() ; i++)
			{
				int hash = m_features_hash[i](entry->address , entry->m_pc);
				allocDecision alloc_pred = entry->PHC_allocation_pred[i].second;
				
				bool local_error = false;
				if( des == ALLOCATE_IN_NVM && alloc_pred == ALLOCATE_IN_SRAM)
					local_error = true;
				else if( des == ALLOCATE_IN_SRAM && alloc_pred == ALLOCATE_IN_NVM )
				 	local_error = true;
				 
						
				if(local_error)
				{
					stats_local_error[i][hash]++;
					/*cout << "\tLocal Error detected, " << m_criterias_names[i] << std::dec << \
						"[" << hash << "] = " << str_allocDecision[alloc_pred] << endl; */
				}	
			}

		}	
		if(entry->isLearning)
		{
			if(entry->cost_value > simu_parameters.PHC_cost_threshold)
			{
				//cout << "Decrease allocation counter" << endl; 
				for(unsigned i = 0; i < m_features.size() ; i++)
				{
					int hash = m_features_hash[i](entry->address , entry->m_pc);
					m_features[i]->decreaseAlloc(hash);
					/*cout << "\t - Feature " << m_criterias_names[i] << std::dec << ": Hash=" \
						<< hash  << ", Alloc=" << m_features[i]->getAllocationPrediction(hash, false) << endl; */

				}
			}			
			else
			{
				//cout << "Increase allocation counter" << endl; 
				for(unsigned i = 0; i < m_features.size() ; i++)
				{
					int hash = m_features_hash[i](entry->address , entry->m_pc);
					m_features[i]->increaseAlloc(hash);
					/*cout << "\t - Feature " << m_criterias_names[i] << std::dec << ": Hash=" \
						<< hash  << ", Alloc" << m_features[i]->getAllocationPrediction(hash, false) << endl; */
				}
			}
		}

		if(entry->nbWrite == 0 && entry->nbRead == 0)
			stats_nbDeadLine[stats_nbDeadLine.size()-1]++;
	}
	
	evictRecording(set , assoc_victim , inNVM);	
	return assoc_victim;
}

// Assembly:
subq $0x88, %rsp
movb %dl, %al
movq %rdi, 0x80(%rsp)
movl %esi, 0x7c(%rsp)
andb $0x1, %al
movb %al, 0x7b(%rsp)
movq 0x80(%rsp), %rax
movq %rax, 0x30(%rsp)
movl $0xffffffff, 0x74(%rsp) # imm = 0xFFFFFFFF
cmpq $0x0, 0x60(%rax)
je 0x4b669
jmp 0x4b688
leaq 0x25b31(%rip), %rdi     # 0x711a1
leaq 0x27aa4(%rip), %rsi     # 0x7311b
movl $0x129, %edx            # imm = 0x129
leaq 0x27ac5(%rip), %rcx     # 0x73148
callq 0x5260
movq 0x30(%rsp), %rax
cmpq $0x0, 0x68(%rax)
je 0x4b696
jmp 0x4b6b5
leaq 0x25b5d(%rip), %rdi     # 0x711fa
leaq 0x27a77(%rip), %rsi     # 0x7311b
movl $0x12a, %edx            # imm = 0x12A
leaq 0x27a98(%rip), %rcx     # 0x73148
callq 0x5260
movq $0x0, 0x68(%rsp)
testb $0x1, 0x7b(%rsp)
je 0x4b708
movq 0x30(%rsp), %rax
movq 0x60(%rax), %rdi
movl 0x7c(%rsp), %esi
movq (%rdi), %rax
callq *0x20(%rax)
movl %eax, %ecx
movq 0x30(%rsp), %rax
movl %ecx, 0x74(%rsp)
movq 0x10(%rax), %rdi
movslq 0x7c(%rsp), %rsi
callq 0xf9a0
movq %rax, %rdi
movslq 0x74(%rsp), %rsi
callq 0xf9c0
movq (%rax), %rax
movq %rax, 0x68(%rsp)
jmp 0x4b749
movq 0x30(%rsp), %rax
movq 0x68(%rax), %rdi
movl 0x7c(%rsp), %esi
movq (%rdi), %rax
callq *0x20(%rax)
movl %eax, %ecx
movq 0x30(%rsp), %rax
movl %ecx, 0x74(%rsp)
movq 0x8(%rax), %rdi
movslq 0x7c(%rsp), %rsi
callq 0xf9a0
movq %rax, %rdi
movslq 0x74(%rsp), %rsi
callq 0xf9c0
movq (%rax), %rax
movq %rax, 0x68(%rsp)
movq 0x68(%rsp), %rax
testb $0x1, (%rax)
je 0x4bb37
leaq 0x48892(%rip), %rax     # 0x93ff0
testb $0x1, 0x1cc(%rax)
je 0x4b976
movb $0x0, 0x67(%rsp)
movq 0x68(%rsp), %rax
movsd 0x130(%rax), %xmm0
leaq 0x4886c(%rip), %rax     # 0x93ff0
cvtsi2sdl 0x1e8(%rax), %xmm1
movl $0x1, %eax
xorl %ecx, %ecx
ucomisd %xmm1, %xmm0
cmoval %ecx, %eax
movl %eax, 0x60(%rsp)
cmpl $0x0, 0x60(%rsp)
jne 0x4b7ac
testb $0x1, 0x7b(%rsp)
jne 0x4b7ba
cmpl $0x1, 0x60(%rsp)
jne 0x4b7bf
testb $0x1, 0x7b(%rsp)
jne 0x4b7bf
movb $0x1, 0x67(%rsp)
testb $0x1, 0x67(%rsp)
je 0x4b87e
movq 0x30(%rsp), %rdi
addq $0x288, %rdi            # imm = 0x288
xorl %eax, %eax
movl %eax, %esi
callq 0x4d780
movq (%rax), %rax
movq 0x68(%rsp), %rcx
movq 0x8(%rcx), %rdi
movq 0x68(%rsp), %rcx
movq 0x10(%rcx), %rsi
callq *%rax
movq 0x30(%rsp), %rdi
movl %eax, 0x5c(%rsp)
addq $0x270, %rdi            # imm = 0x270
callq 0xf840
cmpq $0x1, %rax
jbe 0x4b844
movq 0x30(%rsp), %rdi
addq $0x288, %rdi            # imm = 0x288
movl $0x1, %esi
callq 0x4d780
movq (%rax), %rax
movq 0x68(%rsp), %rcx
movq 0x8(%rcx), %rdi
movq 0x68(%rsp), %rcx
movq 0x10(%rcx), %rsi
callq *%rax
movl %eax, 0x2c(%rsp)
jmp 0x4b84c
xorl %eax, %eax
movl %eax, 0x2c(%rsp)
jmp 0x4b84c
movq 0x30(%rsp), %rdi
movl 0x2c(%rsp), %eax
movl %eax, 0x58(%rsp)
addq $0x418, %rdi            # imm = 0x418
movslq 0x5c(%rsp), %rsi
callq 0xef70
movq %rax, %rdi
movslq 0x58(%rsp), %rsi
callq 0xef90
movl (%rax), %ecx
addl $0x1, %ecx
movl %ecx, (%rax)
movl $0x0, 0x54(%rsp)
movq 0x30(%rsp), %rdi
movl 0x54(%rsp), %eax
movq %rax, 0x20(%rsp)
addq $0x270, %rdi            # imm = 0x270
callq 0xf840
movq %rax, %rcx
movq 0x20(%rsp), %rax
cmpq %rcx, %rax
jae 0x4b974
movq 0x30(%rsp), %rdi
addq $0x288, %rdi            # imm = 0x288
movl 0x54(%rsp), %eax
movl %eax, %esi
callq 0x4d780
movq (%rax), %rax
movq 0x68(%rsp), %rcx
movq 0x8(%rcx), %rdi
movq 0x68(%rsp), %rcx
movq 0x10(%rcx), %rsi
callq *%rax
movl %eax, 0x50(%rsp)
movq 0x68(%rsp), %rdi
addq $0xd0, %rdi
movl 0x54(%rsp), %eax
movl %eax, %esi
callq 0xf900
movl 0x4(%rax), %eax
movl %eax, 0x4c(%rsp)
movb $0x0, 0x4b(%rsp)
cmpl $0x1, 0x60(%rsp)
jne 0x4b91b
cmpl $0x0, 0x4c(%rsp)
jne 0x4b91b
movb $0x1, 0x4b(%rsp)
jmp 0x4b930
cmpl $0x0, 0x60(%rsp)
jne 0x4b92e
cmpl $0x1, 0x4c(%rsp)
jne 0x4b92e
movb $0x1, 0x4b(%rsp)
jmp 0x4b930
testb $0x1, 0x4b(%rsp)
je 0x4b962
movq 0x30(%rsp), %rdi
addq $0x400, %rdi            # imm = 0x400
movl 0x54(%rsp), %eax
movl %eax, %esi
callq 0xef70
movq %rax, %rdi
movslq 0x50(%rsp), %rsi
callq 0xef90
movl (%rax), %ecx
addl $0x1, %ecx
movl %ecx, (%rax)
jmp 0x4b964
movl 0x54(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x54(%rsp)
jmp 0x4b886
jmp 0x4b976
movq 0x68(%rsp), %rax
testb $0x1, 0x148(%rax)
je 0x4badf
movq 0x68(%rsp), %rax
movsd 0x130(%rax), %xmm0
leaq 0x48654(%rip), %rax     # 0x93ff0
cvtsi2sdl 0x1e8(%rax), %xmm1
ucomisd %xmm1, %xmm0
jbe 0x4ba47
movl $0x0, 0x44(%rsp)
movq 0x30(%rsp), %rdi
movl 0x44(%rsp), %eax
movq %rax, 0x18(%rsp)
addq $0x270, %rdi            # imm = 0x270
callq 0xf840
movq %rax, %rcx
movq 0x18(%rsp), %rax
cmpq %rcx, %rax
jae 0x4ba42
movq 0x30(%rsp), %rdi
addq $0x288, %rdi            # imm = 0x288
movl 0x44(%rsp), %eax
movl %eax, %esi
callq 0x4d780
movq (%rax), %rax
movq 0x68(%rsp), %rcx
movq 0x8(%rcx), %rdi
movq 0x68(%rsp), %rcx
movq 0x10(%rcx), %rsi
callq *%rax
movq 0x30(%rsp), %rdi
movl %eax, 0x40(%rsp)
addq $0x270, %rdi            # imm = 0x270
movl 0x44(%rsp), %eax
movl %eax, %esi
callq 0xf8c0
movq (%rax), %rdi
movl 0x40(%rsp), %esi
callq 0x2d420
movl 0x44(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x44(%rsp)
jmp 0x4b9b6
jmp 0x4badd
movl $0x0, 0x3c(%rsp)
movq 0x30(%rsp), %rdi
movl 0x3c(%rsp), %eax
movq %rax, 0x10(%rsp)
addq $0x270, %rdi            # imm = 0x270
callq 0xf840
movq %rax, %rcx
movq 0x10(%rsp), %rax
cmpq %rcx, %rax
jae 0x4badb
movq 0x30(%rsp), %rdi
addq $0x288, %rdi            # imm = 0x288
movl 0x3c(%rsp), %eax
movl %eax, %esi
callq 0x4d780
movq (%rax), %rax
movq 0x68(%rsp), %rcx
movq 0x8(%rcx), %rdi
movq 0x68(%rsp), %rcx
movq 0x10(%rcx), %rsi
callq *%rax
movq 0x30(%rsp), %rdi
movl %eax, 0x38(%rsp)
addq $0x270, %rdi            # imm = 0x270
movl 0x3c(%rsp), %eax
movl %eax, %esi
callq 0xf8c0
movq (%rax), %rdi
movl 0x38(%rsp), %esi
callq 0x2d480
movl 0x3c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x3c(%rsp)
jmp 0x4ba4f
jmp 0x4badd
jmp 0x4badf
movq 0x68(%rsp), %rax
cmpl $0x0, 0x11c(%rax)
jne 0x4bb35
movq 0x68(%rsp), %rax
cmpl $0x0, 0x120(%rax)
jne 0x4bb35
movq 0x30(%rsp), %rdi
movq %rdi, %rax
addq $0x338, %rax            # imm = 0x338
movq %rax, 0x8(%rsp)
addq $0x338, %rdi            # imm = 0x338
callq 0xfa40
movq 0x8(%rsp), %rdi
movq %rax, %rsi
subq $0x1, %rsi
callq 0xfa20
movq (%rax), %rcx
addq $0x1, %rcx
movq %rcx, (%rax)
jmp 0x4bb37
movq 0x30(%rsp), %rdi
movl 0x7c(%rsp), %esi
movl 0x74(%rsp), %edx
movb 0x7b(%rsp), %al
andb $0x1, %al
movzbl %al, %ecx
callq 0x4bb60
movl 0x74(%rsp), %eax
addq $0x88, %rsp
retq
nop