// File: /workspace/github_c_makefile_star2_O2/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
pushq $0x1
popq %rdx
cmpl $0x0, 0x24(%rdi)
je 0x3916
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 0x397c
leaq 0x8(%rdi), %r14
leaq (%rax,%rsi), %r15
leaq 0xbdc(%rip), %r9        # 0x4520
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 0x3d89
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
jmp 0x3d93
cmpl $0x90, %r9d
je 0x390e
movw %si, 0x16(%rdi)
movl $0x1, 0x24(%rdi)
pushq $0x2
popq %rbx
jmp 0x390e
callq 0x3753
jmp 0x390e
movzbl 0x1(%r15), %eax
movzwl (%r14,%rax,2), %edi
callq 0x1050
movq 0x3610(%rip), %rax      # 0x6fc8
movq (%rax), %rdi
callq 0x1200
jmp 0x390e
movzbl 0x2(%r15), %ecx
movb (%r14,%rcx,2), %cl
movzbl 0x1(%r15), %edx
movzwl (%r14,%rdx,2), %edx
jmp 0x3af9
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
orw %ax, (%r14,%rcx,2)
jmp 0x390e
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 0x390e
cmpl $0x0, 0x20(%rdi)
jne 0x390e
jmp 0x3d07
cmpl $0x0, 0x20(%rdi)
jne 0x3d07
jmp 0x390e
cmpl $0x0, 0x20(%rdi)
jns 0x3d07
jmp 0x390e
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 0x390e
movzbl 0x2(%r15), %eax
movzbl 0x3(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
orw (%r14,%rax,2), %cx
jmp 0x3cd0
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
subw %ax, (%r14,%rcx,2)
jmp 0x390e
movzwl 0x1a(%rdi), %ecx
movzwl (%rax,%rcx), %eax
rolw $0x8, %ax
movw %ax, 0x16(%rdi)
leal 0x2(%rcx), %eax
movw %ax, 0x1a(%rdi)
jmp 0x390e
movzbl 0x1(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
rolw $0x8, %cx
movzwl 0x2(%r15), %edx
rolw $0x8, %dx
movzwl %dx, %edx
jmp 0x3bd4
movzbl 0x2(%r15), %eax
movzbl 0x3(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
addw (%r14,%rax,2), %cx
jmp 0x3cd0
movzbl 0x1(%r15), %ecx
movb (%r14,%rcx,2), %cl
movzwl 0x2(%r15), %edx
movb %cl, (%rax,%rdx)
jmp 0x390e
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
addw %ax, (%r14,%rcx,2)
jmp 0x390e
movzbl 0x2(%r15), %eax
movzwl (%r14,%rax,2), %eax
movzbl 0x3(%r15), %ecx
xorl %edx, %edx
divw (%r14,%rcx,2)
xorl %ebx, %ebx
jmp 0x3d5a
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 0x390e
movzbl 0x2(%r15), %eax
movzbl 0x3(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
andw (%r14,%rax,2), %cx
jmp 0x3cd0
cmpl $0x0, 0x20(%rdi)
jns 0x390e
jmp 0x3d07
movzbl 0x2(%r15), %eax
movzwl (%r14,%rax,2), %eax
movzbl 0x3(%r15), %ecx
subw (%r14,%rcx,2), %ax
jmp 0x3d5a
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 0x3c98
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 0x390e
movzbl 0x2(%r15), %eax
movzbl 0x3(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
imulw (%r14,%rax,2), %cx
jmp 0x3cd0
movl $0x1, 0x24(%rdi)
jmp 0x390c
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
imulw (%r14,%rcx,2), %ax
jmp 0x3d5f
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
andw %ax, (%r14,%rcx,2)
jmp 0x390e
cmpl $0x0, 0x20(%rdi)
jg 0x3d07
jmp 0x390e
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 0x390e
movzbl 0x2(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
jmp 0x3c7f
movzwl 0x2(%r15), %ecx
rolw $0x8, %cx
movzwl %cx, %ecx
movzbl (%rax,%rcx), %eax
jmp 0x3d41
movzwl 0x1a(%rdi), %ecx
addl $-0x2, %ecx
movw %cx, 0x1a(%rdi)
movzwl 0x2(%r15), %edx
movzwl %cx, %ecx
movw %dx, (%rax,%rcx)
jmp 0x390e
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
movzbl 0x1(%r15), %ecx
xorw %ax, (%r14,%rcx,2)
jmp 0x390e
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 0x390e
movzwl 0x2(%r15), %ecx
rolw $0x8, %cx
movzwl %cx, %ecx
jmp 0x3cf7
movzbl 0x2(%r15), %ecx
movzwl (%r14,%rcx,2), %ecx
movzwl (%rax,%rcx), %eax
jmp 0x3d36
cmpl $0x0, 0x20(%rdi)
jg 0x390e
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
addl %eax, %ecx
movw %cx, 0x16(%rdi)
jmp 0x390e
movzbl 0x1(%r15), %eax
movzwl 0x8(%rdi,%rax,2), %eax
movzbl 0x2(%r15), %ecx
movzwl 0x8(%rdi,%rcx,2), %ecx
jmp 0x3d7f
movzwl 0x2(%r15), %eax
rolw $0x8, %ax
jmp 0x3d5a
callq 0x11a0
movzbl 0x1(%r15), %ecx
movw %ax, (%r14,%rcx,2)
jmp 0x390e
movzbl 0x2(%r15), %eax
movzwl (%r14,%rax,2), %eax
movzbl 0x1(%r15), %ecx
movw %ax, (%r14,%rcx,2)
jmp 0x390e
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 0x390e
movzbl 0x1(%r15), %eax
movzwl 0x8(%rdi,%rax,2), %eax
addw %ax, 0x16(%rdi)
jmp 0x390e
nopl (%rax)