// File: /workspace/github_cpp_makefile_star2_O2/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 $0x88, %rsp
movq %rsi, %r14
movq %rdi, %rbx
movq 0x38(%rdi), %rdi
callq 0x31a90
movq %rax, %r15
movq 0x38(%rbx), %rdi
movq %r14, %rsi
callq 0x31a2e
movl %eax, %ebp
movl %eax, 0x34(%rsp)
movq %rbx, %rdi
movq %r15, %rsi
movl %eax, %edx
callq 0x337b0
testb %al, %al
je 0x3356d
movups (%r14), %xmm0
leaq 0x50(%rsp), %r12
movaps %xmm0, (%r12)
movl 0x14(%r14), %eax
movl %eax, 0x14(%r12)
movl %ebp, 0x10(%r12)
movl %ebp, %eax
shlq $0x6, %rax
addq 0x10(%r15), %rax
movq %rax, 0x40(%rsp)
movq 0x38(%rbx), %rdi
leaq 0x70(%rsp), %rsi
movl %ebp, (%rsi)
xorps %xmm0, %xmm0
movups %xmm0, 0x4(%rsi)
andl $0x0, 0x14(%rsi)
callq 0x31b22
movq %r15, %rdi
addq $0xb0, %rdi
leaq 0x34(%rsp), %rsi
callq 0x27600
movq 0x30(%rbx), %rdi
movq (%rdi), %rax
movq %r12, %rsi
callq *0x98(%rax)
movq 0x38(%rbx), %rdi
movq %r12, %rsi
callq 0x31ae8
testb %al, %al
je 0x3356d
leaq 0x30a37(%rip), %rax     # 0x63f40
incl (%rax)
movq 0x40(%rbx), %rdi
callq 0x264ce
movl $0x98, %edi
callq 0x7370
movq %rax, %rdi
movq 0x10(%r15), %rax
movl 0x34(%rsp), %ecx
shlq $0x6, %rcx
movzwl 0x20(%rax,%rcx), %edx
pushq $0x2
popq %rsi
leaq 0x50(%rsp), %rcx
movq %rdi, 0x38(%rsp)
callq 0x3a0dc
movq 0x40(%rsp), %rbp
movl 0x4(%rbp), %eax
cmpl 0xc(%rbp), %eax
jne 0x3357f
movq 0x38(%rsp), %rsi
movq %rsi, 0x28(%rbp)
movq 0x40(%rbx), %rdi
callq 0x264ec
movq 0x40(%rbx), %rdi
movq (%rdi), %rax
callq *0x30(%rax)
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x70(%rsp), %rcx
andq $0x0, (%rcx)
movq 0x38(%rsp), %rcx
subq $-0x80, %rcx
movq %rcx, 0x68(%rsp)
xorl %r13d, %r13d
pushq $0x2
popq %r14
movq %rbx, 0x48(%rsp)
cmpl %eax, %r13d
jae 0x33551
movq 0x38(%rbx), %rdi
movq %rbp, %rsi
movl %r13d, %edx
callq 0x31c92
testb %al, %al
je 0x33738
movl %r13d, 0x64(%rsp)
cmpb $0x1, 0x64(%rbx)
jne 0x3363b
movl $0xb0, %edi
callq 0x7370
movq %rax, %r15
movzwl 0x20(%rbp), %ebp
movl 0x10c(%rbx), %r12d
movq 0x30(%rbx), %rdi
movq (%rdi), %rax
leaq 0x50(%rsp), %rsi
callq *0x90(%rax)
shll $0x9, %r12d
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rsp)
movups %xmm0, (%rsp)
orq $-0x1, 0x20(%rsp)
movzwl %bp, %edx
movq %r15, %rdi
movl %r14d, %esi
movl %r12d, %ecx
pushq $-0x1
popq %r8
movq %rax, %r9
callq 0x3a2c6
movq %r15, 0x70(%rsp)
movl $0x1, 0xa8(%r15)
movq 0x40(%rsp), %rbp
jmp 0x3371d
movl $0xa0, %edi
callq 0x7370
movq %rax, %r15
movzwl 0x20(%rbp), %ebp
movl 0x10c(%rbx), %r12d
movq 0x30(%rbx), %rdi
movq (%rdi), %rax
leaq 0x50(%rsp), %rsi
callq *0x90(%rax)
pushq $-0x1
popq %rbx
shll $0x9, %r12d
xorps %xmm0, %xmm0
movups %xmm0, 0x18(%rsp)
movups %xmm0, 0x8(%rsp)
orq $-0x1, 0x28(%rsp)
leaq 0x50(%rsp), %rcx
movq %rcx, (%rsp)
movzwl %bp, %edx
movq %r15, %rdi
movl %r14d, %esi
movl %r12d, %ecx
movq %rbx, %r8
movq %rax, %r9
callq 0x3a176
movl $0xb0, %edi
callq 0x7370
movq %rax, %r12
movq 0x40(%rsp), %rbp
movzwl 0x20(%rbp), %edx
movq 0x48(%rsp), %rax
movl 0x10c(%rax), %ecx
shll $0x9, %ecx
movq %r15, 0x18(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, 0x8(%rsp)
orq $-0x1, 0x28(%rsp)
andq $0x0, 0x20(%rsp)
leaq 0x50(%rsp), %rax
movq %rax, (%rsp)
movq %r12, %rdi
movl %r14d, %esi
movq %rbx, %r8
movq %rbx, %r9
callq 0x3a270
andl $0x0, 0xa8(%r12)
movq %r12, 0x70(%rsp)
movq 0x38(%rsp), %rax
movq %rax, 0x90(%r12)
movq %r12, 0x88(%r15)
movq 0x48(%rsp), %rbx
movq 0x40(%rbx), %rdi
movq %r15, %rsi
callq 0x264ec
movq 0x68(%rsp), %rdi
leaq 0x70(%rsp), %rsi
callq 0x3381a
incl %r13d
movl 0x4(%rbp), %eax
jmp 0x335a2
movq %rax, %rbx
movq 0x38(%rsp), %rdi
jmp 0x3375d
movq %rax, %rbx
movq %r12, %r15
jmp 0x3375a
jmp 0x33757
movq %rax, %rbx
movq %r15, %rdi
callq 0x7340
movq %rbx, %rdi
callq 0x75d0