// File: khedoros[P]khednes/cpu2.cpp
// Function: cpu::run_ops()
const int cpu::run_ops() {
    memory->set_frame(frame);
    //util::debug("Running CPU. PPU will start at cycle %d.\n",ppu_cycle);
    int ops_run=0;
    ppu_cycle=0;
    unsigned int cycles_this_frame = memory->get_ppu_cycles(frame);
    while(ppu_cycle<cycles_this_frame) {
        prevopsrun = ops_run;
        ops_run=run_next_op();
        if(ops_run<0)
            return ops_run;
        ppu_cycle+=(ops_run*3);
        //cout<<hex<<"Prevop: "<<prevop<<" Prevodaddr: "<<prevopaddr<<dec<<endl;
        #ifdef SKIP_LOOPS
        if(nextopaddr == addr) { //Operation seems to be looping back on itself
            if(nextop == 0x4c || nextop == 0x6c) {
                //cout<<"Op is a jump. I'm going to jump to the end of the frame since this will repeat until NMI is hit."<<endl;
                //Remaining ppu cycles in the frame...
                unsigned int to_forward = cycles_this_frame - ppu_cycle;
                //cout<<to_forward<<"PPU cycles remaining in the frame."<<endl;
                //...divided by cycles per operation gives how many times I can run it and be within the frame.
                to_forward /= (ops_run * 3);
                //Add one more so that I'm outside of the frame.
                ++to_forward;
                //cout<<"That means I can run the operation "<<to_forward<<" times to be at cycle "<<ppu_cycle + (to_forward * 3 * ops_run)<<" out of "<<cycles_this_frame<<endl;
                ppu_cycle += (to_forward * 3 * ops_run);
            }
       }
       if (pc == prevopaddr && (nextop&0x1f) == 0x10 &&
           prevoparg <= 0x2002 && prevop >= 0xA0 && prevop <= 0xBE && prevop != 0xB0) {
            //cout<<"Looks like wait loop: prevoparg: "<<hex<<prevoparg<<" prevopaddr: "<<prevopaddr<<" pc: "<<pc<<endl;
            unsigned int to_forward = cycles_this_frame - ppu_cycle; //cycles remaining in frame
            to_forward /= ((ops_run + prevopsrun) * 3); //divided by how many cycles those two ops take together
            ppu_cycle += (to_forward * 3 * (ops_run + prevopsrun));
        }
        #endif //SKIP_LOOPS
    }
    //util::debug("I think an NMI might go here.\n");
    if(ppu_cycle>=cycles_this_frame) {
        //util::debug("Frame complete at cycle %d.\n",ppu_cycle);
        ppu_cycle-=cycles_this_frame;
    }
    frame++;
    //util::debug(ORIGIN,"About to run PPU. It should end at: %d.\n",ppu_cycle);
    return 0;
}

// Assembly:
subq $0x28, %rsp
movq %rdi, 0x18(%rsp)
movq 0x18(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0x10(%rax), %rdi
movl 0x468(%rax), %esi
callq 0x14e60
movq 0x8(%rsp), %rax
movl $0x0, 0x14(%rsp)
movl $0x0, 0x460(%rax)
movq 0x10(%rax), %rdi
movl 0x468(%rax), %esi
callq 0x14e10
movl %eax, 0x10(%rsp)
movq 0x8(%rsp), %rax
movl 0x460(%rax), %eax
cmpl 0x10(%rsp), %eax
jae 0x1916e
movq 0x8(%rsp), %rdi
movl 0x14(%rsp), %eax
movl %eax, 0x444(%rdi)
callq 0x173e0
movl %eax, 0x14(%rsp)
cmpl $0x0, 0x14(%rsp)
jge 0x19156
movl 0x14(%rsp), %eax
movl %eax, 0x24(%rsp)
jmp 0x191b2
movq 0x8(%rsp), %rax
imull $0x3, 0x14(%rsp), %ecx
addl 0x460(%rax), %ecx
movl %ecx, 0x460(%rax)
jmp 0x1911c
movq 0x8(%rsp), %rax
movl 0x460(%rax), %eax
cmpl 0x10(%rsp), %eax
jb 0x19196
movq 0x8(%rsp), %rax
movl 0x10(%rsp), %edx
movl 0x460(%rax), %ecx
subl %edx, %ecx
movl %ecx, 0x460(%rax)
movq 0x8(%rsp), %rax
movl 0x468(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x468(%rax)
movl $0x0, 0x24(%rsp)
movl 0x24(%rsp), %eax
addq $0x28, %rsp
retq
nopl (%rax,%rax)