// File: /workspace/github_c_makefile_star2_O2/minkcv[P]vm/machine/cpu.c
// Function: exec
void exec(CPU* cpu, Instruction* instr, uint8_t memory[MEMORY_SEGMENT_COUNT][MEMORY_SEGMENT_SIZE])
{
    switch(instr->opcode)
    {
        case EXT:
            switch(instr->arg0)
            {
                case EXT_HALT:
                    printf("Exiting at halt instruction (instruction %ld)\n", (cpu->pc - cpu->code));
                    exit(0);
                    break;
                case EXT_CPY:
                    cpu->regs[instr->arg1] = cpu->regs[instr->arg2];
                    break;
                case EXT_NOT:
                    cpu->regs[instr->arg1] = ~(cpu->regs[instr->arg2]);
                    break;
                case EXT_LSL:
                    cpu->regs[instr->arg1] = cpu->regs[instr->arg1] << cpu->regs[instr->arg2];
                    break;
                case EXT_LSR:
                    cpu->regs[instr->arg1] = cpu->regs[instr->arg1] >> cpu->regs[instr->arg2];
                    break;
                case EXT_JMP:
                    cpu->pc = cpu->code + (cpu->regs[instr->arg1] * JUMP_SEGMENT_SIZE) + cpu->regs[instr->arg2] - 1;
                    break;
                case EXT_NOP:
                    break;
                case EXT_BRKP:
                    if (cpu->debugMode)
                    {
                        cpu->breakState = 1;
                        printf("Entering break state\n");
                    }
                    break;
            }
            break;
        case ADD:
            cpu->regs[instr->arg0] = cpu->regs[instr->arg1] + cpu->regs[instr->arg2];
            break;
        case SUB:
            cpu->regs[instr->arg0] = cpu->regs[instr->arg1] - cpu->regs[instr->arg2];
            break;
        case ADDC:
            cpu->regs[instr->arg0] += ((instr->arg1 << 4) & 0x00F0) + instr->arg2;
            break;
        case SUBC:
            cpu->regs[instr->arg0] -= ((instr->arg1 << 4) & 0x00F0) + instr->arg2;
            break;
        case CMP:
            if (cpu->regs[instr->arg1] < cpu->regs[instr->arg2])
                cpu->regs[instr->arg0] = 0;
            else if (cpu->regs[instr->arg1] > cpu->regs[instr->arg2])
                cpu->regs[instr->arg0] = 2;
            else
                cpu->regs[instr->arg0] = 1;
            break;
        case JLT:
            if (cpu->regs[instr->arg0] == 0)
                cpu->pc = cpu->code + (cpu->regs[instr->arg1] * JUMP_SEGMENT_SIZE) + cpu->regs[instr->arg2] - 1;
            break;
        case JGT:
            if (cpu->regs[instr->arg0] == 2)
                cpu->pc = cpu->code + (cpu->regs[instr->arg1] * JUMP_SEGMENT_SIZE) + cpu->regs[instr->arg2] - 1;
            break;
        case JEQ:
            if (cpu->regs[instr->arg0] == 1)
                cpu->pc = cpu->code + (cpu->regs[instr->arg1] * JUMP_SEGMENT_SIZE) + cpu->regs[instr->arg2] - 1;
            break;
        case LDR:
            cpu->regs[instr->arg0] = memory[cpu->regs[instr->arg1]][cpu->regs[instr->arg2]];
            break;
        case STR:
            if (cpu->regs[instr->arg1] < 128) // Segment is not part of ROM
                memory[cpu->regs[instr->arg1]][cpu->regs[instr->arg2]] = cpu->regs[instr->arg0];
            else
            {
                printf("Attempted illegal write to ROM\n");
                exit(1);
            }
            break;
        case LRC:
            cpu->regs[instr->arg0] = ((instr->arg1 << 4) & 0x00F0) + instr->arg2;
            break;
        case AND:
            cpu->regs[instr->arg0] = cpu->regs[instr->arg1] & cpu->regs[instr->arg2];
            break;
        case OR:
            cpu->regs[instr->arg0] = cpu->regs[instr->arg1] | cpu->regs[instr->arg2];
            break;
        case XOR:
            cpu->regs[instr->arg0] = cpu->regs[instr->arg1] ^ cpu->regs[instr->arg2];
            break;
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
movzwl (%rsi), %eax
movl %eax, %ecx
andl $0xf, %ecx
leaq 0xbb7(%rip), %rsi       # 0x3200
movslq (%rsi,%rcx,4), %rcx
addq %rsi, %rcx
jmpq *%rcx
movl %eax, %ecx
shrl $0x4, %ecx
andl $0xf, %ecx
cmpw $0x7, %cx
ja 0x283a
leaq 0xbd5(%rip), %rdx       # 0x3240
movslq (%rdx,%rcx,4), %rcx
addq %rdx, %rcx
jmpq *%rcx
movl %eax, %ecx
shrl $0xc, %ecx
movb (%rdi,%rcx), %cl
jmp 0x28a0
movl %eax, %ecx
shrl $0x8, %ecx
andl $0xf, %ecx
movl %eax, %edx
shrl $0xc, %edx
movb (%rdi,%rdx), %dl
orb (%rdi,%rcx), %dl
jmp 0x27ac
movl %eax, %ecx
shrl $0x8, %ecx
andl $0xf, %ecx
movsbq (%rdi,%rcx), %rcx
testq %rcx, %rcx
js 0x28a8
movl %eax, %esi
shrl $0x4, %esi
andl $0xf, %esi
movb (%rdi,%rsi), %sil
shrl $0xc, %eax
movzbl (%rdi,%rax), %eax
shlq $0x8, %rcx
addq %rcx, %rdx
movb %sil, (%rax,%rdx)
jmp 0x283a
movl %eax, %ecx
shrl $0x4, %ecx
movl %ecx, %edx
andl $0xf0, %edx
shrl $0xc, %eax
orl %edx, %eax
andl $0xf, %ecx
addb %al, (%rdi,%rcx)
jmp 0x283a
movl %eax, %ecx
shrl $0x4, %ecx
movl %ecx, %edx
andl $0xf0, %edx
shrl $0xc, %eax
orl %edx, %eax
andl $0xf, %ecx
movb %al, (%rdi,%rcx)
jmp 0x283a
movl %eax, %ecx
shrl $0x4, %ecx
andl $0xf, %ecx
cmpb $0x1, (%rdi,%rcx)
je 0x2814
jmp 0x283a
movl %eax, %ecx
shrl $0x8, %ecx
andl $0xf, %ecx
movl %eax, %edx
shrl $0xc, %edx
movb (%rdi,%rdx), %dl
addb (%rdi,%rcx), %dl
jmp 0x27ac
movl %eax, %ecx
shrl $0x8, %ecx
andl $0xf, %ecx
movl %eax, %edx
shrl $0xc, %edx
movb (%rdi,%rdx), %dl
xorb (%rdi,%rcx), %dl
jmp 0x27ac
movl %eax, %ecx
shrl $0x8, %ecx
andl $0xf, %ecx
movb (%rdi,%rcx), %cl
movl %eax, %edx
shrl $0xc, %edx
subb (%rdi,%rdx), %cl
jmp 0x27fb
movl %eax, %ecx
shrl $0x4, %ecx
andl $0xf, %ecx
cmpb $0x0, (%rdi,%rcx)
jne 0x283a
jmp 0x2814
movl %eax, %ecx
shrl $0x4, %ecx
movl %ecx, %edx
andl $0xf0, %edx
shrl $0xc, %eax
orl %edx, %eax
andl $0xf, %ecx
subb %al, (%rdi,%rcx)
jmp 0x283a
movl %eax, %ecx
shrl $0x8, %ecx
andl $0xf, %ecx
movl %eax, %edx
shrl $0xc, %edx
movb (%rdi,%rdx), %dl
andb (%rdi,%rcx), %dl
shrl $0x4, %eax
andl $0xf, %eax
movb %dl, (%rdi,%rax)
jmp 0x283a
movl %eax, %ecx
shrl $0x8, %ecx
andl $0xf, %ecx
movb (%rdi,%rcx), %cl
movl %eax, %edx
shrl $0xc, %edx
movb (%rdi,%rdx), %dl
shrl $0x4, %eax
andl $0xf, %eax
cmpb %dl, %cl
jae 0x283c
movb $0x0, (%rdi,%rax)
jmp 0x283a
movl %eax, %ecx
shrl $0x8, %ecx
andl $0xf, %ecx
movzbl (%rdi,%rcx), %ecx
movl %eax, %esi
shrl $0xc, %esi
movzbl (%rdi,%rsi), %esi
shll $0x8, %ecx
addq %rcx, %rdx
movb (%rsi,%rdx), %cl
shrl $0x4, %eax
andl $0xf, %eax
movb %cl, (%rdi,%rax)
jmp 0x283a
movl %eax, %ecx
shrl $0x4, %ecx
andl $0xf, %ecx
cmpb $0x2, (%rdi,%rcx)
jne 0x283a
movl %eax, %ecx
shrl $0x8, %ecx
andl $0xf, %ecx
movzbl (%rdi,%rcx), %ecx
shll $0x9, %ecx
addq 0x18(%rdi), %rcx
shrl $0xc, %eax
movzbl (%rdi,%rax), %eax
leaq (%rcx,%rax,2), %rax
addq $-0x2, %rax
movq %rax, 0x10(%rdi)
popq %rbp
retq
cmpb %dl, %cl
jbe 0x2846
movb $0x2, (%rdi,%rax)
jmp 0x283a
movb $0x1, (%rdi,%rax)
jmp 0x283a
movl %eax, %edx
shrl $0x8, %edx
andl $0xf, %edx
movzbl (%rdi,%rdx), %esi
shrl $0xc, %eax
movb (%rdi,%rax), %cl
shll %cl, %esi
jmp 0x2876
movl %eax, %edx
shrl $0x8, %edx
andl $0xf, %edx
movzbl (%rdi,%rdx), %esi
shrl $0xc, %eax
movb (%rdi,%rax), %cl
shrl %cl, %esi
movb %sil, (%rdi,%rdx)
jmp 0x283a
cmpl $0x0, 0x20(%rdi)
je 0x283a
movl $0x1, 0x24(%rdi)
leaq 0x89a(%rip), %rdi       # 0x312a
popq %rbp
jmp 0x11d0
movl %eax, %ecx
shrl $0xc, %ecx
movb (%rdi,%rcx), %cl
notb %cl
shrl $0x8, %eax
jmp 0x27fe
leaq 0xbc6(%rip), %rdi       # 0x3475
callq 0x11d0
pushq $0x1
popq %rdi
callq 0x1180
movq 0x10(%rdi), %rsi
subq 0x18(%rdi), %rsi
sarq %rsi
leaq 0xb19(%rip), %rdi       # 0x33e7
xorl %eax, %eax
callq 0x1040
xorl %edi, %edi
callq 0x1180