// File: mindbeast[P]rnes/ppu.cpp
// Function: Rnes::Ppu::writeReg(unsigned int, unsigned char)
void Ppu::writeReg(uint32_t reg, uint8_t val) {
  // CONTROL1_REG            = 0,
  // CONTROL2_REG            = 1,
  // STATUS_REG              = 2,
  // SPR_ADDR_REG            = 3,
  // SPR_DATA_REG            = 4,
  // VRAM_ADDR_REG1          = 5,
  // VRAM_ADDR_REG2          = 6,
  // VRAM_DATA_REG           = 7,
  switch (reg) {
  case CONTROL1_REG:
    vramTempAddr = (vramTempAddr & 0xf3ff) | ((uint16_t)val & 0x3) << 10;
  case CONTROL2_REG:
    // Write only registers.
    regs[reg] = val;
    break;
  case STATUS_REG:
    // Read only register.
    break;
  case SPR_ADDR_REG:
    regs[reg] = val;
    break;
  case SPR_DATA_REG:
    memcpy(regs[SPR_ADDR_REG] + (uint8_t *)&spriteRam[0], &val, 1);
    regs[SPR_ADDR_REG]++;
    break;
  case VRAM_ADDR_REG1:
    if (vramToggle == 0) {
      vramTempAddr = (0xffe0 & vramTempAddr) | (val >> 3);
      vramFineXScroll = val & 0x7;
    } else {
      vramTempAddr =
          (0xc1f & vramTempAddr) | (((uint16_t)val & 0x7) << 12) | (((uint16_t)val & 0xf8) << 2);
    }
    vramToggle = not vramToggle;
    break;
  case VRAM_ADDR_REG2:
    if (vramToggle == 0) {
      vramTempAddr = (((uint16_t)val & 0x3f) << 8) | (vramTempAddr & 0xff);
    } else {
      vramTempAddr = val | (vramTempAddr & 0xff00);
      vramCurrentAddr = vramTempAddr;
    }
    vramToggle = not vramToggle;
    break;
  case VRAM_DATA_REG:
    nes->vidMemWrite(vramCurrentAddr, val);
    vramCurrentAddr += getVramAddrInc();
    break;
  default:
    assert(0);
    break;
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x20, %rsp
movb %dl, %al
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movb %al, -0xd(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x20(%rbp)
movl -0xc(%rbp), %eax
movq %rax, -0x18(%rbp)
subq $0x7, %rax
ja 0x2415c
movq -0x18(%rbp), %rax
leaq 0x45078(%rip), %rcx     # 0x69000
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x20(%rbp), %rax
movzwl 0x13a(%rax), %ecx
andl $0xf3ff, %ecx           # imm = 0xF3FF
movzbl -0xd(%rbp), %edx
movzwl %dx, %edx
andl $0x3, %edx
shll $0xa, %edx
orl %edx, %ecx
movw %cx, 0x13a(%rax)
movq -0x20(%rbp), %rax
movb -0xd(%rbp), %dl
movl -0xc(%rbp), %ecx
movb %dl, 0x28(%rax,%rcx)
jmp 0x2417b
jmp 0x2417b
movq -0x20(%rbp), %rax
movb -0xd(%rbp), %dl
movl -0xc(%rbp), %ecx
movb %dl, 0x28(%rax,%rcx)
jmp 0x2417b
movq -0x20(%rbp), %rax
movzbl 0x2b(%rax), %ecx
movslq %ecx, %rcx
movb -0xd(%rbp), %dl
movb %dl, 0x30(%rax,%rcx)
movb 0x2b(%rax), %cl
addb $0x1, %cl
movb %cl, 0x2b(%rax)
jmp 0x2417b
movq -0x20(%rbp), %rax
cmpl $0x0, 0x130(%rax)
jne 0x24040
movq -0x20(%rbp), %rax
movzwl 0x13a(%rax), %ecx
andl $0xffe0, %ecx           # imm = 0xFFE0
movzbl -0xd(%rbp), %edx
sarl $0x3, %edx
orl %edx, %ecx
movw %cx, 0x13a(%rax)
movzbl -0xd(%rbp), %ecx
andl $0x7, %ecx
movl %ecx, 0x134(%rax)
jmp 0x24079
movq -0x20(%rbp), %rax
movzwl 0x13a(%rax), %ecx
andl $0xc1f, %ecx            # imm = 0xC1F
movzbl -0xd(%rbp), %edx
movzwl %dx, %edx
andl $0x7, %edx
shll $0xc, %edx
orl %edx, %ecx
movzbl -0xd(%rbp), %edx
movzwl %dx, %edx
andl $0xf8, %edx
shll $0x2, %edx
orl %edx, %ecx
movw %cx, 0x13a(%rax)
movq -0x20(%rbp), %rax
cmpl $0x0, 0x130(%rax)
setne %cl
xorb $-0x1, %cl
andb $0x1, %cl
movzbl %cl, %ecx
movl %ecx, 0x130(%rax)
jmp 0x2417b
movq -0x20(%rbp), %rax
cmpl $0x0, 0x130(%rax)
jne 0x240d1
movq -0x20(%rbp), %rax
movzbl -0xd(%rbp), %ecx
movzwl %cx, %ecx
andl $0x3f, %ecx
shll $0x8, %ecx
movzwl 0x13a(%rax), %edx
andl $0xff, %edx
orl %edx, %ecx
movw %cx, 0x13a(%rax)
jmp 0x240fd
movq -0x20(%rbp), %rax
movzbl -0xd(%rbp), %ecx
movzwl 0x13a(%rax), %edx
andl $0xff00, %edx           # imm = 0xFF00
orl %edx, %ecx
movw %cx, 0x13a(%rax)
movw 0x13a(%rax), %cx
movw %cx, 0x138(%rax)
movq -0x20(%rbp), %rax
cmpl $0x0, 0x130(%rax)
setne %cl
xorb $-0x1, %cl
andb $0x1, %cl
movzbl %cl, %ecx
movl %ecx, 0x130(%rax)
jmp 0x2417b
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rdi
movw 0x138(%rax), %ax
movzwl %ax, %esi
movzbl -0xd(%rbp), %edx
callq 0x3c5b0
movq -0x20(%rbp), %rdi
callq 0x24190
movw %ax, %cx
movq -0x20(%rbp), %rax
movzwl %cx, %edx
movzwl 0x138(%rax), %ecx
addl %edx, %ecx
movw %cx, 0x138(%rax)
jmp 0x2417b
leaq 0x44366(%rip), %rdi     # 0x684c9
leaq 0x45012(%rip), %rsi     # 0x6917c
movl $0xfc, %edx
leaq 0x4507f(%rip), %rcx     # 0x691f5
callq 0xe240
addq $0x20, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)