// File: /workspace/github_cpp_makefile_star2_O2/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, %r15
movq %rsi, %r13
movq %rdi, %r12
callq 0x8e8a
movl %eax, %r14d
incl %r14d
movq %r12, 0x18(%rsp)
movq %r12, %rdi
movq %r15, 0x20(%rsp)
movq %r15, %rsi
movq %rbx, %rdx
movl %r14d, %ecx
callq 0x7dc6
testb %al, %al
je 0x7c0b
movq %r13, 0x8(%rsp)
movq %r13, %rdi
callq 0xe90c
movl $0x0, 0x14(%rsp)
movl %eax, %edi
xorl %esi, %esi
callq 0x4440
callq 0x43c0
movl %eax, 0x2c(%rsp)
leaq 0x50(%rsp), %r13
pushq $0x1
popq %r12
movl $0x0, 0x4(%rsp)
movq %r13, %rdi
callq 0x4220
testl %eax, %eax
je 0x7a1b
movl 0x50(%rsp), %edi
cmpl $0x300, %edi            # imm = 0x300
je 0x79ba
cmpl $0x301, %edi            # imm = 0x301
je 0x7983
cmpl $0x100, %edi            # imm = 0x100
je 0x7ca3
callq 0x4690
jmp 0x7983
movl 0x60(%rsp), %eax
cmpl $0x14, %eax
je 0x7c2e
movl 0x68(%rsp), %ecx
addl $-0x40, %ecx
testw $0xffbf, %cx            # imm = 0xFFBF
sete %cl
cmpl $0x6, %eax
jne 0x79e3
testb %cl, %cl
jne 0x7c2e
cmpl $0x15, %eax
je 0x7b9e
cmpl $0x7, %eax
je 0x7a5c
cmpl $0x13, %eax
je 0x7abc
cmpl $0x4, %eax
jne 0x7983
cmpl $0x1, %r14d
jg 0x7b9b
movq 0x18(%rsp), %rdi
callq 0x8e78
movl %eax, %r14d
jmp 0x7b9e
testb $0x1, 0x4(%rsp)
jne 0x7b4e
xorl %ebp, %ebp
movl %r12d, %r15d
testl %r15d, %r15d
jle 0x7aed
movq %rbx, %rdi
callq 0xa3be
movl %eax, %r15d
leal (%r15,%r15,2), %eax
addl %eax, %ebp
movq %rbx, %rdi
movl %ebp, %esi
callq 0xb3c4
cmpl $0x15cfd, %ebp          # imm = 0x15CFD
jle 0x7a2b
jmp 0x7b01
movl %r12d, %ebp
leal 0x1(%r14), %r15d
movq 0x18(%rsp), %r12
movq %r12, %rdi
callq 0x8e78
cmpl %eax, %r14d
cmovgel %ebp, %r15d
movq 0x8(%rsp), %r14
movq %r14, %rdi
callq 0xe90c
movl %eax, %edi
movl %ebp, %esi
callq 0x4440
movq %r12, %rdi
movq 0x20(%rsp), %rsi
movq %rbx, %rdx
movl %r15d, %ecx
callq 0x7dc6
movq %r14, %rdi
callq 0xe90c
movl %eax, %edi
xorl %esi, %esi
callq 0x4440
movl %r15d, %r14d
movl %ebp, %r12d
jmp 0x7983
movl 0x4(%rsp), %eax
movl %eax, %ebp
xorb $0x1, %bpl
testb $0x1, %al
je 0x7be0
leaq 0xa8b4(%rip), %rdi      # 0x12389
callq 0x4540
movq 0x8(%rsp), %rdi
callq 0xe90c
movl %eax, %edi
xorl %esi, %esi
jmp 0x7bfb
movq 0x18(%rsp), %rdi
callq 0x8eea
movq %rbx, %rdi
movl %eax, %esi
callq 0xb3b4
testl %r15d, %r15d
js 0x7ceb
movq 0x8(%rsp), %rdi
callq 0xe90c
testl %eax, %eax
pushq $0x1
popq %r12
jle 0x7b4e
movl %eax, %ebp
movl %eax, %edi
callq 0x4380
movq 0x8(%rsp), %r12
movq %r12, %rdi
movl 0x14(%rsp), %esi
callq 0xe910
movq %r12, %rdi
pushq $0x1
popq %r12
movl $0x2df, %esi            # imm = 0x2DF
callq 0xf246
movl %ebp, %edi
callq 0x4600
callq 0x43c0
movl %eax, %ebp
movl 0x14(%rsp), %r15d
incl %r15d
movq %rbx, %rdi
callq 0xb3cc
movl %r15d, 0x14(%rsp)
cvtsi2sd %r15d, %xmm0
mulsd 0xa491(%rip), %xmm0     # 0x12008
divsd 0xa491(%rip), %xmm0     # 0x12010
cvttsd2si %xmm0, %edi
addl 0x2c(%rsp), %edi
subl %ebp, %edi
testl %edi, %edi
jle 0x7983
callq 0x42b0
jmp 0x7983
decl %r14d
movq 0x8(%rsp), %rbp
movq %rbp, %rdi
callq 0xe90c
movl %eax, %edi
movl %r12d, %esi
callq 0x4440
movq 0x18(%rsp), %rdi
movq 0x20(%rsp), %rsi
movq %rbx, %rdx
movl %r14d, %ecx
callq 0x7dc6
movq %rbp, %rdi
callq 0xe90c
movl %eax, %edi
xorl %esi, %esi
callq 0x4440
jmp 0x7983
leaq 0xa7b6(%rip), %rdi      # 0x1239d
callq 0x4540
movq 0x8(%rsp), %rdi
callq 0xe90c
movl %eax, %edi
movl %r12d, %esi
callq 0x4440
movl %ebp, %eax
movl %eax, 0x4(%rsp)
jmp 0x7983
pushq $0x1
popq %rbx
movq 0x1339b(%rip), %rdi     # 0x1afb0
leaq 0xa759(%rip), %rsi      # 0x12375
callq 0x4390
movq %rax, %rdi
callq 0x41c0
jmp 0x7cd7
leaq 0xa77a(%rip), %rdi      # 0x123af
callq 0x4540
leaq 0xa4f8(%rip), %rsi      # 0x12139
leaq 0x30(%rsp), %rdi
leaq 0x3(%rsp), %rdx
callq 0x4150
leaq 0x30(%rsp), %rsi
movq %rbx, %rdi
callq 0x9f50
leaq 0x30(%rsp), %rdi
callq 0x41b0
movq 0x13342(%rip), %rbx     # 0x1afb0
leaq 0xa658(%rip), %rsi      # 0x122cd
movq %rbx, %rdi
callq 0x4390
movq %rax, %rdi
callq 0x41c0
callq 0x4080
leaq 0xa64f(%rip), %rsi      # 0x122e0
movq %rbx, %rdi
callq 0x4390
movq %rax, %rdi
callq 0x41c0
jmp 0x7cd5
callq 0x4080
leaq 0xa48a(%rip), %rsi      # 0x12139
leaq 0x30(%rsp), %rdi
leaq 0x3(%rsp), %rdx
callq 0x4150
leaq 0x30(%rsp), %rsi
movq %rbx, %rdi
callq 0x9f50
leaq 0x30(%rsp), %rdi
callq 0x41b0
xorl %ebx, %ebx
movl %ebx, %eax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
pushq $0x1
popq %rbx
jmp 0x7cd7
jmp 0x7cf4
jmp 0x7d03
movq %rax, %rbx
leaq 0x30(%rsp), %rdi
callq 0x41b0
jmp 0x7d06
movq %rax, %rbx
movq %rbx, %rdi
callq 0x4640