// File: /workspace/github_cpp_makefile_star2_O3/nicoeps[P]NicoGB/src/cartridge.cpp
// Function: Cartridge::load(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>)
void Cartridge::load(std::string path) {
    std::ifstream cartridgeFile(path, std::ifstream::binary);

    if (!cartridgeFile.is_open()) {
        loaded = false;
        return;
    } else {
        cartridgeFile.seekg(0, cartridgeFile.end);
        romSize = cartridgeFile.tellg();
        cartridgeFile.seekg(0, cartridgeFile.beg);
        cartridgeFile.clear();
        if (romSize % 32768 != 0) {
            loaded = false;
            cartridgeFile.close();
            return;
        }
        cartridgeROM.resize(romSize);
        cartridgeFile.read((char*) cartridgeROM.data(), romSize);
        cartridgeFile.close();
        loaded = true;

        cartridgeType = cartridgeROM[0x0147];
        switch (cartridgeROM[0x0149]) {
            case 0:  ramSize = 1;         break;
            case 1:  ramSize = 2048;      break;
            case 2:  ramSize = 8192;      break;
            case 3:  ramSize = 4 * 8192;  break;
            case 4:  ramSize = 16 * 8192; break;
            case 5:  ramSize = 8 * 8192;  break;
            default: ramSize = 1;         break;
        }

        if (cartridgeType == 0x05 || cartridgeType == 0x06) { // MBC2
            ramSize = 512;
        }

        cartridgeRAM.resize(ramSize);
        std::fill_n(cartridgeRAM.begin(), ramSize, 0);

        int titleSize = cartridgeROM[0x0143] & 0x80 ? 15 : 16; // CGB Flag
        title.assign(&cartridgeROM[0x0134], &cartridgeROM[0x0134] + titleSize);

        switch (cartridgeType) {
            // ROM
            case 0x00:
            case 0x08:
            case 0x09:
                mbc.reset(new MBC0(cartridgeROM, cartridgeRAM, ramSize));
                break;

            // MBC1
            case 0x01:
            case 0x02:
            case 0x03:
                mbc.reset(new MBC1(cartridgeROM, cartridgeRAM, romSize, ramSize));
                break;

            // MBC2
            case 0x05:
            case 0x06:
                mbc.reset(new MBC2(cartridgeROM, cartridgeRAM, romSize, ramSize));
                break;

            // MMM01
            // case 0x0B:
            // case 0x0C:
            // case 0x0D:
                // break;

            // MBC3
            case 0x0F:
            case 0x10:
            case 0x11:
            case 0x12:
            case 0x13:
                mbc.reset(new MBC3(cartridgeROM, cartridgeRAM, romSize, ramSize));
                break;

            // MBC5
            case 0x19:
            case 0x1A:
            case 0x1B:
            case 0x1C:
            case 0x1D:
            case 0x1E:
                mbc.reset(new MBC5(cartridgeROM, cartridgeRAM, romSize, ramSize));
                break;

            // MBC6
            // case 0x20:
            //     break;

            // MBC7
            // case 0x22:
            //     break;

            default:
                mbc.reset(new MBC0(cartridgeROM, cartridgeRAM, ramSize));
                break;
        }
    }
}

// Assembly:
pushq %r15
pushq %r14
pushq %rbx
subq $0x210, %rsp            # imm = 0x210
movq %rdi, %rbx
leaq 0x8(%rsp), %rdi
movl $0x4, %edx
callq 0x2220
leaq 0x80(%rsp), %rdi
callq 0x20a0
testb %al, %al
je 0x2522
leaq 0x8(%rsp), %rdi
xorl %esi, %esi
movl $0x2, %edx
callq 0x2200
leaq 0x8(%rsp), %rdi
callq 0x2250
movq %rax, 0x68(%rbx)
leaq 0x8(%rsp), %r14
movq %r14, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x2200
movq 0x8(%rsp), %rax
addq -0x18(%rax), %r14
movq %r14, %rdi
xorl %esi, %esi
callq 0x2240
movq 0x68(%rbx), %rsi
testl $0x7fff, %esi           # imm = 0x7FFF
je 0x253d
movb $0x0, 0x20(%rbx)
leaq 0x8(%rsp), %rdi
callq 0x2090
jmp 0x2526
movb $0x0, 0x20(%rbx)
leaq 0x8(%rsp), %rdi
callq 0x20b0
addq $0x210, %rsp            # imm = 0x210
popq %rbx
popq %r14
popq %r15
retq
leaq 0x30(%rbx), %r14
movq %r14, %rdi
callq 0x27ac
movq 0x30(%rbx), %rsi
movq 0x68(%rbx), %rdx
leaq 0x8(%rsp), %rdi
callq 0x21f0
leaq 0x8(%rsp), %rdi
callq 0x2090
movb $0x1, 0x20(%rbx)
movq 0x30(%rbx), %rcx
movb 0x147(%rcx), %al
movb %al, 0x60(%rbx)
movb 0x149(%rcx), %cl
decb %cl
cmpb $0x4, %cl
ja 0x259d
leaq 0x6afa(%rip), %rdx      # 0x9084
movzbl %cl, %esi
movl (%rdx,%rsi,4), %ecx
leaq 0x6b01(%rip), %rdx      # 0x9098
movq (%rdx,%rsi,8), %rsi
jmp 0x25a7
movl $0x1, %esi
movl $0x1, %ecx
movl %ecx, 0x70(%rbx)
addb $-0x5, %al
cmpb $0x1, %al
ja 0x25bc
movl $0x200, 0x70(%rbx)      # imm = 0x200
movl $0x200, %esi            # imm = 0x200
leaq 0x48(%rbx), %r15
movq %r15, %rdi
callq 0x27ac
movslq 0x70(%rbx), %rdx
testq %rdx, %rdx
jle 0x25db
movq (%r15), %rdi
xorl %esi, %esi
callq 0x2120
movq (%rbx), %rsi
movq 0x30(%rbx), %rcx
xorl %eax, %eax
cmpb $0x0, 0x143(%rcx)
setns %al
leaq (%rax,%rcx), %r8
addq $0x143, %r8             # imm = 0x143
addq $0x134, %rcx            # imm = 0x134
movq 0x8(%rbx), %rdx
addq %rsi, %rdx
movq %rbx, %rdi
callq 0x28dc
movzbl 0x60(%rbx), %eax
cmpq $0x1e, %rax
ja 0x2737
leaq 0x69e4(%rip), %rcx      # 0x9008
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl $0x28, %edi
callq 0x21b0
movl 0x68(%rbx), %ecx
movl 0x70(%rbx), %edx
leaq 0xa71c(%rip), %rsi      # 0xcd60
addq $0x10, %rsi
movq %rsi, (%rax)
movq %r14, 0x8(%rax)
movq %r15, 0x10(%rax)
movl %ecx, 0x18(%rax)
movl %edx, 0x1c(%rax)
movw $0x100, 0x20(%rax)      # imm = 0x100
xorl %ecx, %ecx
movb %cl, 0x22(%rax)
movw $0x0, 0x24(%rax)
movb %cl, 0x26(%rax)
jmp 0x275d
movl $0x30, %edi
callq 0x21b0
movl 0x68(%rbx), %ecx
movl 0x70(%rbx), %edx
leaq 0xa68f(%rip), %rsi      # 0xcd18
addq $0x10, %rsi
movq %rsi, (%rax)
movq %r14, 0x8(%rax)
movq %r15, 0x10(%rax)
movb $0x0, 0x18(%rax)
movl %ecx, 0x1c(%rax)
movl %edx, 0x20(%rax)
movb $0x1, 0x24(%rax)
movl $0x0, 0x25(%rax)
movw $0x0, 0x29(%rax)
jmp 0x275d
movl $0x30, %edi
callq 0x21b0
movl 0x68(%rbx), %ecx
movl 0x70(%rbx), %edx
leaq 0xa5b9(%rip), %rsi      # 0xcc88
addq $0x10, %rsi
movq %rsi, (%rax)
movq %r14, 0x8(%rax)
movq %r15, 0x10(%rax)
movb $0x0, 0x18(%rax)
movl %ecx, 0x1c(%rax)
movl %edx, 0x20(%rax)
movb $0x1, 0x24(%rax)
movl $0x0, 0x25(%rax)
jmp 0x275d
movl $0x20, %edi
callq 0x21b0
jmp 0x2741
movl $0x28, %edi
callq 0x21b0
movl 0x68(%rbx), %ecx
movl 0x70(%rbx), %edx
leaq 0xa5b8(%rip), %rsi      # 0xccd0
addq $0x10, %rsi
movq %rsi, (%rax)
movq %r14, 0x8(%rax)
movq %r15, 0x10(%rax)
movb $0x0, 0x18(%rax)
movl %ecx, 0x1c(%rax)
movl %edx, 0x20(%rax)
movb $0x1, 0x24(%rax)
jmp 0x275d
movl $0x20, %edi
callq 0x21b0
movl 0x70(%rbx), %ecx
leaq 0xa4f5(%rip), %rdx      # 0xcc40
addq $0x10, %rdx
movq %rdx, (%rax)
movq %r14, 0x8(%rax)
movq %r15, 0x10(%rax)
movl %ecx, 0x18(%rax)
movq 0x28(%rbx), %rdi
movq %rax, 0x28(%rbx)
testq %rdi, %rdi
je 0x2526
movq (%rdi), %rax
callq *0x18(%rax)
jmp 0x2526
jmp 0x277d
jmp 0x277d
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0x20b0
movq %rbx, %rdi
callq 0x2270