// File: /workspace/github_cpp_makefile_star2_O2/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, 0x8(%rsp)
leal -0x5(%rdi), %eax
cmpl $-0x4, %eax
ja 0x59c3
movq 0x5757(%rip), %rdi      # 0xaff0
leaq 0x1d80(%rip), %rsi      # 0x7620
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
movq %rax, %rdi
callq 0x20f0
leaq 0x1d9e(%rip), %rsi      # 0x765a
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
leaq 0x1dbc(%rip), %rsi      # 0x768f
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
movq %rax, %rdi
callq 0x20f0
leaq 0x1dd5(%rip), %rsi      # 0x76c7
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
leaq 0x1de4(%rip), %rsi      # 0x76ed
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
leaq 0x1dfc(%rip), %rsi      # 0x771c
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
movq %rax, %rdi
callq 0x20f0
leaq 0x1e0b(%rip), %rsi      # 0x774a
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
leaq 0x1e04(%rip), %rsi      # 0x775a
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
leaq 0x1e33(%rip), %rsi      # 0x77a0
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
leaq 0x1e5e(%rip), %rsi      # 0x77e2
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
leaq 0x1e88(%rip), %rsi      # 0x7823
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
movq %rax, %rdi
callq 0x20f0
movq %rax, %rdi
callq 0x20f0
pushq $-0x1
popq %rbx
jmp 0x5d91
leaq 0x30(%rsp), %rax
movq %rax, -0x10(%rax)
andq $0x0, -0x8(%rax)
movb $0x0, (%rax)
movl %edi, %eax
decq %rax
movq %rax, 0x18(%rsp)
xorl %r13d, %r13d
leaq 0x290(%rsp), %r14
xorl %ebp, %ebp
xorl %r15d, %r15d
movq $0x0, 0x10(%rsp)
cmpq %r13, 0x18(%rsp)
je 0x5a8c
movq 0x8(%rsp), %rax
movq 0x8(%rax,%r13,8), %rsi
movq %r14, %rdi
leaq 0x90(%rsp), %rdx
callq 0x2740
movq %r14, %rdi
leaq 0x1e19(%rip), %rsi      # 0x783f
callq 0x32ea
movl %eax, %ebx
movq %r14, %rdi
leaq 0x1e12(%rip), %rsi      # 0x7849
callq 0x32ea
movl %eax, %r12d
movq %r14, %rdi
leaq 0x1e08(%rip), %rsi      # 0x7851
callq 0x32ea
movzbl %bpl, %ebp
testb %al, %al
pushq $0x1
popq %rax
cmovnel %eax, %ebp
testq %r13, %r13
jne 0x5a6c
leaq 0x20(%rsp), %rdi
movq %r14, %rsi
callq 0x2120
orb %bl, %r15b
movq 0x10(%rsp), %rax
orb %r12b, %al
movq %rax, 0x10(%rsp)
movq %r14, %rdi
callq 0x23e8
incq %r13
jmp 0x59f7
leaq 0x40(%rsp), %rdi
callq 0x5f98
leaq 0x160(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x257c
leaq 0x1d8(%rsp), %rdi
leaq 0x160(%rsp), %rsi
callq 0x2cbc
leaq 0x290(%rsp), %r14
leaq 0x20(%rsp), %rsi
pushq $0x4
popq %rdx
movq %r14, %rdi
callq 0x2330
leaq 0x308(%rsp), %rdi
callq 0x2060
movl %eax, %ecx
orb %bpl, %cl
testb $0x1, %cl
je 0x5b76
movq %r15, 0x8(%rsp)
notb %al
orb %bpl, %al
movq 0x54d7(%rip), %rcx      # 0xafd8
leaq 0x20(%rcx), %rdx
testb $0x1, %al
cmovneq %rcx, %r14
leaq 0x2b0(%rsp), %r13
cmovneq %rdx, %r13
pushq $0x10
popq %rbx
leaq 0x4(%rsp), %r15
pushq $0x4
popq %r12
leaq 0x40(%rsp), %rbp
movq %r14, %rdi
movq %r15, %rsi
movq %r12, %rdx
callq 0x2280
movq (%r14), %rax
movq -0x18(%rax), %rax
testb $0x2, (%r13,%rax)
jne 0x5bb5
leal -0x10(%rbx), %esi
movd 0x4(%rsp), %xmm0
punpcklbw 0x1aba(%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, 0x4(%rsp)
movd %xmm0, %edx
movq %rbp, %rdi
callq 0x5ff2
addl $0x4, %ebx
jmp 0x5b28
movq 0x5473(%rip), %rdi      # 0xaff0
leaq 0x1cd3(%rip), %rsi      # 0x7857
callq 0x21e0
leaq 0x20(%rsp), %rsi
movq %rax, %rdi
callq 0x21d0
leaq 0x1ccb(%rip), %rsi      # 0x7868
movq %rax, %rdi
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
pushq $-0x1
popq %rbx
jmp 0x5d56
testb $0x1, 0x8(%rsp)
je 0x5da5
movq 0x5429(%rip), %rdi      # 0xaff0
leaq 0x1c9c(%rip), %rsi      # 0x786a
callq 0x21e0
movq 0x53fe(%rip), %rdi      # 0xafd8
callq 0x5790
leaq 0x1d8(%rsp), %rdi
pushq $0x1
popq %rsi
movl %eax, %edx
callq 0x2d16
movq 0x53f8(%rip), %rdi      # 0xaff0
leaq 0x1c88(%rip), %rsi      # 0x7887
callq 0x21e0
movq 0x53cd(%rip), %rdi      # 0xafd8
callq 0x5790
leaq 0x1d8(%rsp), %rdi
pushq $0x2
popq %rsi
movl %eax, %edx
callq 0x2d16
movq 0x5397(%rip), %rax      # 0xafc0
movq (%rax), %rdi
callq 0x2230
movl %eax, %edi
callq 0x2380
testl %eax, %eax
je 0x5c71
leaq 0xa0(%rsp), %rax
movq %rax, -0x10(%rax)
andq $0x0, -0x8(%rax)
movb $0x0, (%rax)
movq 0x5381(%rip), %rdi      # 0xafd8
leaq 0x90(%rsp), %rsi
callq 0x2050
leaq 0x90(%rsp), %rdi
callq 0x23e8
movq 0x5378(%rip), %rdi      # 0xaff0
callq 0x20f0
leaq 0x90(%rsp), %rdi
leaq 0x1d8(%rsp), %rsi
leaq 0x40(%rsp), %rdx
leaq 0x160(%rsp), %rcx
callq 0x32f8
movq 0x534a(%rip), %rdi      # 0xaff0
leaq 0x1c24(%rip), %rsi      # 0x78d1
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
leaq 0x90(%rsp), %rbx
leaq 0x1d8(%rsp), %r14
leaq 0x70(%rsp), %r15
leaq 0x160(%rsp), %r12
movq 0x52ea(%rip), %r13      # 0xafc8
testb $0x1, 0x10(%rsp)
je 0x5ced
movq %rbx, %rdi
callq 0x40ee
movq %r14, %rdi
callq 0x2f62
movq %r15, %rdi
movq %r12, %rsi
callq 0x2700
movq %r13, %rdi
movq %r15, %rsi
callq 0x21d0
movq %r15, %rdi
callq 0x23e8
movq %r14, %rdi
callq 0x2d12
testb %al, %al
jne 0x5cde
movq 0x52ca(%rip), %rdi      # 0xaff0
leaq 0x1bb4(%rip), %rsi      # 0x78e1
callq 0x21e0
movq %rax, %rdi
callq 0x20f0
xorl %ebx, %ebx
leaq 0x90(%rsp), %rdi
callq 0x35f6
leaq 0x90(%rsp), %rdi
callq 0x3406
leaq 0x290(%rsp), %rdi
callq 0x2090
leaq 0x1d8(%rsp), %rdi
callq 0x2d10
leaq 0x160(%rsp), %rdi
callq 0x25c6
leaq 0x40(%rsp), %rdi
callq 0x5fb4
leaq 0x20(%rsp), %rdi
callq 0x23e8
movl %ebx, %eax
addq $0x498, %rsp            # imm = 0x498
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x5244(%rip), %rdi      # 0xaff0
leaq 0x1af1(%rip), %rsi      # 0x78a4
callq 0x21e0
movq 0x5219(%rip), %rdi      # 0xafd8
callq 0x5790
movl %eax, %ebp
leaq 0x1d8(%rsp), %rdi
pushq $0x2
popq %rsi
movl %eax, %edx
callq 0x2d16
leaq 0x1d8(%rsp), %rdi
pushq $0x1
popq %rsi
movl %ebx, %edx
callq 0x2d16
xorl %r14d, %r14d
testl %ebp, %ebp
cmovlel %r14d, %ebp
leaq 0x1b0f(%rip), %r13      # 0x7909
movq 0x51d7(%rip), %r15      # 0xafd8
leaq 0x40(%rsp), %r12
cmpl %r14d, %ebp
je 0x5c22
movq 0x51da(%rip), %rdi      # 0xaff0
leaq 0x1a9f(%rip), %rsi      # 0x78bc
callq 0x21e0
movq %rax, %rdi
movl %r14d, %esi
callq 0x2370
movq %rax, %rdi
movq %r13, %rsi
callq 0x21e0
movq %r15, %rdi
callq 0x5790
movq %r12, %rdi
movl %ebx, %esi
movl %eax, %edx
callq 0x5ff2
addl $0x4, %ebx
incl %r14d
jmp 0x5e06
movq %rax, %rbx
leaq 0x90(%rsp), %rdi
callq 0x23e8
jmp 0x5eb5
jmp 0x5eb2
jmp 0x5eb2
jmp 0x5eb2
movq %rax, %rbx
jmp 0x5ec2
movq %rax, %rbx
jmp 0x5ecf
movq %rax, %rbx
jmp 0x5edc
jmp 0x5ead
jmp 0x5eb2
jmp 0x5eb2
jmp 0x5ef8
movq %rax, %rbx
leaq 0x290(%rsp), %rdi
callq 0x23e8
jmp 0x5ee6
jmp 0x5eb2
jmp 0x5ef8
movq %rdx, %r14
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x23e8
jmp 0x5efe
jmp 0x5eb2
movq %rax, %rbx
jmp 0x5ee6
movq %rax, %rbx
leaq 0x290(%rsp), %rdi
callq 0x2090
leaq 0x1d8(%rsp), %rdi
callq 0x2d10
leaq 0x160(%rsp), %rdi
callq 0x25c6
leaq 0x40(%rsp), %rdi
callq 0x5fb4
leaq 0x20(%rsp), %rdi
callq 0x23e8
movq %rbx, %rdi
callq 0x23a0
movq %rdx, %r14
movq %rax, %rbx
cmpl $0x1, %r14d
jne 0x5f5c
movq %rbx, %rdi
callq 0x20d0
movq %rax, %rbx
movq 0x50da(%rip), %rdi      # 0xaff0
leaq 0x19e6(%rip), %rsi      # 0x7903
callq 0x21e0
movq %rax, %rdi
movq %rbx, %rsi
callq 0x21d0
movq %rax, %rdi
callq 0x20f0
leaq 0x90(%rsp), %rdi
callq 0x35f6
callq 0x2350
pushq $-0x1
popq %rbx
jmp 0x5d49
movq %rax, %rbx
jmp 0x5f5c
movq %rax, %rbx
callq 0x2350
leaq 0x90(%rsp), %rdi
callq 0x3406
jmp 0x5eb5
movq %rax, %rdi
callq 0x292d