// File: /workspace/github_cpp_makefile_star2_O3/CMU-SAFARI[P]MQSim/src/ssd/Data_Cache_Manager_Flash_Simple.cpp
// Function: SSD_Components::Data_Cache_Manager_Flash_Simple::handle_transaction_serviced_signal_from_PHY(SSD_Components::NVM_Transaction_Flash*)
void Data_Cache_Manager_Flash_Simple::handle_transaction_serviced_signal_from_PHY(NVM_Transaction_Flash* transaction)
	{
		//First check if the transaction source is a user request or the cache itself
		if (transaction->Source != Transaction_Source_Type::USERIO && transaction->Source != Transaction_Source_Type::CACHE) {
			return;
		}

		if (transaction->Source == Transaction_Source_Type::USERIO)
			_my_instance->broadcast_user_memory_transaction_serviced_signal(transaction);
		/* This is an update read (a read that is generated for a write request that partially updates page data).
		*  An update read transaction is issued in Address Mapping Unit, but is consumed in data cache manager.*/
		if (transaction->Type == Transaction_Type::READ) {
			if (((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite != NULL) {
				((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite->RelatedRead = NULL;
				return;
			}
			switch (Data_Cache_Manager_Flash_Simple::caching_mode_per_input_stream[transaction->Stream_id])
			{
				case Caching_Mode::TURNED_OFF:
				case Caching_Mode::WRITE_CACHE:
					transaction->UserIORequest->Transaction_list.remove(transaction);
					if (_my_instance->is_user_request_finished(transaction->UserIORequest)) {
						_my_instance->broadcast_user_request_serviced_signal(transaction->UserIORequest);
					}
					break;
				default:
					PRINT_ERROR("The specified caching mode is not not support in simple cache manager!")
			}
		} else { //This is a write request
			switch (Data_Cache_Manager_Flash_Simple::caching_mode_per_input_stream[transaction->Stream_id])
			{
				case Caching_Mode::TURNED_OFF:
					transaction->UserIORequest->Transaction_list.remove(transaction);
					if (_my_instance->is_user_request_finished(transaction->UserIORequest)) {
						_my_instance->broadcast_user_request_serviced_signal(transaction->UserIORequest);
					}
					break;
				case Caching_Mode::WRITE_CACHE:
				{
					((Data_Cache_Manager_Flash_Simple*)_my_instance)->back_pressure_buffer_depth -= transaction->Data_and_metadata_size_in_byte / SECTOR_SIZE_IN_BYTE + (transaction->Data_and_metadata_size_in_byte % SECTOR_SIZE_IN_BYTE == 0 ? 0 : 1);

					if (((Data_Cache_Manager_Flash_Simple*)_my_instance)->data_cache->Exists(transaction->Stream_id, ((NVM_Transaction_Flash_WR*)transaction)->LPA)) {
						Data_Cache_Slot_Type slot = ((Data_Cache_Manager_Flash_Simple*)_my_instance)->data_cache->Get_slot(transaction->Stream_id, ((NVM_Transaction_Flash_WR*)transaction)->LPA);
						sim_time_type timestamp = slot.Timestamp;
						NVM::memory_content_type content = slot.Content;
						if (((NVM_Transaction_Flash_WR*)transaction)->DataTimeStamp >= timestamp) {
							((Data_Cache_Manager_Flash_Simple*)_my_instance)->data_cache->Remove_slot(transaction->Stream_id, ((NVM_Transaction_Flash_WR*)transaction)->LPA);
						}
					}

					for (unsigned int i = 0; i < _my_instance->stream_count; i++) {
						((Data_Cache_Manager_Flash_Simple*)_my_instance)->request_queue_turn++;
						((Data_Cache_Manager_Flash_Simple*)_my_instance)->request_queue_turn %= ((Data_Cache_Manager_Flash_Simple*)_my_instance)->stream_count;
						if (((Data_Cache_Manager_Flash_Simple*)_my_instance)->waiting_user_requests_queue_for_dram_free_slot[((Data_Cache_Manager_Flash_Simple*)_my_instance)->request_queue_turn].size() > 0) {
							auto user_request = ((Data_Cache_Manager_Flash_Simple*)_my_instance)->waiting_user_requests_queue_for_dram_free_slot[((Data_Cache_Manager_Flash_Simple*)_my_instance)->request_queue_turn].begin();
							((Data_Cache_Manager_Flash_Simple*)_my_instance)->write_to_destage_buffer(*user_request);
							if ((*user_request)->Transaction_list.size() == 0) {
								((Data_Cache_Manager_Flash_Simple*)_my_instance)->waiting_user_requests_queue_for_dram_free_slot[((Data_Cache_Manager_Flash_Simple*)_my_instance)->request_queue_turn].remove(*user_request);
							}
							//The traffic load on the backend is high and the waiting requests cannot be serviced
							if (((Data_Cache_Manager_Flash_Simple*)_my_instance)->back_pressure_buffer_depth >= ((Data_Cache_Manager_Flash_Simple*)_my_instance)->back_pressure_buffer_max_depth) {
								break;
							}
						}
					}
					break;
				}
				default:
					PRINT_ERROR("The specified caching mode is not not support in simple cache manager!")
			}
		}
	}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %rbx
subq $0x38, %rsp
movl 0x4(%rdi), %eax
cmpl $0x1, %eax
ja 0x34ff2
movq %rdi, %rbx
testl %eax, %eax
jne 0x34e53
leaq 0x3a7d8(%rip), %rax     # 0x6f620
movq (%rax), %rdi
movq %rbx, %rsi
callq 0x32256
cmpl $0x0, 0x8(%rbx)
je 0x34eb8
leaq 0x3a7c8(%rip), %rax     # 0x6f628
movq (%rax), %rcx
movzwl (%rbx), %eax
movl (%rcx,%rax,4), %ecx
testl %ecx, %ecx
je 0x34ed8
cmpl $0x3, %ecx
jne 0x3501e
movq 0x10(%rbx), %rdi
addq $0x40, %rdi
leaq 0x8(%rsp), %rsi
movq %rbx, (%rsi)
callq 0x344cc
movq 0x10(%rbx), %rsi
cmpq $0x0, 0x50(%rsi)
jne 0x34ff2
cmpl $0x0, 0x58(%rsi)
jne 0x34ff2
leaq 0x3a775(%rip), %rax     # 0x6f620
movq (%rax), %rdi
callq 0x321ee
jmp 0x34ff2
movq 0x88(%rbx), %rax
testq %rax, %rax
je 0x34ffd
movq $0x0, 0x88(%rax)
jmp 0x34ff2
movl 0x50(%rbx), %ecx
movl %ecx, %edx
shrl $0x9, %edx
andl $0x1ff, %ecx            # imm = 0x1FF
leaq 0x3a733(%rip), %r15     # 0x6f620
movq (%r15), %rsi
movl 0xe0(%rsi), %edi
subl %edx, %edi
cmpl $0x1, %ecx
adcl $-0x1, %edi
movl %edi, 0xe0(%rsi)
movq 0xc0(%rsi), %rdi
movq 0x58(%rbx), %rdx
movzwl %ax, %esi
callq 0x31522
testb %al, %al
je 0x34f5c
movq (%r15), %rax
movq 0xc0(%rax), %rsi
movzwl (%rbx), %edx
movq 0x58(%rbx), %rcx
leaq 0x8(%rsp), %r14
movq %r14, %rdi
callq 0x3158a
movq 0xa0(%rbx), %rax
cmpq 0x18(%r14), %rax
jb 0x34f5c
movq (%r15), %rax
movq 0xc0(%rax), %rdi
movzwl (%rbx), %esi
movq 0x58(%rbx), %rdx
callq 0x31ae6
movq (%r15), %rdi
movl 0x74(%rdi), %ecx
testl %ecx, %ecx
je 0x34ff2
xorl %ebp, %ebp
movl 0xd8(%rdi), %eax
incl %eax
xorl %edx, %edx
divl %ecx
movl %edx, 0xd8(%rdi)
movq 0xd0(%rdi), %rax
movslq %edx, %rcx
leaq (%rcx,%rcx,2), %rcx
cmpq $0x0, 0x10(%rax,%rcx,8)
je 0x34fe5
leaq (%rax,%rcx,8), %rax
movq (%rax), %rbx
movq 0x10(%rbx), %rsi
callq 0x35734
movq 0x10(%rbx), %rax
cmpq $0x0, 0x50(%rax)
jne 0x34fd4
addq $0x10, %rbx
movq (%r15), %rax
movslq 0xd8(%rax), %rcx
leaq (%rcx,%rcx,2), %rdi
shlq $0x3, %rdi
addq 0xd0(%rax), %rdi
movq %rbx, %rsi
callq 0x36150
movq (%r15), %rdi
movl 0xe0(%rdi), %eax
cmpl 0xdc(%rdi), %eax
jae 0x34ff2
incl %ebp
movl 0x74(%rdi), %ecx
cmpl %ecx, %ebp
jb 0x34f6c
addq $0x38, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
leaq 0x3a624(%rip), %rax     # 0x6f628
movq (%rax), %rax
movzwl (%rbx), %ecx
movl (%rax,%rcx,4), %eax
cmpl $0x3, %eax
je 0x34e76
testl %eax, %eax
je 0x34e76
movq 0x39fcb(%rip), %rbx     # 0x6eff0
leaq 0x2157c(%rip), %rsi     # 0x565a8
movq %rbx, %rdi
callq 0x7390
leaq 0x241b3(%rip), %rsi     # 0x591ee
movq %rbx, %rdi
callq 0x7390
movq %rax, %rdi
callq 0x71c0
movq 0x39f7e(%rip), %rdi     # 0x6efd0
callq 0x7430
movl $0x1, %edi
callq 0x7440
nop