// File: /workspace/github_cpp_makefile_star2_O1/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 $0x28, %rsp
movl $0x10, %edi
callq 0x4390
movq %rax, %r14
leaq -0x40(%rbp), %rbx
movq %rbx, -0x10(%rbx)
leaq 0x619c(%rip), %rsi      # 0x1f861
leaq 0x61ce(%rip), %rdx      # 0x1f89a
leaq -0x50(%rbp), %rdi
callq 0x173f0
leaq -0x50(%rbp), %rsi
movq %r14, %rdi
callq 0x1bb40
movq -0x50(%rbp), %rdi
cmpq %rbx, %rdi
je 0x196f6
movq -0x40(%rbp), %rsi
incq %rsi
callq 0x43a0
cmpb $0x0, 0x8(%r14)
je 0x19806
movl $0x143b0, %edi          # imm = 0x143B0
callq 0x4390
movq %rax, %rbx
movq %rax, %rdi
movq %r14, %rsi
callq 0x1b3a4
movl $0x20, %edi
callq 0x4390
movq %rax, %r14
movq %rax, %rdi
movq %rbx, %rsi
callq 0x1999e
movl $0x18, %edi
callq 0x4390
movq %rax, %r15
movq %rax, %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x1bc04
movl $0x30, %edi
callq 0x4390
movq %rax, %r12
movq %rax, %rdi
movq %r14, %rsi
movq %rbx, %rdx
movq %r15, %rcx
callq 0x1bf9c
movl $0x5aa0, %edi           # imm = 0x5AA0
callq 0x4390
movq %rax, %r13
movq %rax, %rdi
movq %rbx, -0x30(%rbp)
movq %rbx, %rsi
movl $0x3, %edx
callq 0x1c5e6
movq %r15, %rdi
callq 0x1bcb0
movl %eax, %ebx
movq %r12, %rdi
callq 0x1c030
testb %bl, %bl
je 0x197ab
movq %r15, %rdi
callq 0x1bd22
jmp 0x197b3
movq %r14, %rdi
callq 0x19cfa
movq %r12, %rdi
callq 0x1c030
movq %r14, %rdi
callq 0x19b3e
movzbl %al, %esi
movq (%r13), %rax
movq %r13, %rdi
callq *0x90(%rax)
cmpw $0x100, 0x18(%r14)      # imm = 0x100
jne 0x1978b
movq -0x30(%rbp), %rax
cmpb $0x1, 0xe398(%rax)
jne 0x1978b
movq %r14, %rdi
callq 0x1b232
movq -0x30(%rbp), %rbx
movq %rbx, %rdi
callq 0x1b958
movb $0x0, 0xe398(%rbx)
jmp 0x1978b
movq 0x107bb(%rip), %rdi     # 0x29fc8
leaq 0x6087(%rip), %rsi      # 0x1f89b
callq 0x4360
movq %rax, %rdi
callq 0x4190
movl $0x1, %edi
callq 0x4460
movq %rax, -0x30(%rbp)
movl $0x5aa0, %esi           # imm = 0x5AA0
movq %r13, %rdi
jmp 0x19895
movq %rax, -0x30(%rbp)
movl $0x30, %esi
movq %r12, %rdi
jmp 0x19895
movq %rax, -0x30(%rbp)
movl $0x18, %esi
movq %r15, %rdi
jmp 0x19895
movq %rax, -0x30(%rbp)
movl $0x20, %esi
jmp 0x19892
movq %rax, -0x30(%rbp)
movl $0x143b0, %esi          # imm = 0x143B0
movq %rbx, %rdi
jmp 0x19895
movq %rax, -0x30(%rbp)
movq -0x50(%rbp), %rdi
cmpq %rbx, %rdi
je 0x1988d
movq -0x40(%rbp), %rsi
incq %rsi
callq 0x43a0
jmp 0x1988d
movq %rax, -0x30(%rbp)
movl $0x10, %esi
movq %r14, %rdi
callq 0x43a0
movq -0x30(%rbp), %rdi
callq 0x45d0
nop