// File: narges64[P]SIMBA/ftl.cpp
// Function: find_lun_gc_requests(ssd_info*, unsigned int, unsigned int, sub_request**, int*)
int find_lun_gc_requests(ssd_info * ssd, unsigned int channel, unsigned int lun,
						sub_request ** subs, int * operation) {
	int max_subs_count = ssd->parameter->plane_lun;
	unsigned int page_offset = -1;
	int subs_count = 0;
	(*operation) = -1;
	static int k = 0; 
	for (int i = 0; i < max_subs_count; i++){
		if (subs[i] != NULL) {
			subs_count++;
			(*operation) = subs[i]->operation;
			page_offset = subs[i]->location->page;
		}
	}

	if (ssd->channel_head[channel]->lun_head[lun]->GCSubs.is_empty()) return subs_count;
	for (int i = 0; i < max_subs_count; i++){
		if (subs[i] != NULL) continue;
		sub_request * temp = ssd->channel_head[channel]->lun_head[lun]->
					GCSubs.target_request(i, -1, page_offset);
		if (temp == NULL ||
			((*operation) != -1 && temp->operation != (*operation)))
			continue;  // can be improved
		ssd->channel_head[channel]->lun_head[lun]->GCSubs.remove_node(temp);
		if (find_subrequest_state(ssd, temp) == SR_MODE_COMPLETE) {
			i--;
			continue;
		}
		if (temp->operation == ERASE || temp->operation == READ) {
			subs[i] = temp;
			(*operation) = subs[i]->operation;
			subs_count++;
			continue;
		}
		// If it's write

		if ((temp->buf_entry != NULL) || (ssd->dram->gc_buffer->buffer_capacity== 0)){
			subs[i] = temp;
			(*operation) = subs[i]->operation;
			subs_count++;
			continue;
		}

		int lpn = temp->lpn;
		buffer_entry * buf_ent = ssd->dram->map->map_entry[lpn].buf_ent;
		if (buf_ent != NULL) {
			if (buf_ent->gc) 
				ssd->dram->gc_buffer->hit_write(buf_ent); 
			else 
				ssd->dram->buffer->hit_write(buf_ent);  
			i--;
			continue;
		}else {
			buf_ent = ssd->dram->gc_buffer->add_head(lpn);
			temp->buf_entry = buf_ent;
			buf_ent->gc = true;

			if (!buf_ent->outlier) {
				ssd->dram->map->map_entry[lpn].buf_ent= buf_ent;
				ssd->channel_head[channel]->lun_head[lun]->GCSubs.push_tail(temp);
				i--;
				continue;
			}else {
				buf_ent->sub = temp;
				subs[i] = temp;
				(*operation) = subs[i]->operation;
				subs_count++;
			}

		}

		if (ssd->parameter->plane_level_tech != GCGC)
			return subs_count; // NOT FOR GCGC
	}

	return subs_count;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x60, %rsp
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movl %edx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq -0x10(%rbp), %rax
movq 0x58(%rax), %rax
movl 0x22c(%rax), %eax
movl %eax, -0x2c(%rbp)
movl $0xffffffff, -0x30(%rbp) # imm = 0xFFFFFFFF
movl $0x0, -0x34(%rbp)
movq -0x28(%rbp), %rax
movl $0xffffffff, (%rax)     # imm = 0xFFFFFFFF
movl $0x0, -0x38(%rbp)
movl -0x38(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jge 0x79b2
movq -0x20(%rbp), %rax
movslq -0x38(%rbp), %rcx
cmpq $0x0, (%rax,%rcx,8)
je 0x79a5
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
movq -0x20(%rbp), %rax
movslq -0x38(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movl 0x20(%rax), %ecx
movq -0x28(%rbp), %rax
movl %ecx, (%rax)
movq -0x20(%rbp), %rax
movslq -0x38(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq 0x60(%rax), %rax
movl 0x10(%rax), %eax
movl %eax, -0x30(%rbp)
jmp 0x79a7
movl -0x38(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x38(%rbp)
jmp 0x795a
movq -0x10(%rbp), %rax
movq 0x90(%rax), %rax
movl -0x14(%rbp), %ecx
movq (%rax,%rcx,8), %rax
movq 0x50(%rax), %rax
movl -0x18(%rbp), %ecx
movq (%rax,%rcx,8), %rdi
addq $0x48, %rdi
callq 0x5320
testb $0x1, %al
jne 0x79de
jmp 0x79e9
movl -0x34(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x7cb7
movl $0x0, -0x3c(%rbp)
movl -0x3c(%rbp), %eax
cmpl -0x2c(%rbp), %eax
jge 0x7cb1
movq -0x20(%rbp), %rax
movslq -0x3c(%rbp), %rcx
cmpq $0x0, (%rax,%rcx,8)
je 0x7a10
jmp 0x7ca3
movq -0x10(%rbp), %rax
movq 0x90(%rax), %rax
movl -0x14(%rbp), %ecx
movq (%rax,%rcx,8), %rax
movq 0x50(%rax), %rax
movl -0x18(%rbp), %ecx
movq (%rax,%rcx,8), %rdi
addq $0x48, %rdi
movl -0x3c(%rbp), %esi
movl -0x30(%rbp), %ecx
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x5290
movq %rax, -0x48(%rbp)
cmpq $0x0, -0x48(%rbp)
je 0x7a64
movq -0x28(%rbp), %rax
cmpl $-0x1, (%rax)
je 0x7a69
movq -0x48(%rbp), %rax
movl 0x20(%rax), %eax
movq -0x28(%rbp), %rcx
cmpl (%rcx), %eax
je 0x7a69
jmp 0x7ca3
movq -0x10(%rbp), %rax
movq 0x90(%rax), %rax
movl -0x14(%rbp), %ecx
movq (%rax,%rcx,8), %rax
movq 0x50(%rax), %rax
movl -0x18(%rbp), %ecx
movq (%rax,%rcx,8), %rdi
addq $0x48, %rdi
movq -0x48(%rbp), %rsi
callq 0x5190
movq -0x10(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x9d90
cmpl $0x9, %eax
jne 0x7ab3
movl -0x3c(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x3c(%rbp)
jmp 0x7ca3
movq -0x48(%rbp), %rax
cmpl $0x2, 0x20(%rax)
je 0x7ac7
movq -0x48(%rbp), %rax
cmpl $0x1, 0x20(%rax)
jne 0x7afa
movq -0x48(%rbp), %rdx
movq -0x20(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
movq -0x20(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movl 0x20(%rax), %ecx
movq -0x28(%rbp), %rax
movl %ecx, (%rax)
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
jmp 0x7ca3
movq -0x48(%rbp), %rax
cmpq $0x0, 0x18(%rax)
jne 0x7b17
movq -0x10(%rbp), %rax
movq 0x60(%rax), %rax
movq 0x20(%rax), %rax
cmpl $0x0, 0x8(%rax)
jne 0x7b4a
movq -0x48(%rbp), %rdx
movq -0x20(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
movq -0x20(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movl 0x20(%rax), %ecx
movq -0x28(%rbp), %rax
movl %ecx, (%rax)
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
jmp 0x7ca3
movq -0x48(%rbp), %rax
movl 0xc(%rax), %eax
movl %eax, -0x4c(%rbp)
movq -0x10(%rbp), %rax
movq 0x60(%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rax
movslq -0x4c(%rbp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rax
movq %rax, -0x58(%rbp)
cmpq $0x0, -0x58(%rbp)
je 0x7bc0
movq -0x58(%rbp), %rax
testb $0x1, (%rax)
je 0x7b9d
movq -0x10(%rbp), %rax
movq 0x60(%rax), %rax
movq 0x20(%rax), %rdi
movq -0x58(%rbp), %rsi
callq 0x8c70
jmp 0x7bb2
movq -0x10(%rbp), %rax
movq 0x60(%rax), %rax
movq 0x18(%rax), %rdi
movq -0x58(%rbp), %rsi
callq 0x8c70
movl -0x3c(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x3c(%rbp)
jmp 0x7ca3
movq -0x10(%rbp), %rax
movq 0x60(%rax), %rax
movq 0x20(%rax), %rdi
movl -0x4c(%rbp), %esi
callq 0x8be0
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rcx
movq -0x48(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x58(%rbp), %rax
movb $0x1, (%rax)
movq -0x58(%rbp), %rax
testb $0x1, 0x8(%rax)
jne 0x7c4c
movq -0x58(%rbp), %rcx
movq -0x10(%rbp), %rax
movq 0x60(%rax), %rax
movq 0x10(%rax), %rax
movq (%rax), %rax
movslq -0x4c(%rbp), %rdx
shlq $0x4, %rdx
addq %rdx, %rax
movq %rcx, 0x8(%rax)
movq -0x10(%rbp), %rax
movq 0x90(%rax), %rax
movl -0x14(%rbp), %ecx
movq (%rax,%rcx,8), %rax
movq 0x50(%rax), %rax
movl -0x18(%rbp), %ecx
movq (%rax,%rcx,8), %rdi
addq $0x48, %rdi
movq -0x48(%rbp), %rsi
callq 0x50c0
movl -0x3c(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x3c(%rbp)
jmp 0x7ca3
movq -0x48(%rbp), %rcx
movq -0x58(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x48(%rbp), %rdx
movq -0x20(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
movq -0x20(%rbp), %rax
movslq -0x3c(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movl 0x20(%rax), %ecx
movq -0x28(%rbp), %rax
movl %ecx, (%rax)
movl -0x34(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x34(%rbp)
jmp 0x7c88
movq -0x10(%rbp), %rax
movq 0x58(%rax), %rax
cmpl $0x3, 0x334(%rax)
je 0x7ca1
movl -0x34(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x7cb7
jmp 0x7ca3
movl -0x3c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3c(%rbp)
jmp 0x79f0
movl -0x34(%rbp), %eax
movl %eax, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x60, %rsp
popq %rbp
retq