// File: /workspace/github_c_makefile_star2_O3/endeav0r[P]hsvm/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 :
        vm->regs[ins->operand_0] = vm->regs[ins->operand_1] + vm->regs[ins->operand_2];
        break;
    case OP_SUB :
        vm->regs[ins->operand_0] = vm->regs[ins->operand_1] - vm->regs[ins->operand_2];
        break;
    case OP_MUL :
        vm->regs[ins->operand_0] = vm->regs[ins->operand_1] * vm->regs[ins->operand_2];
        break;
    case OP_DIV :
        vm->regs[ins->operand_0] = vm->regs[ins->operand_1] / vm->regs[ins->operand_2];
        break;
    case OP_MOD :
        vm->regs[ins->operand_0] = vm->regs[ins->operand_1] % vm->regs[ins->operand_2];
        break;
    case OP_AND :
        vm->regs[ins->operand_0] = vm->regs[ins->operand_1] & vm->regs[ins->operand_2];
        break;
    case OP_OR :
        vm->regs[ins->operand_0] = vm->regs[ins->operand_1] | vm->regs[ins->operand_2];
        break;
    case OP_XOR :
        vm->regs[ins->operand_0] = vm->regs[ins->operand_1] ^ vm->regs[ins->operand_2];
        break;
    case OP_ADDLVAL :
        vm->regs[ins->operand_0] += ntohs(ins->lval);
        break;
    case OP_SUBLVAL :
        vm->regs[ins->operand_0] -= ntohs(ins->lval);
        break;
    case OP_MULLVAL :
        vm->regs[ins->operand_0] *= ntohs(ins->lval);
        break;
    case OP_DIVLVAL :
        vm->regs[ins->operand_0] /= ntohs(ins->lval);
        break;
    case OP_MODLVAL :
        vm->regs[ins->operand_0] %= ntohs(ins->lval);
        break;
    case OP_ANDLVAL :
        vm->regs[ins->operand_0] &= ntohs(ins->lval);
        break;
    case OP_ORLVAL :
        vm->regs[ins->operand_0] |= ntohs(ins->lval);
        break;
    case OP_XORLVAL :
        vm->regs[ins->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);
        vm->regs[ins->operand_0] = ntohs(tmp);
        break;
    case OP_LOADR :
        memcpy(&tmp, &(vm->mem[vm->regs[ins->operand_1]]), 2);
        vm->regs[ins->operand_0] = ntohs(tmp);
        break;
    case OP_LOADB :
        vm->regs[ins->operand_0] = vm->mem[ntohs(ins->lval)];
        break;
    case OP_LOADBR :
        vm->regs[ins->operand_0] = vm->mem[vm->regs[ins->operand_1]];
        break;
    case OP_STOR :
        tmp = htons(vm->regs[ins->operand_0]);
        memcpy(&(vm->mem[ntohs(ins->lval)]), &tmp, 2);
        break;
    case OP_STORR :
        tmp = htons(vm->regs[ins->operand_1]);
        memcpy(&(vm->mem[vm->regs[ins->operand_0]]), &tmp, 2);
        break;
    case OP_STORB :
        vm->mem[ins->lval] = vm->regs[ins->operand_0] & 0xff;
        break;
    case OP_STORBR :
        vm->mem[vm->regs[ins->operand_0]] = vm->regs[ins->operand_1] & 0xff;
        break;
    case OP_IN :
        vm->regs[ins->operand_0] = getchar();
        break;
    case OP_OUT :
        putchar(vm->regs[ins->operand_0]);
        fflush(stdout);
        break;
    case OP_PUSH :
        vm->regs[REG_SP] -= 2;
        tmp = htons(vm->regs[ins->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);
        vm->regs[ins->operand_0] = ntohs(tmp);
        vm->regs[REG_SP] += 2;
        break;
    case OP_MOV :
        vm->regs[ins->operand_0] = vm->regs[ins->operand_1];
        break;
    case OP_MOVLVAL :
        vm->regs[ins->operand_0] = ntohs(ins->lval);
        break;
    case OP_CMP :
        vm->flags = vm->regs[ins->operand_0] - vm->regs[ins->operand_1];
        break;
    case OP_CMPLVAL :
        vm->flags = vm->regs[ins->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
movl $0x1, %ebx
cmpl $0x0, 0x24(%rdi)
je 0x3b10
movl %ebx, %eax
popq %rbx
popq %r14
popq %r15
retq
movq (%rdi), %rax
movzwl 0x16(%rdi), %edx
leal 0x4(%rdx), %ecx
movw %cx, 0x16(%rdi)
movzbl (%rax,%rdx), %r8d
xorl %ebx, %ebx
leal -0x10(%r8), %esi
cmpl $0x51, %esi
ja 0x3b74
leaq 0x8(%rdi), %r14
leaq (%rax,%rdx), %r15
leaq 0xa73(%rip), %r8        # 0x45b0
movslq (%r8,%rsi,4), %rsi
addq %r8, %rsi
jmpq *%rsi
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 0x3f88
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
jmp 0x3f92
cmpl $0x90, %r8d
je 0x3b08
movw %dx, 0x16(%rdi)
movl $0x1, 0x24(%rdi)
movl $0x2, %ebx
jmp 0x3b08
callq 0x3916
jmp 0x3b08
movzbl 0x1(%r15), %eax
movzwl (%r14,%rax,2), %edi
callq 0x1050
movq 0x3416(%rip), %rax      # 0x6fc8
movq (%rax), %rdi
callq 0x1200
jmp 0x3b08
movzbl 0x2(%r15), %ecx
movb (%r14,%rcx,2), %cl
movzbl 0x1(%r15), %edx
movzwl (%r14,%rdx,2), %edx
jmp 0x3cf3
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
orw %ax, (%r14,%rcx,2)
jmp 0x3b08
movzwl 0x1a(%rdi), %ecx
movzwl (%rax,%rcx), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
movw %ax, 0x8(%rdi,%rcx,2)
addw $0x2, 0x1a(%rdi)
jmp 0x3b08
cmpl $0x0, 0x20(%rdi)
jne 0x3b08
jmp 0x3f06
cmpl $0x0, 0x20(%rdi)
jne 0x3f06
jmp 0x3b08
cmpl $0x0, 0x20(%rdi)
jns 0x3f06
jmp 0x3b08
movzwl 0x2(%r15), %ecx
rolw $0x8, %cx
movzbl 0x1(%r15), %esi
movzwl (%r14,%rsi,2), %eax
xorl %ebx, %ebx
xorl %edx, %edx
divw %cx
movw %dx, (%r14,%rsi,2)
jmp 0x3b08
movzbl 0x2(%r15), %eax
movzbl 0x3(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
orw (%r14,%rax,2), %cx
jmp 0x3ecf
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
subw %ax, (%r14,%rcx,2)
jmp 0x3b08
movzwl 0x1a(%rdi), %ecx
movzwl (%rax,%rcx), %eax
rolw $0x8, %ax
movw %ax, 0x16(%rdi)
leal 0x2(%rcx), %eax
movw %ax, 0x1a(%rdi)
jmp 0x3b08
movzbl 0x1(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
rolw $0x8, %cx
movzwl 0x2(%r15), %edx
rolw $0x8, %dx
movzwl %dx, %edx
jmp 0x3dce
movzbl 0x2(%r15), %eax
movzbl 0x3(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
addw (%r14,%rax,2), %cx
jmp 0x3ecf
movzbl 0x1(%r15), %ecx
movb (%r14,%rcx,2), %cl
movzwl 0x2(%r15), %edx
movb %cl, (%rax,%rdx)
jmp 0x3b08
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
addw %ax, (%r14,%rcx,2)
jmp 0x3b08
movzbl 0x2(%r15), %eax
movzwl (%r14,%rax,2), %eax
movzbl 0x3(%r15), %ecx
xorl %edx, %edx
divw (%r14,%rcx,2)
xorl %ebx, %ebx
jmp 0x3f59
movzbl 0x2(%r15), %eax
movzwl (%r14,%rax,2), %eax
movzbl 0x3(%r15), %ecx
xorl %edx, %edx
divw (%r14,%rcx,2)
xorl %ebx, %ebx
movzbl 0x1(%r15), %eax
movw %dx, (%r14,%rax,2)
jmp 0x3b08
movzbl 0x2(%r15), %eax
movzbl 0x3(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
andw (%r14,%rax,2), %cx
jmp 0x3ecf
cmpl $0x0, 0x20(%rdi)
jns 0x3b08
jmp 0x3f06
movzbl 0x2(%r15), %eax
movzwl (%r14,%rax,2), %eax
movzbl 0x3(%r15), %ecx
subw (%r14,%rcx,2), %ax
jmp 0x3f59
movzwl 0x1a(%rdi), %ecx
addl $-0x2, %ecx
movw %cx, 0x1a(%rdi)
movzbl 0x1(%r15), %edx
movzwl 0x8(%rdi,%rdx,2), %edx
rolw $0x8, %dx
jmp 0x3e97
movzbl 0x2(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
rolw $0x8, %cx
movzbl 0x1(%r15), %edx
movzwl (%r14,%rdx,2), %edx
movw %cx, (%rax,%rdx)
jmp 0x3b08
movzbl 0x2(%r15), %eax
movzbl 0x3(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
imulw (%r14,%rax,2), %cx
jmp 0x3ecf
movl $0x1, 0x24(%rdi)
movl $0x1, %ebx
jmp 0x3b08
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
imulw (%r14,%rcx,2), %ax
jmp 0x3f5e
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
andw %ax, (%r14,%rcx,2)
jmp 0x3b08
cmpl $0x0, 0x20(%rdi)
jg 0x3f06
jmp 0x3b08
movzwl 0x2(%r15), %ecx
rolw $0x8, %cx
movzbl 0x1(%r15), %esi
movzwl (%r14,%rsi,2), %eax
xorl %ebx, %ebx
xorl %edx, %edx
divw %cx
movw %ax, (%r14,%rsi,2)
jmp 0x3b08
movzbl 0x2(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
jmp 0x3e7e
movzwl 0x2(%r15), %ecx
rolw $0x8, %cx
movzwl %cx, %ecx
movzbl (%rax,%rcx), %eax
jmp 0x3f40
movzwl 0x1a(%rdi), %ecx
addl $-0x2, %ecx
movw %cx, 0x1a(%rdi)
movzwl 0x2(%r15), %edx
movzwl %cx, %ecx
movw %dx, (%rax,%rcx)
jmp 0x3b08
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
xorw %ax, (%r14,%rcx,2)
jmp 0x3b08
movzbl 0x2(%r15), %eax
movzbl 0x3(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
xorw (%r14,%rax,2), %cx
movzbl 0x1(%r15), %eax
movw %cx, (%r14,%rax,2)
jmp 0x3b08
movzwl 0x2(%r15), %ecx
rolw $0x8, %cx
movzwl %cx, %ecx
jmp 0x3ef6
movzbl 0x2(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
movzwl (%rax,%rcx), %eax
jmp 0x3f35
cmpl $0x0, 0x20(%rdi)
jg 0x3b08
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
addl %eax, %ecx
movw %cx, 0x16(%rdi)
jmp 0x3b08
movzbl 0x1(%r15), %eax
movzwl 0x8(%rdi,%rax,2), %eax
movzbl 0x2(%r15), %ecx
movzwl 0x8(%rdi,%rcx,2), %ecx
jmp 0x3f7e
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
jmp 0x3f59
callq 0x11a0
movzbl 0x1(%r15), %ecx
movw %ax, (%r14,%rcx,2)
jmp 0x3b08
movzbl 0x2(%r15), %eax
movzwl (%r14,%rax,2), %eax
movzbl 0x1(%r15), %ecx
movw %ax, (%r14,%rcx,2)
jmp 0x3b08
movzbl 0x1(%r15), %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 0x3b08
movzbl 0x1(%r15), %eax
movzwl 0x8(%rdi,%rax,2), %eax
addw %ax, 0x16(%rdi)
jmp 0x3b08
nopl (%rax,%rax)