// File: /workspace/github_c_makefile_star2_O0/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
movq %rsp, %rbp
subq $0xf0, %rsp
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
cmpl $0x2, -0x8(%rbp)
je 0xc380
movq -0x10(%rbp), %rax
movq (%rax), %rsi
leaq 0x2603(%rip), %rdi      # 0xe970
movb $0x0, %al
callq 0x2050
movl $0x1, -0x4(%rbp)
jmp 0xca2c
movl $0x10058, %edi          # imm = 0x10058
callq 0x2210
movq %rax, -0x18(%rbp)
movq -0x18(%rbp), %rdi
callq 0xcb80
movq -0x18(%rbp), %rdi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0xd0e0
leaq 0x25da(%rip), %rdi      # 0xe989
movb $0x0, %al
callq 0x2050
movq -0x18(%rbp), %rax
movq 0x10038(%rax), %rsi
leaq 0x25cc(%rip), %rdi      # 0xe994
movb $0x0, %al
callq 0x2050
movq -0x18(%rbp), %rax
movq 0x10038(%rax), %rax
movzbl 0x11(%rax), %esi
leaq 0x25ba(%rip), %rdi      # 0xe99f
movb $0x0, %al
callq 0x2050
movq -0x18(%rbp), %rax
movq 0x10038(%rax), %rax
movzbl 0x12(%rax), %esi
leaq 0x25b5(%rip), %rdi      # 0xe9b7
movb $0x0, %al
callq 0x2050
movq -0x18(%rbp), %rax
movq 0x10038(%rax), %rax
movzbl 0x13(%rax), %esi
leaq 0x25aa(%rip), %rdi      # 0xe9c9
movb $0x0, %al
callq 0x2050
movl $0x14, %edi
callq 0x2210
movq %rax, -0x20(%rbp)
movq -0x20(%rbp), %rdi
callq 0x3320
movl $0x38, %edi
callq 0x2210
movq %rax, -0x28(%rbp)
movq -0x28(%rbp), %rdi
callq 0xb090
movl $0x8, %edi
callq 0x2210
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rdi
callq 0xd6a0
movl $0x20, %edi
callq 0x2210
movq %rax, -0x38(%rbp)
movq -0x38(%rbp), %rdi
callq 0xc080
movl $0x88, %edi
callq 0x2210
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rdi
movl $0xac44, %esi           # imm = 0xAC44
callq 0x2380
movl $0xf231, %edi           # imm = 0xF231
callq 0x2150
leaq 0x252c(%rip), %rdi      # 0xe9db
movl $0x1fff0000, %edx       # imm = 0x1FFF0000
movl $0xa0, %ecx
movl $0x90, %r8d
movl $0x20, %r9d
movl %edx, %esi
callq 0x2060
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rdi
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
movl $0x2, %edx
callq 0x2040
movq %rax, -0x50(%rbp)
movq -0x50(%rbp), %rdi
movl $0xa0, %esi
movl $0x90, %edx
callq 0x20a0
movq -0x50(%rbp), %rdi
movl $0x16762004, %esi       # imm = 0x16762004
movl $0x1, %edx
movl $0xa0, %ecx
movl $0x90, %r8d
callq 0x2260
movq %rax, -0x58(%rbp)
callq 0x2220
movq %rax, -0x98(%rbp)
movq -0x20(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x18(%rbp), %rdx
movq -0x30(%rbp), %rcx
movq -0x38(%rbp), %r8
callq 0x33c0
movl %eax, -0x9c(%rbp)
cmpl $0x0, -0x9c(%rbp)
jne 0xc57c
movq -0x20(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x18(%rbp), %rdx
movq -0x40(%rbp), %rcx
movq -0x30(%rbp), %r8
movq -0x38(%rbp), %r9
movl $0x1, (%rsp)
callq 0xca40
movl %eax, -0x4(%rbp)
jmp 0xca2c
movq -0x20(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x18(%rbp), %rdx
callq 0xb1c0
movq -0x20(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x30(%rbp), %rdx
callq 0xd6f0
movq -0x18(%rbp), %rdi
callq 0xd5d0
movq -0x38(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0xc120
movq -0x40(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0x2630
movq -0x28(%rbp), %rax
testb $0x1, 0x10(%rax)
je 0xca27
jmp 0xc5d1
leaq -0x90(%rbp), %rdi
callq 0x20e0
cmpl $0x0, %eax
je 0xc81a
movl -0x90(%rbp), %eax
movl %eax, -0xac(%rbp)
subl $0x100, %eax            # imm = 0x100
je 0xc620
jmp 0xc5fb
movl -0xac(%rbp), %eax
subl $0x300, %eax            # imm = 0x300
je 0xc64e
jmp 0xc60a
movl -0xac(%rbp), %eax
subl $0x301, %eax            # imm = 0x301
je 0xc733
jmp 0xc815
movq -0x20(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x18(%rbp), %rdx
movq -0x40(%rbp), %rcx
movq -0x30(%rbp), %r8
movq -0x38(%rbp), %r9
xorl %eax, %eax
movl $0x0, (%rsp)
callq 0xca40
movl %eax, -0x4(%rbp)
jmp 0xca2c
movl -0x7c(%rbp), %eax
movl %eax, -0xb0(%rbp)
subl $0x8, %eax
je 0xc6ef
jmp 0xc662
movl -0xb0(%rbp), %eax
subl $0xd, %eax
je 0xc6e2
jmp 0xc66f
movl -0xb0(%rbp), %eax
subl $0x61, %eax
je 0xc6c9
jmp 0xc67c
movl -0xb0(%rbp), %eax
subl $0x7a, %eax
je 0xc6d5
jmp 0xc689
movl -0xb0(%rbp), %eax
subl $0x4000004f, %eax       # imm = 0x4000004F
je 0xc723
jmp 0xc69c
movl -0xb0(%rbp), %eax
subl $0x40000050, %eax       # imm = 0x40000050
je 0xc716
jmp 0xc6ab
movl -0xb0(%rbp), %eax
subl $0x40000051, %eax       # imm = 0x40000051
je 0xc709
jmp 0xc6ba
movl -0xb0(%rbp), %eax
subl $0x40000052, %eax       # imm = 0x40000052
je 0xc6fc
jmp 0xc72e
movq -0x38(%rbp), %rax
movl $0x1, (%rax)
jmp 0xc72e
movq -0x38(%rbp), %rax
movl $0x1, 0x4(%rax)
jmp 0xc72e
movq -0x38(%rbp), %rax
movl $0x1, 0x8(%rax)
jmp 0xc72e
movq -0x38(%rbp), %rax
movl $0x1, 0xc(%rax)
jmp 0xc72e
movq -0x38(%rbp), %rax
movl $0x1, 0x10(%rax)
jmp 0xc72e
movq -0x38(%rbp), %rax
movl $0x1, 0x14(%rax)
jmp 0xc72e
movq -0x38(%rbp), %rax
movl $0x1, 0x18(%rax)
jmp 0xc72e
movq -0x38(%rbp), %rax
movl $0x1, 0x1c(%rax)
jmp 0xc815
movl -0x7c(%rbp), %eax
movl %eax, -0xb4(%rbp)
subl $0x8, %eax
je 0xc7d4
jmp 0xc747
movl -0xb4(%rbp), %eax
subl $0xd, %eax
je 0xc7c7
jmp 0xc754
movl -0xb4(%rbp), %eax
subl $0x61, %eax
je 0xc7ae
jmp 0xc761
movl -0xb4(%rbp), %eax
subl $0x7a, %eax
je 0xc7ba
jmp 0xc76e
movl -0xb4(%rbp), %eax
subl $0x4000004f, %eax       # imm = 0x4000004F
je 0xc808
jmp 0xc781
movl -0xb4(%rbp), %eax
subl $0x40000050, %eax       # imm = 0x40000050
je 0xc7fb
jmp 0xc790
movl -0xb4(%rbp), %eax
subl $0x40000051, %eax       # imm = 0x40000051
je 0xc7ee
jmp 0xc79f
movl -0xb4(%rbp), %eax
subl $0x40000052, %eax       # imm = 0x40000052
je 0xc7e1
jmp 0xc813
movq -0x38(%rbp), %rax
movl $0x0, (%rax)
jmp 0xc813
movq -0x38(%rbp), %rax
movl $0x0, 0x4(%rax)
jmp 0xc813
movq -0x38(%rbp), %rax
movl $0x0, 0x8(%rax)
jmp 0xc813
movq -0x38(%rbp), %rax
movl $0x0, 0xc(%rax)
jmp 0xc813
movq -0x38(%rbp), %rax
movl $0x0, 0x10(%rax)
jmp 0xc813
movq -0x38(%rbp), %rax
movl $0x0, 0x14(%rax)
jmp 0xc813
movq -0x38(%rbp), %rax
movl $0x0, 0x18(%rax)
jmp 0xc813
movq -0x38(%rbp), %rax
movl $0x0, 0x1c(%rax)
jmp 0xc815
jmp 0xc5d1
movq -0x58(%rbp), %rdi
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rdx
xorl %eax, %eax
movl %eax, %esi
movl $0x280, %ecx            # imm = 0x280
callq 0x2110
movq -0x50(%rbp), %rdi
callq 0x2170
movq -0x50(%rbp), %rdi
movq -0x58(%rbp), %rsi
xorl %eax, %eax
movl %eax, %ecx
movq %rcx, %rdx
callq 0x21a0
movq -0x50(%rbp), %rdi
callq 0x2070
movq -0x28(%rbp), %rax
movb $0x0, 0x10(%rax)
movsd 0x20f6(%rip), %xmm0     # 0xe960
movsd %xmm0, -0xa8(%rbp)
callq 0x2220
movq -0x98(%rbp), %rcx
subq %rcx, %rax
movq %rax, %rdx
shrq %rdx
movl %eax, %ecx
andl $0x1, %ecx
orq %rdx, %rcx
cvtsi2ss %rcx, %xmm0
addss %xmm0, %xmm0
cvtsi2ss %rax, %xmm1
movss %xmm1, -0xbc(%rbp)
testq %rax, %rax
movss %xmm0, -0xb8(%rbp)
js 0xc8c2
movss -0xbc(%rbp), %xmm0
movss %xmm0, -0xb8(%rbp)
movss -0xb8(%rbp), %xmm0
movss %xmm0, -0xc8(%rbp)
callq 0x2140
movq %rax, %rdx
shrq %rdx
movl %eax, %ecx
andl $0x1, %ecx
orq %rdx, %rcx
cvtsi2ss %rcx, %xmm0
addss %xmm0, %xmm0
cvtsi2ss %rax, %xmm1
movss %xmm1, -0xc4(%rbp)
testq %rax, %rax
movss %xmm0, -0xc0(%rbp)
js 0xc918
movss -0xc4(%rbp), %xmm0
movss %xmm0, -0xc0(%rbp)
movss -0xc8(%rbp), %xmm0
movss -0xc0(%rbp), %xmm1
divss %xmm1, %xmm0
cvtss2sd %xmm0, %xmm1
movsd -0xa8(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0xc943
jmp 0xc872
callq 0x2220
movq -0x98(%rbp), %rcx
subq %rcx, %rax
movq %rax, %rdx
shrq %rdx
movl %eax, %ecx
andl $0x1, %ecx
orq %rdx, %rcx
cvtsi2ss %rcx, %xmm0
addss %xmm0, %xmm0
cvtsi2ss %rax, %xmm1
movss %xmm1, -0xd0(%rbp)
testq %rax, %rax
movss %xmm0, -0xcc(%rbp)
js 0xc993
movss -0xd0(%rbp), %xmm0
movss %xmm0, -0xcc(%rbp)
movss -0xcc(%rbp), %xmm0
movss %xmm0, -0xdc(%rbp)
callq 0x2140
movq %rax, %rdx
shrq %rdx
movl %eax, %ecx
andl $0x1, %ecx
orq %rdx, %rcx
cvtsi2ss %rcx, %xmm0
addss %xmm0, %xmm0
cvtsi2ss %rax, %xmm1
movss %xmm1, -0xd8(%rbp)
testq %rax, %rax
movss %xmm0, -0xd4(%rbp)
js 0xc9e9
movss -0xd8(%rbp), %xmm0
movss %xmm0, -0xd4(%rbp)
movss -0xdc(%rbp), %xmm0
movss -0xd4(%rbp), %xmm1
divss %xmm1, %xmm0
cvtss2sd %xmm0, %xmm1
movsd 0x1f5f(%rip), %xmm0     # 0xe968
divsd %xmm1, %xmm0
leaq 0x1fcf(%rip), %rdi      # 0xe9e3
movb $0x1, %al
callq 0x2050
callq 0x2220
movq %rax, -0x98(%rbp)
jmp 0xc528
movl -0x4(%rbp), %eax
addq $0xf0, %rsp
popq %rbp
retq
nopl (%rax,%rax)