// File: /workspace/github_cpp_makefile_star2_O3/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 $0xb8, %rsp
movq %rdi, %r14
movq 0x3079b(%rip), %rax     # 0x6f648
movq 0x38(%rax), %rdi
movq 0x8(%rdi), %rdx
leaq 0x38(%r14), %r15
movl 0x4(%r14), %ecx
movl 0x38(%r14), %esi
movq (%rdx,%rsi,8), %rdx
movl 0x3c(%r14), %esi
movq (%rdx,%rsi,8), %rdx
movl 0x40(%r14), %esi
movl 0x44(%r14), %r8d
imulq $0xe0, %r8, %rbx
addq (%rdx,%rsi,8), %rbx
cmpl $0x3, %ecx
ja 0x3f1ec
cmpl $0x2, %ecx
je 0x3f1ec
movl 0x8(%r14), %eax
cmpl $0x1, %eax
je 0x3ef0d
testl %eax, %eax
jne 0x3f549
movq %r15, %rsi
callq 0x3d840
jmp 0x3ef15
movq %r15, %rsi
callq 0x3d80c
movq 0x3072c(%rip), %rax     # 0x6f648
movq 0x38(%rax), %rdi
movq %r15, %rsi
callq 0x3d702
testb %al, %al
je 0x3f537
movq 0x30711(%rip), %rax     # 0x6f648
movq 0x38(%rax), %rdi
movq %r15, %rsi
callq 0x3d736
testb %al, %al
je 0x3f537
movups 0x38(%r14), %xmm0
leaq 0x40(%rsp), %r15
movaps %xmm0, (%r15)
movq 0x48(%r14), %rax
movq %rax, 0x10(%r15)
movq 0x10(%rbx), %rbx
leaq 0x317f0(%rip), %rcx     # 0x7075c
incl (%rcx)
movl %eax, %r14d
shlq $0x6, %r14
movq 0x306cc(%rip), %rax     # 0x6f648
movq 0x40(%rax), %rdi
callq 0x2f762
movl $0x98, %edi
callq 0x73a0
movq %rax, %r12
movzwl 0x20(%rbx,%r14), %edx
movq %rax, %rdi
movl $0x2, %esi
movq %r15, %rcx
callq 0x47fd4
addq %r14, %rbx
movl 0x4(%rbx), %eax
cmpl 0xc(%rbx), %eax
sete %cl
testl %eax, %eax
sete %al
orb %cl, %al
jne 0x3f1e3
movq %r12, %rax
subq $-0x80, %rax
movq %rax, 0x78(%rsp)
xorl %ebp, %ebp
movq %rbx, 0x80(%rsp)
movq %r12, 0x30(%rsp)
movq 0x30665(%rip), %rax     # 0x6f648
movq 0x38(%rax), %rdi
movq %rbx, %rsi
movl %ebp, %edx
callq 0x3d8e0
testb %al, %al
je 0x3f1d8
leaq 0x31b60(%rip), %rax     # 0x70b60
incl (%rax)
movl %ebp, 0x54(%rsp)
movq 0x3063b(%rip), %r12     # 0x6f648
cmpb $0x1, 0x64(%r12)
jne 0x3f091
movl $0xb0, %edi
callq 0x73a0
movq %rax, %r14
movzwl 0x20(%rbx), %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 %r14, %rdi
movl $0x2, %esi
movl %r13d, %ecx
movq $-0x1, %r8
movq %rax, %r9
callq 0x481c8
movl $0x1, 0xa8(%r14)
movq %r14, %r13
movq 0x30(%rsp), %rbx
jmp 0x3f17a
movl $0xa0, %edi
callq 0x73a0
movq %rax, %r14
movzwl 0x20(%rbx), %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 %r14, %rdi
movl $0x2, %esi
movl %r13d, %ecx
movq $-0x1, %r8
movq %rax, %r9
callq 0x4806e
movl $0xb0, %edi
callq 0x73a0
movq %rax, %r13
movzwl 0x20(%rbx), %edx
movq 0x30533(%rip), %rax     # 0x6f648
movl 0x10c(%rax), %ecx
shll $0x9, %ecx
movq %r14, 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 0x4816c
movl $0x0, 0xa8(%r13)
movq 0x30(%rsp), %rbx
movq %rbx, 0x90(%r13)
movq %r13, 0x88(%r14)
movq 0x304c7(%rip), %rax     # 0x6f648
movq 0x40(%rax), %r12
leaq 0x78(%r12), %r15
movl $0x18, %edi
callq 0x73a0
movq %r14, 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 0x78(%rsp), %rsi
callq 0x7060
incq 0x90(%rbx)
movq %rbx, %r12
movq 0x80(%rsp), %rbx
incl %ebp
cmpl 0x4(%rbx), %ebp
jb 0x3efdc
movq %r12, 0x28(%rbx)
jmp 0x3f526
movl 0x8(%r14), %ecx
cmpl $0x2, %ecx
je 0x3f2a3
cmpl $0x1, %ecx
je 0x3f269
testl %ecx, %ecx
jne 0x3f537
movq 0x10(%rbx), %rcx
movl 0x48(%r14), %esi
shlq $0x6, %rsi
movq 0x30(%rax), %rdi
movzwl (%r14), %eax
movq 0x58(%r14), %rdx
cmpb $0x1, 0x22(%rcx,%rsi)
jne 0x3f474
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(%r14)
jne 0x3f58c
movq 0x303f4(%rip), %rax     # 0x6f648
movq 0x40(%rax), %rdi
callq 0x2f762
movq $-0x1, %rax
jmp 0x3f4ad
movq 0x10(%rbx), %rcx
movq 0x90(%r14), %rdx
movl 0x48(%rdx), %esi
shlq $0x6, %rsi
movq 0x30(%rax), %rdi
movzwl (%r14), %eax
movq 0x58(%r14), %rdx
cmpb $0x1, 0x22(%rcx,%rsi)
jne 0x3f43b
movq (%rdi), %rcx
movzwl %ax, %esi
callq *0xb8(%rcx)
jmp 0x3f447
leaq 0xb0(%rbx), %rdi
movq 0xc0(%rbx), %rax
leaq 0xb8(%rbx), %rsi
testq %rax, %rax
je 0x3f2e8
movl 0x48(%r14), %ecx
movq %rsi, %rdx
xorl %r8d, %r8d
cmpl %ecx, 0x20(%rax)
setb %r8b
cmovaeq %rax, %rdx
movq 0x10(%rax,%r8,8), %rax
testq %rax, %rax
jne 0x3f2c4
cmpq %rsi, %rdx
je 0x3f2e8
cmpl 0x20(%rdx), %ecx
cmovaeq %rdx, %rsi
callq 0x30878
movq 0x30354(%rip), %rax     # 0x6f648
movq 0x38(%rax), %rdi
movq (%rdi), %rax
movq %r15, %rsi
callq *0x40(%rax)
movq 0x30340(%rip), %rax     # 0x6f648
movq 0x38(%rax), %rdi
movq %r15, %rsi
callq 0x3d8ac
movq 0x3032d(%rip), %r12     # 0x6f648
movl 0x38(%r14), %ecx
movl %ecx, 0x60(%rsp)
movl 0x3c(%r14), %edx
movl %edx, 0x64(%rsp)
movl 0x40(%r14), %r8d
movl %r8d, 0x68(%rsp)
movl 0x44(%r14), %r9d
movl %r9d, 0x6c(%rsp)
movl 0x48(%r14), %r10d
movl %r10d, 0x70(%rsp)
movl 0x4c(%r14), %r11d
movl %r11d, 0x74(%rsp)
cmpb $0x1, 0x66(%r12)
jne 0x3f3d0
movq 0x38(%r12), %rdi
leaq 0x60(%rsp), %rsi
callq 0x3d5f6
movl 0x38(%r14), %ecx
movl 0x3c(%r14), %edx
movl 0x40(%r14), %r8d
movl 0x44(%r14), %r9d
movl 0x48(%r14), %r10d
movl 0x4c(%r14), %r11d
cmpl 0x68(%r12), %eax
movq 0x302be(%rip), %r12     # 0x6f648
jb 0x3f3d0
leaq 0xa0(%rsp), %rsi
movl %ecx, (%rsi)
movl %edx, 0x4(%rsi)
movl %r8d, 0x8(%rsi)
movl %r9d, 0xc(%rsi)
movl %r10d, 0x10(%rsi)
movl %r11d, 0x14(%rsi)
movq %r12, %rdi
callq 0x3f5d0
movq 0x30290(%rip), %r12     # 0x6f648
movl 0x38(%r14), %ecx
movl 0x3c(%r14), %edx
movl 0x40(%r14), %r8d
movl 0x44(%r14), %r9d
movl 0x48(%r14), %r10d
movl 0x4c(%r14), %r11d
movq 0x30(%r12), %rdi
leaq 0x88(%rsp), %rsi
movl %ecx, (%rsi)
movl %edx, 0x4(%rsi)
movl %r8d, 0x8(%rsi)
movl %r9d, 0xc(%rsi)
movl %r10d, 0x10(%rsi)
movl %r11d, 0x14(%rsi)
movq (%rdi), %rax
callq *0xc0(%rax)
movq 0x30246(%rip), %r14     # 0x6f648
movq 0x38(%r14), %rdi
movq (%rdi), %rax
movq %r15, %rsi
callq *0x48(%rax)
cmpl 0x7c(%r14), %eax
jae 0x3f537
movq 0x30228(%rip), %r14     # 0x6f648
movq %rbx, %rdi
callq 0x3d5f2
movq (%r14), %rcx
movq %r14, %rdi
movl %eax, %esi
movq %r15, %rdx
callq *0x28(%rcx)
jmp 0x3f537
movq (%rdi), %rcx
movzwl %ax, %esi
callq *0xb0(%rcx)
movq 0x10(%rbx), %rax
movq 0x90(%r14), %rcx
movl 0x48(%rcx), %ecx
shlq $0x6, %rcx
movq 0x28(%rax,%rcx), %rdi
subq $-0x80, %rdi
leaq 0x40(%rsp), %rsi
movq %r14, (%rsi)
callq 0x3fa08
jmp 0x3f537
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(%r14), %rax
jne 0x3f58c
movq 0x301a9(%rip), %rax     # 0x6f648
movq 0x40(%rax), %rdi
callq 0x2f762
movq 0x38(%rsp), %rax
movq 0x88(%r14), %rsi
movq %rax, 0x98(%rsi)
movq 0x58(%r14), %rax
movq %rax, 0x58(%rsi)
movq $0x0, 0x88(%rsi)
movq 0x30173(%rip), %rax     # 0x6f648
movq 0x30(%rax), %rdi
movq 0x10(%rbx), %rax
movl 0x48(%r14), %ecx
shlq $0x6, %rcx
movzbl 0x22(%rax,%rcx), %edx
movq (%rdi), %rax
callq *0x78(%rax)
movq 0x30151(%rip), %rax     # 0x6f648
movq 0x40(%rax), %r15
movq 0x88(%r14), %r14
leaq 0x78(%r15), %rbx
movl $0x18, %edi
callq 0x73a0
movq %r14, 0x10(%rax)
movq %rax, %rdi
movq %rbx, %rsi
callq 0x7060
incq 0x88(%r15)
movq 0x3011b(%rip), %rax     # 0x6f648
movq 0x40(%rax), %rdi
movq (%rdi), %rax
callq *0x30(%rax)
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x2faa0(%rip), %rbx     # 0x6eff0
leaq 0x17051(%rip), %rsi     # 0x565a8
movq %rbx, %rdi
callq 0x7390
leaq 0x1a7f9(%rip), %rsi     # 0x59d5f
movq %rbx, %rdi
callq 0x7390
movq %rax, %rdi
callq 0x71c0
movq 0x2fa53(%rip), %rdi     # 0x6efd0
callq 0x7430
movl $0x1, %edi
callq 0x7440
movq 0x2fa5d(%rip), %rbx     # 0x6eff0
leaq 0x1700e(%rip), %rsi     # 0x565a8
movq %rbx, %rdi
callq 0x7390
leaq 0x1a7f0(%rip), %rsi     # 0x59d99
jmp 0x3f566
movq %rax, %rbx
movq %r12, %r14
jmp 0x3f5c0
movq %rax, %rbx
movq %r13, %r14
jmp 0x3f5c0
jmp 0x3f5bd
movq %rax, %rbx
movq %r14, %rdi
callq 0x7370
movq %rbx, %rdi
callq 0x7620