// File: /workspace/github_c_makefile_star2_O2/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 $0x68, %rsp
movq %rsi, %r14
cmpl $0x2, %edi
jne 0x5f26
movl $0x10058, %edi          # imm = 0x10058
callq 0x2200
movq %rax, %rbx
movq %rax, %rdi
callq 0x6094
movq 0x8(%r14), %rsi
movq %rbx, %rdi
callq 0x6327
leaq 0x1eff(%rip), %rdi      # 0x7a05
callq 0x2240
movq 0x10038(%rbx), %rsi
leaq 0x1e88(%rip), %rdi      # 0x79a1
xorl %eax, %eax
callq 0x2050
movq 0x10038(%rbx), %rax
movzbl 0x11(%rax), %esi
leaq 0x1e7a(%rip), %rdi      # 0x79ac
xorl %eax, %eax
callq 0x2050
movq 0x10038(%rbx), %rax
movzbl 0x12(%rax), %esi
leaq 0x1e79(%rip), %rdi      # 0x79c4
xorl %eax, %eax
callq 0x2050
movq 0x10038(%rbx), %rax
movzbl 0x13(%rax), %esi
leaq 0x1e72(%rip), %rdi      # 0x79d6
xorl %eax, %eax
callq 0x2050
pushq $0x14
popq %rdi
callq 0x2200
movq %rax, %r14
movq %rax, %rdi
callq 0x2919
pushq $0x38
popq %rdi
callq 0x2200
movq %rax, %r15
movq %rax, %rdi
callq 0x5224
pushq $0x8
popq %rdi
callq 0x2200
movq %rax, %r12
movq %rax, %rdi
callq 0x6658
pushq $0x20
popq %rdi
callq 0x2200
movq %rax, %r13
movq %rax, %rdi
callq 0x5a1c
movl $0x88, %edi
callq 0x2200
movq %rax, 0x28(%rsp)
movq %rax, %rdi
movl $0xac44, %esi           # imm = 0xAC44
callq 0x237c
movl $0xf231, %edi           # imm = 0xF231
callq 0x2140
leaq 0x1e04(%rip), %rdi      # 0x79e8
pushq $0x20
popq %r9
movl $0x1fff0000, %esi       # imm = 0x1FFF0000
movl $0x1fff0000, %edx       # imm = 0x1FFF0000
movl $0xa0, %ecx
movl $0x90, %r8d
callq 0x2060
pushq $-0x1
popq %rsi
pushq $0x2
popq %rdx
movq %rax, %rdi
callq 0x2040
movq %rax, %rbp
movq %rax, %rdi
movl $0xa0, %esi
movl $0x90, %edx
callq 0x20a0
pushq $0x1
popq %rdx
movq %rbp, 0x18(%rsp)
movq %rbp, %rdi
movl $0x16762004, %esi       # imm = 0x16762004
movl $0xa0, %ecx
movl $0x90, %r8d
callq 0x2260
movq %rax, 0x20(%rsp)
callq 0x2210
movq %rax, %rbp
movq %r14, %rdi
movq %r15, %rsi
movq %rbx, %rdx
movq %r12, %rcx
movq %r13, %r8
callq 0x293b
testl %eax, %eax
je 0x5f3c
movq %r14, %rdi
movq %r15, %rsi
movq %rbx, %rdx
callq 0x52a6
movq %r14, %rdi
movq %rbx, %rsi
movq %r12, %rdx
callq 0x6661
movq %rbx, %rdi
callq 0x65f3
movq %r13, %rdi
movq %rbx, %rsi
callq 0x5a2c
movq 0x28(%rsp), %rdi
movq %rbx, %rsi
callq 0x2515
cmpb $0x1, 0x10(%r15)
jne 0x5c52
jmp 0x5de6
movl 0x30(%rsp), %eax
cmpl $0x300, %eax            # imm = 0x300
je 0x5d15
cmpl $0x301, %eax            # imm = 0x301
je 0x5cd8
cmpl $0x100, %eax            # imm = 0x100
jne 0x5de6
jmp 0x5f6c
movl 0x44(%rsp), %eax
leal -0x4000004f(%rax), %ecx
cmpl $0x3, %ecx
jbe 0x5d51
cmpl $0x8, %eax
je 0x5d82
cmpl $0xd, %eax
je 0x5daf
cmpl $0x7a, %eax
je 0x5d90
cmpl $0x61, %eax
jne 0x5de6
andl $0x0, (%r13)
jmp 0x5de6
movl 0x44(%rsp), %eax
leal -0x4000004f(%rax), %ecx
cmpl $0x3, %ecx
jbe 0x5d68
cmpl $0x8, %eax
je 0x5d9e
cmpl $0xd, %eax
je 0x5dde
cmpl $0x7a, %eax
je 0x5dc0
cmpl $0x61, %eax
jne 0x5de6
movl $0x1, (%r13)
jmp 0x5de6
leaq 0x1c10(%rip), %rdx      # 0x7968
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
andl $0x0, 0x1c(%r13)
jmp 0x5de6
leaq 0x1c09(%rip), %rdx      # 0x7978
movslq (%rdx,%rcx,4), %rax
addq %rdx, %rax
jmpq *%rax
movl $0x1, 0x1c(%r13)
jmp 0x5de6
andl $0x0, 0xc(%r13)
jmp 0x5de6
andl $0x0, 0x14(%r13)
jmp 0x5de6
andl $0x0, 0x4(%r13)
jmp 0x5de6
andl $0x0, 0x10(%r13)
jmp 0x5de6
movl $0x1, 0xc(%r13)
jmp 0x5de6
andl $0x0, 0x18(%r13)
jmp 0x5de6
andl $0x0, 0x8(%r13)
jmp 0x5de6
movl $0x1, 0x14(%r13)
jmp 0x5de6
movl $0x1, 0x4(%r13)
jmp 0x5de6
movl $0x1, 0x10(%r13)
jmp 0x5de6
movl $0x1, 0x18(%r13)
jmp 0x5de6
movl $0x1, 0x8(%r13)
leaq 0x30(%rsp), %rdi
callq 0x20e0
testl %eax, %eax
jne 0x5cb6
movq 0x8(%r15), %rdx
movq 0x20(%rsp), %rdi
xorl %esi, %esi
movl $0x280, %ecx            # imm = 0x280
callq 0x2110
movq 0x18(%rsp), %rdi
callq 0x2160
movq 0x18(%rsp), %rdi
movq 0x20(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x2190
movq 0x18(%rsp), %rdi
callq 0x2070
movb $0x0, 0x10(%r15)
callq 0x2210
subq %rbp, %rax
js 0x5e4a
cvtsi2ss %rax, %xmm0
jmp 0x5e5f
movq %rax, %rcx
shrq %rcx
andl $0x1, %eax
orq %rcx, %rax
cvtsi2ss %rax, %xmm0
addss %xmm0, %xmm0
movss %xmm0, 0x14(%rsp)
callq 0x2130
testq %rax, %rax
js 0x5e76
cvtsi2ss %rax, %xmm0
jmp 0x5e8b
movq %rax, %rcx
shrq %rcx
andl $0x1, %eax
orq %rcx, %rax
cvtsi2ss %rax, %xmm0
addss %xmm0, %xmm0
movss 0x14(%rsp), %xmm1
divss %xmm0, %xmm1
cvtss2sd %xmm1, %xmm0
movsd 0x1ab7(%rip), %xmm1     # 0x7958
ucomisd %xmm0, %xmm1
ja 0x5e39
callq 0x2210
subq %rbp, %rax
js 0x5eb8
cvtsi2ss %rax, %xmm0
jmp 0x5ecd
movq %rax, %rcx
shrq %rcx
andl $0x1, %eax
orq %rcx, %rax
cvtsi2ss %rax, %xmm0
addss %xmm0, %xmm0
movss %xmm0, 0x14(%rsp)
callq 0x2130
testq %rax, %rax
js 0x5ee4
cvtsi2ss %rax, %xmm0
jmp 0x5ef9
movq %rax, %rcx
shrq %rcx
andl $0x1, %eax
orq %rcx, %rax
cvtsi2ss %rax, %xmm0
addss %xmm0, %xmm0
movss 0x14(%rsp), %xmm1
divss %xmm0, %xmm1
cvtss2sd %xmm1, %xmm1
movsd 0x1a51(%rip), %xmm0     # 0x7960
divsd %xmm1, %xmm0
leaq 0x1ad6(%rip), %rdi      # 0x79f0
movb $0x1, %al
callq 0x2050
jmp 0x5c4a
movq (%r14), %rsi
leaq 0x1a58(%rip), %rdi      # 0x7988
xorl %eax, %eax
callq 0x2050
pushq $0x1
popq %rbp
jmp 0x5f5b
pushq $0x1
popq %rbp
movl %ebp, (%rsp)
movq %r14, %rdi
movq %r15, %rsi
movq %rbx, %rdx
movq 0x28(%rsp), %rcx
movq %r12, %r8
movq %r13, %r9
callq 0x5f70
movl %ebp, %eax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
xorl %ebp, %ebp
jmp 0x5f3f