// File: mikeakohn[P]cloudtari/build/../src/TIA.cxx
// Function: TIA::write_memory(int, unsigned char)
void TIA::write_memory(int address, uint8_t value)
{
  if (address > 0x2c) { return; }

  switch (address)
  {
    case VSYNC:
      if ((value & 2) == 2)
      {
        //show_fps();

        television->refresh();
        pos_x = 0;
        pos_y = 0;

        // In case the Television is page flipping.
        set_image();
      }

      write_regs[VSYNC] = value;
      break;
    case VBLANK:
      break;
    case WSYNC:
      // This one pauses the CPU until the "video beam" starts back over
      // at 0. This is usually done by an "sta WSYNC" instruction which is
      // 2 CPU cycles (6 TIA cycles). The issue it seems like the CPU should
      // be halted after the instruction finishes (hence hsync_latch variable
      // which will pause it after the TIA runs the 6 pixel clocks). If it's
      // halted here and between those 6 cycles in the TIA it resets to 0
      // it seems like the CPU could unhalt early. However, with the latch
      // code it seems to cause video glitches, so it's commented out for now.
      write_regs[WSYNC] = 1;
      //hsync_latch = true;
      break;
    case RSYNC:
      // "This address resets the horizontal sync counter to define the
      // beginning of horizontal blank time, and is used in chip testing."
      pos_x = 0;
      break;
    case NUSIZ0:
      player_size(player_0, value);
      missile_0.set_width(1 << ((value >> 4) & 0x3));
      break;
    case NUSIZ1:
      player_size(player_1, value);
      missile_1.set_width(1 << ((value >> 4) & 0x3));
      break;
#if 0
    case COLUP0:
      colors.player_0 = value;
      break;
    case COLUP1:
      colors.player_1 = value;
      break;
    case COLUBK:
      colors.background = value;
      break;
    case COLUPF:
      colors.playfield = value;
      break;
#endif
    case CTRLPF:
      write_regs[CTRLPF] = value;
      ball.set_width(1 << ((value >> 4) & 0x3));
      break;
    case REFP0:
      write_regs[REFP0] = value;
      build_player_0();
      break;
    case REFP1:
      write_regs[REFP1] = value;
      build_player_1();
      break;
    case PF0:
    case PF1:
    case PF2:
      write_regs[address] = value;
      build_playfield();
      break;
    case RESP0:
      // Reset player 0 (aka, start drawing).
      player_0.set_position();
      break;
    case RESP1:
      // Reset player 1 (aka, start drawing).
      player_1.set_position();
      break;
    case RESM0:
      // Reset missile 0.
      missile_0.set_position();
      break;
    case RESM1:
      // Reset missile 1.
      missile_1.set_position();
      break;
    case RESBL:
      // Reset ball.
      ball.set_position();
      break;
    case AUDC0:
    case AUDC1:
    case AUDF0:
      break;
    case AUDF1:
      break;
    case AUDV0:
    case AUDV1:
      break;
    case GRP0:
      write_regs[GRP0] = value;

      if (!player_0.vertical_delay)
      {
        build_player_0();
      }
        else
      {
        player_0.need_update = true;
      }
      break;
    case GRP1:
      write_regs[GRP1] = value;

      if (!player_1.vertical_delay)
      {
        build_player_1();
      }
        else
      {
        player_1.need_update = true;
      }
      break;
    case ENAM0:
      missile_0.set_enabled((value & 2) != 0);
      break;
    case ENAM1:
      missile_1.set_enabled((value & 2) != 0);
      break;
    case ENABL:
      if ((value & 2) == 0)
      {
        ball.set_enabled(false);
      }
        else
      {
        if (!ball.vertical_delay)
        {
          ball.set_enabled(true);
        }
          else
        {
          ball.need_update = true;
        }
      }
      break;
    case HMP0:
      player_0.set_move(compute_offset(value));
      break;
    case HMP1:
      player_1.set_move(compute_offset(value));
      break;
    case HMM0:
      missile_0.set_move(compute_offset(value));
      break;
    case HMM1:
      missile_1.set_move(compute_offset(value));
      break;
    case HMBL:
      ball.set_move(compute_offset(value));
      break;
    case VDELP0:
      player_0.vertical_delay = value & 1;
      break;
    case VDELP1:
      player_1.vertical_delay = value & 1;
      break;
    case VDELBL:
      ball.vertical_delay = value & 1;
      break;
    case RESMP0:
      missile_0.start_pos = player_0.start_pos;
      break;
    case RESMP1:
      missile_1.start_pos = player_1.start_pos;
      break;
    case HMOVE:
      // Strobing HMOVE will subtract the "move" values set by the HMP0, etc
      // registers. If HMOVE is called again, the same values are subtracted
      // again.
      player_0.apply_move();
      player_1.apply_move();
      missile_0.apply_move();
      missile_1.apply_move();
      ball.apply_move();
      break;
    case HMCLR:
      // Clear motion registers.
      player_0.clear_move();
      player_1.clear_move();
      missile_0.clear_move();
      missile_1.clear_move();
      ball.clear_move();
      break;
    case CXCLR:
      // Clear collision latches.
      read_regs[CXM0P] = 0;
      read_regs[CXM1P] = 0;
      read_regs[CXP0FB] = 0;
      read_regs[CXP1FB] = 0;
      read_regs[CXM0FB] = 0;
      read_regs[CXM1FB] = 0;
      read_regs[CXBLPF] = 0;
      read_regs[CXPPMM] = 0;
      break;
    default:
      write_regs[address] = value;
      break;
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x50, %rsp
movb %dl, %al
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movb %al, -0xd(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x18(%rbp)
cmpl $0x2c, -0xc(%rbp)
jle 0xa8c7
jmp 0xad9d
movl -0xc(%rbp), %eax
movq %rax, -0x20(%rbp)
subq $0x2c, %rax
ja 0xad8b
movq -0x20(%rbp), %rax
leaq 0x5165(%rip), %rcx      # 0xfa48
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movzbl -0xd(%rbp), %eax
andl $0x2, %eax
cmpl $0x2, %eax
jne 0xa91c
movq -0x18(%rbp), %rax
movq (%rax), %rdi
movq (%rdi), %rax
callq *0x18(%rax)
movq -0x18(%rbp), %rdi
movl $0x0, 0x8(%rdi)
movl $0x0, 0xc(%rdi)
callq 0x54e0
movq -0x18(%rbp), %rax
movb -0xd(%rbp), %cl
movb %cl, 0x80(%rax)
jmp 0xad9d
jmp 0xad9d
movq -0x18(%rbp), %rax
movb $0x1, 0x82(%rax)
jmp 0xad9d
movq -0x18(%rbp), %rax
movl $0x0, 0x8(%rax)
jmp 0xad9d
movq -0x18(%rbp), %rdi
movq %rdi, %rsi
addq $0x30, %rsi
movzbl -0xd(%rbp), %edx
callq 0xadb0
movq -0x18(%rbp), %rdi
addq $0x58, %rdi
movzbl -0xd(%rbp), %ecx
sarl $0x4, %ecx
andl $0x3, %ecx
movl $0x1, %esi
shll %cl, %esi
callq 0xb8c0
jmp 0xad9d
movq -0x18(%rbp), %rdi
movq %rdi, %rsi
addq $0x44, %rsi
movzbl -0xd(%rbp), %edx
callq 0xadb0
movq -0x18(%rbp), %rdi
addq $0x64, %rdi
movzbl -0xd(%rbp), %ecx
sarl $0x4, %ecx
andl $0x3, %ecx
movl $0x1, %esi
shll %cl, %esi
callq 0xb8c0
jmp 0xad9d
movq -0x18(%rbp), %rdi
movb -0xd(%rbp), %al
movb %al, 0x8a(%rdi)
addq $0x70, %rdi
movzbl -0xd(%rbp), %ecx
sarl $0x4, %ecx
andl $0x3, %ecx
movl $0x1, %esi
shll %cl, %esi
callq 0xb8c0
jmp 0xad9d
movq -0x18(%rbp), %rdi
movb -0xd(%rbp), %al
movb %al, 0x8b(%rdi)
callq 0xae30
jmp 0xad9d
movq -0x18(%rbp), %rdi
movb -0xd(%rbp), %al
movb %al, 0x8c(%rdi)
callq 0xae80
jmp 0xad9d
movq -0x18(%rbp), %rdi
movb -0xd(%rbp), %cl
movslq -0xc(%rbp), %rax
movb %cl, 0x80(%rdi,%rax)
callq 0xaed0
jmp 0xad9d
movq -0x18(%rbp), %rdi
addq $0x30, %rdi
callq 0xb8e0
jmp 0xad9d
movq -0x18(%rbp), %rdi
addq $0x44, %rdi
callq 0xb8e0
jmp 0xad9d
movq -0x18(%rbp), %rdi
addq $0x58, %rdi
callq 0xb900
jmp 0xad9d
movq -0x18(%rbp), %rdi
addq $0x64, %rdi
callq 0xb900
jmp 0xad9d
movq -0x18(%rbp), %rdi
addq $0x70, %rdi
callq 0xb900
jmp 0xad9d
jmp 0xad9d
jmp 0xad9d
jmp 0xad9d
movq -0x18(%rbp), %rax
movb -0xd(%rbp), %cl
movb %cl, 0x9b(%rax)
testb $0x1, 0x32(%rax)
jne 0xaabe
movq -0x18(%rbp), %rdi
callq 0xae30
jmp 0xaac6
movq -0x18(%rbp), %rax
movb $0x1, 0x33(%rax)
jmp 0xad9d
movq -0x18(%rbp), %rax
movb -0xd(%rbp), %cl
movb %cl, 0x9c(%rax)
testb $0x1, 0x46(%rax)
jne 0xaae9
movq -0x18(%rbp), %rdi
callq 0xae80
jmp 0xaaf1
movq -0x18(%rbp), %rax
movb $0x1, 0x47(%rax)
jmp 0xad9d
movq -0x18(%rbp), %rdi
addq $0x58, %rdi
movzbl -0xd(%rbp), %eax
andl $0x2, %eax
cmpl $0x0, %eax
setne %al
movzbl %al, %esi
andl $0x1, %esi
callq 0xb920
jmp 0xad9d
movq -0x18(%rbp), %rdi
addq $0x64, %rdi
movzbl -0xd(%rbp), %eax
andl $0x2, %eax
cmpl $0x0, %eax
setne %al
movzbl %al, %esi
andl $0x1, %esi
callq 0xb920
jmp 0xad9d
movzbl -0xd(%rbp), %eax
andl $0x2, %eax
cmpl $0x0, %eax
jne 0xab5d
movq -0x18(%rbp), %rdi
addq $0x70, %rdi
xorl %esi, %esi
callq 0xb920
jmp 0xab85
movq -0x18(%rbp), %rax
testb $0x1, 0x7d(%rax)
jne 0xab7b
movq -0x18(%rbp), %rdi
addq $0x70, %rdi
movl $0x1, %esi
callq 0xb920
jmp 0xab83
movq -0x18(%rbp), %rax
movb $0x1, 0x7c(%rax)
jmp 0xab85
jmp 0xad9d
movq -0x18(%rbp), %rdi
movq %rdi, %rax
addq $0x30, %rax
movq %rax, -0x28(%rbp)
movzbl -0xd(%rbp), %esi
callq 0xb960
movq -0x28(%rbp), %rdi
movl %eax, %esi
callq 0xb940
jmp 0xad9d
movq -0x18(%rbp), %rdi
movq %rdi, %rax
addq $0x44, %rax
movq %rax, -0x30(%rbp)
movzbl -0xd(%rbp), %esi
callq 0xb960
movq -0x30(%rbp), %rdi
movl %eax, %esi
callq 0xb940
jmp 0xad9d
movq -0x18(%rbp), %rdi
movq %rdi, %rax
addq $0x58, %rax
movq %rax, -0x38(%rbp)
movzbl -0xd(%rbp), %esi
callq 0xb960
movq -0x38(%rbp), %rdi
movl %eax, %esi
callq 0xb980
jmp 0xad9d
movq -0x18(%rbp), %rdi
movq %rdi, %rax
addq $0x64, %rax
movq %rax, -0x40(%rbp)
movzbl -0xd(%rbp), %esi
callq 0xb960
movq -0x40(%rbp), %rdi
movl %eax, %esi
callq 0xb980
jmp 0xad9d
movq -0x18(%rbp), %rdi
movq %rdi, %rax
addq $0x70, %rax
movq %rax, -0x48(%rbp)
movzbl -0xd(%rbp), %esi
callq 0xb960
movq -0x48(%rbp), %rdi
movl %eax, %esi
callq 0xb980
jmp 0xad9d
movq -0x18(%rbp), %rax
movzbl -0xd(%rbp), %ecx
andl $0x1, %ecx
cmpl $0x0, %ecx
setne %cl
andb $0x1, %cl
movb %cl, 0x32(%rax)
jmp 0xad9d
movq -0x18(%rbp), %rax
movzbl -0xd(%rbp), %ecx
andl $0x1, %ecx
cmpl $0x0, %ecx
setne %cl
andb $0x1, %cl
movb %cl, 0x46(%rax)
jmp 0xad9d
movq -0x18(%rbp), %rax
movzbl -0xd(%rbp), %ecx
andl $0x1, %ecx
cmpl $0x0, %ecx
setne %cl
andb $0x1, %cl
movb %cl, 0x7d(%rax)
jmp 0xad9d
movq -0x18(%rbp), %rax
movl 0x3c(%rax), %ecx
movl %ecx, 0x5c(%rax)
jmp 0xad9d
movq -0x18(%rbp), %rax
movl 0x50(%rax), %ecx
movl %ecx, 0x68(%rax)
jmp 0xad9d
movq -0x18(%rbp), %rdi
addq $0x30, %rdi
callq 0xb9a0
movq -0x18(%rbp), %rdi
addq $0x44, %rdi
callq 0xb9a0
movq -0x18(%rbp), %rdi
addq $0x58, %rdi
callq 0xb9c0
movq -0x18(%rbp), %rdi
addq $0x64, %rdi
callq 0xb9c0
movq -0x18(%rbp), %rdi
addq $0x70, %rdi
callq 0xb9c0
jmp 0xad9d
movq -0x18(%rbp), %rdi
addq $0x30, %rdi
callq 0xb9e0
movq -0x18(%rbp), %rdi
addq $0x44, %rdi
callq 0xb9e0
movq -0x18(%rbp), %rdi
addq $0x58, %rdi
callq 0xba00
movq -0x18(%rbp), %rdi
addq $0x64, %rdi
callq 0xba00
movq -0x18(%rbp), %rdi
addq $0x70, %rdi
callq 0xba00
jmp 0xad9d
movq -0x18(%rbp), %rax
movb $0x0, 0xc0(%rax)
movb $0x0, 0xc1(%rax)
movb $0x0, 0xc2(%rax)
movb $0x0, 0xc3(%rax)
movb $0x0, 0xc4(%rax)
movb $0x0, 0xc5(%rax)
movb $0x0, 0xc6(%rax)
movb $0x0, 0xc7(%rax)
jmp 0xad9d
movq -0x18(%rbp), %rax
movb -0xd(%rbp), %dl
movslq -0xc(%rbp), %rcx
movb %dl, 0x80(%rax,%rcx)
addq $0x50, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)