// File: /workspace/github_cpp_makefile_star2_O2/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
pushq $0x4
popq %rdx
callq 0x2260
leaq 0x80(%rsp), %rdi
callq 0x20a0
testb %al, %al
je 0x2561
leaq 0x8(%rsp), %rdi
pushq $0x2
popq %rdx
xorl %esi, %esi
callq 0x2230
leaq 0x8(%rsp), %rdi
callq 0x2290
movq %rax, 0x68(%rbx)
leaq 0x8(%rsp), %r14
movq %r14, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x2230
movq 0x8(%rsp), %rax
addq -0x18(%rax), %r14
movq %r14, %rdi
xorl %esi, %esi
callq 0x2280
movq 0x68(%rbx), %rsi
testw $0x7fff, %si            # imm = 0x7FFF
je 0x257c
movb $0x0, 0x20(%rbx)
leaq 0x8(%rsp), %rdi
callq 0x2090
jmp 0x2565
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 0x27e4
movq 0x30(%rbx), %rsi
movq 0x68(%rbx), %rdx
leaq 0x8(%rsp), %rdi
callq 0x2210
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 0x25dc
leaq 0x6ad3(%rip), %rdx      # 0x909c
movzbl %cl, %esi
movl (%rdx,%rsi,4), %ecx
leaq 0x6ada(%rip), %rdx      # 0x90b0
movq (%rdx,%rsi,8), %rsi
jmp 0x25e2
pushq $0x1
popq %rsi
pushq $0x1
popq %rcx
movl %ecx, 0x70(%rbx)
addb $-0x5, %al
cmpb $0x1, %al
ja 0x25f7
movl $0x200, 0x70(%rbx)      # imm = 0x200
movl $0x200, %esi            # imm = 0x200
leaq 0x48(%rbx), %r15
movq %r15, %rdi
callq 0x27e4
movq 0x48(%rbx), %rdi
movl 0x70(%rbx), %esi
leaq 0x4(%rsp), %rdx
andl $0x0, (%rdx)
callq 0x29ed
movq 0x30(%rbx), %rsi
xorl %eax, %eax
cmpb $0x0, 0x143(%rsi)
setns %al
leaq (%rax,%rsi), %rdx
addq $0x143, %rdx            # imm = 0x143
addq $0x134, %rsi            # imm = 0x134
movq %rbx, %rdi
callq 0x2810
movzbl 0x60(%rbx), %eax
cmpq $0x1e, %rax
ja 0x2757
leaq 0x69ca(%rip), %rcx      # 0x9020
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
pushq $0x28
popq %rdi
callq 0x21d0
movl 0x68(%rbx), %ecx
movl 0x70(%rbx), %edx
leaq 0xb6ec(%rip), %rsi      # 0xdd60
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)
andw $0x0, 0x24(%rax)
movb %cl, 0x26(%rax)
jmp 0x277b
pushq $0x30
popq %rdi
callq 0x21d0
movl 0x68(%rbx), %ecx
movl 0x70(%rbx), %edx
leaq 0xb662(%rip), %rsi      # 0xdd18
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)
andl $0x0, 0x25(%rax)
andw $0x0, 0x29(%rax)
jmp 0x277b
pushq $0x30
popq %rdi
callq 0x21d0
movl 0x68(%rbx), %ecx
movl 0x70(%rbx), %edx
leaq 0xb592(%rip), %rsi      # 0xdc88
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)
andl $0x0, 0x25(%rax)
jmp 0x277b
pushq $0x20
popq %rdi
callq 0x21d0
jmp 0x275f
pushq $0x28
popq %rdi
callq 0x21d0
movl 0x68(%rbx), %ecx
movl 0x70(%rbx), %edx
leaq 0xb598(%rip), %rsi      # 0xdcd0
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 0x277b
pushq $0x20
popq %rdi
callq 0x21d0
movl 0x70(%rbx), %ecx
leaq 0xb4d7(%rip), %rdx      # 0xdc40
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 0x2565
movq (%rdi), %rax
callq *0x18(%rax)
jmp 0x2565
jmp 0x279d
jmp 0x279d
jmp 0x279d
movq %rax, %rbx
leaq 0x8(%rsp), %rdi
callq 0x20b0
movq %rbx, %rdi
callq 0x22b0