// File: /workspace/github_cpp_makefile_star2_O3/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 0x5450(%rip), %rsi      # 0x1d861
leaq 0x5482(%rip), %rdx      # 0x1d89a
leaq -0x50(%rbp), %rdi
callq 0x161fa
leaq -0x50(%rbp), %rsi
movq %r14, %rdi
callq 0x1a804
movq -0x50(%rbp), %rdi
cmpq %rbx, %rdi
je 0x18442
movq -0x40(%rbp), %rsi
incq %rsi
callq 0x43a0
cmpb $0x0, 0x8(%r14)
je 0x18552
movl $0x143b0, %edi          # imm = 0x143B0
callq 0x4390
movq %rax, %rbx
movq %rax, %rdi
movq %r14, %rsi
callq 0x1a070
movl $0x20, %edi
callq 0x4390
movq %rax, %r14
movq %rax, %rdi
movq %rbx, %rsi
callq 0x186e8
movl $0x18, %edi
callq 0x4390
movq %rax, %r15
movq %rax, %rdi
movq %r14, %rsi
movq %rbx, %rdx
callq 0x1a8c8
movl $0x30, %edi
callq 0x4390
movq %rax, %r12
movq %rax, %rdi
movq %r14, %rsi
movq %rbx, %rdx
movq %r15, %rcx
callq 0x1ac5c
movl $0x5aa0, %edi           # imm = 0x5AA0
callq 0x4390
movq %rax, %r13
movq %rax, %rdi
movq %rbx, -0x30(%rbp)
movq %rbx, %rsi
movl $0x3, %edx
callq 0x1b284
movq %r15, %rdi
callq 0x1a970
movl %eax, %ebx
movq %r12, %rdi
callq 0x1acea
testb %bl, %bl
je 0x184f7
movq %r15, %rdi
callq 0x1a9e2
jmp 0x184ff
movq %r14, %rdi
callq 0x18a3c
movq %r12, %rdi
callq 0x1acea
movq %r14, %rdi
callq 0x18880
movzbl %al, %esi
movq (%r13), %rax
movq %r13, %rdi
callq *0x90(%rax)
cmpw $0x100, 0x18(%r14)      # imm = 0x100
jne 0x184d7
movq -0x30(%rbp), %rax
cmpb $0x1, 0xe398(%rax)
jne 0x184d7
movq %r14, %rdi
callq 0x19efc
movq -0x30(%rbp), %rbx
movq %rbx, %rdi
callq 0x1a61c
movb $0x0, 0xe398(%rbx)
jmp 0x184d7
movq 0xfa6f(%rip), %rdi      # 0x27fc8
leaq 0x533b(%rip), %rsi      # 0x1d89b
callq 0x4360
movq %rax, %rdi
callq 0x4190
movl $0x1, %edi
callq 0x4450
movq %rax, -0x30(%rbp)
movl $0x5aa0, %esi           # imm = 0x5AA0
movq %r13, %rdi
jmp 0x185e1
movq %rax, -0x30(%rbp)
movl $0x30, %esi
movq %r12, %rdi
jmp 0x185e1
movq %rax, -0x30(%rbp)
movl $0x18, %esi
movq %r15, %rdi
jmp 0x185e1
movq %rax, -0x30(%rbp)
movl $0x20, %esi
jmp 0x185de
movq %rax, -0x30(%rbp)
movl $0x143b0, %esi          # imm = 0x143B0
movq %rbx, %rdi
jmp 0x185e1
movq %rax, -0x30(%rbp)
movq -0x50(%rbp), %rdi
cmpq %rbx, %rdi
je 0x185d9
movq -0x40(%rbp), %rsi
incq %rsi
callq 0x43a0
jmp 0x185d9
movq %rax, -0x30(%rbp)
movl $0x10, %esi
movq %r14, %rdi
callq 0x43a0
movq -0x30(%rbp), %rdi
callq 0x45c0
nop