// File: CMU-SAFARI[P]MQSim/src/ssd/Host_Interface_NVMe.cpp
// Function: SSD_Components::Request_Fetch_Unit_NVMe::Process_pcie_write_message(unsigned long, void*, unsigned int)
void Request_Fetch_Unit_NVMe::Process_pcie_write_message(uint64_t address, void *payload, unsigned int payload_size)
{
	Host_Interface_NVMe *hi = (Host_Interface_NVMe *)host_interface;
	uint64_t val = (uint64_t)payload;
	switch (address)
	{
	case SUBMISSION_QUEUE_REGISTER_1:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Submission_queue_tail_pointer_update(0, (uint16_t)val);
		break;
	case COMPLETION_QUEUE_REGISTER_1:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Completion_queue_head_pointer_update(0, (uint16_t)val);
		break;
	case SUBMISSION_QUEUE_REGISTER_2:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Submission_queue_tail_pointer_update(1, (uint16_t)val);
		break;
	case COMPLETION_QUEUE_REGISTER_2:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Completion_queue_head_pointer_update(1, (uint16_t)val);
		break;
	case SUBMISSION_QUEUE_REGISTER_3:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Submission_queue_tail_pointer_update(2, (uint16_t)val);
		break;
	case COMPLETION_QUEUE_REGISTER_3:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Completion_queue_head_pointer_update(2, (uint16_t)val);
		break;
	case SUBMISSION_QUEUE_REGISTER_4:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Submission_queue_tail_pointer_update(3, (uint16_t)val);
		break;
	case COMPLETION_QUEUE_REGISTER_4:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Completion_queue_head_pointer_update(3, (uint16_t)val);
		break;
	case SUBMISSION_QUEUE_REGISTER_5:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Submission_queue_tail_pointer_update(4, (uint16_t)val);
		break;
	case COMPLETION_QUEUE_REGISTER_5:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Completion_queue_head_pointer_update(4, (uint16_t)val);
		break;
	case SUBMISSION_QUEUE_REGISTER_6:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Submission_queue_tail_pointer_update(5, (uint16_t)val);
		break;
	case COMPLETION_QUEUE_REGISTER_6:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Completion_queue_head_pointer_update(5, (uint16_t)val);
		break;
	case SUBMISSION_QUEUE_REGISTER_7:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Submission_queue_tail_pointer_update(6, (uint16_t)val);
		break;
	case COMPLETION_QUEUE_REGISTER_7:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Completion_queue_head_pointer_update(6, (uint16_t)val);
		break;
	case SUBMISSION_QUEUE_REGISTER_8:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Submission_queue_tail_pointer_update(7, (uint16_t)val);
		break;
	case COMPLETION_QUEUE_REGISTER_8:
		((Input_Stream_Manager_NVMe *)(hi->input_stream_manager))->Completion_queue_head_pointer_update(7, (uint16_t)val);
		break;
	default:
		throw std::invalid_argument("Unknown register is written!");
	}
}

// Assembly:
subq $0x58, %rsp
movq %rdi, 0x50(%rsp)
movq %rsi, 0x48(%rsp)
movq %rdx, 0x40(%rsp)
movl %ecx, 0x3c(%rsp)
movq 0x50(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0x30(%rsp)
movq 0x40(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0x48(%rsp), %rax
addq $-0x1010, %rax          # imm = 0xEFF0
movq %rax, 0x10(%rsp)
subq $0x73, %rax
ja 0x86502
movq 0x10(%rsp), %rax
leaq 0x27c57(%rip), %rcx     # 0xadf5c
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
xorl %esi, %esi
movzwl %ax, %edx
callq 0x88070
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
xorl %esi, %esi
movzwl %ax, %edx
callq 0x881c0
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x1, %esi
movzwl %ax, %edx
callq 0x88070
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x1, %esi
movzwl %ax, %edx
callq 0x881c0
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x2, %esi
movzwl %ax, %edx
callq 0x88070
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x2, %esi
movzwl %ax, %edx
callq 0x881c0
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x3, %esi
movzwl %ax, %edx
callq 0x88070
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x3, %esi
movzwl %ax, %edx
callq 0x881c0
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x4, %esi
movzwl %ax, %edx
callq 0x88070
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x4, %esi
movzwl %ax, %edx
callq 0x881c0
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x5, %esi
movzwl %ax, %edx
callq 0x88070
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x5, %esi
movzwl %ax, %edx
callq 0x881c0
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x6, %esi
movzwl %ax, %edx
callq 0x88070
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x6, %esi
movzwl %ax, %edx
callq 0x881c0
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x7, %esi
movzwl %ax, %edx
callq 0x88070
jmp 0x86557
movq 0x30(%rsp), %rax
movq 0x50(%rax), %rdi
movq 0x28(%rsp), %rax
movl $0x7, %esi
movzwl %ax, %edx
callq 0x881c0
jmp 0x86557
movl $0x10, %edi
callq 0x8200
movq %rax, %rdi
movq %rdi, %rax
movq %rax, 0x8(%rsp)
leaq 0x27d03(%rip), %rsi     # 0xae221
callq 0x87d0
jmp 0x86525
movq 0x8(%rsp), %rdi
movq 0x53a97(%rip), %rsi     # 0xd9fc8
movq 0x53a78(%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 0x8655c
addq $0x58, %rsp
retq
movq 0x20(%rsp), %rdi
callq 0x8770
nopw %cs:(%rax,%rax)