// File: /workspace/github_cpp_makefile_star2_O1/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 $0x488, %rsp            # imm = 0x488
movq %rsi, 0x28(%rsp)
leal -0x5(%rdi), %eax
cmpl $-0x4, %eax
ja 0x7991
movq 0x59e2(%rip), %rbx      # 0xcff0
leaq 0x1ff6(%rip), %rsi      # 0x960b
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 0x1fc8(%rip), %rsi      # 0x9645
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 0x1fbf(%rip), %rsi      # 0x967a
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 0x1f8f(%rip), %rsi      # 0x96b2
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 0x1f77(%rip), %rsi      # 0x96d8
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 0x1f68(%rip), %rsi      # 0x9707
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 0x1f2e(%rip), %rsi      # 0x9735
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 0x1f00(%rip), %rsi      # 0x9745
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 0x1f08(%rip), %rsi      # 0x978b
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 0x1f0c(%rip), %rsi      # 0x97cd
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 0x1f0f(%rip), %rsi      # 0x980e
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 0x7f60
leaq 0x18(%rsp), %r14
movq %r14, -0x10(%r14)
movq $0x0, -0x8(%r14)
movb $0x0, (%r14)
cmpl $0x2, %edi
jl 0x7a87
movl %edi, %r15d
decq %r15
xorl %ebp, %ebp
leaq 0x280(%rsp), %r14
movl $0x1, %ebx
movl $0x0, 0x4(%rsp)
xorl %r13d, %r13d
xorl %r12d, %r12d
movq 0x28(%rsp), %rax
movq 0x8(%rax,%rbp,8), %rsi
movq %r14, %rdi
leaq 0x80(%rsp), %rdx
callq 0x8120
movq %r14, %rdi
leaq 0x1e34(%rip), %rsi      # 0x982a
callq 0x3090
testl %eax, %eax
movzbl %r13b, %r13d
cmovel %ebx, %r13d
movq %r14, %rdi
leaq 0x1e25(%rip), %rsi      # 0x9834
callq 0x3090
testl %eax, %eax
movl 0x4(%rsp), %eax
movzbl %al, %eax
cmovel %ebx, %eax
movl %eax, 0x4(%rsp)
movq %r14, %rdi
leaq 0x1e0e(%rip), %rsi      # 0x983c
callq 0x3090
testl %eax, %eax
movzbl %r12b, %r12d
cmovel %ebx, %r12d
testq %rbp, %rbp
jne 0x7a4f
leaq 0x8(%rsp), %rdi
movq %r14, %rsi
callq 0x3120
movq 0x280(%rsp), %rdi
leaq 0x290(%rsp), %rax
cmpq %rax, %rdi
je 0x7a74
movq 0x290(%rsp), %rsi
incq %rsi
callq 0x3200
incq %rbp
cmpq %rbp, %r15
jne 0x79d2
leaq 0x18(%rsp), %r14
jmp 0x7a95
xorl %r12d, %r12d
xorl %r13d, %r13d
movl $0x0, 0x4(%rsp)
leaq 0x50(%rsp), %rdi
callq 0x8160
leaq 0x150(%rsp), %rdi
leaq 0x50(%rsp), %rsi
callq 0x358c
leaq 0x1c8(%rsp), %rdi
leaq 0x150(%rsp), %rsi
callq 0x3d6c
leaq 0x280(%rsp), %r15
leaq 0x8(%rsp), %rsi
movq %r15, %rdi
movl $0x4, %edx
callq 0x3330
leaq 0x2f8(%rsp), %rdi
callq 0x3060
orb %r12b, %al
testb $0x1, %al
je 0x7b6c
movq 0x54dd(%rip), %rax      # 0xcfd8
testb $0x1, %r12b
cmovneq %rax, %r15
leaq 0x20(%rax), %rax
leaq 0x2a0(%rsp), %rbp
cmovneq %rax, %rbp
movl $0x10, %r14d
movq %rsp, %rbx
leaq 0x50(%rsp), %r12
movl $0x4, %edx
movq %r15, %rdi
movq %rbx, %rsi
callq 0x3290
movq (%r15), %rax
movq -0x18(%rax), %rax
testb $0x2, (%rbp,%rax)
jne 0x7be2
movb (%rsp), %al
movb 0x3(%rsp), %cl
movb %cl, (%rsp)
movb %al, 0x3(%rsp)
rolw $0x8, 0x1(%rsp)
leal -0x10(%r14), %esi
movl (%rsp), %edx
movq %r12, %rdi
callq 0x81be
addl $0x4, %r14d
jmp 0x7b21
movq 0x547d(%rip), %rdi      # 0xcff0
leaq 0x1cc8(%rip), %rsi      # 0x9842
movl $0x12, %edx
callq 0x3250
movq 0x8(%rsp), %rsi
movq 0x10(%rsp), %rdx
movq 0x545b(%rip), %rdi      # 0xcff0
callq 0x3250
movq %rax, %rbx
leaq 0x1caf(%rip), %rsi      # 0x9853
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 0x7f18
testb $0x1, %r13b
je 0x7c5d
movq 0x5401(%rip), %rdi      # 0xcff0
leaq 0x1c5f(%rip), %rsi      # 0x9855
movl $0x1c, %edx
callq 0x3250
movq 0x53d1(%rip), %rdi      # 0xcfd8
callq 0x74bc
leaq 0x1c8(%rsp), %rdi
movl $0x1, %esi
movl %eax, %edx
callq 0x3dd2
movq 0x53c9(%rip), %rdi      # 0xcff0
leaq 0x1c44(%rip), %rsi      # 0x9872
movl $0x1c, %edx
callq 0x3250
movq 0x5399(%rip), %rdi      # 0xcfd8
callq 0x74bc
leaq 0x1c8(%rsp), %rdi
movl $0x2, %esi
movl %eax, %edx
callq 0x3dd2
jmp 0x7d1c
movq 0x538c(%rip), %rdi      # 0xcff0
leaq 0x1c24(%rip), %rsi      # 0x988f
movl $0x17, %edx
callq 0x3250
movq 0x535c(%rip), %rdi      # 0xcfd8
callq 0x74bc
movl %eax, %r13d
leaq 0x1c8(%rsp), %rdi
movl $0x2, %esi
movl %eax, %edx
callq 0x3dd2
leaq 0x1c8(%rsp), %rdi
movl $0x1, %esi
movl %r14d, %edx
callq 0x3dd2
testl %r13d, %r13d
jle 0x7d1c
xorl %r15d, %r15d
movq 0x5334(%rip), %r12      # 0xcff0
leaq 0x1be4(%rip), %rbp      # 0x98a7
leaq 0x50(%rsp), %rbx
movl $0x14, %edx
movq %r12, %rdi
movq %rbp, %rsi
callq 0x3250
movq %r12, %rdi
movl %r15d, %esi
callq 0x3370
movl $0x2, %edx
movq %rax, %rdi
leaq 0x1c02(%rip), %rsi      # 0x98f4
callq 0x3250
movq 0x52da(%rip), %rdi      # 0xcfd8
callq 0x74bc
movq %rbx, %rdi
movl %r14d, %esi
movl %eax, %edx
callq 0x81be
addl $0x4, %r14d
incl %r15d
cmpl %r15d, %r13d
jne 0x7cc8
movq 0x5295(%rip), %rax      # 0xcfb8
movq (%rax), %rdi
callq 0x3230
movl %eax, %edi
callq 0x3380
testl %eax, %eax
je 0x7d9a
leaq 0x90(%rsp), %r14
movq %r14, -0x10(%r14)
movq $0x0, -0x8(%r14)
movb $0x0, (%r14)
movq 0x5283(%rip), %rdi      # 0xcfd8
movq (%rdi), %rax
addq -0x18(%rax), %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %edx
movq 0x5268(%rip), %rdi      # 0xcfd8
leaq 0x80(%rsp), %rsi
callq 0x33c0
movq 0x80(%rsp), %rdi
cmpq %r14, %rdi
je 0x7d9a
movq 0x90(%rsp), %rsi
incq %rsi
callq 0x3200
movq 0x524f(%rip), %rdi      # 0xcff0
movq (%rdi), %rax
addq -0x18(%rax), %rdi
movl $0xa, %esi
callq 0x31e0
movsbl %al, %esi
movq 0x5234(%rip), %rdi      # 0xcff0
callq 0x3040
movq %rax, %rdi
callq 0x3160
leaq 0x80(%rsp), %rdi
leaq 0x1c8(%rsp), %rsi
leaq 0x50(%rsp), %rdx
leaq 0x150(%rsp), %rcx
callq 0x4414
movq 0x51fe(%rip), %rbx      # 0xcff0
leaq 0x1ac3(%rip), %rsi      # 0x98bc
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 0x51cc(%rip), %rdi      # 0xcff0
callq 0x3040
movq %rax, %rdi
callq 0x3160
leaq 0x40(%rsp), %rbp
leaq 0x80(%rsp), %rbx
leaq 0x1c8(%rsp), %r14
leaq 0x30(%rsp), %r15
leaq 0x150(%rsp), %r12
movq 0x516e(%rip), %r13      # 0xcfc8
testb $0x1, 0x4(%rsp)
je 0x7e69
movq %rbx, %rdi
callq 0x5afc
movq %r14, %rdi
callq 0x4024
movq %r15, %rdi
movq %r12, %rsi
callq 0x37b4
movq 0x30(%rsp), %rsi
movq 0x38(%rsp), %rdx
movq %r13, %rdi
callq 0x3250
movq 0x30(%rsp), %rdi
cmpq %rbp, %rdi
je 0x7ea5
movq 0x40(%rsp), %rsi
incq %rsi
callq 0x3200
movq %r14, %rdi
callq 0x3dce
testb %al, %al
jne 0x7e5a
movq 0x5138(%rip), %rbx      # 0xcff0
leaq 0x1a0d(%rip), %rsi      # 0x98cc
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 0x5106(%rip), %rdi      # 0xcff0
callq 0x3040
movq %rax, %rdi
callq 0x3160
xorl %ebx, %ebx
leaq 0x80(%rsp), %rdi
callq 0x489a
leaq 0x80(%rsp), %rdi
callq 0x4530
leaq 0x18(%rsp), %r14
leaq 0x280(%rsp), %rdi
callq 0x3070
leaq 0x1c8(%rsp), %rdi
callq 0x3dcc
leaq 0x150(%rsp), %rdi
callq 0x35f2
leaq 0x50(%rsp), %rdi
callq 0x817e
movq 0x8(%rsp), %rdi
cmpq %r14, %rdi
je 0x7f60
movq 0x18(%rsp), %rsi
incq %rsi
callq 0x3200
movl %ebx, %eax
addq $0x488, %rsp            # imm = 0x488
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x801a
movq %rax, %rbx
movq 0x80(%rsp), %rdi
cmpq %r14, %rdi
je 0x801d
movq 0x90(%rsp), %rsi
incq %rsi
callq 0x3200
jmp 0x801d
jmp 0x801a
movq %rax, %rbx
jmp 0x802a
movq %rax, %rbx
jmp 0x8037
movq %rax, %rbx
jmp 0x8044
jmp 0x8015
jmp 0x801a
jmp 0x801a
jmp 0x801a
jmp 0x8072
movq %rax, %rbx
movq 0x280(%rsp), %rdi
leaq 0x290(%rsp), %rax
cmpq %rax, %rdi
je 0x804e
movq 0x290(%rsp), %rsi
incq %rsi
callq 0x3200
jmp 0x804e
jmp 0x801a
jmp 0x8072
movq %rdx, %r14
movq %rax, %rbx
movq 0x30(%rsp), %rdi
cmpq %rbp, %rdi
je 0x8078
movq 0x40(%rsp), %rsi
incq %rsi
callq 0x3200
jmp 0x8078
jmp 0x801a
movq %rax, %rbx
jmp 0x804e
movq %rax, %rbx
leaq 0x280(%rsp), %rdi
callq 0x3070
leaq 0x1c8(%rsp), %rdi
callq 0x3dcc
leaq 0x150(%rsp), %rdi
callq 0x35f2
leaq 0x50(%rsp), %rdi
callq 0x817e
movq 0x8(%rsp), %rdi
leaq 0x18(%rsp), %rax
cmpq %rax, %rdi
je 0x806a
movq 0x18(%rsp), %rsi
incq %rsi
callq 0x3200
movq %rbx, %rdi
callq 0x33a0
movq %rdx, %r14
movq %rax, %rbx
cmpl $0x1, %r14d
jne 0x80e5
movq %rbx, %rdi
callq 0x30c0
movq %rax, %rbx
movq 0x4f60(%rip), %rdi      # 0xcff0
leaq 0x1857(%rip), %rsi      # 0x98ee
movl $0x8, %edx
callq 0x3250
movq (%rbx), %rsi
movq 0x8(%rbx), %rdx
movq 0x4f41(%rip), %rdi      # 0xcff0
callq 0x3250
movq %rax, %rdi
callq 0x30e0
leaq 0x80(%rsp), %rdi
callq 0x489a
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
callq 0x3350
jmp 0x7f06
movq %rax, %rbx
jmp 0x80e5
movq %rax, %rbx
callq 0x3350
leaq 0x80(%rsp), %rdi
callq 0x4530
jmp 0x801d
movq %rax, %rdi
callq 0x39cb