// File: /workspace/github_c_makefile_star2_O3/qad114[P]yobeboy/src/main.c
// Function: main
int main(int argc, char** argv) {
    if (argc != 2) {
        printf("Usage: %s <path to ROM>\n", argv[0]);
        return 1;
    }

    Memory* mem = malloc(sizeof(*mem)); // freed in quit
    MEM_init(mem);
    MEM_loadROM(mem, argv[1]);

    printf("ROM info:\n");
    printf("Title: %s\n", mem->cartridge->title);
    printf("Cartridge type: 0x%02x\n", mem->cartridge->type);
    printf("ROM size: 0x%02x\n", mem->cartridge->romSize);
    printf("RAM size: 0x%02x\n", mem->cartridge->ramSize);

    CPU* cpu = malloc(sizeof(*cpu)); // freed in quit
    CPU_init(cpu);

    GPU* gpu = malloc(sizeof(*gpu)); // freed in quit
    GPU_init(gpu);

    Timer* timer = malloc(sizeof(*timer)); // freed in quit
    TIMER_init(timer);

    Joypad* joy = malloc(sizeof(*joy)); // freed in quit
    JOY_init(joy);

    Audio* audio = malloc(sizeof(*audio)); // freed in quit
    AUD_init(audio, 44100);

    #ifndef DISABLE_GRAPHICS
    // Init graphics
    SDL_Init(SDL_INIT_EVERYTHING);
    SDL_Window* window = SDL_CreateWindow("yobeboy", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, GB_SCREEN_WIDTH, GB_SCREEN_HEIGHT, SDL_WINDOW_RESIZABLE);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    SDL_RenderSetLogicalSize(renderer, GB_SCREEN_WIDTH, GB_SCREEN_HEIGHT);
    SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, GB_SCREEN_WIDTH, GB_SCREEN_HEIGHT);
    #endif

    SDL_Event event;
    uint64_t startTime = SDL_GetPerformanceCounter();

    while (1) {
        int res = CPU_emulateCycle(cpu, gpu, mem, timer, joy);
        if (!res) {
            return quit(cpu, gpu, mem, audio, timer, joy, 1);
        }
        GPU_update(cpu, gpu, mem);
        TIMER_update(cpu, mem, timer);
        MEM_dmaUpdate(mem);
        JOY_update(joy, mem);
        AUD_update(audio, mem);

        #ifndef DISABLE_GRAPHICS
        if (gpu->fbUpdated) {
            // Handle events
            while (SDL_PollEvent(&event)) {
                switch (event.type) {
                    case SDL_QUIT:
                        return quit(cpu, gpu, mem, audio, timer, joy, 0);

                    case SDL_KEYDOWN:
                        switch (event.key.keysym.sym) {
                            case SDLK_a: joy->a = 1; break;
                            case SDLK_z: joy->b = 1; break;
                            case SDLK_RETURN: joy->start = 1; break;
                            case SDLK_BACKSPACE: joy->select = 1; break;
                            case SDLK_UP: joy->up = 1; break;
                            case SDLK_DOWN: joy->down = 1; break;
                            case SDLK_LEFT: joy->left = 1; break;
                            case SDLK_RIGHT: joy->right = 1; break;
                        }
                        break;

                    case SDL_KEYUP:
                        switch (event.key.keysym.sym) {
                            case SDLK_a: joy->a = 0; break;
                            case SDLK_z: joy->b = 0; break;
                            case SDLK_RETURN: joy->start = 0; break;
                            case SDLK_BACKSPACE: joy->select = 0; break;
                            case SDLK_UP: joy->up = 0; break;
                            case SDLK_DOWN: joy->down = 0; break;
                            case SDLK_LEFT: joy->left = 0; break;
                            case SDLK_RIGHT: joy->right = 0; break;
                        }
                        break;
                }
            }

            // Update the screen
            SDL_UpdateTexture(texture, NULL, gpu->framebuffer, GB_SCREEN_WIDTH * 4);
            SDL_RenderClear(renderer);
            SDL_RenderCopy(renderer, texture, NULL, NULL);
            SDL_RenderPresent(renderer);
            gpu->fbUpdated = false;

            // Maintain 60fps
            double targetTime = 1.0 / 60.0;
            while (((SDL_GetPerformanceCounter() - startTime) / (float) SDL_GetPerformanceFrequency()) < targetTime);
            printf("FPS %.2f\r", 1.0 / ((SDL_GetPerformanceCounter() - startTime) / (float) SDL_GetPerformanceFrequency()));
            startTime = SDL_GetPerformanceCounter();
        }
        #endif
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x78, %rsp
movq %rsi, %r14
cmpl $0x2, %edi
jne 0x688d
movl $0x10058, %edi          # imm = 0x10058
callq 0x2200
movq %rax, %rbx
movq %rax, %rdi
callq 0x6a04
movq 0x8(%r14), %rsi
movq %rbx, %rdi
callq 0x6caf
leaq 0x2673(%rip), %rdi      # 0x8a2d
callq 0x2240
movq 0x10038(%rbx), %rsi
leaq 0x25fc(%rip), %rdi      # 0x89c9
xorl %eax, %eax
callq 0x2050
movq 0x10038(%rbx), %rax
movzbl 0x11(%rax), %esi
leaq 0x25ee(%rip), %rdi      # 0x89d4
xorl %eax, %eax
callq 0x2050
movq 0x10038(%rbx), %rax
movzbl 0x12(%rax), %esi
leaq 0x25ed(%rip), %rdi      # 0x89ec
xorl %eax, %eax
callq 0x2050
movq 0x10038(%rbx), %rax
movzbl 0x13(%rax), %esi
leaq 0x25e6(%rip), %rdi      # 0x89fe
xorl %eax, %eax
callq 0x2050
movl $0x14, %edi
callq 0x2200
movq %rax, %r14
movq %rax, %rdi
callq 0x2af9
movl $0x38, %edi
callq 0x2200
movq %rax, %r15
movq %rax, %rdi
callq 0x5a28
movl $0x8, %edi
callq 0x2200
movq %rax, %rbp
movq %rax, %rdi
callq 0x6fe8
movl $0x20, %edi
callq 0x2200
movq %rax, %r13
movq %rax, %rdi
callq 0x62d0
movl $0x88, %edi
callq 0x2200
movq %rax, 0x28(%rsp)
movq %rax, %rdi
movl $0xac44, %esi           # imm = 0xAC44
callq 0x239c
movl $0xf231, %edi           # imm = 0xF231
callq 0x2140
leaq 0x2570(%rip), %rdi      # 0x8a10
movl $0x1fff0000, %esi       # imm = 0x1FFF0000
movl $0x1fff0000, %edx       # imm = 0x1FFF0000
movl $0xa0, %ecx
movl $0x90, %r8d
movl $0x20, %r9d
callq 0x2060
movq %rax, %rdi
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
movl $0x2, %edx
callq 0x2040
movq %rax, %r12
movq %rax, %rdi
movl $0xa0, %esi
movl $0x90, %edx
callq 0x20a0
movq %r12, 0x38(%rsp)
movq %r12, %rdi
movl $0x16762004, %esi       # imm = 0x16762004
movl $0x1, %edx
movl $0xa0, %ecx
movl $0x90, %r8d
callq 0x2260
movq %rax, 0x30(%rsp)
callq 0x2210
movq %rax, %r12
movq %r14, %rdi
movq %r15, 0x10(%rsp)
movq %r15, %rsi
movq %rbx, %rdx
movq %rbp, %rcx
movq %r13, %r8
callq 0x2b1e
testl %eax, %eax
je 0x6885
movq 0x10(%rsp), %r15
movq %rbp, 0x20(%rsp)
movq %r14, 0x18(%rsp)
movq %r14, %rdi
movq %r15, %rsi
movq %rbx, %rdx
callq 0x5ab0
movq %r14, %rdi
movq %rbx, %rsi
movq %rbp, %rdx
callq 0x6ff4
movq %rbx, %rdi
callq 0x6f7d
movq %r13, %rdi
movq %rbx, %rsi
callq 0x62e0
movq 0x28(%rsp), %rdi
movq %rbx, %rsi
callq 0x2549
cmpb $0x1, 0x10(%r15)
movq %r15, %rbp
jne 0x685c
leaq 0x40(%rsp), %r14
movq %r14, %rdi
callq 0x20e0
testl %eax, %eax
je 0x6711
movl 0x40(%rsp), %eax
cmpl $0x300, %eax            # imm = 0x300
je 0x65ed
cmpl $0x301, %eax            # imm = 0x301
je 0x65c3
cmpl $0x100, %eax            # imm = 0x100
jne 0x6595
jmp 0x68a6
movl 0x54(%rsp), %eax
cmpl $0x79, %eax
jg 0x6613
cmpl $0x8, %eax
je 0x6663
cmpl $0xd, %eax
je 0x667d
cmpl $0x61, %eax
jne 0x6595
movl $0x0, (%r13)
jmp 0x6595
movl 0x54(%rsp), %eax
cmpl $0x79, %eax
jg 0x663b
cmpl $0x8, %eax
je 0x6670
cmpl $0xd, %eax
je 0x668a
cmpl $0x61, %eax
jne 0x6595
movl $0x1, (%r13)
jmp 0x6595
leal -0x4000004f(%rax), %ecx
cmpl $0x3, %ecx
ja 0x6697
leaq 0x236b(%rip), %rdx      # 0x8990
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movl $0x0, 0x1c(%r13)
jmp 0x6595
leal -0x4000004f(%rax), %ecx
cmpl $0x3, %ecx
ja 0x66ad
leaq 0x2353(%rip), %rdx      # 0x89a0
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movl $0x1, 0x1c(%r13)
jmp 0x6595
movl $0x0, 0xc(%r13)
jmp 0x6595
movl $0x1, 0xc(%r13)
jmp 0x6595
movl $0x0, 0x8(%r13)
jmp 0x6595
movl $0x1, 0x8(%r13)
jmp 0x6595
cmpl $0x7a, %eax
jne 0x6595
movl $0x0, 0x4(%r13)
jmp 0x6595
cmpl $0x7a, %eax
jne 0x6595
movl $0x1, 0x4(%r13)
jmp 0x6595
movl $0x0, 0x14(%r13)
jmp 0x6595
movl $0x0, 0x10(%r13)
jmp 0x6595
movl $0x0, 0x18(%r13)
jmp 0x6595
movl $0x1, 0x14(%r13)
jmp 0x6595
movl $0x1, 0x10(%r13)
jmp 0x6595
movl $0x1, 0x18(%r13)
jmp 0x6595
movq 0x8(%rbp), %rdx
movq 0x30(%rsp), %r15
movq %r15, %rdi
xorl %esi, %esi
movl $0x280, %ecx            # imm = 0x280
callq 0x2110
movq 0x38(%rsp), %r14
movq %r14, %rdi
callq 0x2160
movq %r14, %rdi
movq %r15, %rsi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x2190
movq %r14, %rdi
callq 0x2070
movb $0x0, 0x10(%rbp)
callq 0x2210
subq %r12, %rax
js 0x6765
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
jmp 0x677d
movq %rax, %rcx
shrq %rcx
andl $0x1, %eax
orq %rcx, %rax
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
addss %xmm0, %xmm0
movss %xmm0, 0xc(%rsp)
callq 0x2130
testq %rax, %rax
js 0x6797
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
jmp 0x67af
movq %rax, %rcx
shrq %rcx
andl $0x1, %eax
orq %rcx, %rax
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
addss %xmm0, %xmm0
movss 0xc(%rsp), %xmm1
divss %xmm0, %xmm1
xorps %xmm0, %xmm0
cvtss2sd %xmm1, %xmm0
movsd 0x21b8(%rip), %xmm1     # 0x8980
ucomisd %xmm0, %xmm1
ja 0x6751
callq 0x2210
subq %r12, %rax
js 0x67e2
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
jmp 0x67fa
movq %rax, %rcx
shrq %rcx
andl $0x1, %eax
orq %rcx, %rax
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
addss %xmm0, %xmm0
movss %xmm0, 0xc(%rsp)
callq 0x2130
testq %rax, %rax
js 0x6814
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
jmp 0x682c
movq %rax, %rcx
shrq %rcx
andl $0x1, %eax
orq %rcx, %rax
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
addss %xmm0, %xmm0
movss 0xc(%rsp), %xmm1
divss %xmm0, %xmm1
cvtss2sd %xmm1, %xmm1
movsd 0x2146(%rip), %xmm0     # 0x8988
divsd %xmm1, %xmm0
leaq 0x21cb(%rip), %rdi      # 0x8a18
movb $0x1, %al
callq 0x2050
callq 0x2210
movq %rax, %r12
movq 0x18(%rsp), %r14
movq %r14, %rdi
movq %rbp, %rsi
movq %rbx, %rdx
movq %rbp, %r15
movq 0x20(%rsp), %rbp
movq %rbp, %rcx
movq %r13, %r8
callq 0x2b1e
testl %eax, %eax
jne 0x6546
movl $0x1, %r15d
jmp 0x68b3
movq (%r14), %rsi
leaq 0x2119(%rip), %rdi      # 0x89b0
xorl %eax, %eax
callq 0x2050
movl $0x1, %r15d
jmp 0x68d2
xorl %r15d, %r15d
movq 0x20(%rsp), %rbp
movq 0x18(%rsp), %r14
movl %r15d, (%rsp)
movq %r14, %rdi
movq 0x10(%rsp), %rsi
movq %rbx, %rdx
movq 0x28(%rsp), %rcx
movq %rbp, %r8
movq %r13, %r9
callq 0x68e4
movl %r15d, %eax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq