// 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::run_static_wearleveling(NVM::FlashMemory::Physical_Page_Address)
void GC_and_WL_Unit_Base::run_static_wearleveling(const NVM::FlashMemory::Physical_Page_Address plane_address)
	{
		PlaneBookKeepingType* pbke = block_manager->Get_plane_bookkeeping_entry(plane_address);
		flash_block_ID_type wl_candidate_block_id = block_manager->Get_coldest_block_id(plane_address);
		if (!is_safe_gc_wl_candidate(pbke, wl_candidate_block_id)) {
			return;
		}

		NVM::FlashMemory::Physical_Page_Address wl_candidate_address(plane_address);
		wl_candidate_address.BlockID = wl_candidate_block_id;
		Block_Pool_Slot_Type* block = &pbke->Blocks[wl_candidate_block_id];

		//Run the state machine to protect against race condition
		block_manager->GC_WL_started(wl_candidate_block_id);
		pbke->Ongoing_erase_operations.insert(wl_candidate_block_id);
		address_mapping_unit->Set_barrier_for_accessing_physical_block(wl_candidate_address);//Lock the block, so no user request can intervene while the GC is progressing
		if (block_manager->Can_execute_gc_wl(wl_candidate_address)) {//If there are ongoing requests targeting the candidate block, the gc execution should be postponed
			Stats::Total_wl_executions++;
			tsu->Prepare_for_transaction_submit();

			NVM_Transaction_Flash_ER* wl_erase_tr = new NVM_Transaction_Flash_ER(Transaction_Source_Type::GC_WL, pbke->Blocks[wl_candidate_block_id].Stream_id, wl_candidate_address);
			if (block->Current_page_write_index - block->Invalid_page_count > 0) {//If there are some valid pages in block, then prepare flash transactions for page movement
				NVM_Transaction_Flash_RD* wl_read = NULL;
				NVM_Transaction_Flash_WR* wl_write = NULL;
				for (flash_page_ID_type pageID = 0; pageID < block->Current_page_write_index; pageID++) {
					if (block_manager->Is_page_valid(block, pageID)) {
						Stats::Total_page_movements_for_gc;
						wl_candidate_address.PageID = pageID;
						if (use_copyback) {
							wl_write = new NVM_Transaction_Flash_WR(Transaction_Source_Type::GC_WL, block->Stream_id, sector_no_per_page * SECTOR_SIZE_IN_BYTE,
								NO_LPA, address_mapping_unit->Convert_address_to_ppa(wl_candidate_address), NULL, 0, NULL, 0, INVALID_TIME_STAMP);
							wl_write->ExecutionMode = WriteExecutionModeType::COPYBACK;
							tsu->Submit_transaction(wl_write);
						} else {
							wl_read = new NVM_Transaction_Flash_RD(Transaction_Source_Type::GC_WL, block->Stream_id, sector_no_per_page * SECTOR_SIZE_IN_BYTE,
								NO_LPA, address_mapping_unit->Convert_address_to_ppa(wl_candidate_address), wl_candidate_address, NULL, 0, NULL, 0, INVALID_TIME_STAMP);
							wl_write = new NVM_Transaction_Flash_WR(Transaction_Source_Type::GC_WL, block->Stream_id, sector_no_per_page * SECTOR_SIZE_IN_BYTE,
								NO_LPA, NO_PPA, wl_candidate_address, NULL, 0, wl_read, 0, INVALID_TIME_STAMP);
							wl_write->ExecutionMode = WriteExecutionModeType::SIMPLE;
							wl_write->RelatedErase = wl_erase_tr;
							wl_read->RelatedWrite = wl_write;
							tsu->Submit_transaction(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
						}
						wl_erase_tr->Page_movement_activities.push_back(wl_write);
					}
				}
			}
			block->Erase_transaction = wl_erase_tr;
			tsu->Submit_transaction(wl_erase_tr);

			tsu->Schedule();
		}
	}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x98, %rsp
movq %rsi, %r14
movq %rdi, %rbx
movq 0x38(%rdi), %rdi
callq 0x3d6de
movq %rax, %r15
movq 0x38(%rbx), %rdi
movq %r14, %rsi
callq 0x3d678
movl %eax, %ebp
movl %eax, 0x3c(%rsp)
movq %rbx, %rdi
movq %r15, %rsi
movl %eax, %edx
callq 0x3f9ac
testb %al, %al
je 0x3f92f
movups (%r14), %xmm0
leaq 0x60(%rsp), %r12
movaps %xmm0, (%r12)
movl 0x14(%r14), %eax
movl %eax, 0x14(%r12)
movl %ebp, 0x10(%r12)
movl %ebp, %r14d
shlq $0x6, %r14
addq 0x10(%r15), %r14
movq 0x38(%rbx), %rdi
leaq 0x80(%rsp), %rsi
movl %ebp, (%rsi)
xorps %xmm0, %xmm0
movups %xmm0, 0x4(%rsi)
movl $0x0, 0x14(%rsi)
callq 0x3d770
movq %r15, %rdi
addq $0xb0, %rdi
leaq 0x3c(%rsp), %rsi
callq 0x30732
movq 0x30(%rbx), %rdi
movq (%rdi), %rax
movq %r12, %rsi
callq *0x98(%rax)
movq 0x38(%rbx), %rdi
movq %r12, %rsi
callq 0x3d736
testb %al, %al
je 0x3f92f
leaq 0x318cf(%rip), %rax     # 0x70f70
incl (%rax)
movq 0x40(%rbx), %rdi
callq 0x2f762
movl $0x98, %edi
callq 0x73a0
movq %rax, %r13
movq 0x10(%r15), %rax
movl 0x3c(%rsp), %ecx
shlq $0x6, %rcx
movzwl 0x20(%rax,%rcx), %edx
leaq 0x60(%rsp), %rcx
movq %r13, %rdi
movl $0x2, %esi
callq 0x47fd4
movl 0x4(%r14), %eax
cmpl 0xc(%r14), %eax
sete %cl
testl %eax, %eax
sete %al
orb %cl, %al
jne 0x3f8f9
movq %r13, %rax
subq $-0x80, %rax
movq %rax, 0x50(%rsp)
xorl %ebp, %ebp
movq %r14, 0x58(%rsp)
movq %rbx, 0x40(%rsp)
movq %r13, 0x48(%rsp)
movq 0x38(%rbx), %rdi
movq %r14, %rsi
movl %ebp, %edx
callq 0x3d8e0
testb %al, %al
je 0x3f8ed
movl %ebp, 0x74(%rsp)
cmpb $0x1, 0x64(%rbx)
movq %rbx, %r13
jne 0x3f7b2
movl $0xb0, %edi
callq 0x73a0
movq %rax, %rbx
movzwl 0x20(%r14), %r12d
movl 0x10c(%r13), %r15d
movq 0x30(%r13), %rdi
movq (%rdi), %rax
leaq 0x60(%rsp), %rsi
callq *0x90(%rax)
shll $0x9, %r15d
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rsp)
movups %xmm0, (%rsp)
movq $-0x1, 0x20(%rsp)
movzwl %r12w, %edx
movq %rbx, %rdi
movl $0x2, %esi
movl %r15d, %ecx
movq $-0x1, %r8
movq %rax, %r9
callq 0x481c8
movl $0x1, 0xa8(%rbx)
movq %rbx, %r15
movq 0x48(%rsp), %r13
movq 0x40(%rsp), %r14
jmp 0x3f899
movl $0xa0, %edi
callq 0x73a0
movq %rax, %rbx
movzwl 0x20(%r14), %r12d
movl 0x10c(%r13), %r15d
movq 0x30(%r13), %rdi
movq (%rdi), %rax
leaq 0x60(%rsp), %r13
movq %r13, %rsi
callq *0x90(%rax)
shll $0x9, %r15d
xorps %xmm0, %xmm0
movups %xmm0, 0x18(%rsp)
movups %xmm0, 0x8(%rsp)
movq %r13, (%rsp)
movq $-0x1, 0x28(%rsp)
movzwl %r12w, %edx
movq %rbx, %rdi
movl $0x2, %esi
movl %r15d, %ecx
movq $-0x1, %r8
movq %rax, %r9
callq 0x4806e
movl $0xb0, %edi
callq 0x73a0
movq %rax, %r15
movzwl 0x20(%r14), %edx
movq 0x40(%rsp), %r14
movl 0x10c(%r14), %ecx
shll $0x9, %ecx
movq %rbx, 0x18(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, 0x8(%rsp)
movq %r13, (%rsp)
movq $-0x1, 0x28(%rsp)
movq $0x0, 0x20(%rsp)
movq %rax, %rdi
movl $0x2, %esi
movq $-0x1, %r8
movq $-0x1, %r9
callq 0x4816c
movl $0x0, 0xa8(%r15)
movq 0x48(%rsp), %r13
movq %r13, 0x90(%r15)
movq %r15, 0x88(%rbx)
movq 0x40(%r14), %r14
leaq 0x78(%r14), %r12
movl $0x18, %edi
callq 0x73a0
movq %rbx, 0x10(%rax)
movq %rax, %rdi
movq %r12, %rsi
movq 0x40(%rsp), %rbx
callq 0x7060
incq 0x88(%r14)
movl $0x18, %edi
callq 0x73a0
movq %r15, 0x10(%rax)
movq %rax, %rdi
movq 0x50(%rsp), %rsi
callq 0x7060
incq 0x90(%r13)
movq 0x58(%rsp), %r14
incl %ebp
cmpl 0x4(%r14), %ebp
jb 0x3f711
movq %r13, 0x28(%r14)
movq 0x40(%rbx), %r15
leaq 0x78(%r15), %r14
movl $0x18, %edi
callq 0x73a0
movq %r13, 0x10(%rax)
movq %rax, %rdi
movq %r14, %rsi
callq 0x7060
incq 0x88(%r15)
movq 0x40(%rbx), %rdi
movq (%rdi), %rax
callq *0x30(%rax)
addq $0x98, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %r14
movq %r13, %rbx
jmp 0x3f956
movq %rax, %r14
movq %r15, %rbx
jmp 0x3f956
jmp 0x3f953
movq %rax, %r14
movq %rbx, %rdi
callq 0x7370
movq %r14, %rdi
callq 0x7620