// File: /workspace/github_c_makefile_star2_O2/endeav0r[P]hvm/src/vm.c
// Function: vm_step
int vm_step (struct _vm * vm)
{
    const struct _instruction * ins;
    uint16_t tmp;

    if (vm->halted) return VM_HALTED;

    ins = (const struct _instruction *) &(vm->mem[vm->regs[REG_IP]]);

    vm->regs[REG_IP] += 4;

    switch (ins->opcode) {
    case OP_ADD     : RREG(operand_0) = RREG(operand_1) + RREG(operand_2); break;
    case OP_SUB     : RREG(operand_0) = RREG(operand_1) - RREG(operand_2); break;
    case OP_MUL     : RREG(operand_0) = RREG(operand_1) * RREG(operand_2); break;
    case OP_DIV     : RREG(operand_0) = RREG(operand_1) / RREG(operand_2); break;
    case OP_MOD     : RREG(operand_0) = RREG(operand_1) % RREG(operand_2); break;
    case OP_AND     : RREG(operand_0) = RREG(operand_1) & RREG(operand_2); break;
    case OP_OR      : RREG(operand_0) = RREG(operand_1) | RREG(operand_2); break;
    case OP_XOR     : RREG(operand_0) = RREG(operand_1) ^ RREG(operand_2); break;
    case OP_ADDLVAL : RREG(operand_0) += ntohs(ins->lval); break;
    case OP_SUBLVAL : RREG(operand_0) -= ntohs(ins->lval); break;
    case OP_MULLVAL : RREG(operand_0) *= ntohs(ins->lval); break;
    case OP_DIVLVAL : RREG(operand_0) /= ntohs(ins->lval); break;
    case OP_MODLVAL : RREG(operand_0) %= ntohs(ins->lval); break;
    case OP_ANDLVAL : RREG(operand_0) &= ntohs(ins->lval); break;
    case OP_ORLVAL  : RREG(operand_0) |= ntohs(ins->lval); break;
    case OP_XORLVAL : RREG(operand_0) ^= ntohs(ins->lval); break;

    case OP_JMP : vm->regs[REG_IP] += ntohs(ins->lval); break;
    case OP_JE  : if (vm->flags == 0) vm->regs[REG_IP] += ntohs(ins->lval); break;
    case OP_JNE : if (vm->flags != 0) vm->regs[REG_IP] += ntohs(ins->lval); break;
    case OP_JL  : if (vm->flags <  0) vm->regs[REG_IP] += ntohs(ins->lval); break;
    case OP_JLE : if (vm->flags <= 0) vm->regs[REG_IP] += ntohs(ins->lval); break;
    case OP_JG  : if (vm->flags >  0) vm->regs[REG_IP] += ntohs(ins->lval); break;
    case OP_JGE : if (vm->flags >= 0) vm->regs[REG_IP] += ntohs(ins->lval); break;

    case OP_CALL  :
    case OP_CALLR :
        vm->regs[REG_SP] -= 2;
        tmp = htons(vm->regs[REG_IP]);
        memcpy(&(vm->mem[vm->regs[REG_SP]]), &tmp, 2);
        if (ins->opcode == OP_CALL)
            vm->regs[REG_IP] += ntohs(ins->lval);
        else
            vm->regs[REG_IP] += vm->regs[ins->operand_0];
        break;
    case OP_RET :
        memcpy(&tmp, &(vm->mem[vm->regs[REG_SP]]), 2);
        vm->regs[REG_IP] = ntohs(tmp);
        vm->regs[REG_SP] += 2;
        break;
    case OP_LOAD :
        memcpy(&tmp, &(vm->mem[ntohs(ins->lval)]), 2);
        RREG(operand_0) = ntohs(tmp);
        break;
    case OP_LOADR :
        memcpy(&tmp, &(vm->mem[RREG(operand_1)]), 2);
        RREG(operand_0) = ntohs(tmp);
        break;
    case OP_STOR :
        tmp = htons(RREG(operand_0));
        memcpy(&(vm->mem[ntohs(ins->lval)]), &tmp, 2);
        break;
    case OP_STORR :
        tmp = htons(RREG(operand_1));
        memcpy(&(vm->mem[vm->regs[RREG(operand_0)]]), &tmp, 2);
        break;
    case OP_LOADB  : RREG(operand_0) = vm->mem[ntohs(ins->lval)]; break;
    case OP_LOADBR : RREG(operand_0) = vm->mem[RREG(operand_1)]; break;
    case OP_STORB  : vm->mem[ins->lval] = RREG(operand_0) & 0xff; break;
    case OP_STORBR : vm->mem[RREG(operand_0)] = RREG(operand_1) & 0xff; break;
    case OP_IN     : RREG(operand_0) = getchar(); break;
    case OP_OUT :
        putchar(RREG(operand_0));
        fflush(stdout);
        break;
    case OP_PUSH :
        vm->regs[REG_SP] -= 2;
        tmp = htons(RREG(operand_0));
        memcpy(&(vm->mem[vm->regs[REG_SP]]), &tmp, 2);
        break;
    case OP_PUSHLVAL :
        vm->regs[REG_SP] -= 2;
        tmp = ins->lval; // already in correct byte order
        memcpy(&(vm->mem[vm->regs[REG_SP]]), &tmp, 2);
        break;
    case OP_POP :
        memcpy(&tmp, &(vm->mem[vm->regs[REG_SP]]), 2);
        RREG(operand_0) = ntohs(tmp);
        vm->regs[REG_SP] += 2;
        break;
    case OP_MOV     : RREG(operand_0) = RREG(operand_1); break;
    case OP_MOVLVAL : RREG(operand_0) = ntohs(ins->lval); break;
    case OP_CMP     : vm->flags = RREG(operand_0) - RREG(operand_1); break;
    case OP_CMPLVAL : vm->flags = RREG(operand_0) - ntohs(ins->lval); break;
    case OP_HLT     : vm->halted = 1; return VM_HALTED;
    case OP_SYSCALL : vm_syscall(vm); break;
    case OP_NOP     : break;
    default :
        // on a bad instruction, reset IP
        vm->regs[REG_IP] -= 4;
        vm->halted = 1;
        return VM_BAD_INSTRUCTION;
    }
    return 0;
}

// Assembly:
pushq %r15
pushq %r14
pushq %rbx
pushq $0x1
popq %rdx
cmpl $0x0, 0x24(%rdi)
je 0x4e82
movl %edx, %ebx
movl %ebx, %eax
popq %rbx
popq %r14
popq %r15
retq
movq (%rdi), %rax
movzwl 0x16(%rdi), %esi
leal 0x4(%rsi), %ecx
movw %cx, 0x16(%rdi)
movzbl (%rax,%rsi), %r9d
xorl %ebx, %ebx
leal -0x10(%r9), %r8d
cmpl $0x51, %r8d
ja 0x4ee8
leaq 0x8(%rdi), %r14
leaq (%rax,%rsi), %r15
leaq 0x175c(%rip), %r9       # 0x660c
movslq (%r9,%r8,4), %r8
addq %r9, %r8
jmpq *%r8
movzwl 0x1a(%rdi), %edx
addl $-0x2, %edx
movw %dx, 0x1a(%rdi)
rolw $0x8, %cx
movzwl %dx, %edx
movw %cx, (%rax,%rdx)
cmpb $0x27, (%r15)
jne 0x537a
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
jmp 0x5384
cmpl $0x90, %r9d
je 0x4e7a
movw %si, 0x16(%rdi)
movl $0x1, 0x24(%rdi)
pushq $0x2
popq %rbx
jmp 0x4e7a
callq 0x4cbf
jmp 0x4e7a
movzbl 0x1(%r15), %eax
andl $0x7, %eax
movzwl (%r14,%rax,2), %edi
callq 0x2050
movq 0x40a1(%rip), %rax      # 0x8fc8
movq (%rax), %rdi
callq 0x2200
jmp 0x4e7a
movzbl 0x2(%r15), %ecx
andl $0x7, %ecx
movb (%r14,%rcx,2), %cl
movzbl 0x1(%r15), %edx
andl $0x7, %edx
movzwl (%r14,%rdx,2), %edx
jmp 0x5087
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
andl $0x7, %ecx
orw %ax, (%r14,%rcx,2)
jmp 0x4e7a
movzwl 0x1a(%rdi), %ecx
movzwl (%rax,%rcx), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %edx
andl $0x7, %edx
movw %ax, 0x8(%rdi,%rdx,2)
jmp 0x5029
cmpl $0x0, 0x20(%rdi)
jne 0x4e7a
jmp 0x52e2
cmpl $0x0, 0x20(%rdi)
jne 0x52e2
jmp 0x4e7a
cmpl $0x0, 0x20(%rdi)
jns 0x52e2
jmp 0x4e7a
movzwl 0x2(%r15), %ecx
rolw $0x8, %cx
movzbl 0x1(%r15), %esi
andl $0x7, %esi
movzwl (%r14,%rsi,2), %eax
xorl %ebx, %ebx
xorl %edx, %edx
divw %cx
movw %dx, (%r14,%rsi,2)
jmp 0x4e7a
movzbl 0x2(%r15), %eax
andl $0x7, %eax
movzbl 0x3(%r15), %ecx
andl $0x7, %ecx
movzwl (%r14,%rcx,2), %ecx
orw (%r14,%rax,2), %cx
jmp 0x52a5
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
andl $0x7, %ecx
subw %ax, (%r14,%rcx,2)
jmp 0x4e7a
movzwl 0x1a(%rdi), %ecx
movzwl (%rax,%rcx), %eax
rolw $0x8, %ax
movw %ax, 0x16(%rdi)
leal 0x2(%rcx), %eax
movw %ax, 0x1a(%rdi)
jmp 0x4e7a
movzbl 0x1(%r15), %ecx
andl $0x7, %ecx
movzwl (%r14,%rcx,2), %ecx
rolw $0x8, %cx
movzwl 0x2(%r15), %edx
rolw $0x8, %dx
movzwl %dx, %edx
jmp 0x518e
movzbl 0x2(%r15), %eax
andl $0x7, %eax
movzbl 0x3(%r15), %ecx
andl $0x7, %ecx
movzwl (%r14,%rcx,2), %ecx
addw (%r14,%rax,2), %cx
jmp 0x52a5
movzbl 0x1(%r15), %ecx
andl $0x7, %ecx
movb (%r14,%rcx,2), %cl
movzwl 0x2(%r15), %edx
movb %cl, (%rax,%rdx)
jmp 0x4e7a
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
andl $0x7, %ecx
addw %ax, (%r14,%rcx,2)
jmp 0x4e7a
movzbl 0x2(%r15), %eax
andl $0x7, %eax
movzwl (%r14,%rax,2), %eax
movzbl 0x3(%r15), %ecx
andl $0x7, %ecx
xorl %ebx, %ebx
xorl %edx, %edx
divw (%r14,%rcx,2)
jmp 0x5345
movzbl 0x2(%r15), %eax
andl $0x7, %eax
movzwl (%r14,%rax,2), %eax
movzbl 0x3(%r15), %ecx
andl $0x7, %ecx
xorl %ebx, %ebx
xorl %edx, %edx
divw (%r14,%rcx,2)
movzbl 0x1(%r15), %eax
andl $0x7, %eax
movw %dx, (%r14,%rax,2)
jmp 0x4e7a
movzbl 0x2(%r15), %eax
andl $0x7, %eax
movzbl 0x3(%r15), %ecx
andl $0x7, %ecx
movzwl (%r14,%rcx,2), %ecx
andw (%r14,%rax,2), %cx
jmp 0x52a5
cmpl $0x0, 0x20(%rdi)
jns 0x4e7a
jmp 0x52e2
movzbl 0x2(%r15), %eax
andl $0x7, %eax
movzwl (%r14,%rax,2), %eax
movzbl 0x3(%r15), %ecx
andl $0x7, %ecx
subw (%r14,%rcx,2), %ax
jmp 0x5345
movzwl 0x1a(%rdi), %ecx
addl $-0x2, %ecx
movw %cx, 0x1a(%rdi)
movzbl 0x1(%r15), %edx
andl $0x7, %edx
movzwl 0x8(%rdi,%rdx,2), %edx
rolw $0x8, %dx
jmp 0x5264
movzbl 0x2(%r15), %ecx
andl $0x7, %ecx
movzwl (%r14,%rcx,2), %ecx
rolw $0x8, %cx
movzbl 0x1(%r15), %edx
andl $0x7, %edx
movzwl (%r14,%rdx,2), %edx
movzwl (%r14,%rdx,2), %edx
movw %cx, (%rax,%rdx)
jmp 0x4e7a
movzbl 0x2(%r15), %eax
andl $0x7, %eax
movzbl 0x3(%r15), %ecx
andl $0x7, %ecx
movzwl (%r14,%rcx,2), %ecx
imulw (%r14,%rax,2), %cx
jmp 0x52a5
movl $0x1, 0x24(%rdi)
jmp 0x4e78
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
andl $0x7, %ecx
imulw (%r14,%rcx,2), %ax
jmp 0x534d
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
andl $0x7, %ecx
andw %ax, (%r14,%rcx,2)
jmp 0x4e7a
cmpl $0x0, 0x20(%rdi)
jg 0x52e2
jmp 0x4e7a
movzwl 0x2(%r15), %ecx
rolw $0x8, %cx
movzbl 0x1(%r15), %esi
andl $0x7, %esi
movzwl (%r14,%rsi,2), %eax
xorl %ebx, %ebx
xorl %edx, %edx
divw %cx
movw %ax, (%r14,%rsi,2)
jmp 0x4e7a
movzbl 0x2(%r15), %ecx
andl $0x7, %ecx
movzwl (%r14,%rcx,2), %ecx
jmp 0x524b
movzwl 0x2(%r15), %ecx
rolw $0x8, %cx
movzwl %cx, %ecx
movzbl (%rax,%rcx), %eax
jmp 0x5326
movzwl 0x1a(%rdi), %ecx
addl $-0x2, %ecx
movw %cx, 0x1a(%rdi)
movzwl 0x2(%r15), %edx
movzwl %cx, %ecx
movw %dx, (%rax,%rcx)
jmp 0x4e7a
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
andl $0x7, %ecx
xorw %ax, (%r14,%rcx,2)
jmp 0x4e7a
movzbl 0x2(%r15), %eax
andl $0x7, %eax
movzbl 0x3(%r15), %ecx
andl $0x7, %ecx
movzwl (%r14,%rcx,2), %ecx
xorw (%r14,%rax,2), %cx
movzbl 0x1(%r15), %eax
andl $0x7, %eax
movw %cx, (%r14,%rax,2)
jmp 0x4e7a
movzwl 0x2(%r15), %ecx
rolw $0x8, %cx
movzwl %cx, %ecx
jmp 0x52d2
movzbl 0x2(%r15), %ecx
andl $0x7, %ecx
movzwl (%r14,%rcx,2), %ecx
movzwl (%rax,%rcx), %eax
jmp 0x5317
cmpl $0x0, 0x20(%rdi)
jg 0x4e7a
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
addl %eax, %ecx
movw %cx, 0x16(%rdi)
jmp 0x4e7a
movzbl 0x1(%r15), %eax
andl $0x7, %eax
movzwl 0x8(%rdi,%rax,2), %eax
movzbl 0x2(%r15), %ecx
andl $0x7, %ecx
movzwl 0x8(%rdi,%rcx,2), %ecx
jmp 0x5370
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
jmp 0x5345
xorl %ebx, %ebx
xorl %eax, %eax
callq 0x245e
movzbl 0x1(%r15), %ecx
andl $0x7, %ecx
movw %ax, (%r14,%rcx,2)
jmp 0x4e7a
movzbl 0x2(%r15), %eax
andl $0x7, %eax
movzwl (%r14,%rax,2), %eax
movzbl 0x1(%r15), %ecx
andl $0x7, %ecx
movw %ax, (%r14,%rcx,2)
jmp 0x4e7a
movzbl 0x1(%r15), %eax
andl $0x7, %eax
movzwl 0x2(%r15), %ecx
rolw $0x8, %cx
movzwl 0x8(%rdi,%rax,2), %eax
movzwl %cx, %ecx
subl %ecx, %eax
movl %eax, 0x20(%rdi)
jmp 0x4e7a
movzbl 0x1(%r15), %eax
movzwl 0x8(%rdi,%rax,2), %eax
addw %ax, 0x16(%rdi)
jmp 0x4e7a
nopl (%rax)