// File: /workspace/github_cpp_makefile_star2_O3/daniel5151[P]mips241/src/main.cc
// Function: main
int main(int argc, char const *argv[]) {
  // Check arguments
  if (argc < 2 || argc > 4) {
    std::cerr
      << "Usage: ./mips241 <filename> [--cin] [--twoints] [--debug]"
      << std::endl
      << std::endl
      << "  By default, mips241 operates in `mips.array` mode."    << std::endl
      << "  To switch to `mips.twoints` mode, pass in [--twoints]" << std::endl
      << std::endl
      << "    --cin     : Read program from cin"          << std::endl
      << "    --twoints : operate in `mips.twoints` mode" << std::endl
      << "    --debug   : enable interactive debug mode"  << std::endl
      << std::endl
      << "  Known issues:"  << std::endl
      << "    - Don't use [--debug] in conjunction with [--cin], it won't work." << std::endl
      << "    - [--cin] mode doesn't let you input initial register values." << std::endl
      << "        It's not that it's impossible, i'm just lazy and did not" << std::endl
      << "        implement it yet :)" << std::endl
      << std::endl
      << std::endl;
    return -1;
  }

  std::string filename;
  bool use_debug_mode = false;
  bool use_twoints = false;
  bool use_cin = false;
  for (int i = 1; i < argc; i++) {
    std::string arg = string(argv[i]);

    if (arg == "--twoints") use_twoints = true;
    if (arg == "--debug" ) use_debug_mode = true;
    if (arg == "--cin") use_cin = true;

    if (i == 1) filename = arg;
  }

  //--------------------------------- SETUP ---------------------------------//

  // Setup and connect up System
  MIPS::RAM ram;
  MIPS::BUS bus (ram);
  MIPS::CPU cpu (bus);

  // Open file
  std::ifstream f (filename, std::ifstream::binary);
  if (!f.is_open() && !use_cin) {
    std::cerr << "Cannot open file `" << filename << "`" << std::endl;
    return -1;
  }

  std::istream &bin = (use_cin) ? std::cin : f;

  // Insert executable into virtual memory

  uint32_t memaddr = 0x0; // base memaddr

  char word[4];
  for ever {
    bin.read(word, 4);

    if(bin.eof()) break;

    // Reverse endiannessss
    char x;
    x = word[0];
    word[0] = word[3];
    word[3] = x;
    x = word[1];
    word[1] = word[2];
    word[2] = x;

    // Store it in RAM (with some funky casting)
    ram.store(memaddr, *(uint32_t *)word );

    memaddr += 4;
  }

  // Accept user input
  if (use_twoints) {
    // Let user input 2 integers
    std::cerr << "Enter value for Register 1: ";
    cpu.setRegister(1, readNum(std::cin));
    std::cerr << "Enter value for Register 2: ";
    cpu.setRegister(2, readNum(std::cin));
  } else {
    // Let user enter Array of values
    std::cerr << "Enter length of Array: ";
    int arr_length = readNum(std::cin);
    cpu.setRegister(2, arr_length); // $2 = length of array

    // Start populating the array 16 words after the end of the program
    // this was chosen relatively arbitrarilly...
    memaddr += 0x10;

    cpu.setRegister(1, memaddr); // $1 = Pointer to base of array

    for (int i = 0; i < arr_length; i++) {
      std::cerr << "Enter Array element " << i << ": ";
      ram.store(memaddr, readNum(std::cin));
      memaddr += 4;
    }
  }

  // If this program is running interactively, clear cin before starting cpu
  //  emulation
  bool isTTY = isatty(fileno(stdin));
  if (isTTY) { std::string dummy; getline(std::cin, dummy); }


  std::cerr << std::endl;

  // Start CPU execution
  MIPS::Debugger debugger (cpu, ram, bus);

  try {
    std::cerr << "Starting CPU..." << std::endl;
    do {
      if (use_debug_mode) debugger.debugREPL();

      // Execute cpu cycle
      cpu.do_cycle();

      std::cout << bus.getOutput();

    } while (cpu.stillExecuting());

    std::cerr
      << "Execution completed successfully!"
      << std::endl;
    debugger.printCPUState();

  } catch (const std::string & msg) {
    std::cerr
      << "ERROR : "
      << msg
      << std::endl;
    debugger.printCPUState();
    return -1;
  }

  return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x498, %rsp            # imm = 0x498
movq %rsi, 0x38(%rsp)
leal -0x5(%rdi), %eax
cmpl $-0x4, %eax
ja 0x7974
movq 0x59ff(%rip), %rbx      # 0xcff0
leaq 0x2028(%rip), %rsi      # 0x9620
movl $0x39, %edx
movq %rbx, %rdi
callq 0x3250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
leaq 0x1ffa(%rip), %rsi      # 0x965a
movl $0x34, %edx
movq %rax, %rdi
callq 0x3250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
leaq 0x1ff1(%rip), %rsi      # 0x968f
movl $0x37, %edx
movq %rax, %rdi
callq 0x3250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
leaq 0x1fc1(%rip), %rsi      # 0x96c7
movl $0x25, %edx
movq %rax, %rdi
callq 0x3250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
leaq 0x1fa9(%rip), %rsi      # 0x96ed
movl $0x2e, %edx
movq %rax, %rdi
callq 0x3250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
leaq 0x1f9a(%rip), %rsi      # 0x971c
movl $0x2d, %edx
movq %rax, %rdi
callq 0x3250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
leaq 0x1f60(%rip), %rsi      # 0x974a
movl $0xf, %edx
movq %rax, %rdi
callq 0x3250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
leaq 0x1f32(%rip), %rsi      # 0x975a
movl $0x45, %edx
movq %rax, %rdi
callq 0x3250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
leaq 0x1f3a(%rip), %rsi      # 0x97a0
movl $0x41, %edx
movq %rax, %rdi
callq 0x3250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
leaq 0x1f3e(%rip), %rsi      # 0x97e2
movl $0x40, %edx
movq %rax, %rdi
callq 0x3250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
leaq 0x1f41(%rip), %rsi      # 0x9823
movl $0x1b, %edx
movq %rax, %rdi
callq 0x3250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movq %rax, %rdi
callq 0x3160
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
jmp 0x7f28
leaq 0x20(%rsp), %rax
movq %rax, -0x10(%rax)
movq $0x0, -0x8(%rax)
movb $0x0, (%rax)
movl %edi, %eax
decq %rax
movq %rax, 0x30(%rsp)
xorl %ebx, %ebx
leaq 0x290(%rsp), %rbp
xorl %r12d, %r12d
xorl %r13d, %r13d
movl $0x0, 0x8(%rsp)
movq 0x38(%rsp), %rax
movq 0x8(%rax,%rbx,8), %rsi
movq %rbp, %rdi
leaq 0x90(%rsp), %rdx
callq 0x80e8
movq %rbp, %rdi
leaq 0x1e71(%rip), %rsi      # 0x983f
callq 0x3090
testl %eax, %eax
sete %r15b
movq %rbp, %rdi
leaq 0x1e66(%rip), %rsi      # 0x9849
callq 0x3090
testl %eax, %eax
movq %rbp, %rdi
sete %r14b
leaq 0x1e59(%rip), %rsi      # 0x9851
callq 0x3090
testl %eax, %eax
movl 0x8(%rsp), %eax
movzbl %al, %eax
movl $0x1, %ecx
cmovel %ecx, %eax
movl %eax, 0x8(%rsp)
testq %rbx, %rbx
jne 0x7a24
leaq 0x10(%rsp), %rdi
movq %rbp, %rsi
callq 0x3120
movq 0x290(%rsp), %rdi
leaq 0x2a0(%rsp), %rax
cmpq %rax, %rdi
je 0x7a49
movq 0x2a0(%rsp), %rsi
incq %rsi
callq 0x3200
orb %r15b, %r13b
orb %r14b, %r12b
incq %rbx
cmpq %rbx, 0x30(%rsp)
jne 0x79aa
leaq 0x60(%rsp), %rdi
callq 0x8128
leaq 0x160(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x358c
leaq 0x1d8(%rsp), %rdi
leaq 0x160(%rsp), %rsi
callq 0x3d7c
movl 0x8(%rsp), %ebx
leaq 0x290(%rsp), %r15
leaq 0x10(%rsp), %rsi
movq %r15, %rdi
movl $0x4, %edx
callq 0x3330
leaq 0x308(%rsp), %rdi
callq 0x3060
orb %bl, %al
testb $0x1, %al
je 0x7b3e
movq 0x5512(%rip), %rax      # 0xcfd8
testb $0x1, %bl
cmovneq %rax, %r15
leaq 0x20(%rax), %rax
leaq 0x2b0(%rsp), %rbx
cmovneq %rax, %rbx
movl $0x10, %r14d
leaq 0x60(%rsp), %rbp
movl $0x4, %edx
movq %r15, %rdi
leaq 0xc(%rsp), %rsi
callq 0x3290
movq (%r15), %rax
movq -0x18(%rax), %rax
testb $0x2, (%rbx,%rax)
jne 0x7bb4
leal -0x10(%r14), %esi
movd 0xc(%rsp), %xmm0
punpcklbw 0x1af3(%rip), %xmm0 # xmm0 = xmm0[0],mem[0],xmm0[1],mem[1],xmm0[2],mem[2],xmm0[3],mem[3],xmm0[4],mem[4],xmm0[5],mem[5],xmm0[6],mem[6],xmm0[7],mem[7]
pshuflw $0x1b, %xmm0, %xmm0     # xmm0 = xmm0[3,2,1,0,4,5,6,7]
packuswb %xmm0, %xmm0
movd %xmm0, 0xc(%rsp)
movd %xmm0, %edx
movq %rbp, %rdi
callq 0x8186
addl $0x4, %r14d
jmp 0x7ae8
movq 0x54ab(%rip), %rdi      # 0xcff0
leaq 0x1d0b(%rip), %rsi      # 0x9857
movl $0x12, %edx
callq 0x3250
movq 0x10(%rsp), %rsi
movq 0x18(%rsp), %rdx
movq 0x5489(%rip), %rdi      # 0xcff0
callq 0x3250
movq %rax, %rbx
leaq 0x1cf2(%rip), %rsi      # 0x9868
movl $0x1, %edx
movq %rax, %rdi
callq 0x3250
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq %rbx, %rdi
callq 0x3040
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
movq %rax, %rdi
callq 0x3160
jmp 0x7edb
testb $0x1, %r13b
je 0x7c2f
movq 0x542f(%rip), %rdi      # 0xcff0
leaq 0x1ca2(%rip), %rsi      # 0x986a
movl $0x1c, %edx
callq 0x3250
movq 0x53ff(%rip), %rdi      # 0xcfd8
callq 0x7498
leaq 0x1d8(%rsp), %rdi
movl $0x1, %esi
movl %eax, %edx
callq 0x3de2
movq 0x53f7(%rip), %rdi      # 0xcff0
leaq 0x1c87(%rip), %rsi      # 0x9887
movl $0x1c, %edx
callq 0x3250
movq 0x53c7(%rip), %rdi      # 0xcfd8
callq 0x7498
leaq 0x1d8(%rsp), %rdi
movl $0x2, %esi
movl %eax, %edx
callq 0x3de2
jmp 0x7ce9
movq 0x53ba(%rip), %rdi      # 0xcff0
leaq 0x1c67(%rip), %rsi      # 0x98a4
movl $0x17, %edx
callq 0x3250
movq 0x538a(%rip), %rdi      # 0xcfd8
callq 0x7498
movl %eax, %ebp
leaq 0x1d8(%rsp), %rdi
movl $0x2, %esi
movl %eax, %edx
callq 0x3de2
leaq 0x1d8(%rsp), %rdi
movl $0x1, %esi
movl %r14d, %edx
callq 0x3de2
testl %ebp, %ebp
jle 0x7ce9
xorl %r15d, %r15d
movq 0x5364(%rip), %r13      # 0xcff0
leaq 0x60(%rsp), %rbx
movl $0x14, %edx
movq %r13, %rdi
leaq 0x1c1c(%rip), %rsi      # 0x98bc
callq 0x3250
movq %r13, %rdi
movl %r15d, %esi
callq 0x3370
movl $0x2, %edx
movq %rax, %rdi
leaq 0x1c4a(%rip), %rsi      # 0x9909
callq 0x3250
movq 0x530d(%rip), %rdi      # 0xcfd8
callq 0x7498
movq %rbx, %rdi
movl %r14d, %esi
movl %eax, %edx
callq 0x8186
addl $0x4, %r14d
incl %r15d
cmpl %r15d, %ebp
jne 0x7c91
movq 0x52c8(%rip), %rax      # 0xcfb8
movq (%rax), %rdi
callq 0x3230
movl %eax, %edi
callq 0x3380
testl %eax, %eax
je 0x7d66
leaq 0xa0(%rsp), %rbx
movq %rbx, -0x10(%rbx)
movq $0x0, -0x8(%rbx)
movb $0x0, (%rbx)
movq 0x52b7(%rip), %rdi      # 0xcfd8
movq (%rdi), %rax
addq -0x18(%rax), %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %edx
movq 0x529c(%rip), %rdi      # 0xcfd8
leaq 0x90(%rsp), %rsi
callq 0x33c0
movq 0x90(%rsp), %rdi
cmpq %rbx, %rdi
je 0x7d66
movq 0xa0(%rsp), %rsi
incq %rsi
callq 0x3200
movq 0x5283(%rip), %rdi      # 0xcff0
movq (%rdi), %rax
addq -0x18(%rax), %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq 0x5268(%rip), %rdi      # 0xcff0
callq 0x3040
movq %rax, %rdi
callq 0x3160
leaq 0x90(%rsp), %rdi
leaq 0x1d8(%rsp), %rsi
leaq 0x60(%rsp), %rdx
leaq 0x160(%rsp), %rcx
callq 0x4424
movq 0x5232(%rip), %rbx      # 0xcff0
leaq 0x1b0c(%rip), %rsi      # 0x98d1
movl $0xf, %edx
movq %rbx, %rdi
callq 0x3250
movq (%rbx), %rax
addq -0x18(%rax), %rbx
movq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq 0x5200(%rip), %rdi      # 0xcff0
callq 0x3040
movq %rax, %rdi
callq 0x3160
leaq 0x50(%rsp), %rbx
leaq 0x1d8(%rsp), %r14
leaq 0x40(%rsp), %r15
leaq 0x160(%rsp), %rbp
movq 0x51aa(%rip), %r13      # 0xcfc8
testb $0x1, %r12b
je 0x7e31
leaq 0x90(%rsp), %rdi
callq 0x5ada
movq %r14, %rdi
callq 0x4034
movq %r15, %rdi
movq %rbp, %rsi
callq 0x37b0
movq 0x40(%rsp), %rsi
movq 0x48(%rsp), %rdx
movq %r13, %rdi
callq 0x3250
movq 0x40(%rsp), %rdi
cmpq %rbx, %rdi
je 0x7e6d
movq 0x50(%rsp), %rsi
incq %rsi
callq 0x3200
movq %r14, %rdi
callq 0x3dde
testb %al, %al
jne 0x7e1e
movq 0x5170(%rip), %rbx      # 0xcff0
leaq 0x1a5a(%rip), %rsi      # 0x98e1
movl $0x21, %edx
movq %rbx, %rdi
callq 0x3250
movq (%rbx), %rax
addq -0x18(%rax), %rbx
movq %rbx, %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq 0x513e(%rip), %rdi      # 0xcff0
callq 0x3040
movq %rax, %rdi
callq 0x3160
xorl %ebx, %ebx
leaq 0x90(%rsp), %rdi
callq 0x489a
leaq 0x90(%rsp), %rdi
callq 0x4540
leaq 0x290(%rsp), %rdi
callq 0x3070
leaq 0x1d8(%rsp), %rdi
callq 0x3ddc
leaq 0x160(%rsp), %rdi
callq 0x35f2
leaq 0x60(%rsp), %rdi
callq 0x8146
movq 0x10(%rsp), %rdi
leaq 0x20(%rsp), %rax
cmpq %rax, %rdi
je 0x7f28
movq 0x20(%rsp), %rsi
incq %rsi
callq 0x3200
movl %ebx, %eax
addq $0x498, %rsp            # imm = 0x498
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x7fdd
movq %rax, %r15
movq 0x90(%rsp), %rdi
cmpq %rbx, %rdi
je 0x7fe0
movq 0xa0(%rsp), %rsi
incq %rsi
callq 0x3200
jmp 0x7fe0
jmp 0x7fdd
movq %rax, %r15
jmp 0x7fed
movq %rax, %r15
jmp 0x7ffa
movq %rax, %r15
jmp 0x8007
jmp 0x8013
jmp 0x7fdd
jmp 0x7fdd
jmp 0x7fdd
jmp 0x803a
movq %rax, %r15
movq 0x290(%rsp), %rdi
leaq 0x2a0(%rsp), %rax
cmpq %rax, %rdi
je 0x8016
movq 0x2a0(%rsp), %rsi
incq %rsi
callq 0x3200
jmp 0x8016
jmp 0x7fdd
jmp 0x803a
movq %rdx, %r14
movq %rax, %r15
movq 0x40(%rsp), %rdi
cmpq %rbx, %rdi
je 0x8040
movq 0x50(%rsp), %rsi
incq %rsi
callq 0x3200
jmp 0x8040
jmp 0x7fdd
movq %rax, %r15
leaq 0x290(%rsp), %rdi
callq 0x3070
leaq 0x1d8(%rsp), %rdi
callq 0x3ddc
leaq 0x160(%rsp), %rdi
callq 0x35f2
leaq 0x60(%rsp), %rdi
callq 0x8146
jmp 0x8016
movq %rax, %r15
movq 0x10(%rsp), %rdi
leaq 0x20(%rsp), %rax
cmpq %rax, %rdi
je 0x8032
movq 0x20(%rsp), %rsi
incq %rsi
callq 0x3200
movq %r15, %rdi
callq 0x33a0
movq %rdx, %r14
movq %rax, %r15
cmpl $0x1, %r14d
jne 0x80ad
movq %r15, %rdi
callq 0x30c0
movq %rax, %rbx
movq 0x4f98(%rip), %rdi      # 0xcff0
leaq 0x18a4(%rip), %rsi      # 0x9903
movl $0x8, %edx
callq 0x3250
movq (%rbx), %rsi
movq 0x8(%rbx), %rdx
movq 0x4f79(%rip), %rdi      # 0xcff0
callq 0x3250
movq %rax, %rdi
callq 0x30e0
leaq 0x90(%rsp), %rdi
callq 0x489a
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
callq 0x3350
jmp 0x7ece
movq %rax, %r15
jmp 0x80ad
movq %rax, %r15
callq 0x3350
leaq 0x90(%rsp), %rdi
callq 0x4540
jmp 0x7fe0
movq %rax, %rdi
callq 0x39c7