// File: mindbeast[P]rnes/nes.cpp
// Function: Rnes::Nes::loadRom(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&)
int Nes::loadRom(const std::string &filename) {
  int result = mapRom(filename);
  if (result == -1) {
    return -1;
  }
  romFile = filename;
  const NesHeader *header = (const NesHeader *)rom;
  std::cerr << "Loading rom.. " << std::endl;
  std::cerr << "rom banks: " << (int)header->numRomBanks << std::endl;
  std::cerr << "vrom banks: " << (int)header->numVRomBanks << std::endl;
  std::cerr << "ram banks: " << (int)header->numPrgRamBanks << std::endl;
  if (header->info[0] & (1 << 2)) {
    std::cerr << "trainer present" << std::endl;
  }
  uint8_t mapper = (header->info[0] & 0xf0) >> 4;
  mapper |= (header->info[1] & 0xf0);
  std::cerr << "mapper: " << (int)mapper << std::endl;

  std::vector<uint8_t *> prgRoms;
  std::vector<uint8_t *> chrRoms;

  uint8_t *prgRomBase = (uint8_t *)rom + sizeof(NesHeader);
  for (int i = 0; i < header->numRomBanks; i++) {
    std::cerr << "loading rom section " << std::endl;
    uint8_t *prgRom = prgRomBase + i * prgRomSize;
    prgRoms.push_back(prgRom);
  }

  uint8_t *chrRomBase = prgRomBase + header->numRomBanks * prgRomSize;
  for (int i = 0; i < header->numVRomBanks; i++) {
    uint8_t *chrRom = chrRomBase + i * chrRomSize;
    chrRoms.push_back(chrRom);
  }

  bool verticalMirroring = (header->info[0] & 1) != 0;
  switch (mapper) {
  case 0: {
    std::cout << "Loading no mmc game." << std::endl;
    std::unique_ptr<Mmc> mmcLocal(
        new MmcNone(prgRoms, chrRoms, header->numPrgRamBanks, verticalMirroring));
    mmc = std::move(mmcLocal);
    break;
  }
  case 1: {
    std::cout << "Loading MMC1 game." << std::endl;
    std::unique_ptr<Mmc> mmcLocal(new Mmc1(prgRoms, chrRoms, header->numPrgRamBanks,
                                           verticalMirroring, cpuMemory.get(), videoMemory.get()));
    mmc = std::move(mmcLocal);
    break;
  }
  case 4: {
    std::cout << "Loading MMC3 game." << std::endl;
    std::unique_ptr<Mmc> mmcLocal(new Mmc3(prgRoms, chrRoms, header->numPrgRamBanks,
                                           verticalMirroring, cpuMemory.get(), videoMemory.get()));
    mmc = std::move(mmcLocal);
    break;
  }
  default:
    std::cout << "Unsupported mapper: " << std::hex << mapper << std::endl;
    assert(0);
    break;
  }
  cpuMemory->setMmc(mmc.get());
  videoMemory->setMmc(mmc.get());
  return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x160, %rsp            # imm = 0x160
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq -0x10(%rbp), %rdi
movq %rdi, -0xc8(%rbp)
movq -0x18(%rbp), %rsi
callq 0x3cc70
movl %eax, -0x1c(%rbp)
cmpl $-0x1, -0x1c(%rbp)
jne 0x3cdbc
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x3d4bc
movq -0xc8(%rbp), %rdi
movq -0x18(%rbp), %rsi
addq $0x10, %rdi
callq 0xec50
movq -0xc8(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x28(%rbp)
movq 0x55203(%rip), %rdi     # 0x91fe8
leaq 0x2cc2f(%rip), %rsi     # 0x69a1b
callq 0xe680
movq %rax, %rdi
movq 0x551dd(%rip), %rsi     # 0x91fd8
callq 0xeae0
movq 0x551e1(%rip), %rdi     # 0x91fe8
leaq 0x2cc1d(%rip), %rsi     # 0x69a2b
callq 0xe680
movq %rax, %rdi
movq -0x28(%rbp), %rax
movzbl 0x4(%rax), %esi
callq 0xe440
movq %rax, %rdi
movq 0x551ab(%rip), %rsi     # 0x91fd8
callq 0xeae0
movq 0x551af(%rip), %rdi     # 0x91fe8
leaq 0x2cbea(%rip), %rsi     # 0x69a2a
callq 0xe680
movq %rax, %rdi
movq -0x28(%rbp), %rax
movzbl 0x5(%rax), %esi
callq 0xe440
movq %rax, %rdi
movq 0x55179(%rip), %rsi     # 0x91fd8
callq 0xeae0
movq 0x5517d(%rip), %rdi     # 0x91fe8
leaq 0x2cbc5(%rip), %rsi     # 0x69a37
callq 0xe680
movq %rax, %rdi
movq -0x28(%rbp), %rax
movzbl 0x8(%rax), %esi
callq 0xe440
movq %rax, %rdi
movq 0x55147(%rip), %rsi     # 0x91fd8
callq 0xeae0
movq -0x28(%rbp), %rax
movzbl 0x6(%rax), %eax
andl $0x4, %eax
cmpl $0x0, %eax
je 0x3cec8
movq 0x5513b(%rip), %rdi     # 0x91fe8
leaq 0x2cb8f(%rip), %rsi     # 0x69a43
callq 0xe680
movq %rax, %rdi
movq 0x55115(%rip), %rsi     # 0x91fd8
callq 0xeae0
movq -0x28(%rbp), %rax
movzbl 0x6(%rax), %eax
andl $0xf0, %eax
sarl $0x4, %eax
movb %al, -0x29(%rbp)
movq -0x28(%rbp), %rax
movzbl 0x7(%rax), %ecx
andl $0xf0, %ecx
movzbl -0x29(%rbp), %eax
orl %ecx, %eax
movb %al, -0x29(%rbp)
movq 0x550ef(%rip), %rdi     # 0x91fe8
leaq 0x2cbaf(%rip), %rsi     # 0x69aaf
callq 0xe680
movq %rax, %rdi
movzbl -0x29(%rbp), %esi
callq 0xe440
movq %rax, %rdi
movq 0x550bd(%rip), %rsi     # 0x91fd8
callq 0xeae0
leaq -0x48(%rbp), %rdi
callq 0x3ddc0
leaq -0x60(%rbp), %rdi
callq 0x3ddc0
movq -0xc8(%rbp), %rax
movq (%rax), %rax
addq $0x10, %rax
movq %rax, -0x68(%rbp)
movl $0x0, -0x6c(%rbp)
movl -0x6c(%rbp), %eax
movq -0x28(%rbp), %rcx
movzbl 0x4(%rcx), %ecx
cmpl %ecx, %eax
jge 0x3cfd2
movq 0x55087(%rip), %rdi     # 0x91fe8
leaq 0x2caeb(%rip), %rsi     # 0x69a53
callq 0xe680
movq %rax, -0xd0(%rbp)
jmp 0x3cf76
movq -0xd0(%rbp), %rdi
movq 0x55054(%rip), %rsi     # 0x91fd8
callq 0xeae0
jmp 0x3cf8b
movq -0x68(%rbp), %rax
movl -0x6c(%rbp), %ecx
shll $0xe, %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x88(%rbp)
leaq -0x48(%rbp), %rdi
leaq -0x88(%rbp), %rsi
callq 0x3dde0
jmp 0x3cfb4
jmp 0x3cfb6
movl -0x6c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x6c(%rbp)
jmp 0x3cf4b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
jmp 0x3d4a8
movq -0x68(%rbp), %rax
movq -0x28(%rbp), %rcx
movzbl 0x4(%rcx), %ecx
shll $0xe, %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x90(%rbp)
movl $0x0, -0x94(%rbp)
movl -0x94(%rbp), %eax
movq -0x28(%rbp), %rcx
movzbl 0x5(%rcx), %ecx
cmpl %ecx, %eax
jge 0x3d04c
movq -0x90(%rbp), %rax
movl -0x94(%rbp), %ecx
shll $0xd, %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0xa0(%rbp)
leaq -0x60(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x3dde0
jmp 0x3d039
jmp 0x3d03b
movl -0x94(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x94(%rbp)
jmp 0x3cff8
movq -0x28(%rbp), %rax
movb 0x6(%rax), %al
andb $0x1, %al
movb %al, -0xa1(%rbp)
movzbl -0x29(%rbp), %eax
movl %eax, -0xd4(%rbp)
testl %eax, %eax
je 0x3d090
jmp 0x3d06b
movl -0xd4(%rbp), %eax
subl $0x1, %eax
je 0x3d15e
jmp 0x3d07c
movl -0xd4(%rbp), %eax
subl $0x4, %eax
je 0x3d27b
jmp 0x3d398
movq 0x54ef9(%rip), %rdi     # 0x91f90
leaq 0x2c9ca(%rip), %rsi     # 0x69a68
callq 0xe680
movq %rax, -0xe0(%rbp)
jmp 0x3d0ac
movq -0xe0(%rbp), %rdi
movq 0x54f1e(%rip), %rsi     # 0x91fd8
callq 0xeae0
jmp 0x3d0c1
movl $0x40, %edi
callq 0xe200
movq %rax, -0xe8(%rbp)
jmp 0x3d0d4
movq -0xe8(%rbp), %rdi
movq -0x28(%rbp), %rax
movzbl 0x8(%rax), %ecx
movzbl -0xa1(%rbp), %r8d
andl $0x1, %r8d
leaq -0x48(%rbp), %rsi
leaq -0x60(%rbp), %rdx
callq 0x41a10
jmp 0x3d0fe
movq -0xe8(%rbp), %rsi
leaq -0xb0(%rbp), %rdi
callq 0x3de50
movq -0xc8(%rbp), %rdi
addq $0x80, %rdi
leaq -0xb0(%rbp), %rsi
callq 0x3de80
leaq -0xb0(%rbp), %rdi
callq 0x3deb0
jmp 0x3d41d
movq -0xe8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
movl $0x40, %esi
callq 0xe170
jmp 0x3d4a8
movq 0x54e2b(%rip), %rdi     # 0x91f90
leaq 0x2c911(%rip), %rsi     # 0x69a7d
callq 0xe680
movq %rax, -0xf0(%rbp)
jmp 0x3d17a
movq -0xf0(%rbp), %rdi
movq 0x54e50(%rip), %rsi     # 0x91fd8
callq 0xeae0
jmp 0x3d18f
movl $0x58, %edi
callq 0xe200
movq %rax, -0xf8(%rbp)
jmp 0x3d1a2
movq -0xc8(%rbp), %rdi
movq -0x28(%rbp), %rax
movzbl 0x8(%rax), %eax
movl %eax, -0x104(%rbp)
addq $0x70, %rdi
movzbl -0xa1(%rbp), %eax
movl %eax, -0x108(%rbp)
callq 0x3df00
movq -0xc8(%rbp), %rdi
movq %rax, -0x100(%rbp)
addq $0x78, %rdi
callq 0x3df30
movl -0x108(%rbp), %r8d
movq -0xf8(%rbp), %rdi
movl -0x104(%rbp), %ecx
movq -0x100(%rbp), %r9
movq %rax, %rdx
movq %rsp, %rax
movq %rdx, (%rax)
andl $0x1, %r8d
leaq -0x48(%rbp), %rsi
leaq -0x60(%rbp), %rdx
callq 0x41f50
jmp 0x3d21b
movq -0xf8(%rbp), %rsi
leaq -0xb8(%rbp), %rdi
callq 0x3de50
movq -0xc8(%rbp), %rdi
addq $0x80, %rdi
leaq -0xb8(%rbp), %rsi
callq 0x3de80
leaq -0xb8(%rbp), %rdi
callq 0x3deb0
jmp 0x3d41d
movq -0xf8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
movl $0x58, %esi
callq 0xe170
jmp 0x3d4a8
movq 0x54d0e(%rip), %rdi     # 0x91f90
leaq 0x2c807(%rip), %rsi     # 0x69a90
callq 0xe680
movq %rax, -0x110(%rbp)
jmp 0x3d297
movq -0x110(%rbp), %rdi
movq 0x54d33(%rip), %rsi     # 0x91fd8
callq 0xeae0
jmp 0x3d2ac
movl $0x60, %edi
callq 0xe200
movq %rax, -0x118(%rbp)
jmp 0x3d2bf
movq -0xc8(%rbp), %rdi
movq -0x28(%rbp), %rax
movzbl 0x8(%rax), %eax
movl %eax, -0x124(%rbp)
addq $0x70, %rdi
movzbl -0xa1(%rbp), %eax
movl %eax, -0x128(%rbp)
callq 0x3df00
movq -0xc8(%rbp), %rdi
movq %rax, -0x120(%rbp)
addq $0x78, %rdi
callq 0x3df30
movl -0x128(%rbp), %r8d
movq -0x118(%rbp), %rdi
movl -0x124(%rbp), %ecx
movq -0x120(%rbp), %r9
movq %rax, %rdx
movq %rsp, %rax
movq %rdx, (%rax)
andl $0x1, %r8d
leaq -0x48(%rbp), %rsi
leaq -0x60(%rbp), %rdx
callq 0x42a10
jmp 0x3d338
movq -0x118(%rbp), %rsi
leaq -0xc0(%rbp), %rdi
callq 0x3de50
movq -0xc8(%rbp), %rdi
addq $0x80, %rdi
leaq -0xc0(%rbp), %rsi
callq 0x3de80
leaq -0xc0(%rbp), %rdi
callq 0x3deb0
jmp 0x3d41d
movq -0x118(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x78(%rbp)
movl %eax, -0x7c(%rbp)
movl $0x60, %esi
callq 0xe170
jmp 0x3d4a8
movq 0x54bf1(%rip), %rdi     # 0x91f90
leaq 0x2c6fd(%rip), %rsi     # 0x69aa3
callq 0xe680
movq %rax, -0x130(%rbp)
jmp 0x3d3b4
movq -0x130(%rbp), %rdi
leaq -0x3762(%rip), %rsi     # 0x39c60
callq 0xed20
movq %rax, -0x138(%rbp)
jmp 0x3d3d0
movq -0x138(%rbp), %rdi
movzbl -0x29(%rbp), %esi
callq 0xe860
movq %rax, -0x140(%rbp)
jmp 0x3d3e9
movq -0x140(%rbp), %rdi
movq 0x54be1(%rip), %rsi     # 0x91fd8
callq 0xeae0
jmp 0x3d3fe
leaq 0x2b0c4(%rip), %rdi     # 0x684c9
leaq 0x2c572(%rip), %rsi     # 0x6997e
movl $0x174, %edx            # imm = 0x174
leaq 0x2c6a0(%rip), %rcx     # 0x69ab8
callq 0xe240
movq -0xc8(%rbp), %rdi
addq $0x70, %rdi
callq 0x3da30
movq -0xc8(%rbp), %rdi
movq %rax, -0x148(%rbp)
subq $-0x80, %rdi
callq 0x3df80
movq -0x148(%rbp), %rdi
movq %rax, %rsi
callq 0x3df60
jmp 0x3d455
movq -0xc8(%rbp), %rdi
addq $0x78, %rdi
callq 0x3da50
movq -0xc8(%rbp), %rdi
movq %rax, -0x150(%rbp)
subq $-0x80, %rdi
callq 0x3df80
movq -0x150(%rbp), %rdi
movq %rax, %rsi
callq 0x3dfb0
jmp 0x3d48d
movl $0x0, -0x4(%rbp)
leaq -0x60(%rbp), %rdi
callq 0x3dfd0
leaq -0x48(%rbp), %rdi
callq 0x3dfd0
jmp 0x3d4bc
leaq -0x60(%rbp), %rdi
callq 0x3dfd0
leaq -0x48(%rbp), %rdi
callq 0x3dfd0
jmp 0x3d4c8
movl -0x4(%rbp), %eax
addq $0x160, %rsp            # imm = 0x160
popq %rbp
retq
movq -0x78(%rbp), %rdi
callq 0xe700
nopw %cs:(%rax,%rax)