// File: 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:
subq $0x88, %rsp
movq %rdi, 0x80(%rsp)
movq 0x80(%rsp), %rax
cmpl $0x0, 0x4(%rax)
je 0x6f4e0
movq 0x80(%rsp), %rax
cmpl $0x1, 0x4(%rax)
je 0x6f4e0
jmp 0x6f9b3
movq 0x80(%rsp), %rax
cmpl $0x0, 0x4(%rax)
jne 0x6f505
leaq 0x6b1eb(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x80(%rsp), %rsi
callq 0x67ca0
movq 0x80(%rsp), %rax
cmpl $0x0, 0x8(%rax)
jne 0x6f62a
movq 0x80(%rsp), %rax
cmpq $0x0, 0x88(%rax)
je 0x6f548
movq 0x80(%rsp), %rax
movq 0x88(%rax), %rax
movq $0x0, 0x88(%rax)
jmp 0x6f9b3
leaq 0x6b199(%rip), %rax     # 0xda6e8
movq (%rax), %rax
movq 0x80(%rsp), %rcx
movzwl (%rcx), %ecx
movl (%rax,%rcx,4), %eax
movl %eax, 0x1c(%rsp)
testl %eax, %eax
je 0x6f575
jmp 0x6f56a
movl 0x1c(%rsp), %eax
subl $0x3, %eax
jne 0x6f5da
jmp 0x6f575
movq 0x80(%rsp), %rax
movq 0x10(%rax), %rdi
addq $0x40, %rdi
movq 0x80(%rsp), %rax
movq %rax, 0x78(%rsp)
leaq 0x78(%rsp), %rsi
callq 0x6c2c0
leaq 0x6b13d(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x80(%rsp), %rax
movq 0x10(%rax), %rsi
callq 0x6c3c0
testb $0x1, %al
jne 0x6f5bd
jmp 0x6f5d8
leaq 0x6b11c(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x80(%rsp), %rax
movq 0x10(%rax), %rsi
callq 0x67bf0
jmp 0x6f625
movq 0x6aa0f(%rip), %rdi     # 0xd9ff0
leaq 0x3b300(%rip), %rsi     # 0xaa8e8
callq 0x8440
movq 0x6a9fc(%rip), %rdi     # 0xd9ff0
leaq 0x3dc83(%rip), %rsi     # 0xad27e
callq 0x8440
movq %rax, %rdi
movq 0x6a94e(%rip), %rsi     # 0xd9f58
callq 0x8480
movq 0x6a9ba(%rip), %rdi     # 0xd9fd0
callq 0x84f0
movl $0x1, %edi
callq 0x8500
jmp 0x6f9b3
leaq 0x6b0b7(%rip), %rax     # 0xda6e8
movq (%rax), %rax
movq 0x80(%rsp), %rcx
movzwl (%rcx), %ecx
movl (%rax,%rcx,4), %eax
movl %eax, 0x18(%rsp)
testl %eax, %eax
je 0x6f6c3
jmp 0x6f64c
movl 0x18(%rsp), %eax
subl $0x3, %eax
jne 0x6f966
jmp 0x6f65b
movq 0x80(%rsp), %rax
movq 0x10(%rax), %rdi
addq $0x40, %rdi
movq 0x80(%rsp), %rax
movq %rax, 0x70(%rsp)
leaq 0x70(%rsp), %rsi
callq 0x6c2c0
leaq 0x6b057(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x80(%rsp), %rax
movq 0x10(%rax), %rsi
callq 0x6c3c0
testb $0x1, %al
jne 0x6f6a3
jmp 0x6f6be
leaq 0x6b036(%rip), %rax     # 0xda6e0
movq (%rax), %rdi
movq 0x80(%rsp), %rax
movq 0x10(%rax), %rsi
callq 0x67bf0
jmp 0x6f9b1
movq 0x80(%rsp), %rax
movl 0x50(%rax), %edx
shrl $0x9, %edx
movq 0x80(%rsp), %rax
movl 0x50(%rax), %esi
andl $0x1ff, %esi            # imm = 0x1FF
movl $0x1, %eax
xorl %ecx, %ecx
cmpl $0x0, %esi
cmovel %ecx, %eax
addl %eax, %edx
leaq 0x6afe8(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movl 0xe0(%rax), %ecx
subl %edx, %ecx
movl %ecx, 0xe0(%rax)
leaq 0x6afd0(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xc0(%rax), %rdi
movq 0x80(%rsp), %rax
movw (%rax), %ax
movq 0x80(%rsp), %rcx
movq 0x58(%rcx), %rdx
movzwl %ax, %esi
callq 0x64390
testb $0x1, %al
jne 0x6f742
jmp 0x6f7d3
leaq 0x6af97(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xc0(%rax), %rsi
movq 0x80(%rsp), %rax
movw (%rax), %ax
movq 0x80(%rsp), %rcx
movq 0x58(%rcx), %rcx
leaq 0x40(%rsp), %rdi
movzwl %ax, %edx
callq 0x644c0
movq 0x58(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0x50(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0x80(%rsp), %rax
movq 0xa0(%rax), %rax
cmpq 0x38(%rsp), %rax
jb 0x6f7d1
leaq 0x6af38(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xc0(%rax), %rdi
movq 0x80(%rsp), %rax
movw (%rax), %ax
movq 0x80(%rsp), %rcx
movq 0x58(%rcx), %rdx
movzwl %ax, %esi
callq 0x65060
jmp 0x6f7d3
movl $0x0, 0x2c(%rsp)
movl 0x2c(%rsp), %eax
leaq 0x6aefa(%rip), %rcx     # 0xda6e0
movq (%rcx), %rcx
cmpl 0x74(%rcx), %eax
jae 0x6f964
leaq 0x6aee7(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movl 0xd8(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0xd8(%rax)
leaq 0x6aece(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movl 0x74(%rax), %ecx
leaq 0x6aec1(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq %rax, 0x10(%rsp)
movl 0xd8(%rax), %eax
xorl %edx, %edx
divl %ecx
movq 0x10(%rsp), %rax
movl %edx, 0xd8(%rax)
leaq 0x6ae9d(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xd0(%rax), %rdi
leaq 0x6ae8c(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movslq 0xd8(%rax), %rax
imulq $0x18, %rax, %rax
addq %rax, %rdi
callq 0x709b0
cmpq $0x0, %rax
jbe 0x6f952
leaq 0x6ae65(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xd0(%rax), %rdi
leaq 0x6ae54(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movslq 0xd8(%rax), %rax
imulq $0x18, %rax, %rax
addq %rax, %rdi
callq 0x6bfd0
movq %rax, 0x20(%rsp)
leaq 0x6ae32(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq %rax, 0x8(%rsp)
leaq 0x20(%rsp), %rdi
callq 0x6c050
movq 0x8(%rsp), %rdi
movq (%rax), %rsi
callq 0x6ff80
leaq 0x20(%rsp), %rdi
callq 0x6c050
movq (%rax), %rdi
addq $0x40, %rdi
callq 0x59910
cmpq $0x0, %rax
jne 0x6f92c
leaq 0x6adf0(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movq 0xd0(%rax), %rax
leaq 0x6addf(%rip), %rcx     # 0xda6e0
movq (%rcx), %rcx
movslq 0xd8(%rcx), %rcx
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movq %rax, (%rsp)
leaq 0x20(%rsp), %rdi
callq 0x6c050
movq (%rsp), %rdi
movq %rax, %rsi
callq 0x709e0
leaq 0x6adad(%rip), %rax     # 0xda6e0
movq (%rax), %rax
movl 0xe0(%rax), %eax
leaq 0x6ad9d(%rip), %rcx     # 0xda6e0
movq (%rcx), %rcx
cmpl 0xdc(%rcx), %eax
jb 0x6f950
jmp 0x6f964
jmp 0x6f952
jmp 0x6f954
movl 0x2c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x2c(%rsp)
jmp 0x6f7db
jmp 0x6f9b1
movq 0x6a683(%rip), %rdi     # 0xd9ff0
leaq 0x3af74(%rip), %rsi     # 0xaa8e8
callq 0x8440
movq 0x6a670(%rip), %rdi     # 0xd9ff0
leaq 0x3d8f7(%rip), %rsi     # 0xad27e
callq 0x8440
movq %rax, %rdi
movq 0x6a5c2(%rip), %rsi     # 0xd9f58
callq 0x8480
movq 0x6a62e(%rip), %rdi     # 0xd9fd0
callq 0x84f0
movl $0x1, %edi
callq 0x8500
jmp 0x6f9b3
addq $0x88, %rsp
retq
nopl (%rax,%rax)