// File: /workspace/github_cpp_makefile_star2_O3/mikeakohn[P]cloudtari/build/../src/cloudtari.cxx
// Function: main
int main(int argc, char *argv[])
{
  int cycles;
  bool debug = false;
  bool step = false;
  int step_address = -1;
  int port = 5900;
  Television *television;

  // Used to see how many CPU cycles a set of instructions takes.
  DebugTimer debug_timer;

  if (argc < 3 || argc > 5)
  {
    printf(
      "Usage: %s <gamefile.bin> <null/sdl/vnc/debug/break/timer/step>\n"
      "          null\n"
#ifdef USE_SDL
      "          sdl\n"
#endif
      "          vnc <port>\n"
      "          http <port>\n"
      "          debug\n"
      "          break <address>\n"
      "          timer <start_address> <end_address>\n"
      "          step <start_address>\n",
      argv[0]);
    exit(0);
  }

  M6502 *m6502 = new M6502();
  MemoryBus *memory_bus = new MemoryBus();
  ROM *rom = new ROM();

  if (rom->load(argv[1]) != 0) { exit(-1); }

  memory_bus->init();
  memory_bus->set_rom(rom);
  m6502->set_memory_bus(memory_bus);
  m6502->reset();

#ifdef USE_SDL
  if (strcmp(argv[2], "sdl") == 0)
  {
    television = new TelevisionSDL();
  }
    else
#endif
  if (strcmp(argv[2], "vnc") == 0)
  {
    television = new TelevisionVNC();

    if (argc > 3) { port = atoi(argv[3]); }

    television->set_port(port);
  }
    else
  if (strcmp(argv[2], "http") == 0)
  {
    television = new TelevisionHttp();

    port = 8080;
    if (argc > 3) { port = atoi(argv[3]); }

    television->set_port(port);
  }
    else
  if (strcmp(argv[2], "debug") == 0)
  {
    television = new TelevisionNull();
    debug = true;
    m6502->set_debug();
  }
    else
  if (strcmp(argv[2], "break") == 0)
  {
    television = new TelevisionNull();

    int address = 0xf000;
    if (argc > 3) { address = strtol(argv[3], NULL, 0); }
    debug = true;
    m6502->set_breakpoint(address);
  }
    else
  if (strcmp(argv[2], "timer") == 0)
  {
    television = new TelevisionNull();
    debug = true;
    m6502->set_debug();

    int address_start = -1, address_end = -1;

    if (argc > 3) { address_start = strtol(argv[3], NULL, 0); }
    if (argc > 4) { address_end = strtol(argv[4], NULL, 0); }

    debug_timer.set(address_start, address_end);
  }
    else
  if (strcmp(argv[2], "step") == 0)
  {
    television = new TelevisionNull();
    debug = true;
    m6502->set_debug();

    step_address = 0xf000;
    if (argc > 3) { step_address = strtol(argv[3], NULL, 0); }
  }
    else
  if (strcmp(argv[2], "null") == 0)
  {
    television = new TelevisionNull();
  }
    else
  {
    printf("Unknown mode %s\n", argv[2]);
    exit(1);
  }

  if (television->init() != 0)
  {
    delete m6502;
    delete rom;
    delete memory_bus;
    delete television;

    printf("Display init error.\n");
    return -1;
  }

  RIOT *riot = memory_bus->get_riot();
  TIA *tia = memory_bus->get_tia();
  tia->set_television(television);

  // memory_bus->dump(0xf000, 0xffff);

  while (m6502->is_running())
  {
    if (m6502->get_pc() == step_address)
    {
      step = true;
    }

    if (tia->wait_for_hsync())
    {
      cycles = 1;
      m6502->clock();
    }
      else
    {
      //int address = m6502->get_pc();
      cycles = m6502->step();
      //debug_timer.compute(address, cycles);
    }

    memory_bus->clock(cycles);

    if (debug)
    {
      printf("  cycles=%d\n", cycles);
      m6502->dump();
      tia->dump();
      memory_bus->dump(0x80, 0xff);

      if (!tia->wait_for_hsync())
      {
        //sleep(1);
        usleep(1000);
      }
    }

    if (tia->need_check_events())
    {
      int event_code = television->handle_events();

      if (event_code == Television::KEY_QUIT) { break; }

      switch (event_code)
      {
        case Television::KEY_SELECT_DOWN:
          riot->set_switch_select();
          break;
        case Television::KEY_SELECT_UP:
          riot->clear_switch_select();
          break;
        case Television::KEY_RESET_DOWN:
          riot->set_switch_reset();
          break;
        case Television::KEY_RESET_UP:
          riot->clear_switch_reset();
          break;
        case Television::KEY_LEFT_DOWN:
          riot->set_joystick_0_left();
          break;
        case Television::KEY_LEFT_UP:
          riot->clear_joystick_0_left();
          break;
        case Television::KEY_RIGHT_DOWN:
          riot->set_joystick_0_right();
          break;
        case Television::KEY_RIGHT_UP:
          riot->clear_joystick_0_right();
          break;
        case Television::KEY_UP_DOWN:
          riot->set_joystick_0_up();
          break;
        case Television::KEY_UP_UP:
          riot->clear_joystick_0_up();
          break;
        case Television::KEY_DOWN_DOWN:
          riot->set_joystick_0_down();
          break;
        case Television::KEY_DOWN_UP:
          riot->clear_joystick_0_down();
          break;
        case Television::KEY_FIRE_DOWN:
          tia->set_joystick_0_fire();
          break;
        case Television::KEY_FIRE_UP:
          tia->clear_joystick_0_fire();
          break;
      }
    }

    if (step)
    {
      getchar();
    }
  }

#if 0
   m6502->dump();
   tia->dump();
   memory_bus->dump(0x80, 0xff);
#endif

  delete m6502;
  delete rom;
  delete memory_bus;
  delete television;

  return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq %rsi, %rbp
movl %edi, %r15d
leal -0x6(%r15), %eax
cmpl $-0x4, %eax
jbe 0x4a3d
movl $0x30, %edi
callq 0x41d0
movq %rax, %r14
movq %rax, %rdi
callq 0x5294
movl $0x18, %edi
callq 0x41d0
movq %rax, %rbx
movq %rax, %rdi
callq 0x6f10
movl $0x3004, %edi           # imm = 0x3004
callq 0x41d0
movq %rax, %r13
movq %rax, %rdi
callq 0x7774
movq 0x8(%rbp), %rsi
movq %r13, %rdi
callq 0x778c
testl %eax, %eax
jne 0x4a56
movq %rbx, %rdi
callq 0x6fc4
movq %r13, (%rbx)
movq %rbx, (%r14)
movq %r14, %rdi
callq 0x52ba
movq 0x10(%rbp), %r12
leaq 0x6c3e(%rip), %rsi      # 0xb13f
movq %r12, %rdi
callq 0x42c0
testl %eax, %eax
je 0x45c9
leaq 0x6c2b(%rip), %rsi      # 0xb143
movq %r12, %rdi
callq 0x42c0
testl %eax, %eax
je 0x45e0
leaq 0x6c18(%rip), %rsi      # 0xb147
movq %r12, %rdi
callq 0x42c0
testl %eax, %eax
je 0x45fc
leaq 0x6c06(%rip), %rsi      # 0xb14c
movq %r12, %rdi
callq 0x42c0
testl %eax, %eax
je 0x4938
leaq 0x6bf5(%rip), %rsi      # 0xb152
movq %r12, %rdi
callq 0x42c0
testl %eax, %eax
je 0x4954
leaq 0x6be4(%rip), %rsi      # 0xb158
movq %r12, %rdi
callq 0x42c0
testl %eax, %eax
je 0x499a
leaq 0x6bd3(%rip), %rsi      # 0xb15e
movq %r12, %rdi
callq 0x42c0
testl %eax, %eax
je 0x49f7
leaq 0x6bc1(%rip), %rsi      # 0xb163
movq %r12, %rdi
callq 0x42c0
testl %eax, %eax
jne 0x4a60
movl $0x28, %edi
callq 0x41d0
movq %rax, %r12
movq %rax, %rdi
callq 0x924c
jmp 0x4631
movl $0x58, %edi
callq 0x41d0
movq %rax, %r12
movq %rax, %rdi
callq 0x9e5c
jmp 0x4631
movl $0x60, %edi
callq 0x41d0
movq %rax, %r12
movq %rax, %rdi
callq 0x92e0
movl $0x170c, %esi           # imm = 0x170C
jmp 0x4616
movl $0x180, %edi            # imm = 0x180
callq 0x41d0
movq %rax, %r12
movq %rax, %rdi
callq 0x8588
movl $0x1f90, %esi           # imm = 0x1F90
cmpl $0x4, %r15d
jb 0x4627
movq 0x18(%rbp), %rdi
callq 0x4320
movl %eax, %esi
movq (%r12), %rax
movq %r12, %rdi
callq *0x38(%rax)
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movq %rax, 0x10(%rsp)
movl $0x0, 0x4(%rsp)
movq (%r12), %rax
movq %r12, %rdi
callq *0x10(%rax)
testl %eax, %eax
je 0x46b0
movq %r14, %rdi
callq 0x52b8
movl $0x30, %esi
movq %r14, %rdi
callq 0x41e0
movq %r13, %rdi
callq 0x778a
movl $0x3004, %esi           # imm = 0x3004
movq %r13, %rdi
callq 0x41e0
movq %rbx, %rdi
callq 0x6f7a
movl $0x18, %esi
movq %rbx, %rdi
callq 0x41e0
movq (%r12), %rax
movq %r12, %rdi
callq *0x8(%rax)
leaq 0x6ae5(%rip), %rdi      # 0xb186
callq 0x4310
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
jmp 0x4929
movq %r13, 0x20(%rsp)
movq 0x8(%rbx), %rax
movq %rax, 0x8(%rsp)
movq 0x10(%rbx), %rbp
movq %r12, (%rbp)
movq (%r12), %rax
movq %r12, 0x18(%rsp)
movq %r12, %rdi
callq *0x30(%rax)
movl %eax, 0x1e0(%rbp)
xorl %r15d, %r15d
cmpl $0x8, %eax
sete %r15b
movq (%rbp), %rdi
movq (%rdi), %rax
callq *0x28(%rax)
movq %rax, 0x1d0(%rbp,%r15,8)
cmpb $0x1, 0x8(%r14)
jne 0x48d8
xorl %r13d, %r13d
movzwl 0x18(%r14), %eax
cmpl %eax, 0x10(%rsp)
sete %r12b
cmpb $0x0, 0x82(%rbp)
je 0x4727
incl 0x1c(%r14)
movl $0x1, %r15d
jmp 0x4732
movq %r14, %rdi
callq 0x53fe
movl %eax, %r15d
movq %rbx, %rdi
movl %r15d, %esi
callq 0x710a
cmpb $0x0, 0x4(%rsp)
je 0x478a
leaq 0x6a2e(%rip), %rdi      # 0xb179
movl %r15d, %esi
xorl %eax, %eax
callq 0x4050
movq %r14, %rdi
callq 0x5314
movq %rbp, %rdi
callq 0x8464
movq %rbx, %rdi
movl $0x80, %esi
movl $0xff, %edx
callq 0x7074
cmpb $0x0, 0x82(%rbp)
jne 0x478a
movl $0x3e8, %edi            # imm = 0x3E8
callq 0x42e0
movb 0x1e4(%rbp), %al
movb $0x0, 0x1e4(%rbp)
cmpb $0x1, %al
jne 0x48bf
movq 0x18(%rsp), %rdi
movq (%rdi), %rax
callq *0x20(%rax)
decl %eax
cmpl $0xe, %eax
ja 0x48bf
leaq 0x6848(%rip), %rcx      # 0xb004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x8(%rsp), %rcx
movl 0x28(%rcx), %eax
andl $0x7, %eax
andb $-0x3, 0x38(%rcx,%rax)
jmp 0x48bf
orb $-0x80, 0xcc(%rbp)
jmp 0x48bf
movq 0x8(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
andb $-0x21, 0x38(%rcx,%rax)
jmp 0x48bf
movq 0x8(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
orb $0x10, 0x38(%rcx,%rax)
jmp 0x48bf
movq 0x8(%rsp), %rcx
movl 0x28(%rcx), %eax
andl $0x7, %eax
orb $0x1, 0x38(%rcx,%rax)
jmp 0x48bf
movq 0x8(%rsp), %rcx
movl 0x28(%rcx), %eax
andl $0x7, %eax
orb $0x2, 0x38(%rcx,%rax)
jmp 0x48bf
movq 0x8(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
orb $-0x80, 0x38(%rcx,%rax)
jmp 0x48bf
movq 0x8(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
orb $0x40, 0x38(%rcx,%rax)
jmp 0x48bf
movq 0x8(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
andb $0x7f, 0x38(%rcx,%rax)
jmp 0x48bf
movq 0x8(%rsp), %rcx
movl 0x28(%rcx), %eax
andl $0x7, %eax
andb $-0x2, 0x38(%rcx,%rax)
jmp 0x48bf
andb $0x7f, 0xcc(%rbp)
jmp 0x48bf
movq 0x8(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
andb $-0x11, 0x38(%rcx,%rax)
jmp 0x48bf
movq 0x8(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
andb $-0x41, 0x38(%rcx,%rax)
jmp 0x48bf
movq 0x8(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
orb $0x20, 0x38(%rcx,%rax)
orb %r12b, %r13b
testb $0x1, %r13b
je 0x48cd
callq 0x42a0
cmpb $0x0, 0x8(%r14)
jne 0x4705
movq %r14, %rdi
callq 0x52b8
movl $0x30, %esi
movq %r14, %rdi
callq 0x41e0
movq 0x20(%rsp), %r14
movq %r14, %rdi
callq 0x778a
movl $0x3004, %esi           # imm = 0x3004
movq %r14, %rdi
callq 0x41e0
movq %rbx, %rdi
callq 0x6f7a
movl $0x18, %esi
movq %rbx, %rdi
callq 0x41e0
movq 0x18(%rsp), %rdi
movq (%rdi), %rax
callq *0x8(%rax)
xorl %eax, %eax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl $0x28, %edi
callq 0x41d0
movq %rax, %r12
movq %rax, %rdi
callq 0x924c
movb $0x1, 0x28(%r14)
jmp 0x4985
movl $0x28, %edi
callq 0x41d0
movq %rax, %r12
movq %rax, %rdi
callq 0x924c
movl $0xf000, %eax           # imm = 0xF000
cmpl $0x4, %r15d
jb 0x4981
movq 0x18(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x42d0
movl %eax, 0x24(%r14)
movb $0x1, %al
movl %eax, 0x4(%rsp)
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movq %rax, 0x10(%rsp)
jmp 0x4643
movl $0x28, %edi
callq 0x41d0
movq %rax, %r12
movq %rax, %rdi
callq 0x924c
movb $0x1, 0x28(%r14)
movb $0x1, %al
movl %eax, 0x4(%rsp)
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movq %rax, 0x10(%rsp)
cmpl $0x3, %r15d
jbe 0x4643
movq 0x18(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x42d0
cmpl $0x4, %r15d
je 0x4643
movq 0x20(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x42d0
jmp 0x4643
movl $0x28, %edi
callq 0x41d0
movq %rax, %r12
movq %rax, %rdi
callq 0x924c
movb $0x1, 0x28(%r14)
movb $0x1, %al
movl %eax, 0x4(%rsp)
movl $0xf000, %eax           # imm = 0xF000
movq %rax, 0x10(%rsp)
cmpl $0x4, %r15d
jb 0x4643
movq 0x18(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x42d0
jmp 0x4990
movq (%rbp), %rsi
leaq 0x65f8(%rip), %rdi      # 0xb040
xorl %eax, %eax
callq 0x4050
xorl %edi, %edi
callq 0x4250
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x4250
leaq 0x6701(%rip), %rdi      # 0xb168
movq %r12, %rsi
xorl %eax, %eax
callq 0x4050
movl $0x1, %edi
callq 0x4250
jmp 0x4a83
jmp 0x4a83
jmp 0x4a83
jmp 0x4a83
movq %rax, %r15
movl $0x28, %esi
jmp 0x4aa9
movq %rax, %r15
movl $0x180, %esi            # imm = 0x180
jmp 0x4aa9
movq %rax, %r15
movl $0x60, %esi
jmp 0x4aa9
movq %rax, %r15
movl $0x58, %esi
movq %r12, %rdi
jmp 0x4ad3
movq %rax, %r15
movl $0x3004, %esi           # imm = 0x3004
movq %r13, %rdi
jmp 0x4ad3
movq %rax, %r15
movl $0x18, %esi
movq %rbx, %rdi
jmp 0x4ad3
movq %rax, %r15
movl $0x30, %esi
movq %r14, %rdi
callq 0x41e0
movq %r15, %rdi
callq 0x4340