// File: /workspace/github_c_makefile_star2_O1/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 0x685b
movl $0x10058, %edi          # imm = 0x10058
callq 0x2200
movq %rax, %rbx
movq %rax, %rdi
callq 0x69a8
movq 0x8(%r14), %rsi
movq %rbx, %rdi
callq 0x6c4e
leaq 0x269f(%rip), %rdi      # 0x89dd
callq 0x2240
movq 0x10038(%rbx), %rsi
leaq 0x2628(%rip), %rdi      # 0x8979
movq $0x0, 0x10(%rsp)
xorl %eax, %eax
callq 0x2050
movq 0x10038(%rbx), %rax
movzbl 0x11(%rax), %esi
leaq 0x2611(%rip), %rdi      # 0x8984
xorl %eax, %eax
callq 0x2050
movq 0x10038(%rbx), %rax
movzbl 0x12(%rax), %esi
leaq 0x2610(%rip), %rdi      # 0x899c
xorl %eax, %eax
callq 0x2050
movq 0x10038(%rbx), %rax
movzbl 0x13(%rax), %esi
leaq 0x2609(%rip), %rdi      # 0x89ae
xorl %eax, %eax
callq 0x2050
movl $0x14, %edi
callq 0x2200
movq %rax, %r15
movq %rax, %rdi
callq 0x2afd
movl $0x38, %edi
callq 0x2200
movq %rax, %r12
movq %rax, %rdi
callq 0x5a50
movl $0x8, %edi
callq 0x2200
movq %rax, %r14
movq %rax, %rdi
callq 0x6f8c
movl $0x20, %edi
callq 0x2200
movq %rax, %rbp
movq %rax, %rdi
callq 0x6250
movl $0x88, %edi
callq 0x2200
movq %rax, 0x18(%rsp)
movq %rax, %rdi
movl $0xac44, %esi           # imm = 0xAC44
callq 0x239c
movl $0xf231, %edi           # imm = 0xF231
callq 0x2140
leaq 0x2593(%rip), %rdi      # 0x89c0
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, %r13
movq %rax, %rdi
movl $0xa0, %esi
movl $0x90, %edx
callq 0x20a0
movq %r13, 0x38(%rsp)
movq %r13, %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, %r13
movq %r15, 0x28(%rsp)
movq %r14, 0x20(%rsp)
movq %r15, %rdi
movq %r12, %rsi
movq %rbx, %rdx
movq %r14, %rcx
movq %rbp, %r8
callq 0x2b29
testl %eax, %eax
je 0x6693
movq %r15, %rdi
movq %r12, %rsi
movq %rbx, %rdx
callq 0x5ae4
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
callq 0x6f98
movq %rbx, %rdi
callq 0x6f23
movq %rbp, %rdi
movq %rbx, %rsi
callq 0x6260
movq 0x18(%rsp), %rdi
movq %rbx, %rsi
callq 0x254c
movb $0x1, %r15b
cmpb $0x1, 0x10(%r12)
jne 0x6816
leaq 0x40(%rsp), %r14
movq %r14, %rdi
callq 0x20e0
testl %eax, %eax
movq 0x28(%rsp), %r15
je 0x66c5
movl 0x40(%rsp), %eax
cmpl $0x300, %eax            # imm = 0x300
je 0x6585
cmpl $0x301, %eax            # imm = 0x301
je 0x655c
cmpl $0x100, %eax            # imm = 0x100
je 0x682b
movq %r14, %rdi
callq 0x20e0
testl %eax, %eax
jne 0x652e
jmp 0x66c5
movl 0x54(%rsp), %eax
cmpl $0x79, %eax
jg 0x65a6
cmpl $0x8, %eax
je 0x65f1
cmpl $0xd, %eax
je 0x6609
cmpl $0x61, %eax
jne 0x654b
movl $0x0, (%rbp)
jmp 0x654b
movl 0x54(%rsp), %eax
cmpl $0x79, %eax
jg 0x65ca
cmpl $0x8, %eax
je 0x65fd
cmpl $0xd, %eax
je 0x6615
cmpl $0x61, %eax
jne 0x654b
movl $0x1, (%rbp)
jmp 0x654b
leal -0x4000004f(%rax), %ecx
cmpl $0x3, %ecx
ja 0x6621
leaq 0x2388(%rip), %rdx      # 0x8940
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movl $0x0, 0x1c(%rbp)
jmp 0x654b
leal -0x4000004f(%rax), %ecx
cmpl $0x3, %ecx
ja 0x6636
leaq 0x2374(%rip), %rdx      # 0x8950
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movl $0x1, 0x1c(%rbp)
jmp 0x654b
movl $0x0, 0xc(%rbp)
jmp 0x654b
movl $0x1, 0xc(%rbp)
jmp 0x654b
movl $0x0, 0x8(%rbp)
jmp 0x654b
movl $0x1, 0x8(%rbp)
jmp 0x654b
cmpl $0x7a, %eax
jne 0x654b
movl $0x0, 0x4(%rbp)
jmp 0x654b
cmpl $0x7a, %eax
jne 0x654b
movl $0x1, 0x4(%rbp)
jmp 0x654b
movl $0x0, 0x14(%rbp)
jmp 0x654b
movl $0x0, 0x10(%rbp)
jmp 0x654b
movl $0x0, 0x18(%rbp)
jmp 0x654b
movl $0x1, 0x14(%rbp)
jmp 0x654b
movl $0x1, 0x10(%rbp)
jmp 0x654b
movl $0x1, 0x18(%rbp)
jmp 0x654b
movl $0x1, (%rsp)
movq %r15, %rdi
movq %r12, %rsi
movq %rbx, %rdx
movq 0x18(%rsp), %rcx
movq %r14, %r8
movq %rbp, %r9
callq 0x6887
movl $0x1, %eax
movq %rax, 0x10(%rsp)
xorl %r15d, %r15d
jmp 0x6816
movq 0x8(%r12), %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(%r12)
callq 0x2210
subq %r13, %rax
js 0x671c
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
jmp 0x6734
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 0x674e
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
jmp 0x6766
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 0x21b1(%rip), %xmm1     # 0x8930
ucomisd %xmm0, %xmm1
ja 0x6708
callq 0x2210
subq %r13, %rax
js 0x6799
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
jmp 0x67b1
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 0x67cb
xorps %xmm0, %xmm0
cvtsi2ss %rax, %xmm0
jmp 0x67e3
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 0x213f(%rip), %xmm0     # 0x8938
divsd %xmm1, %xmm0
movb $0x1, %r15b
leaq 0x21c1(%rip), %rdi      # 0x89c8
movb $0x1, %al
callq 0x2050
callq 0x2210
movq %rax, %r13
testb %r15b, %r15b
movq 0x28(%rsp), %r15
movq 0x20(%rsp), %r14
jne 0x64ad
jmp 0x6873
movl $0x0, (%rsp)
movq %r15, %rdi
movq %r12, %rsi
movq %rbx, %rdx
movq 0x18(%rsp), %rcx
movq 0x20(%rsp), %r8
movq %rbp, %r9
callq 0x6887
xorl %r15d, %r15d
movq $0x0, 0x10(%rsp)
jmp 0x6816
movq (%r14), %rsi
leaq 0x20fb(%rip), %rdi      # 0x8960
xorl %eax, %eax
callq 0x2050
movl $0x1, %eax
jmp 0x6878
movq 0x10(%rsp), %rax
addq $0x78, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq