// File: /workspace/github_cpp_makefile_star2_O3/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, %r15
movq %rdi, %r12
callq 0x9f9a
movl %eax, %r13d
incl %r13d
movq %r12, %rdi
movq %r14, %rsi
movq %rbx, %rdx
movl %r13d, %ecx
callq 0x8a28
testb %al, %al
je 0x87dc
movq %r13, 0x10(%rsp)
movq %r14, 0x48(%rsp)
movq %r15, %rdi
callq 0x1078e
movl $0x0, 0xc(%rsp)
movl %eax, %edi
xorl %esi, %esi
callq 0x4470
callq 0x43d0
movl %eax, 0x18(%rsp)
leaq 0x50(%rsp), %r14
xorl %r13d, %r13d
movq %r12, 0x20(%rsp)
movq %r14, %rdi
callq 0x4230
testl %eax, %eax
je 0x8688
movl 0x50(%rsp), %edi
cmpl $0x300, %edi            # imm = 0x300
je 0x85bf
cmpl $0x301, %edi            # imm = 0x301
je 0x8588
cmpl $0x100, %edi            # imm = 0x100
je 0x88f1
callq 0x4670
jmp 0x8588
movl 0x60(%rsp), %eax
cmpl $0x14, %eax
je 0x8828
movl 0x68(%rsp), %ecx
addl $-0x40, %ecx
testl $0xffbf, %ecx           # imm = 0xFFBF
sete %cl
cmpl $0x6, %eax
jne 0x85e9
testb %cl, %cl
jne 0x8828
cmpl $0x12, %eax
jle 0x861a
cmpl $0x13, %eax
jne 0x864d
movl %r13d, %ebp
xorb $0x1, %bpl
testb $0x1, %r13b
je 0x8660
leaq 0xbdac(%rip), %rdi      # 0x143b3
callq 0x4540
movq %r15, %rdi
callq 0x1078e
movl %eax, %edi
xorl %esi, %esi
jmp 0x867b
cmpl $0x4, %eax
je 0x8783
cmpl $0x7, %eax
jne 0x8588
movq 0x10(%rsp), %rax
leal 0x1(%rax), %ebp
movq %r12, %rdi
callq 0x9f88
cmpl %eax, 0x10(%rsp)
movl $0x1, %eax
cmovgel %eax, %ebp
jmp 0x879b
cmpl $0x15, %eax
jne 0x8588
movq 0x10(%rsp), %rbp
jmp 0x879b
leaq 0xbd60(%rip), %rdi      # 0x143c7
callq 0x4540
movq %r15, %rdi
callq 0x1078e
movl %eax, %edi
movl $0x1, %esi
callq 0x4470
movl %ebp, %r13d
jmp 0x8588
testb $0x1, %r13b
jne 0x871b
xorl %ebp, %ebp
movl $0x1, %r12d
testl %r12d, %r12d
jle 0x86c4
movq %rbx, %rdi
callq 0xb97e
movl %eax, %r12d
leal (%r12,%r12,2), %eax
addl %eax, %ebp
movq %rbx, %rdi
movl %ebp, %esi
callq 0xcd60
cmpl $0x15cfd, %ebp          # imm = 0x15CFD
jle 0x869a
jmp 0x86d8
movq 0x20(%rsp), %rdi
callq 0xa00e
movq %rbx, %rdi
movl %eax, %esi
callq 0xcd50
testl %r12d, %r12d
js 0x881e
movq %r15, %rdi
callq 0x1078e
testl %eax, %eax
movq 0x20(%rsp), %r12
jle 0x871b
movl %eax, %ebp
movl %eax, %edi
callq 0x43a0
movq %r15, %rdi
movl 0xc(%rsp), %esi
callq 0x10792
movq %r15, %rdi
movl $0x2df, %esi            # imm = 0x2DF
callq 0x111be
movl %ebp, %edi
callq 0x45c0
movl %r13d, 0x1c(%rsp)
movq %r14, %r13
movq %r15, %r14
movq %r12, %r15
callq 0x43d0
movl %eax, %ebp
movl 0xc(%rsp), %r12d
incl %r12d
movq %rbx, %rdi
callq 0xcd68
movl %r12d, 0xc(%rsp)
xorps %xmm0, %xmm0
cvtsi2sd %r12d, %xmm0
mulsd 0xb8b3(%rip), %xmm0     # 0x14008
divsd 0xb8b3(%rip), %xmm0     # 0x14010
cvttsd2si %xmm0, %edi
addl 0x18(%rsp), %edi
subl %ebp, %edi
testl %edi, %edi
jle 0x8770
callq 0x42d0
movq %r15, %r12
movq %r14, %r15
movq %r13, %r14
movl 0x1c(%rsp), %r13d
jmp 0x8588
movq 0x10(%rsp), %rbp
cmpl $0x1, %ebp
jg 0x8799
movq %r12, %rdi
callq 0x9f88
movl %eax, %ebp
jmp 0x879b
decl %ebp
movq %r15, %rdi
callq 0x1078e
movl %eax, %edi
movl $0x1, %esi
callq 0x4470
movq %r12, %rdi
movq 0x48(%rsp), %rsi
movq %rbx, %rdx
movq %rbp, 0x10(%rsp)
movl %ebp, %ecx
callq 0x8a28
movq %r15, %rdi
callq 0x1078e
movl %eax, %edi
xorl %esi, %esi
callq 0x4470
jmp 0x8588
movq 0x137cd(%rip), %rbx     # 0x1bfb0
leaq 0xbb8b(%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 0x8931
leaq 0xbbaa(%rip), %rdi      # 0x143d9
callq 0x4540
leaq 0x38(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0xb8f5(%rip), %rdx      # 0x14139
leaq 0x28(%rsp), %rdi
movq %rdx, %rsi
callq 0x8c7e
leaq 0x28(%rsp), %rsi
movq %rbx, %rdi
callq 0xb432
movq 0x28(%rsp), %rdi
cmpq %r14, %rdi
je 0x886d
callq 0x4380
movq 0x1373c(%rip), %rbx     # 0x1bfb0
leaq 0xba52(%rip), %rsi      # 0x142cd
movl $0x12, %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
callq 0x4090
leaq 0xba25(%rip), %rsi      # 0x142e0
movl $0x11, %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
jmp 0x892f
callq 0x4090
leaq 0x38(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0xb833(%rip), %rdx      # 0x14139
leaq 0x28(%rsp), %rdi
movq %rdx, %rsi
callq 0x8c7e
leaq 0x28(%rsp), %rsi
movq %rbx, %rdi
callq 0xb432
movq 0x28(%rsp), %rdi
cmpq %r14, %rdi
je 0x892f
callq 0x4380
xorl %eax, %eax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x8947
jmp 0x895b
movq %rax, %rbx
movq 0x28(%rsp), %rdi
cmpq %r14, %rdi
je 0x895e
callq 0x4380
jmp 0x895e
movq %rax, %rbx
movq %rbx, %rdi
callq 0x4610