// File: AnthonyCalandra[P]chip8-emu/src/cpu.cc
// Function: performCpuCycle(Registers&, MemoryStore&, Stack&)
void performCpuCycle(Registers& registers, MemoryStore& memory, Stack& stack) {
  unsigned short& pc = registers.getSpecialRegister("PC");
  unsigned short opcode = memory[pc] << 8 | memory[pc + 1];
  // Find instruction by using first 4 bits of opcode (identifier).
  auto instIter = instructionTable.find(opcode & 0xF000);
  if (instIter == instructionTable.cend()) {
    throw std::string("Unknown instruction.");
  } else {
    (instIter->second)(ChipContext(opcode, registers, memory, stack));
  }

  unsigned short& delayTimer = registers.getSpecialRegister("DT");
  if (delayTimer > 0) {
    delayTimer--;
  }

  unsigned short& soundTimer = registers.getSpecialRegister("ST");
  if (soundTimer > 0) {
    if (soundTimer == 1) {
      std::cout << "BEEP" << '\a' << std::endl;
    }

    soundTimer--;
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x170, %rsp            # imm = 0x170
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x108(%rbp)
leaq -0x41(%rbp), %rdi
movq %rdi, -0x100(%rbp)
callq 0x4560
movq -0x100(%rbp), %rdx
leaq 0xad62(%rip), %rsi      # 0x1c242
leaq -0x40(%rbp), %rdi
callq 0x4450
jmp 0x114eb
movq -0x108(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x10880
movq %rax, -0x110(%rbp)
jmp 0x11504
leaq -0x40(%rbp), %rdi
callq 0x45a8
leaq -0x41(%rbp), %rdi
callq 0x43d0
movq -0x110(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rax
movzwl (%rax), %eax
movl %eax, %esi
callq 0x10b10
movzbl (%rax), %eax
shll $0x8, %eax
movl %eax, -0x114(%rbp)
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rax
movzwl (%rax), %eax
addl $0x1, %eax
movslq %eax, %rsi
callq 0x10b10
movq %rax, %rcx
movl -0x114(%rbp), %eax
movzbl (%rcx), %ecx
orl %ecx, %eax
movw %ax, -0x56(%rbp)
movzwl -0x56(%rbp), %eax
andl $0xf000, %eax           # imm = 0xF000
movw %ax, -0x62(%rbp)
leaq 0x1ce6d(%rip), %rdi     # 0x2e3e8
leaq -0x62(%rbp), %rsi
callq 0x17d40
movq %rax, -0x60(%rbp)
leaq 0x1ce59(%rip), %rdi     # 0x2e3e8
callq 0x17da0
movq %rax, -0x70(%rbp)
leaq -0x60(%rbp), %rdi
leaq -0x70(%rbp), %rsi
callq 0x17d70
testb $0x1, %al
jne 0x115ae
jmp 0x11678
movb $0x1, -0x72(%rbp)
movl $0x20, %edi
callq 0x41a0
movq %rax, -0x128(%rbp)
movq %rax, -0x130(%rbp)
leaq -0x71(%rbp), %rdi
movq %rdi, -0x120(%rbp)
callq 0x4560
movq -0x128(%rbp), %rdi
movq -0x120(%rbp), %rdx
leaq 0xaecd(%rip), %rsi      # 0x1c4bc
callq 0x4450
jmp 0x115f6
movq -0x130(%rbp), %rdi
movb $0x0, -0x72(%rbp)
leaq 0x1a658(%rip), %rsi     # 0x2bc60
movq 0x1a989(%rip), %rdx     # 0x2bf98
callq 0x4540
jmp 0x118b9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
jmp 0x1163c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x45a8
leaq -0x41(%rbp), %rdi
callq 0x43d0
jmp 0x118b0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0x71(%rbp), %rdi
callq 0x43d0
testb $0x1, -0x72(%rbp)
jne 0x11667
jmp 0x11673
movq -0x130(%rbp), %rdi
callq 0x4280
jmp 0x118b0
leaq -0x60(%rbp), %rdi
callq 0x17dd0
addq $0x8, %rax
movq %rax, -0x138(%rbp)
movw -0x56(%rbp), %ax
movq -0x8(%rbp), %rdx
movq -0x10(%rbp), %rcx
movq -0x18(%rbp), %r8
leaq -0x98(%rbp), %rdi
movzwl %ax, %esi
callq 0x17e40
movq -0x138(%rbp), %rdi
leaq -0x98(%rbp), %rsi
callq 0x17e00
movq -0x8(%rbp), %rax
movq %rax, -0x148(%rbp)
leaq -0xc1(%rbp), %rdi
movq %rdi, -0x140(%rbp)
callq 0x4560
movq -0x140(%rbp), %rdx
leaq 0xab5d(%rip), %rsi      # 0x1c247
leaq -0xc0(%rbp), %rdi
callq 0x4450
jmp 0x116f8
movq -0x148(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0x10880
movq %rax, -0x150(%rbp)
jmp 0x11714
leaq -0xc0(%rbp), %rdi
callq 0x45a8
leaq -0xc1(%rbp), %rdi
callq 0x43d0
movq -0x150(%rbp), %rax
movq %rax, -0xa0(%rbp)
movq -0xa0(%rbp), %rax
movzwl (%rax), %eax
cmpl $0x0, %eax
jle 0x11793
movq -0xa0(%rbp), %rax
movw (%rax), %cx
addw $-0x1, %cx
movw %cx, (%rax)
jmp 0x11793
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
jmp 0x11782
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0xc0(%rbp), %rdi
callq 0x45a8
leaq -0xc1(%rbp), %rdi
callq 0x43d0
jmp 0x118b0
movq -0x8(%rbp), %rax
movq %rax, -0x160(%rbp)
leaq -0xf1(%rbp), %rdi
movq %rdi, -0x158(%rbp)
callq 0x4560
movq -0x158(%rbp), %rdx
leaq 0xaa8b(%rip), %rsi      # 0x1c24a
leaq -0xf0(%rbp), %rdi
callq 0x4450
jmp 0x117cd
movq -0x160(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0x10880
movq %rax, -0x168(%rbp)
jmp 0x117e9
leaq -0xf0(%rbp), %rdi
callq 0x45a8
leaq -0xf1(%rbp), %rdi
callq 0x43d0
movq -0x168(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq -0xd0(%rbp), %rax
movzwl (%rax), %eax
cmpl $0x0, %eax
jle 0x118a7
movq -0xd0(%rbp), %rax
movzwl (%rax), %eax
cmpl $0x1, %eax
jne 0x11896
movq 0x1a790(%rip), %rdi     # 0x2bfc8
leaq 0xac92(%rip), %rsi      # 0x1c4d1
callq 0x4380
movq %rax, %rdi
movl $0x7, %esi
callq 0x4400
movq %rax, %rdi
movq 0x1a72d(%rip), %rsi     # 0x2bf88
callq 0x43c0
jmp 0x11896
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
jmp 0x11888
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0xf0(%rbp), %rdi
callq 0x45a8
leaq -0xf1(%rbp), %rdi
callq 0x43d0
jmp 0x118b0
movq -0xd0(%rbp), %rax
movw (%rax), %cx
addw $-0x1, %cx
movw %cx, (%rax)
addq $0x170, %rsp            # imm = 0x170
popq %rbp
retq
movq -0x50(%rbp), %rdi
callq 0x4550
nopl (%rax)