// File: CMU-SAFARI[P]MQSim/src/host/SATA_HBA.cpp
// Function: Host_Components::SATA_HBA::Read_ncq_entry(unsigned long)
Submission_Queue_Entry* SATA_HBA::Read_ncq_entry(uint64_t address)
	{
		Submission_Queue_Entry* ncq_entry = new Submission_Queue_Entry;
		Host_IO_Request* request = request_queue_in_memory[(uint16_t)((address - sata_ncq.Submission_queue_memory_base_address) / sizeof(Submission_Queue_Entry))];
		
		if (request == NULL) {
			throw std::invalid_argument("SATA HBA: Request to access an NCQ entry that does not exist.");
		}

		ncq_entry->Command_Identifier = request->IO_queue_info;
		//For simplicity, MQSim's SATA host interface uses NVMe opcodes
		if (request->Type == Host_IO_Request_Type::READ) {
			ncq_entry->Opcode = NVME_READ_OPCODE;
			ncq_entry->Command_specific[0] = (uint32_t)request->Start_LBA;
			ncq_entry->Command_specific[1] = (uint32_t)(request->Start_LBA >> 32);
			ncq_entry->Command_specific[2] = ((uint32_t)((uint16_t)request->LBA_count)) & (uint32_t)(0x0000ffff);
			ncq_entry->PRP_entry_1 = (DATA_MEMORY_REGION);//Dummy addresses, just to emulate data read/write access
			ncq_entry->PRP_entry_2 = (DATA_MEMORY_REGION + 0x1000);//Dummy addresses
		} else {
			ncq_entry->Opcode = NVME_WRITE_OPCODE;
			ncq_entry->Command_specific[0] = (uint32_t)request->Start_LBA;
			ncq_entry->Command_specific[1] = (uint32_t)(request->Start_LBA >> 32);
			ncq_entry->Command_specific[2] = ((uint32_t)((uint16_t)request->LBA_count)) & (uint32_t)(0x0000ffff);
			ncq_entry->PRP_entry_1 = (DATA_MEMORY_REGION);//Dummy addresses, just to emulate data read/write access
			ncq_entry->PRP_entry_2 = (DATA_MEMORY_REGION + 0x1000);//Dummy addresses
		}

		return ncq_entry;
	}

// Assembly:
subq $0x48, %rsp
movq %rdi, 0x40(%rsp)
movq %rsi, 0x38(%rsp)
movq 0x40(%rsp), %rax
movq %rax, 0x10(%rsp)
movl $0x48, %edi
callq 0x8450
movq 0x10(%rsp), %rcx
movq %rax, 0x30(%rsp)
movq %rcx, %rdi
addq $0xe0, %rdi
movq 0x38(%rsp), %rax
subq 0x58(%rcx), %rax
movl $0x48, %ecx
xorl %edx, %edx
divq %rcx
movzwl %ax, %eax
movl %eax, %esi
callq 0x344b0
movq (%rax), %rax
movq %rax, 0x28(%rsp)
cmpq $0x0, 0x28(%rsp)
jne 0x4077b
movl $0x10, %edi
callq 0x8200
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x8(%rsp)
leaq 0x6b9d5(%rip), %rsi     # 0xac114
callq 0x87d0
jmp 0x40746
movq 0x8(%rsp), %rdi
movq 0x99876(%rip), %rsi     # 0xd9fc8
movq 0x99857(%rip), %rdx     # 0xd9fb0
callq 0x8710
movq 0x8(%rsp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x20(%rsp)
movl %eax, 0x1c(%rsp)
callq 0x8330
jmp 0x40886
movq 0x28(%rsp), %rax
movw 0x20(%rax), %cx
movq 0x30(%rsp), %rax
movw %cx, 0x2(%rax)
movq 0x28(%rsp), %rax
cmpl $0x0, 0x1c(%rax)
jne 0x4080b
movq 0x30(%rsp), %rax
movb $0x2, (%rax)
movq 0x28(%rsp), %rax
movq 0x10(%rax), %rax
movl %eax, %ecx
movq 0x30(%rsp), %rax
movl %ecx, 0x30(%rax)
movq 0x28(%rsp), %rax
movq 0x10(%rax), %rax
shrq $0x20, %rax
movl %eax, %ecx
movq 0x30(%rsp), %rax
movl %ecx, 0x34(%rax)
movq 0x28(%rsp), %rax
movl 0x18(%rax), %eax
movzwl %ax, %ecx
andl $0xffff, %ecx           # imm = 0xFFFF
movq 0x30(%rsp), %rax
movl %ecx, 0x38(%rax)
movq 0x30(%rsp), %rax
movabsq $0xff0000000000, %rcx   # imm = 0xFF0000000000
movq %rcx, 0x20(%rax)
movq 0x30(%rsp), %rax
movabsq $0xff0000001000, %rcx   # imm = 0xFF0000001000
movq %rcx, 0x28(%rax)
jmp 0x4087c
movq 0x30(%rsp), %rax
movb $0x1, (%rax)
movq 0x28(%rsp), %rax
movq 0x10(%rax), %rax
movl %eax, %ecx
movq 0x30(%rsp), %rax
movl %ecx, 0x30(%rax)
movq 0x28(%rsp), %rax
movq 0x10(%rax), %rax
shrq $0x20, %rax
movl %eax, %ecx
movq 0x30(%rsp), %rax
movl %ecx, 0x34(%rax)
movq 0x28(%rsp), %rax
movl 0x18(%rax), %eax
movzwl %ax, %ecx
andl $0xffff, %ecx           # imm = 0xFFFF
movq 0x30(%rsp), %rax
movl %ecx, 0x38(%rax)
movq 0x30(%rsp), %rax
movabsq $0xff0000000000, %rcx   # imm = 0xFF0000000000
movq %rcx, 0x20(%rax)
movq 0x30(%rsp), %rax
movabsq $0xff0000001000, %rcx   # imm = 0xFF0000001000
movq %rcx, 0x28(%rax)
movq 0x30(%rsp), %rax
addq $0x48, %rsp
retq
movq 0x20(%rsp), %rdi
callq 0x8770