// File: /workspace/github_cpp_makefile_star2_O1/khedoros[P]khednes/main.cpp
// Function: run_nsf(rom&, apu&, mem&, cpu&)
int run_nsf(rom& cart, apu& apui, mem& memi, cpu& cpui) {
    bool paused=false;
    int frame = 0;
    int choice = cart.get_default_song() + 1; //get_choice(cart);
    bool success = init_nsf(cart, memi, cpui, choice);
    if(!success) {
        cout<<"Failed to init nsf."<<endl;
        return 1;
    }
    SDL_PauseAudioDevice(apui.get_id(), false);
    int pstart = SDL_GetTicks();
    while (1==1) {
exit_poll_loop:
        SDL_Event event;
        while(SDL_PollEvent(&event)){  /* Loop until there are no events left on the queue */
            switch(event.type){  /* Process the appropiate event type */
            case SDL_KEYDOWN:  /* Handle a KEYDOWN event */         
                if(event.key.keysym.scancode==SDL_SCANCODE_Q||
                  (event.key.keysym.scancode==SDL_SCANCODE_C&&(event.key.keysym.mod==KMOD_RCTRL))||
                  (event.key.keysym.scancode==SDL_SCANCODE_C&&(event.key.keysym.mod==KMOD_LCTRL))) {
                    printf("You pressed q or ctrl-c. Exiting.\n");
                    cpui.print_details("");
                    //SDL_PauseAudio(true);
                    cout<<"Calling SDL_Quit()"<<endl;
                    SDL_Quit();
                    cout<<"Called SDL_Quit()"<<endl;
                    return 0;
                }
                else if(event.key.keysym.scancode==SDL_SCANCODE_A) {
                    choice--;
                    if(choice<1) choice = cart.get_song_count();
                    SDL_PauseAudioDevice(apui.get_id(), true);
                    init_nsf(cart, memi, cpui, choice);
                    SDL_PauseAudioDevice(apui.get_id(), false);
                    goto exit_poll_loop;
                }
                else if(event.key.keysym.scancode==SDL_SCANCODE_D) {
                    choice++;
                    if(choice > (int)cart.get_song_count()) choice = 1;
                    SDL_PauseAudioDevice(apui.get_id(), true);
                    init_nsf(cart, memi, cpui, choice);
                    SDL_PauseAudioDevice(apui.get_id(), false);
                    goto exit_poll_loop;
                }
                else if(event.key.keysym.scancode==SDL_SCANCODE_R) {
                    SDL_PauseAudioDevice(apui.get_id(), true);
                    init_nsf(cart,memi,cpui, choice);
                    SDL_PauseAudioDevice(apui.get_id(), false);
                    goto exit_poll_loop;
                }
                else if(event.key.keysym.scancode==SDL_SCANCODE_P) {
                    paused=!paused;
                    if(paused) {
                        printf("Paused emulation.\n");
                        SDL_PauseAudioDevice(apui.get_id(), true);
                    }
                    else {
                        printf("Unpaused emulation.\n");
                        SDL_PauseAudioDevice(apui.get_id(), false);
                    }
                }
                else {
                    //printf("Keydown\n");
                    //printf("Time: %d\n",SDL_GetTicks());
                }
                break;
            case SDL_KEYUP: /* Handle a KEYUP event*/
                //printf("Keyup\n");
                break;
            case SDL_QUIT:
                //SDL_PauseAudio(true);
                SDL_Quit();
                cpui.print_details("");
                return 0;
                break;
            default: /* Report an unhandled event */
                //printf("I don't know what this event is! Flushing it.\n");
                SDL_FlushEvent(event.type);
                break;
            }
        }
        if(!paused) {
            //cout<<"Running the CPU"<<endl;
            int cpu_ret = 1;
            int cycle_count = 0;
            bool reset = true;
            //cout<<"Frame "<<dec<<frame<<" start"<<endl;
            while(cpu_ret && cpu_ret > 0) {
                cpu_ret=cpui.run_next_op();
                cycle_count += (3*cpu_ret);
                cpui.set_ppu_cycle(cycle_count);
                if(cycle_count >= CLK_PER_FRAME) { 
                    cycle_count -= CLK_PER_FRAME;
                    reset = false;
                    break;
                }
            }
            //cout<<"Frame "<<dec<<frame<<" end"<<endl;
            if(reset) {
                cpui.reset(cart.get_nmi_addr());
            }

            //cout<<"Ran the CPU"<<endl;
            if(cpu_ret < 0) {
                return 1;
            }
            else {
                //cout<<"Frame "<<ppui.get_frame()<<endl;

                int apu_id = apui.get_id();
                if(apu_id > 0) {
                    //cout<<"Locking audio...";
                    SDL_LockAudioDevice(apu_id);
                    //cout<<"done."<<endl;
                    apui.set_frame(frame);
                    apui.gen_audio();
                    //apui.dat.buffered += 735; Dude, do this in gen_audio, not here =/
                    //cout<<"Unlocking audio...";
                    SDL_UnlockAudioDevice(apu_id);
                    //cout<<"done."<<endl;
                }
            }
        }

        //Calculates the time that the frame should end at, and delays until that time
        //cout<<"Timing two"<<endl;
        int now = SDL_GetTicks();
        frame++;
        cpui.increment_frame();
        int delay = pstart + int(double(frame) * double(1000) / double(60)) - now;
        //cout<<"Frame: "<<frames<<" now: "<<now<<" delay: "<<delay<<endl;       
        if(delay > 0) {
            SDL_Delay(delay);
        }
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x88, %rsp
movq %rcx, %rbx
movq %rdx, %r14
movq %rsi, %r12
movq %rdi, %r15
callq 0xa0ac
movl %eax, %r13d
incl %r13d
movq %r15, %rdi
movq %r14, 0x20(%rsp)
movq %r14, %rsi
movq %rbx, %rdx
movl %r13d, %ecx
callq 0x8b5d
testb %al, %al
je 0x8a18
movq %r13, 0x8(%rsp)
movq %r15, 0x10(%rsp)
movq %r12, %rdi
callq 0x10866
movl $0x0, 0x4(%rsp)
movl %eax, %edi
xorl %esi, %esi
callq 0x4470
callq 0x43d0
movl %eax, 0x2c(%rsp)
leaq 0x50(%rsp), %r14
leaq 0x30(%rsp), %r13
xorl %ebp, %ebp
movq %r12, 0x18(%rsp)
movq %r14, %rdi
callq 0x4230
testl %eax, %eax
je 0x8698
movl 0x50(%rsp), %edi
cmpl $0x300, %edi            # imm = 0x300
je 0x85f7
cmpl $0x301, %edi            # imm = 0x301
je 0x85e0
cmpl $0x100, %edi            # imm = 0x100
je 0x8881
callq 0x4670
movl %ebp, %r15d
movq %r14, %rdi
callq 0x4230
movl %r15d, %ebp
testl %eax, %eax
jne 0x85bb
jmp 0x869b
movl 0x60(%rsp), %eax
cmpl $0x14, %eax
je 0x86e6
movl 0x68(%rsp), %ecx
addl $-0x40, %ecx
testl $0xffbf, %ecx           # imm = 0xFFBF
sete %cl
cmpl $0x6, %eax
jne 0x8621
testb %cl, %cl
jne 0x86e6
cmpl $0x12, %eax
jle 0x8652
cmpl $0x13, %eax
jne 0x8665
movl %ebp, %r15d
xorb $0x1, %r15b
testb $0x1, %bpl
je 0x8673
leaq 0xbd74(%rip), %rdi      # 0x143b3
callq 0x4540
movq %r12, %rdi
callq 0x10866
movl %eax, %edi
xorl %esi, %esi
jmp 0x868e
cmpl $0x4, %eax
je 0x88e2
cmpl $0x7, %eax
jne 0x85e0
jmp 0x8906
cmpl $0x15, %eax
jne 0x85e0
jmp 0x8981
leaq 0xbd4d(%rip), %rdi      # 0x143c7
callq 0x4540
movq %r12, %rdi
callq 0x10866
movl %eax, %edi
movl $0x1, %esi
callq 0x4470
jmp 0x85e3
movl %ebp, %r15d
testb $0x1, %r15b
je 0x86aa
movl (%rsp), %r14d
jmp 0x8829
xorl %ebp, %ebp
movl $0x1, %r12d
movl %r12d, %r14d
testl %r12d, %r12d
jle 0x87b4
movq %rbx, %rdi
callq 0xbae2
movl %eax, %r12d
leal (%r12,%r12,2), %eax
addl %eax, %ebp
movq %rbx, %rdi
movl %ebp, %esi
callq 0xceca
cmpl $0x15cfe, %ebp          # imm = 0x15CFE
jl 0x86b2
jmp 0x87b7
leaq 0xbcec(%rip), %rdi      # 0x143d9
callq 0x4540
leaq 0x40(%rsp), %rax
movq %rax, 0x30(%rsp)
movq %r13, %rdi
leaq 0xba33(%rip), %rdx      # 0x14139
movq %rdx, %rsi
callq 0x8dac
movq %rbx, %rdi
movq %r13, %rsi
callq 0xb596
movq 0x30(%rsp), %rdi
leaq 0x40(%rsp), %rax
cmpq %rax, %rdi
je 0x872d
callq 0x4380
movl $0x12, %edx
movq 0x13877(%rip), %r15     # 0x1bfb0
movq %r15, %rdi
leaq 0xbb8a(%rip), %rsi      # 0x142cd
callq 0x4410
movq (%r15), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x4390
movsbl %al, %esi
movq %r15, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4290
callq 0x4090
movl $0x11, %edx
movq %r15, %rdi
leaq 0xbb5d(%rip), %rsi      # 0x142e0
callq 0x4410
movq (%r15), %rax
movq -0x18(%rax), %rdi
addq %r15, %rdi
movl $0xa, %esi
callq 0x4390
movsbl %al, %esi
movq %r15, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4290
jmp 0x88c1
movl %r14d, %r12d
testl %r14d, %r14d
jg 0x87d0
movq 0x10(%rsp), %rdi
callq 0xa120
movq %rbx, %rdi
movl %eax, %esi
callq 0xceba
movl $0x1, %r13d
movl $0x1, %r14d
testl %r12d, %r12d
js 0x881f
movq 0x18(%rsp), %r14
movq %r14, %rdi
callq 0x10866
testl %eax, %eax
jle 0x881b
movl %eax, %ebp
movl %eax, %edi
callq 0x43a0
movq %r14, %rdi
movl 0x4(%rsp), %esi
callq 0x1086a
movq %r14, %rdi
movl $0x2df, %esi            # imm = 0x2DF
callq 0x11294
movl %ebp, %edi
callq 0x45c0
movl (%rsp), %r14d
testl %r12d, %r12d
movq 0x18(%rsp), %r12
js 0x8873
callq 0x43d0
movl %eax, %ebp
movl 0x4(%rsp), %r13d
incl %r13d
movq %rbx, %rdi
callq 0xced2
movl %r13d, 0x4(%rsp)
xorps %xmm0, %xmm0
cvtsi2sd %r13d, %xmm0
mulsd 0xb7b3(%rip), %xmm0     # 0x14008
divsd 0xb7b3(%rip), %xmm0     # 0x14010
cvttsd2si %xmm0, %edi
addl 0x2c(%rsp), %edi
subl %ebp, %edi
xorl %r13d, %r13d
testl %edi, %edi
jle 0x8873
callq 0x42d0
movl %r15d, %ebp
movl %r14d, (%rsp)
leaq 0x50(%rsp), %r14
jmp 0x88ce
callq 0x4090
leaq 0x40(%rsp), %rax
movq %rax, 0x30(%rsp)
movq %r13, %rdi
leaq 0xb89f(%rip), %rdx      # 0x14139
movq %rdx, %rsi
callq 0x8dac
movq %rbx, %rdi
movq %r13, %rsi
callq 0xb596
movq 0x30(%rsp), %rdi
leaq 0x40(%rsp), %rax
cmpq %rax, %rdi
je 0x88c1
callq 0x4380
movl $0x0, (%rsp)
movl $0x1, %r13d
testb $0x3, %r13b
leaq 0x30(%rsp), %r13
je 0x85ab
jmp 0x8a61
movq 0x8(%rsp), %r15
cmpl $0x1, %r15d
jg 0x89c8
movq 0x10(%rsp), %r14
movq %r14, %rdi
callq 0xa09a
movl %eax, %r15d
jmp 0x89d0
movq 0x8(%rsp), %r15
leal 0x1(%r15), %r12d
movq 0x10(%rsp), %r14
movq %r14, %rdi
callq 0xa09a
cmpl %eax, %r15d
movl $0x1, %eax
cmovgel %eax, %r12d
movq 0x18(%rsp), %rdi
callq 0x10866
movl %eax, %edi
movl $0x1, %esi
callq 0x4470
movq %r14, %rdi
leaq 0x50(%rsp), %r14
movq 0x20(%rsp), %rsi
movq %rbx, %rdx
movl %r12d, %ecx
callq 0x8b5d
movq 0x18(%rsp), %rdi
callq 0x10866
movl %eax, %edi
xorl %esi, %esi
callq 0x4470
movl $0x4, %r13d
movl %r12d, %eax
movq %rax, 0x8(%rsp)
movq 0x18(%rsp), %r12
jmp 0x88ce
movq %r12, %rdi
callq 0x10866
movl %eax, %edi
movl $0x1, %esi
callq 0x4470
movq 0x10(%rsp), %rdi
movq 0x20(%rsp), %rsi
movq %rbx, %rdx
movq 0x8(%rsp), %rcx
callq 0x8b5d
movq %r12, %rdi
callq 0x10866
movl %eax, %edi
xorl %esi, %esi
callq 0x4470
movl $0x4, %r13d
jmp 0x88ce
decl %r15d
movq 0x10(%rsp), %r14
movq %r12, %rdi
callq 0x10866
movl %eax, %edi
movl $0x1, %esi
callq 0x4470
movq %r14, %rdi
movq 0x20(%rsp), %rsi
movq %rbx, %rdx
movq %r15, 0x8(%rsp)
movl %r15d, %ecx
callq 0x8b5d
movq %r12, %rdi
callq 0x10866
movl %eax, %edi
xorl %esi, %esi
callq 0x4470
movl $0x4, %r13d
jmp 0x887a
movq 0x13591(%rip), %rbx     # 0x1bfb0
leaq 0xb94f(%rip), %rsi      # 0x14375
movl $0x13, %edx
movq %rbx, %rdi
callq 0x4410
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x4390
movsbl %al, %esi
movq %rbx, %rdi
callq 0x4030
movq %rax, %rdi
callq 0x4290
movl $0x1, %eax
jmp 0x8a64
movl (%rsp), %eax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x8a7a
jmp 0x8a93
movq %rax, %rbx
movq 0x30(%rsp), %rdi
leaq 0x40(%rsp), %rax
cmpq %rax, %rdi
je 0x8a96
callq 0x4380
jmp 0x8a96
movq %rax, %rbx
movq %rbx, %rdi
callq 0x4610