// File: /workspace/github_cpp_makefile_star2_O1/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 0x4a05
movl $0x30, %edi
callq 0x41c0
movq %rax, %r14
movq %rax, %rdi
callq 0x51a8
movl $0x18, %edi
callq 0x41c0
movq %rax, %rbx
movq %rax, %rdi
callq 0x6e64
movl $0x3004, %edi           # imm = 0x3004
callq 0x41c0
movq %rax, %r13
movq %rax, %rdi
callq 0x76dc
movq 0x8(%rbp), %rsi
movq %r13, %rdi
callq 0x76f4
testl %eax, %eax
jne 0x4a1e
movq %rbx, %rdi
callq 0x6f20
movq %r13, (%rbx)
movq %rbx, (%r14)
movq %r14, %rdi
callq 0x51ce
movq 0x10(%rbp), %r12
leaq 0x5c4e(%rip), %rsi      # 0xa13f
movq %r12, %rdi
callq 0x42b0
testl %eax, %eax
je 0x45b9
leaq 0x5c3b(%rip), %rsi      # 0xa143
movq %r12, %rdi
callq 0x42b0
testl %eax, %eax
je 0x45d0
leaq 0x5c28(%rip), %rsi      # 0xa147
movq %r12, %rdi
callq 0x42b0
testl %eax, %eax
je 0x45ec
leaq 0x5c16(%rip), %rsi      # 0xa14c
movq %r12, %rdi
callq 0x42b0
testl %eax, %eax
je 0x4904
leaq 0x5c05(%rip), %rsi      # 0xa152
movq %r12, %rdi
callq 0x42b0
testl %eax, %eax
je 0x4920
leaq 0x5bf4(%rip), %rsi      # 0xa158
movq %r12, %rdi
callq 0x42b0
testl %eax, %eax
je 0x4966
leaq 0x5be3(%rip), %rsi      # 0xa15e
movq %r12, %rdi
callq 0x42b0
testl %eax, %eax
je 0x49bf
leaq 0x5bd1(%rip), %rsi      # 0xa163
movq %r12, %rdi
callq 0x42b0
testl %eax, %eax
jne 0x4a28
movl $0x28, %edi
callq 0x41c0
movq %rax, %r12
movq %rax, %rdi
callq 0x9094
jmp 0x4621
movl $0x58, %edi
callq 0x41c0
movq %rax, %r12
movq %rax, %rdi
callq 0x9d38
jmp 0x4621
movl $0x60, %edi
callq 0x41c0
movq %rax, %r12
movq %rax, %rdi
callq 0x9128
movl $0x170c, %esi           # imm = 0x170C
jmp 0x4606
movl $0x180, %edi            # imm = 0x180
callq 0x41c0
movq %rax, %r12
movq %rax, %rdi
callq 0x8398
movl $0x1f90, %esi           # imm = 0x1F90
cmpl $0x4, %r15d
jl 0x4617
movq 0x18(%rbp), %rdi
callq 0x4310
movl %eax, %esi
movq (%r12), %rax
movq %r12, %rdi
callq *0x38(%rax)
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movq %rax, 0x18(%rsp)
movl $0x0, 0xc(%rsp)
movq (%r12), %rax
movq %r12, %rdi
callq *0x10(%rax)
testl %eax, %eax
je 0x46a0
movq %r14, %rdi
callq 0x51cc
movl $0x30, %esi
movq %r14, %rdi
callq 0x41d0
movq %r13, %rdi
callq 0x76f2
movl $0x3004, %esi           # imm = 0x3004
movq %r13, %rdi
callq 0x41d0
movq %rbx, %rdi
callq 0x6ece
movl $0x18, %esi
movq %rbx, %rdi
callq 0x41d0
movq (%r12), %rax
movq %r12, %rdi
callq *0x8(%rax)
leaq 0x5af5(%rip), %rdi      # 0xa186
callq 0x4300
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
jmp 0x48f5
movq %r13, 0x20(%rsp)
movq 0x8(%rbx), %rax
movq %rax, 0x10(%rsp)
movq 0x10(%rbx), %r15
movq %r15, %rdi
movq %r12, %rsi
callq 0x4aa8
cmpb $0x1, 0x8(%r14)
jne 0x48a5
xorl %r13d, %r13d
movzwl 0x18(%r14), %eax
cmpl %eax, 0x18(%rsp)
movzbl %r13b, %r13d
movl $0x1, %eax
cmovel %eax, %r13d
cmpb $0x0, 0x82(%r15)
je 0x46f6
incl 0x1c(%r14)
movl $0x1, %ebp
jmp 0x4700
movq %r14, %rdi
callq 0x5312
movl %eax, %ebp
movq %rbx, %rdi
movl %ebp, %esi
callq 0x7066
cmpb $0x0, 0xc(%rsp)
je 0x4757
leaq 0x5a61(%rip), %rdi      # 0xa179
movl %ebp, %esi
xorl %eax, %eax
callq 0x4050
movq %r14, %rdi
callq 0x5228
movq %r15, %rdi
callq 0x8272
movq %rbx, %rdi
movl $0x80, %esi
movl $0xff, %edx
callq 0x6fd0
cmpb $0x0, 0x82(%r15)
jne 0x4757
movl $0x3e8, %edi            # imm = 0x3E8
callq 0x42d0
movb 0x1e4(%r15), %al
movb $0x0, 0x1e4(%r15)
cmpb $0x1, %al
jne 0x488f
movq (%r12), %rax
movq %r12, %rdi
callq *0x20(%rax)
decl %eax
cmpl $0xe, %eax
ja 0x488f
leaq 0x587a(%rip), %rcx      # 0xa004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x10(%rsp), %rcx
movl 0x28(%rcx), %eax
andl $0x7, %eax
andb $-0x3, 0x38(%rcx,%rax)
jmp 0x488f
orb $-0x80, 0xcc(%r15)
jmp 0x488f
movq 0x10(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
andb $-0x21, 0x38(%rcx,%rax)
jmp 0x488f
movq 0x10(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
orb $0x10, 0x38(%rcx,%rax)
jmp 0x488f
movq 0x10(%rsp), %rcx
movl 0x28(%rcx), %eax
andl $0x7, %eax
orb $0x1, 0x38(%rcx,%rax)
jmp 0x488f
movq 0x10(%rsp), %rcx
movl 0x28(%rcx), %eax
andl $0x7, %eax
orb $0x2, 0x38(%rcx,%rax)
jmp 0x488f
movq 0x10(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
orb $-0x80, 0x38(%rcx,%rax)
jmp 0x488f
movq 0x10(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
orb $0x40, 0x38(%rcx,%rax)
jmp 0x488f
movq 0x10(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
andb $0x7f, 0x38(%rcx,%rax)
jmp 0x488f
movq 0x10(%rsp), %rcx
movl 0x28(%rcx), %eax
andl $0x7, %eax
andb $-0x2, 0x38(%rcx,%rax)
jmp 0x488f
andb $0x7f, 0xcc(%r15)
jmp 0x488f
movq 0x10(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
andb $-0x11, 0x38(%rcx,%rax)
jmp 0x488f
movq 0x10(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
andb $-0x41, 0x38(%rcx,%rax)
jmp 0x488f
movq 0x10(%rsp), %rcx
movl 0x20(%rcx), %eax
andl $0x7, %eax
orb $0x20, 0x38(%rcx,%rax)
testb $0x1, %r13b
je 0x489a
callq 0x4290
cmpb $0x0, 0x8(%r14)
jne 0x46cb
movq %r14, %rdi
callq 0x51cc
movl $0x30, %esi
movq %r14, %rdi
callq 0x41d0
movq 0x20(%rsp), %r14
movq %r14, %rdi
callq 0x76f2
movl $0x3004, %esi           # imm = 0x3004
movq %r14, %rdi
callq 0x41d0
movq %rbx, %rdi
callq 0x6ece
movl $0x18, %esi
movq %rbx, %rdi
callq 0x41d0
movq (%r12), %rax
movq %r12, %rdi
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 0x41c0
movq %rax, %r12
movq %rax, %rdi
callq 0x9094
movb $0x1, 0x28(%r14)
jmp 0x4951
movl $0x28, %edi
callq 0x41c0
movq %rax, %r12
movq %rax, %rdi
callq 0x9094
movl $0xf000, %eax           # imm = 0xF000
cmpl $0x4, %r15d
jl 0x494d
movq 0x18(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x42c0
movl %eax, 0x24(%r14)
movb $0x1, %al
movl %eax, 0xc(%rsp)
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movq %rax, 0x18(%rsp)
jmp 0x4633
movl $0x28, %edi
callq 0x41c0
movq %rax, %r12
movq %rax, %rdi
callq 0x9094
movb $0x1, 0x28(%r14)
cmpl $0x4, %r15d
jl 0x4993
movq 0x18(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x42c0
movb $0x1, %al
movl %eax, 0xc(%rsp)
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movq %rax, 0x18(%rsp)
cmpl $0x5, %r15d
jl 0x4633
movq 0x20(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x42c0
jmp 0x4633
movl $0x28, %edi
callq 0x41c0
movq %rax, %r12
movq %rax, %rdi
callq 0x9094
movb $0x1, 0x28(%r14)
movb $0x1, %al
movl %eax, 0xc(%rsp)
movl $0xf000, %eax           # imm = 0xF000
movq %rax, 0x18(%rsp)
cmpl $0x4, %r15d
jl 0x4633
movq 0x18(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x42c0
jmp 0x495c
movq (%rbp), %rsi
leaq 0x5630(%rip), %rdi      # 0xa040
xorl %eax, %eax
callq 0x4050
xorl %edi, %edi
callq 0x4240
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x4240
leaq 0x5739(%rip), %rdi      # 0xa168
movq %r12, %rsi
xorl %eax, %eax
callq 0x4050
movl $0x1, %edi
callq 0x4240
jmp 0x4a4b
jmp 0x4a4b
jmp 0x4a4b
jmp 0x4a4b
movq %rax, %r15
movl $0x28, %esi
jmp 0x4a71
movq %rax, %r15
movl $0x180, %esi            # imm = 0x180
jmp 0x4a71
movq %rax, %r15
movl $0x60, %esi
jmp 0x4a71
movq %rax, %r15
movl $0x58, %esi
movq %r12, %rdi
jmp 0x4a9b
movq %rax, %r15
movl $0x3004, %esi           # imm = 0x3004
movq %r13, %rdi
jmp 0x4a9b
movq %rax, %r15
movl $0x18, %esi
movq %rbx, %rdi
jmp 0x4a9b
movq %rax, %r15
movl $0x30, %esi
movq %r14, %rdi
callq 0x41d0
movq %r15, %rdi
callq 0x4330