// File: /workspace/github_cpp_makefile_star2_O1/CMU-SAFARI[P]MQSim/src/ssd/GC_and_WL_Unit_Base.cpp
// Function: SSD_Components::GC_and_WL_Unit_Base::handle_transaction_serviced_signal_from_PHY(SSD_Components::NVM_Transaction_Flash*)
void GC_and_WL_Unit_Base::handle_transaction_serviced_signal_from_PHY(NVM_Transaction_Flash* transaction)
	{
		PlaneBookKeepingType* pbke = &(_my_instance->block_manager->plane_manager[transaction->Address.ChannelID][transaction->Address.ChipID][transaction->Address.DieID][transaction->Address.PlaneID]);

		switch (transaction->Source) {
			case Transaction_Source_Type::USERIO:
			case Transaction_Source_Type::MAPPING:
			case Transaction_Source_Type::CACHE:
				switch (transaction->Type)
				{
					case Transaction_Type::READ:
						_my_instance->block_manager->Read_transaction_serviced(transaction->Address);
						break;
					case Transaction_Type::WRITE:
						_my_instance->block_manager->Program_transaction_serviced(transaction->Address);
						break;
					default:
						PRINT_ERROR("Unexpected situation in the GC_and_WL_Unit_Base function!")
				}
				if (_my_instance->block_manager->Block_has_ongoing_gc_wl(transaction->Address)) {
					if (_my_instance->block_manager->Can_execute_gc_wl(transaction->Address)) {
						NVM::FlashMemory::Physical_Page_Address gc_wl_candidate_address(transaction->Address);
						Block_Pool_Slot_Type* block = &pbke->Blocks[transaction->Address.BlockID];
						Stats::Total_gc_executions++;
						_my_instance->tsu->Prepare_for_transaction_submit();
						NVM_Transaction_Flash_ER* gc_wl_erase_tr = new NVM_Transaction_Flash_ER(Transaction_Source_Type::GC_WL, block->Stream_id, gc_wl_candidate_address);
						
						//If there are some valid pages in block, then prepare flash transactions for page movement
						if (block->Current_page_write_index - block->Invalid_page_count > 0) {
							//address_mapping_unit->Lock_physical_block_for_gc(gc_candidate_address);//Lock the block, so no user request can intervene while the GC is progressing
							NVM_Transaction_Flash_RD* gc_wl_read = NULL;
							NVM_Transaction_Flash_WR* gc_wl_write = NULL;
							for (flash_page_ID_type pageID = 0; pageID < block->Current_page_write_index; pageID++) {
								if (_my_instance->block_manager->Is_page_valid(block, pageID)) {
									Stats::Total_page_movements_for_gc++;
									gc_wl_candidate_address.PageID = pageID;
									if (_my_instance->use_copyback) {
										gc_wl_write = new NVM_Transaction_Flash_WR(Transaction_Source_Type::GC_WL, block->Stream_id, _my_instance->sector_no_per_page * SECTOR_SIZE_IN_BYTE,
											NO_LPA, _my_instance->address_mapping_unit->Convert_address_to_ppa(gc_wl_candidate_address), NULL, 0, NULL, 0, INVALID_TIME_STAMP);
										gc_wl_write->ExecutionMode = WriteExecutionModeType::COPYBACK;
										_my_instance->tsu->Submit_transaction(gc_wl_write);
									} else {
										gc_wl_read = new NVM_Transaction_Flash_RD(Transaction_Source_Type::GC_WL, block->Stream_id, _my_instance->sector_no_per_page * SECTOR_SIZE_IN_BYTE,
											NO_LPA, _my_instance->address_mapping_unit->Convert_address_to_ppa(gc_wl_candidate_address), gc_wl_candidate_address, NULL, 0, NULL, 0, INVALID_TIME_STAMP);
										gc_wl_write = new NVM_Transaction_Flash_WR(Transaction_Source_Type::GC_WL, block->Stream_id, _my_instance->sector_no_per_page * SECTOR_SIZE_IN_BYTE,
											NO_LPA, NO_PPA, gc_wl_candidate_address, NULL, 0, gc_wl_read, 0, INVALID_TIME_STAMP);
										gc_wl_write->ExecutionMode = WriteExecutionModeType::SIMPLE;
										gc_wl_write->RelatedErase = gc_wl_erase_tr;
										gc_wl_read->RelatedWrite = gc_wl_write;
										_my_instance->tsu->Submit_transaction(gc_wl_read);//Only the read transaction would be submitted. The Write transaction is submitted when the read transaction is finished and the LPA of the target page is determined
									}
									gc_wl_erase_tr->Page_movement_activities.push_back(gc_wl_write);
								}
							}
						}
						block->Erase_transaction = gc_wl_erase_tr;
						_my_instance->tsu->Schedule();
					}
				}

				return;
		}

		switch (transaction->Type) {
			case Transaction_Type::READ:
			{
				PPA_type ppa;
				MPPN_type mppa;
				page_status_type page_status_bitmap;
				if (pbke->Blocks[transaction->Address.BlockID].Holds_mapping_data) {
					_my_instance->address_mapping_unit->Get_translation_mapping_info_for_gc(transaction->Stream_id, (MVPN_type)transaction->LPA, mppa, page_status_bitmap);
					//There has been no write on the page since GC start, and it is still valid
					if (mppa == transaction->PPA) {
						_my_instance->tsu->Prepare_for_transaction_submit();
						((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite->write_sectors_bitmap = FULL_PROGRAMMED_PAGE;
						((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite->LPA = transaction->LPA;
						((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite->RelatedRead = NULL;
						_my_instance->address_mapping_unit->Allocate_new_page_for_gc(((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite, pbke->Blocks[transaction->Address.BlockID].Holds_mapping_data);
						_my_instance->tsu->Submit_transaction(((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite);
						_my_instance->tsu->Schedule();
					} else {
						PRINT_ERROR("Inconsistency found when moving a page for GC/WL!")
					}
				} else {
					_my_instance->address_mapping_unit->Get_data_mapping_info_for_gc(transaction->Stream_id, transaction->LPA, ppa, page_status_bitmap);
					
					//There has been no write on the page since GC start, and it is still valid
					if (ppa == transaction->PPA) {
						_my_instance->tsu->Prepare_for_transaction_submit();
						((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite->write_sectors_bitmap = page_status_bitmap;
						((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite->LPA = transaction->LPA;
						((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite->RelatedRead = NULL;
						_my_instance->address_mapping_unit->Allocate_new_page_for_gc(((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite, pbke->Blocks[transaction->Address.BlockID].Holds_mapping_data);
						_my_instance->tsu->Submit_transaction(((NVM_Transaction_Flash_RD*)transaction)->RelatedWrite);
						_my_instance->tsu->Schedule();
					} else {
						PRINT_ERROR("Inconsistency found when moving a page for GC/WL!")
					}
				}
				break;
			}
			case Transaction_Type::WRITE:
				if (pbke->Blocks[((NVM_Transaction_Flash_WR*)transaction)->RelatedErase->Address.BlockID].Holds_mapping_data) {
					_my_instance->address_mapping_unit->Remove_barrier_for_accessing_mvpn(transaction->Stream_id, (MVPN_type)transaction->LPA);
					DEBUG(Simulator->Time() << ": MVPN=" << (MVPN_type)transaction->LPA << " unlocked!!");
				} else {
					_my_instance->address_mapping_unit->Remove_barrier_for_accessing_lpa(transaction->Stream_id, transaction->LPA);
					DEBUG(Simulator->Time() << ": LPA=" << (MVPN_type)transaction->LPA << " unlocked!!");
				}
				pbke->Blocks[((NVM_Transaction_Flash_WR*)transaction)->RelatedErase->Address.BlockID].Erase_transaction->Page_movement_activities.remove((NVM_Transaction_Flash_WR*)transaction);
				break;
			case Transaction_Type::ERASE:
				pbke->Ongoing_erase_operations.erase(pbke->Ongoing_erase_operations.find(transaction->Address.BlockID));
				_my_instance->block_manager->Add_erased_block_to_pool(transaction->Address);
				_my_instance->block_manager->GC_WL_finished(transaction->Address);
				if (_my_instance->check_static_wl_required(transaction->Address)) {
					_my_instance->run_static_wearleveling(transaction->Address);
				}
				_my_instance->address_mapping_unit->Start_servicing_writes_for_overfull_plane(transaction->Address);//Must be inovked after above statements since it may lead to flash page consumption for waiting program transactions

				if (_my_instance->Stop_servicing_writes(transaction->Address)) {
					_my_instance->Check_gc_required(pbke->Get_free_block_pool_size(), transaction->Address);
				}
				break;
			} //switch (transaction->Type)
	}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xc8, %rsp
movq %rdi, %rbx
movq 0x2fd4b(%rip), %rax     # 0x6f648
movq 0x38(%rax), %rdi
movq 0x8(%rdi), %rdx
leaq 0x38(%rbx), %r15
movl 0x4(%rbx), %ecx
movl 0x38(%rbx), %esi
movq (%rdx,%rsi,8), %rdx
movl 0x3c(%rbx), %esi
movq (%rdx,%rsi,8), %rdx
movl 0x40(%rbx), %esi
movl 0x44(%rbx), %r8d
imulq $0xe0, %r8, %r14
addq (%rdx,%rsi,8), %r14
cmpl $0x3, %ecx
ja 0x3fc34
cmpl $0x2, %ecx
je 0x3fc34
movl 0x8(%rbx), %eax
cmpl $0x1, %eax
je 0x3f958
testl %eax, %eax
jne 0x3ff30
movq %r15, %rsi
callq 0x3e298
jmp 0x3f960
movq %r15, %rsi
callq 0x3e264
movq 0x2fce1(%rip), %rax     # 0x6f648
movq 0x38(%rax), %rdi
movq %r15, %rsi
callq 0x3e15a
testb %al, %al
je 0x3ff1e
movq 0x2fcc6(%rip), %rax     # 0x6f648
movq 0x38(%rax), %rdi
movq %r15, %rsi
callq 0x3e18e
testb %al, %al
je 0x3ff1e
movups 0x38(%rbx), %xmm0
leaq 0x40(%rsp), %r15
movaps %xmm0, (%r15)
movq 0x48(%rbx), %rax
movq %rax, 0x10(%r15)
movq 0x10(%r14), %r14
movl 0x48(%rbx), %ebx
leaq 0x30da3(%rip), %rax     # 0x7075c
incl (%rax)
shlq $0x6, %rbx
movq 0x2fc82(%rip), %rax     # 0x6f648
movq 0x40(%rax), %rdi
callq 0x2fd9e
movl $0x98, %edi
callq 0x73a0
movq %rax, %r12
movzwl 0x20(%r14,%rbx), %edx
movq %rax, %rdi
movl $0x2, %esi
movq %r15, %rcx
callq 0x48a30
addq %rbx, %r14
movl 0x4(%r14), %eax
cmpl 0xc(%r14), %eax
je 0x3fc2b
cmpl $0x0, 0x4(%r14)
je 0x3fc2b
movq %r12, %rax
subq $-0x80, %rax
movq %rax, 0x60(%rsp)
xorl %ebp, %ebp
movq %r14, 0x68(%rsp)
movq %r12, 0x30(%rsp)
movq 0x2fc1b(%rip), %rax     # 0x6f648
movq 0x38(%rax), %rdi
movq %r14, %rsi
movl %ebp, %edx
callq 0x3e338
testb %al, %al
je 0x3fc1f
leaq 0x31116(%rip), %rax     # 0x70b60
incl (%rax)
movl %ebp, 0x54(%rsp)
movq 0x2fbf1(%rip), %r12     # 0x6f648
cmpb $0x1, 0x64(%r12)
jne 0x3fada
movl $0xb0, %edi
callq 0x73a0
movq %rax, %rbx
movzwl 0x20(%r14), %r15d
movl 0x10c(%r12), %r13d
movq 0x30(%r12), %rdi
movq (%rdi), %rax
leaq 0x40(%rsp), %rsi
callq *0x90(%rax)
shll $0x9, %r13d
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rsp)
movups %xmm0, (%rsp)
movq $-0x1, 0x20(%rsp)
movzwl %r15w, %edx
movq %rbx, %rdi
movl $0x2, %esi
movl %r13d, %ecx
movq $-0x1, %r8
movq %rax, %r9
callq 0x48c24
movl $0x1, 0xa8(%rbx)
movq %rbx, %r13
movq 0x30(%rsp), %r14
jmp 0x3fbc4
movl $0xa0, %edi
callq 0x73a0
movq %rax, %rbx
movzwl 0x20(%r14), %r15d
movl 0x10c(%r12), %r13d
movq 0x30(%r12), %rdi
movq (%rdi), %rax
leaq 0x40(%rsp), %r12
movq %r12, %rsi
callq *0x90(%rax)
shll $0x9, %r13d
xorps %xmm0, %xmm0
movups %xmm0, 0x18(%rsp)
movups %xmm0, 0x8(%rsp)
movq %r12, (%rsp)
movq $-0x1, 0x28(%rsp)
movzwl %r15w, %edx
movq %rbx, %rdi
movl $0x2, %esi
movl %r13d, %ecx
movq $-0x1, %r8
movq %rax, %r9
callq 0x48aca
movl $0xb0, %edi
callq 0x73a0
movq %rax, %r13
movzwl 0x20(%r14), %edx
movq 0x2fae9(%rip), %rax     # 0x6f648
movl 0x10c(%rax), %ecx
shll $0x9, %ecx
movq %rbx, 0x18(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, 0x8(%rsp)
movq %r12, (%rsp)
movq $-0x1, 0x28(%rsp)
movq $0x0, 0x20(%rsp)
movq %r13, %rdi
movl $0x2, %esi
movq $-0x1, %r8
movq $-0x1, %r9
callq 0x48bc8
movl $0x0, 0xa8(%r13)
movq 0x30(%rsp), %r14
movq %r14, 0x90(%r13)
movq %r13, 0x88(%rbx)
movq 0x2fa7d(%rip), %rax     # 0x6f648
movq 0x40(%rax), %r12
leaq 0x78(%r12), %r15
movl $0x18, %edi
callq 0x73a0
movq %rbx, 0x10(%rax)
movq %rax, %rdi
movq %r15, %rsi
callq 0x7060
incq 0x88(%r12)
movl $0x18, %edi
callq 0x73a0
movq %r13, 0x10(%rax)
movq %rax, %rdi
movq 0x60(%rsp), %rsi
callq 0x7060
incq 0x90(%r14)
movq %r14, %r12
movq 0x68(%rsp), %r14
incl %ebp
cmpl 0x4(%r14), %ebp
jb 0x3fa26
movq %r12, 0x28(%r14)
jmp 0x3ff0d
movl 0x8(%rbx), %ecx
cmpl $0x2, %ecx
je 0x3fce7
cmpl $0x1, %ecx
je 0x3fcae
testl %ecx, %ecx
jne 0x3ff1e
movq 0x10(%r14), %rcx
movl 0x48(%rbx), %esi
shlq $0x6, %rsi
movq 0x30(%rax), %rdi
movzwl (%rbx), %eax
movq 0x58(%rbx), %rdx
cmpb $0x1, 0x22(%rcx,%rsi)
jne 0x3fe5c
movq (%rdi), %r9
movzwl %ax, %esi
leaq 0x40(%rsp), %r15
leaq 0x38(%rsp), %r8
movq %r15, %rcx
callq *0x70(%r9)
movl (%r15), %eax
cmpq %rax, 0x60(%rbx)
jne 0x3ff73
movq 0x2f9af(%rip), %rax     # 0x6f648
movq 0x40(%rax), %rdi
callq 0x2fd9e
movq $-0x1, %rax
jmp 0x3fe95
movq 0x10(%r14), %rcx
movq 0x90(%rbx), %rdx
movl 0x48(%rdx), %esi
shlq $0x6, %rsi
movq 0x30(%rax), %rdi
movzwl (%rbx), %eax
movq 0x58(%rbx), %rdx
cmpb $0x1, 0x22(%rcx,%rsi)
jne 0x3fe23
movq (%rdi), %rcx
movzwl %ax, %esi
callq *0xb8(%rcx)
jmp 0x3fe2f
movq 0xc0(%r14), %rcx
leaq 0xb8(%r14), %rsi
movq %rsi, %rax
testq %rcx, %rcx
je 0x3fd1a
movl 0x48(%rbx), %edx
movq %rsi, %rax
xorl %edi, %edi
cmpl %edx, 0x20(%rcx)
setb %dil
cmovaeq %rcx, %rax
movq 0x10(%rcx,%rdi,8), %rcx
testq %rcx, %rcx
jne 0x3fd03
leaq 0xb0(%r14), %rdi
cmpq %rsi, %rax
je 0x3fd30
movl 0x48(%rbx), %ecx
cmpl 0x20(%rax), %ecx
cmovaeq %rax, %rsi
callq 0x31098
movq 0x2f90c(%rip), %rax     # 0x6f648
movq 0x38(%rax), %rdi
movq (%rdi), %rax
movq %r15, %rsi
callq *0x40(%rax)
movq 0x2f8f8(%rip), %rax     # 0x6f648
movq 0x38(%rax), %rdi
movq %r15, %rsi
callq 0x3e304
movq 0x2f8e5(%rip), %r12     # 0x6f648
movups 0x38(%rbx), %xmm0
movaps %xmm0, 0x70(%rsp)
movq 0x48(%rbx), %rax
movq %rax, 0x80(%rsp)
cmpb $0x1, 0x66(%r12)
jne 0x3fdb9
movq 0x38(%r12), %rdi
leaq 0x70(%rsp), %rsi
callq 0x3e04e
cmpl 0x68(%r12), %eax
jb 0x3fdb9
movq 0x2f8ab(%rip), %rdi     # 0x6f648
movups 0x38(%rbx), %xmm0
leaq 0xb0(%rsp), %rsi
movaps %xmm0, (%rsi)
movq 0x48(%rbx), %rax
movq %rax, 0x10(%rsi)
callq 0x3ffb8
movq 0x2f888(%rip), %rax     # 0x6f648
movq 0x30(%rax), %rdi
movups 0x38(%rbx), %xmm0
leaq 0x90(%rsp), %rsi
movaps %xmm0, (%rsi)
movq 0x48(%rbx), %rax
movq %rax, 0x10(%rsi)
movq (%rdi), %rax
callq *0xc0(%rax)
movq 0x2f85d(%rip), %rbx     # 0x6f648
movq 0x38(%rbx), %rdi
movq (%rdi), %rax
movq %r15, %rsi
callq *0x48(%rax)
cmpl 0x7c(%rbx), %eax
jae 0x3ff1e
movq 0x2f840(%rip), %rbx     # 0x6f648
movq %r14, %rdi
callq 0x3e04a
movq (%rbx), %rcx
movq %rbx, %rdi
movl %eax, %esi
movq %r15, %rdx
callq *0x28(%rcx)
jmp 0x3ff1e
movq (%rdi), %rcx
movzwl %ax, %esi
callq *0xb0(%rcx)
movq 0x10(%r14), %rax
movq 0x90(%rbx), %rcx
movl 0x48(%rcx), %ecx
shlq $0x6, %rcx
movq 0x28(%rax,%rcx), %rdi
subq $-0x80, %rdi
leaq 0x40(%rsp), %rsi
movq %rbx, (%rsi)
callq 0x40426
jmp 0x3ff1e
movq (%rdi), %r9
movzwl %ax, %esi
leaq 0x40(%rsp), %r15
leaq 0x38(%rsp), %r8
movq %r15, %rcx
callq *0x68(%r9)
movq (%r15), %rax
cmpq 0x60(%rbx), %rax
jne 0x3ff73
movq 0x2f7c1(%rip), %rax     # 0x6f648
movq 0x40(%rax), %rdi
callq 0x2fd9e
movq 0x38(%rsp), %rax
movq 0x88(%rbx), %rsi
movq %rax, 0x98(%rsi)
movq 0x58(%rbx), %rax
movq %rax, 0x58(%rsi)
movq $0x0, 0x88(%rsi)
movq 0x2f78b(%rip), %rax     # 0x6f648
movq 0x30(%rax), %rdi
movq 0x10(%r14), %rax
movl 0x48(%rbx), %ecx
shlq $0x6, %rcx
movzbl 0x22(%rax,%rcx), %edx
movq (%rdi), %rax
callq *0x78(%rax)
movq 0x2f76a(%rip), %rax     # 0x6f648
movq 0x40(%rax), %r14
movq 0x88(%rbx), %r15
leaq 0x78(%r14), %rbx
movl $0x18, %edi
callq 0x73a0
movq %r15, 0x10(%rax)
movq %rax, %rdi
movq %rbx, %rsi
callq 0x7060
incq 0x88(%r14)
movq 0x2f734(%rip), %rax     # 0x6f648
movq 0x40(%rax), %rdi
movq (%rdi), %rax
callq *0x30(%rax)
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x2f0b9(%rip), %rbx     # 0x6eff0
leaq 0x1666a(%rip), %rsi     # 0x565a8
movq %rbx, %rdi
callq 0x7390
leaq 0x19e12(%rip), %rsi     # 0x59d5f
movq %rbx, %rdi
callq 0x7390
movq %rax, %rdi
callq 0x71c0
movq 0x2f06c(%rip), %rdi     # 0x6efd0
callq 0x7430
movl $0x1, %edi
callq 0x7440
movq 0x2f076(%rip), %rbx     # 0x6eff0
leaq 0x16627(%rip), %rsi     # 0x565a8
movq %rbx, %rdi
callq 0x7390
leaq 0x19e09(%rip), %rsi     # 0x59d99
jmp 0x3ff4d
movq %rax, %r14
movq %r12, %rbx
jmp 0x3ffa7
movq %rax, %r14
movq %r13, %rbx
jmp 0x3ffa7
jmp 0x3ffa4
movq %rax, %r14
movq %rbx, %rdi
callq 0x7370
movq %r14, %rdi
callq 0x7620
nop