// File: martinferianc[P]CPUSimulator-EIE2/src/mips_cpu.cpp
// Function: mips_cpu_step
mips_error mips_cpu_step(mips_cpu_h state){
	if(state==0)
		return mips_ErrorInvalidHandle;

	uint32_t* instruction_data = new uint32_t[8];
	string instruction;
	mips_error err;
	uint32_t mem_value;
	uint8_t dataOut[4];

	//FETCH
	if (state->pc % 4 == 0){
		err = mips_mem_read(state->mem, state->pc, 4, dataOut);
		mem_value = dataOut[0] | (uint32_t(dataOut[1]) << 8) | (uint32_t(dataOut[2]) << 16) | (uint32_t(dataOut[3]) << 24);
	} else {
		err = mips_ExceptionInvalidAlignment;
	}

	//DECODE
	if (err == mips_Success)
		err = mips_decode(mem_value, instruction_data);

	//EXECUTE
	if (err == mips_Success)
		err = mips_execute(state, state->mem, state->hi, state->lo, instruction_data, instruction, state->pcN, state->pc);

	//IF SUCCESS increase PC to new value and not JUMP or BRANCH
	if (err == mips_Success){
		state->pc = state->pcN;
		state->pcN = state->pcN + 4;
	}
	//IF JUMP/BRANCH - PC, PCN adjusted in execution
	if (err == mips_ExceptionBreak)
		err = mips_Success;

	//DEBUG
	switch(state->level){
		case 1:
			debug_level_1(state, instruction);
		break;

		case 2:
			debug_level_2(state, instruction);
		break;

		case 3:
			debug_level_3(state, instruction, state->dest);
		break;

		default:
		break;
	}

	delete [] instruction_data;
	return err;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x80, %rsp
movq %rdi, -0x10(%rbp)
cmpq $0x0, -0x10(%rbp)
jne 0x7db2
movl $0x1002, -0x4(%rbp)     # imm = 0x1002
jmp 0x7f6a
movl $0x20, %edi
callq 0x3030
movq %rax, -0x18(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x33b0
movq -0x10(%rbp), %rax
movl (%rax), %eax
andl $0x3, %eax
cmpl $0x0, %eax
jne 0x7e3b
movq -0x10(%rbp), %rax
movq 0xa0(%rax), %rdi
movl (%rax), %esi
movl $0x4, %edx
leaq -0x44(%rbp), %rcx
callq 0x7980
movl %eax, -0x58(%rbp)
jmp 0x7df7
movl -0x58(%rbp), %eax
movl %eax, -0x3c(%rbp)
movzbl -0x44(%rbp), %eax
movzbl -0x43(%rbp), %ecx
shll $0x8, %ecx
orl %ecx, %eax
movzbl -0x42(%rbp), %ecx
shll $0x10, %ecx
orl %ecx, %eax
movzbl -0x41(%rbp), %ecx
shll $0x18, %ecx
orl %ecx, %eax
movl %eax, -0x40(%rbp)
jmp 0x7e42
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x3170
jmp 0x7f76
movl $0x2003, -0x3c(%rbp)    # imm = 0x2003
cmpl $0x0, -0x3c(%rbp)
jne 0x7e60
movq -0x18(%rbp), %rsi
leaq -0x40(%rbp), %rdi
callq 0x8340
movl %eax, -0x5c(%rbp)
jmp 0x7e5a
movl -0x5c(%rbp), %eax
movl %eax, -0x3c(%rbp)
cmpl $0x0, -0x3c(%rbp)
jne 0x7ea8
movq -0x10(%rbp), %rdi
movq 0xa0(%rdi), %rsi
movq %rdi, %rdx
addq $0x4, %rdx
movq %rdi, %rcx
addq $0x8, %rcx
movq -0x18(%rbp), %r8
movq %rdi, %r9
addq $0xc, %r9
movq %rsp, %rax
movq %rdi, 0x8(%rax)
movq %r9, (%rax)
leaq -0x38(%rbp), %r9
callq 0x85e0
movl %eax, -0x60(%rbp)
jmp 0x7ea2
movl -0x60(%rbp), %eax
movl %eax, -0x3c(%rbp)
cmpl $0x0, -0x3c(%rbp)
jne 0x7ecc
movq -0x10(%rbp), %rax
movl 0xc(%rax), %ecx
movq -0x10(%rbp), %rax
movl %ecx, (%rax)
movq -0x10(%rbp), %rax
movl 0xc(%rax), %ecx
addl $0x4, %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0xc(%rax)
cmpl $0x2000, -0x3c(%rbp)    # imm = 0x2000
jne 0x7edc
movl $0x0, -0x3c(%rbp)
movq -0x10(%rbp), %rax
movl 0x90(%rax), %eax
movl %eax, -0x64(%rbp)
subl $0x1, %eax
je 0x7f04
jmp 0x7ef0
movl -0x64(%rbp), %eax
subl $0x2, %eax
je 0x7f15
jmp 0x7efa
movl -0x64(%rbp), %eax
subl $0x3, %eax
je 0x7f26
jmp 0x7f42
leaq -0x10(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0x7f80
jmp 0x7f13
jmp 0x7f44
leaq -0x10(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0x8010
jmp 0x7f24
jmp 0x7f44
movq -0x10(%rbp), %rax
movq 0x98(%rax), %rdx
leaq -0x10(%rbp), %rdi
leaq -0x38(%rbp), %rsi
callq 0x81b0
jmp 0x7f40
jmp 0x7f44
jmp 0x7f44
movq -0x18(%rbp), %rax
movq %rax, -0x70(%rbp)
cmpq $0x0, %rax
je 0x7f5b
movq -0x70(%rbp), %rdi
callq 0x3370
movl -0x3c(%rbp), %eax
movl %eax, -0x4(%rbp)
leaq -0x38(%rbp), %rdi
callq 0x3170
movl -0x4(%rbp), %eax
addq $0x80, %rsp
popq %rbp
retq
movq -0x50(%rbp), %rdi
callq 0x3440
nop