// File: /workspace/github_c_makefile_star2_O3/minkcv[P]vm/machine/vm.c
// Function: run
void run(VM* vm)
{
    uint32_t displayStartTime = SDL_GetTicks();
    uint32_t displayWaitTime = 16; // 16ms = about 60 refreshes per second
    uint32_t cpuStartTime = SDL_GetTicks();
    uint32_t cpuInstructionCount = 0;

    // Enforce the instructions per second limit in sync with the display refreshes
    // 500,000 instructions per second is almost the same as 8064 instructions per 16 milliseconds.
    // 500,000 IPS == 8000 instructions / 0.016 seconds
    // 500,000 / 8064 = 62
    uint32_t instructionsPerSecondFactor = 62;

    int wait = 0;
    SDL_Event event;
    SDL_PollEvent(&event);
    Instruction decoded;
    while (event.type != SDL_QUIT)
    {
        while (SDL_PollEvent(&event))
        {
            if (event.key.keysym.sym == SDLK_ESCAPE && event.type == SDL_KEYUP)
            {
                printf("Exiting at user escape\n");
                exit(0);
            }
            if (vm->cpu.debugMode && event.type == SDL_KEYUP)
            {
                handleDebugKey(vm, event.key.keysym.sym);
            }
            if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP)
            {
                if (event.key.repeat == 0)
                {
                    updateIPU(vm->ipu, event.key, vm->memory);
                }
            }
        }

        if (vm->cpu.breakState)
            continue;

        // Executing
        if (!wait)
        {
            uint16_t instr = retro_le_to_cpu16(*(vm->cpu.pc));
            decode(instr, &decoded);
            exec(&vm->cpu, &decoded, vm->memory);
            vm->cpu.pc++;
            cpuInstructionCount++;

            if (cpuInstructionCount > INSTRUCTIONS_PER_SECOND / instructionsPerSecondFactor)
                // We have done 8064 instructions in this segment of 16 milliseconds. Don't do any more until the 16ms have passed.
                wait = 1;
        }
        if ((SDL_GetTicks() - cpuStartTime) > 1000 / instructionsPerSecondFactor)
        {
            // 16 milliseconds have passed
            // Reset the instruction count and timer
            if (cpuInstructionCount < INSTRUCTIONS_PER_SECOND / instructionsPerSecondFactor)
            {
                //printf("Running below desired instructions per second\n");
                //printf("Desired: %d Actual: %d\n", INSTRUCTIONS_PER_SECOND / instructionsPerSecondFactor, cpuInstructionCount);
            }
            cpuInstructionCount = 0;
            cpuStartTime = SDL_GetTicks();
            wait = 0;
        }
        if (displayStartTime + displayWaitTime < SDL_GetTicks())
        {
            updateGPU(vm->gpu, vm->memory);
            if (vm->gpu->active)
            {
                readSpritesFromMem(vm->gpu, vm->memory);
                drawSprites(vm->gpu, vm->memory);
                updateDisplay(vm->display, vm->gpu);
            }
            displayStartTime = SDL_GetTicks();
        }
        if (vm->cpu.step)
            vm->cpu.breakState = 1;
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movq %rdi, %rbx
callq 0x1140
movq %rax, -0x38(%rbp)
callq 0x1140
movl %eax, -0x30(%rbp)
leaq -0x78(%rbp), %r14
movq %r14, %rdi
callq 0x10b0
leaq 0x30(%rbx), %r12
movl $0x0, -0x2c(%rbp)
xorl %r13d, %r13d
cmpl $0x100, -0x78(%rbp)     # imm = 0x100
je 0x1980
movq %r14, %rdi
callq 0x10b0
testl %eax, %eax
je 0x1895
movl -0x78(%rbp), %eax
movl -0x64(%rbp), %esi
movl %esi, %ecx
xorl $0x1b, %ecx
movl %eax, %edx
xorl $0x301, %edx            # imm = 0x301
orl %ecx, %edx
je 0x198f
cmpl $0x301, %eax            # imm = 0x301
sete %cl
cmpl $0x0, 0x20(%rbx)
setne %dl
andb %cl, %dl
cmpb $0x1, %dl
jne 0x1863
movq %rbx, %rdi
callq 0x19a2
movl -0x78(%rbp), %eax
andl $-0x2, %eax
cmpl $0x300, %eax            # imm = 0x300
jne 0x181b
cmpb $0x0, -0x6b(%rbp)
jne 0x181b
movq 0x10038(%rbx), %rdi
movups -0x78(%rbp), %xmm0
movups -0x68(%rbp), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
movq %r12, %rsi
callq 0x23b2
jmp 0x181b
cmpl $0x0, 0x24(%rbx)
jne 0x180e
movl $0x1, %r15d
testl %r13d, %r13d
jne 0x18e4
movq 0x10(%rbx), %rax
movzwl (%rax), %edi
leaq -0x3c(%rbp), %r15
movq %r15, %rsi
callq 0x2669
movq %rbx, %rdi
movq %r15, %rsi
movq %r12, %rdx
callq 0x2696
addq $0x2, 0x10(%rbx)
movl -0x2c(%rbp), %eax
incl %eax
xorl %r15d, %r15d
movl %eax, -0x2c(%rbp)
cmpl $0x1f81, %eax           # imm = 0x1F81
setae %r15b
callq 0x1140
subl -0x30(%rbp), %eax
movl %r15d, %r13d
cmpl $0x11, %eax
jb 0x1906
movl $0x0, -0x2c(%rbp)
callq 0x1140
movl %eax, -0x30(%rbp)
xorl %r13d, %r13d
movq -0x38(%rbp), %rax
leal 0x10(%rax), %r15d
callq 0x1140
cmpl %eax, %r15d
jae 0x196a
movq 0x10030(%rbx), %rdi
movq %r12, %rsi
callq 0x1ced
movq 0x10030(%rbx), %rdi
testb $0x1, 0xc10(%rdi)
je 0x1961
movq %r12, %rsi
callq 0x1d40
movq 0x10030(%rbx), %rdi
movq %r12, %rsi
callq 0x1df5
movq 0x10030(%rbx), %rsi
movq 0x10040(%rbx), %rdi
callq 0x1c2b
callq 0x1140
movq %rax, -0x38(%rbp)
cmpl $0x0, 0x28(%rbx)
je 0x180e
movl $0x1, 0x24(%rbx)
jmp 0x180e
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x176a(%rip), %rdi      # 0x3100
callq 0x11d0
xorl %edi, %edi
callq 0x1180