// File: /workspace/github_cpp_makefile_star2_O2/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 0x2b8a1
movq %rdi, %rbx
testl %eax, %eax
jne 0x2b82f
leaq 0x36dcc(%rip), %rax     # 0x625f0
movq (%rax), %rdi
movq %rbx, %rsi
callq 0x295b0
cmpl $0x0, 0x8(%rbx)
je 0x2b889
leaq 0x36dbc(%rip), %rax     # 0x625f8
movq (%rax), %rcx
movzwl (%rbx), %eax
movl (%rcx,%rax,4), %ecx
testl %ecx, %ecx
je 0x2b8ac
cmpl $0x3, %ecx
jne 0x2b9e0
movq 0x10(%rbx), %rdi
addq $0x40, %rdi
leaq 0x8(%rsp), %rsi
movq %rbx, (%rsi)
callq 0x2ab4c
movq 0x10(%rbx), %rsi
cmpq $0x0, 0x50(%rsi)
jne 0x2b8a1
cmpl $0x0, 0x58(%rsi)
jne 0x2b8a1
leaq 0x36d71(%rip), %rax     # 0x625f0
movq (%rax), %rdi
callq 0x2956e
jmp 0x2b8a1
movq 0x88(%rbx), %rax
testq %rax, %rax
je 0x2b9bf
andq $0x0, 0x88(%rax)
addq $0x38, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
movl 0x50(%rbx), %ecx
movl %ecx, %edx
shrl $0x9, %edx
andl $0x1ff, %ecx            # imm = 0x1FF
leaq 0x36d2f(%rip), %r15     # 0x625f0
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 0x287ce
testb %al, %al
je 0x2b930
movq (%r15), %rax
movq 0xc0(%rax), %rsi
movzwl (%rbx), %edx
movq 0x58(%rbx), %rcx
leaq 0x8(%rsp), %r14
movq %r14, %rdi
callq 0x28822
movq 0xa0(%rbx), %rax
cmpq 0x18(%r14), %rax
jb 0x2b930
movq (%r15), %rax
movq 0xc0(%rax), %rdi
movzwl (%rbx), %esi
movq 0x58(%rbx), %rdx
callq 0x28d10
movq (%r15), %rdi
xorl %ebp, %ebp
movl 0x74(%rdi), %ecx
cmpl %ecx, %ebp
jae 0x2b8a1
movl 0xd8(%rdi), %eax
incl %eax
xorl %edx, %edx
divl %ecx
movl %edx, 0xd8(%rdi)
movq 0xd0(%rdi), %rax
movslq %edx, %rcx
imulq $0x18, %rcx, %rcx
cmpq $0x0, 0x10(%rax,%rcx)
je 0x2b9b8
addq %rcx, %rax
movq (%rax), %rbx
movq 0x10(%rbx), %rsi
callq 0x2bcc8
movq 0x10(%rbx), %rax
cmpq $0x0, 0x50(%rax)
jne 0x2b9a3
addq $0x10, %rbx
movq (%r15), %rax
movslq 0xd8(%rax), %rcx
imulq $0x18, %rcx, %rdi
addq 0xd0(%rax), %rdi
movq %rbx, %rsi
callq 0x2c194
movq (%r15), %rdi
movl 0xe0(%rdi), %eax
cmpl 0xdc(%rdi), %eax
jae 0x2b8a1
incl %ebp
jmp 0x2b935
leaq 0x36c32(%rip), %rax     # 0x625f8
movq (%rax), %rax
movzwl (%rbx), %ecx
movl (%rax,%rcx,4), %eax
cmpl $0x3, %eax
je 0x2b852
testl %eax, %eax
je 0x2b852
movq 0x36609(%rip), %rbx     # 0x61ff0
leaq 0x18b9a(%rip), %rsi     # 0x44588
movq %rbx, %rdi
callq 0x7360
leaq 0x1b6c1(%rip), %rsi     # 0x470be
movq %rbx, %rdi
callq 0x7360
movq %rax, %rdi
callq 0x71a0
movq 0x365bc(%rip), %rdi     # 0x61fd0
callq 0x73d0
pushq $0x1
popq %rdi
callq 0x73e0
nop