// File: /workspace/github_cpp_makefile_star2_O2/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
pushq $0x30
popq %rdi
callq 0x41f0
movq %rax, %r14
movq %rax, %rdi
callq 0x515c
pushq $0x18
popq %rdi
callq 0x41f0
movq %rax, 0x8(%rsp)
movq %rax, %rdi
callq 0x6a58
movl $0x3004, %edi           # imm = 0x3004
callq 0x41f0
movq %rax, %r12
movq %rax, %rdi
callq 0x7164
movq 0x8(%rbp), %rsi
movq %r12, %rdi
callq 0x717a
testl %eax, %eax
jne 0x4a1e
pushq $-0x1
popq %rax
movq %rax, 0x10(%rsp)
movq 0x8(%rsp), %rbx
movq %rbx, %rdi
callq 0x6b0a
movq %r12, (%rbx)
movq %rbx, (%r14)
movq %r14, %rdi
callq 0x517e
movq 0x10(%rbp), %r13
leaq 0x5c03(%rip), %rsi      # 0xa13f
movq %r13, %rdi
callq 0x42f0
testl %eax, %eax
je 0x4602
leaq 0x5bf0(%rip), %rsi      # 0xa143
movq %r13, %rdi
callq 0x42f0
testl %eax, %eax
je 0x4617
leaq 0x5bdd(%rip), %rsi      # 0xa147
movq %r13, %rdi
callq 0x42f0
testl %eax, %eax
je 0x4631
leaq 0x5bcb(%rip), %rsi      # 0xa14c
movq %r13, %rdi
callq 0x42f0
testl %eax, %eax
je 0x4917
leaq 0x5bba(%rip), %rsi      # 0xa152
movq %r13, %rdi
callq 0x42f0
testl %eax, %eax
je 0x4931
leaq 0x5ba9(%rip), %rsi      # 0xa158
movq %r13, %rdi
callq 0x42f0
testl %eax, %eax
je 0x496b
leaq 0x5b98(%rip), %rsi      # 0xa15e
movq %r13, %rdi
callq 0x42f0
testl %eax, %eax
je 0x49bc
leaq 0x5b86(%rip), %rsi      # 0xa163
movq %r13, %rdi
callq 0x42f0
testl %eax, %eax
jne 0x4a26
pushq $0x28
popq %rdi
callq 0x41f0
movq %rax, %r13
movq %rax, %rdi
callq 0x86f0
jmp 0x4666
pushq $0x58
popq %rdi
callq 0x41f0
movq %rax, %r13
movq %rax, %rdi
callq 0x91cc
jmp 0x4666
pushq $0x60
popq %rdi
callq 0x41f0
movq %rax, %r13
movq %rax, %rdi
callq 0x876c
movl $0x170c, %esi           # imm = 0x170C
jmp 0x464b
movl $0x180, %edi            # imm = 0x180
callq 0x41f0
movq %rax, %r13
movq %rax, %rdi
callq 0x7cdc
movl $0x1f90, %esi           # imm = 0x1F90
cmpl $0x4, %r15d
jb 0x465c
movq 0x18(%rbp), %rdi
callq 0x4350
movl %eax, %esi
movq (%r13), %rax
movq %r13, %rdi
callq *0x38(%rax)
movl $0x0, 0x4(%rsp)
movq (%r13), %rax
movq %r13, %rdi
callq *0x10(%rax)
testl %eax, %eax
je 0x46da
movq %r14, %rdi
callq 0x517c
pushq $0x30
popq %rsi
movq %r14, %rdi
callq 0x4200
movq %r12, %rdi
callq 0x7178
movl $0x3004, %esi           # imm = 0x3004
movq %r12, %rdi
callq 0x4200
movq 0x8(%rsp), %rbx
movq %rbx, %rdi
callq 0x6ac0
pushq $0x18
popq %rsi
movq %rbx, %rdi
callq 0x4200
movq (%r13), %rax
movq %r13, %rdi
callq *0x8(%rax)
leaq 0x5ab9(%rip), %rdi      # 0xa186
callq 0x4340
pushq $-0x1
popq %rax
jmp 0x4908
movq %r12, 0x20(%rsp)
movq 0x8(%rsp), %rax
movq %r13, %rsi
movq 0x8(%rax), %r13
movq 0x10(%rax), %r15
movq %r15, %rdi
movq %rsi, 0x18(%rsp)
callq 0x4a96
xorl %ebx, %ebx
cmpb $0x1, 0x8(%r14)
jne 0x48b6
movzwl 0x18(%r14), %eax
cmpl %eax, 0x10(%rsp)
sete %r12b
cmpb $0x0, 0x82(%r15)
je 0x4729
incl 0x1c(%r14)
pushq $0x1
popq %rbp
jmp 0x4733
movq %r14, %rdi
callq 0x5292
movl %eax, %ebp
movq 0x8(%rsp), %rdi
movl %ebp, %esi
callq 0x6c46
cmpb $0x0, 0x4(%rsp)
je 0x478e
leaq 0x5a2c(%rip), %rdi      # 0xa179
movl %ebp, %esi
xorl %eax, %eax
callq 0x4050
movq %r14, %rdi
callq 0x51aa
movq %r15, %rdi
callq 0x7ad0
movq 0x8(%rsp), %rdi
movl $0x80, %esi
movl $0xff, %edx
callq 0x6bb8
cmpb $0x0, 0x82(%r15)
jne 0x478e
movl $0x3e8, %edi            # imm = 0x3E8
callq 0x4310
movb 0x1e4(%r15), %al
movb $0x0, 0x1e4(%r15)
cmpb $0x1, %al
jne 0x48a0
movq 0x18(%rsp), %rdi
movq (%rdi), %rax
callq *0x20(%rax)
decl %eax
cmpl $0xe, %eax
ja 0x48a0
leaq 0x5842(%rip), %rcx      # 0xa004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl 0x28(%r13), %eax
andl $0x7, %eax
andb $-0x3, 0x38(%r13,%rax)
jmp 0x48a0
orb $-0x80, 0xcc(%r15)
jmp 0x48a0
movl 0x20(%r13), %eax
andl $0x7, %eax
andb $-0x21, 0x38(%r13,%rax)
jmp 0x48a0
movl 0x20(%r13), %eax
andl $0x7, %eax
orb $0x10, 0x38(%r13,%rax)
jmp 0x48a0
movl 0x28(%r13), %eax
andl $0x7, %eax
orb $0x1, 0x38(%r13,%rax)
jmp 0x48a0
movl 0x28(%r13), %eax
andl $0x7, %eax
orb $0x2, 0x38(%r13,%rax)
jmp 0x48a0
movl 0x20(%r13), %eax
andl $0x7, %eax
orb $-0x80, 0x38(%r13,%rax)
jmp 0x48a0
movl 0x20(%r13), %eax
andl $0x7, %eax
orb $0x40, 0x38(%r13,%rax)
jmp 0x48a0
movl 0x20(%r13), %eax
andl $0x7, %eax
andb $0x7f, 0x38(%r13,%rax)
jmp 0x48a0
movl 0x28(%r13), %eax
andl $0x7, %eax
andb $-0x2, 0x38(%r13,%rax)
jmp 0x48a0
andb $0x7f, 0xcc(%r15)
jmp 0x48a0
movl 0x20(%r13), %eax
andl $0x7, %eax
andb $-0x11, 0x38(%r13,%rax)
jmp 0x48a0
movl 0x20(%r13), %eax
andl $0x7, %eax
andb $-0x41, 0x38(%r13,%rax)
jmp 0x48a0
movl 0x20(%r13), %eax
andl $0x7, %eax
orb $0x20, 0x38(%r13,%rax)
orb %r12b, %bl
testb $0x1, %bl
je 0x46fe
callq 0x42d0
jmp 0x46fe
movq %r14, %rdi
callq 0x517c
pushq $0x30
popq %rsi
movq %r14, %rdi
callq 0x4200
movq 0x20(%rsp), %rbx
movq %rbx, %rdi
callq 0x7178
movl $0x3004, %esi           # imm = 0x3004
movq %rbx, %rdi
callq 0x4200
movq 0x8(%rsp), %rbx
movq %rbx, %rdi
callq 0x6ac0
pushq $0x18
popq %rsi
movq %rbx, %rdi
callq 0x4200
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
pushq $0x28
popq %rdi
callq 0x41f0
movq %rax, %r13
movq %rax, %rdi
callq 0x86f0
movb $0x1, 0x28(%r14)
jmp 0x4960
pushq $0x28
popq %rdi
callq 0x41f0
movq %rax, %r13
movq %rax, %rdi
callq 0x86f0
movl $0xf000, %eax           # imm = 0xF000
cmpl $0x4, %r15d
jb 0x495c
movq 0x18(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x4300
movl %eax, 0x24(%r14)
movb $0x1, %al
movl %eax, 0x4(%rsp)
jmp 0x466e
pushq $0x28
popq %rdi
callq 0x41f0
movq %rax, %r13
movq %rax, %rdi
callq 0x86f0
movb $0x1, 0x28(%r14)
movb $0x1, %al
movl %eax, 0x4(%rsp)
cmpl $0x3, %r15d
jbe 0x466e
movq 0x18(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x4300
cmpl $0x4, %r15d
je 0x466e
movq 0x20(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x4300
jmp 0x466e
pushq $0x28
popq %rdi
callq 0x41f0
movq %rax, %r13
movq %rax, %rdi
callq 0x86f0
movb $0x1, 0x28(%r14)
movb $0x1, %al
movl %eax, 0x4(%rsp)
movl $0xf000, %eax           # imm = 0xF000
movq %rax, 0x10(%rsp)
cmpl $0x4, %r15d
jb 0x466e
movq 0x18(%rbp), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x4300
movq %rax, 0x10(%rsp)
jmp 0x466e
movq (%rbp), %rsi
leaq 0x5630(%rip), %rdi      # 0xa040
xorl %eax, %eax
callq 0x4050
xorl %edi, %edi
callq 0x4270
pushq $-0x1
popq %rdi
callq 0x4270
leaq 0x573b(%rip), %rdi      # 0xa168
movq %r13, %rsi
xorl %eax, %eax
callq 0x4050
pushq $0x1
jmp 0x4a20
jmp 0x4a43
jmp 0x4a43
jmp 0x4a43
jmp 0x4a43
movq %rax, %r15
pushq $0x28
jmp 0x4a60
movq %rax, %r15
movl $0x180, %esi            # imm = 0x180
jmp 0x4a61
movq %rax, %r15
pushq $0x60
jmp 0x4a60
movq %rax, %r15
pushq $0x58
popq %rsi
movq %r13, %rdi
jmp 0x4a89
movq %rax, %r15
movl $0x3004, %esi           # imm = 0x3004
movq %r12, %rdi
jmp 0x4a89
movq %rax, %r15
pushq $0x18
popq %rsi
movq 0x8(%rsp), %rdi
jmp 0x4a89
movq %rax, %r15
pushq $0x30
popq %rsi
movq %r14, %rdi
callq 0x4200
movq %r15, %rdi
callq 0x4370