// File: /workspace/github_cpp_makefile_star2_O2/RegulusImpact[P]sadboy/src/main.cpp
// Function: main
int main() {
    /* BLARGGS CPU INSTRUCTION TESTS */
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/cpu_instrs/individual/01-special.gb"); // -- passed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/cpu_instrs/individual/02-interrupts.gb"); // -- passed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/cpu_instrs/individual/03-op sp,hl.gb"); // -- Passed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/cpu_instrs/individual/04-op r,imm.gb"); // -- Passed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/cpu_instrs/individual/05-op rp.gb"); // -- passed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/cpu_instrs/individual/06-ld r,r.gb"); // -- passed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/cpu_instrs/individual/07-jr,jp,call,ret,rst.gb"); // -- passed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/cpu_instrs/individual/08-misc instrs.gb"); // -- passed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/cpu_instrs/individual/09-op r,r.gb"); // -- passed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/cpu_instrs/individual/10-bit ops.gb"); // -- passed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/cpu_instrs/individual/11-op a,(hl).gb"); // -- passed

    /* BLARGGS TIMING TESTS */
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/interrupt_time/interrupt_time.gb"); // -- failed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/instr_timing/instr_timing.gb"); // -- failed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/mem_timing/mem_timing.gb"); // -- failed
    // Cartridge* cart = new Cartridge("submodules/gb-test-roms/mem_timing/individual/01-read_timing.gb");

    // The holy grail of tests :D
    // Cartridge* cart = new Cartridge("/home/regulus/github/sadboy/test/div_write.gb"); // -- failed
    // Cartridge* cart = new Cartridge("/home/regulus/github/sadboy/test/ie_push.gb"); // -- failed
    // Cartridge* cart = new Cartridge("/home/regulus/github/sadboy/test/rapid_toggle.gb"); // -- failed
    Cartridge* cart = new Cartridge("/home/regulus/github/java-gb/src/main/resources/tetris.gb"); // -- failed
    if (!cart->IsLoaded()) {
        std::cout << "Cartridge is not loaded." << std::endl;
        exit(1);
    }

    MMU* mmu = new MMU(cart);
    CPU* cpu = new CPU(mmu);
    InterruptService* is = new InterruptService(cpu, mmu);
    TimerService* ts = new TimerService(cpu, mmu, is);
    iGPU* gpu = new XGPU(mmu, 3);

    uint32_t counter = 0;
    uint32_t breakpointExtension = 0;
    int qq;

    while (true) {
        bool dispatcher = is->CheckInterrupts();

                ts->Increment();
        if (dispatcher) {
            is->Dispatch();
        } else {
            cpu->Read(); // fetch, decode, execute
        }
                ts->Increment();

        gpu->Step(cpu->GetCycles());

        if (0 < breakpointExtension && 50 > breakpointExtension) {
            std::cout << "Breakpoint" << std::endl;
            printf("\tAF=%.4X", cpu->Get(FULL_REGISTERS::AF));
            printf("\tBC=%.4X", cpu->Get(FULL_REGISTERS::BC));
            printf("\tDE=%.4X", cpu->Get(FULL_REGISTERS::DE));
            printf("\tHL=%.4X", cpu->Get(FULL_REGISTERS::HL));
            printf("\tSP=%.4X", cpu->stackPointer           );
            printf("\tPC=%.4X", cpu->programCounter         );
            std::cin >> qq;
            breakpointExtension--;
        }

        if (0x0100 == cpu->programCounter && mmu->readBios) {
            cpu->CheckRegisters();
            mmu->CheckMemory();
            mmu->readBios = false;
        }

        counter++;
    }

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
pushq $0x10
popq %rdi
callq 0x4370
movq %rax, %r14
leaq 0x5e36(%rip), %rsi      # 0x1a861
leaq -0x58(%rbp), %rdi
leaq -0x31(%rbp), %rdx
callq 0x4130
leaq -0x58(%rbp), %rsi
movq %r14, %rdi
callq 0x16c04
leaq -0x58(%rbp), %rdi
callq 0x4170
cmpb $0x0, 0x8(%r14)
je 0x14b55
movl $0x143b0, %edi          # imm = 0x143B0
callq 0x4370
movq %rax, %rbx
movq %rax, %rdi
movq %r14, %rsi
callq 0x164c4
pushq $0x20
popq %rdi
callq 0x4370
movq %rax, %r14
movq %rax, %rdi
movq %rbx, %rsi
callq 0x14c94
pushq $0x18
popq %rdi
callq 0x4370
movq %rax, %r15
movq %rax, %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x16cf4
pushq $0x30
popq %rdi
callq 0x4370
movq %rax, %r12
movq %rax, %rdi
movq %r14, %rsi
movq %rbx, %rdx
movq %r15, %rcx
callq 0x17078
movl $0x5aa0, %edi           # imm = 0x5AA0
callq 0x4370
movq %rax, %r13
pushq $0x3
popq %rdx
movq %rax, %rdi
movq %rbx, -0x30(%rbp)
movq %rbx, %rsi
callq 0x17620
movq %r15, %rdi
callq 0x16d98
movl %eax, %ebx
movq %r12, %rdi
callq 0x17102
testb %bl, %bl
je 0x14afa
movq %r15, %rdi
callq 0x16e0a
jmp 0x14b02
movq %r14, %rdi
callq 0x14fba
movq %r12, %rdi
callq 0x17102
movq %r14, %rdi
callq 0x14e36
movzbl %al, %esi
movq (%r13), %rax
movq %r13, %rdi
callq *0x90(%rax)
cmpw $0x100, 0x18(%r14)      # imm = 0x100
jne 0x14ada
movq -0x30(%rbp), %rax
cmpb $0x1, 0xe398(%rax)
jne 0x14ada
movq %r14, %rdi
callq 0x16354
movq -0x30(%rbp), %rbx
movq %rbx, %rdi
callq 0x16a32
movb $0x0, 0xe398(%rbx)
jmp 0x14ada
movq 0x1146c(%rip), %rdi     # 0x25fc8
leaq 0x5d38(%rip), %rsi      # 0x1a89b
callq 0x4340
movq %rax, %rdi
callq 0x4190
pushq $0x1
popq %rdi
callq 0x4420
movq %rax, -0x30(%rbp)
movl $0x5aa0, %esi           # imm = 0x5AA0
movq %r13, %rdi
jmp 0x14bcd
movq %rax, -0x30(%rbp)
pushq $0x30
popq %rsi
movq %r12, %rdi
jmp 0x14bcd
movq %rax, -0x30(%rbp)
pushq $0x18
popq %rsi
movq %r15, %rdi
jmp 0x14bcd
movq %rax, -0x30(%rbp)
pushq $0x20
jmp 0x14bc9
movq %rax, -0x30(%rbp)
movl $0x143b0, %esi          # imm = 0x143B0
movq %rbx, %rdi
jmp 0x14bcd
movq %rax, -0x30(%rbp)
leaq -0x58(%rbp), %rdi
callq 0x4170
jmp 0x14bc7
movq %rax, -0x30(%rbp)
pushq $0x10
popq %rsi
movq %r14, %rdi
callq 0x4380
movq -0x30(%rbp), %rdi
callq 0x45a0
nop