// File: Ciaxur[P]yagb-emu/src/CPU.cc
// Function: CPU::updateTimers(unsigned char)
void CPU::updateTimers(uint8_t cyclesPassed) {
  // Keep track of Cycles passed for each of the Timers
  this->timerCycles.div += cyclesPassed;

  // Get TAC Configuration
  uint8_t TAC = this->memory.read(0xFF07);


  if (this->timerCycles.div >= 64) {
    uint8_t DIV = this->memory.read(0xFF04);
    memory.memory[0xFF04] = ++DIV;
    this->timerCycles.div -= 64;
  }



  // TAC-Enabled, Tick TIMA
  // TODO: Figure out what happens if TAC changes interval while TAC enabled.
  if (TAC & (1 << 2)) {
    this->timerCycles.tima += cyclesPassed;
    uint8_t TIMA_OLD = this->memory.read(0xFF05);
    uint8_t TIMA = TIMA_OLD;

    switch (TAC & 0x03) {
      case 0x00:
        if (timerCycles.tima >= 256) {
          TIMA++;
          timerCycles.tima -= 256;
        }
        break;
      case 0x01:
        if (timerCycles.tima >= 4) {
          TIMA++;
          timerCycles.tima -= 4;
        }
        break;
      case 0x10:
        if (timerCycles.tima >= 16) {
          TIMA++;
          timerCycles.tima -= 16;
        }
        break;
      case 0x11:
        if (timerCycles.tima >= 64) {
          TIMA++;
          timerCycles.tima -= 64;
        }
        break;
    }

    // CHECK IF OVERFLOW
    if (TIMA < TIMA_OLD) {
      // Request Timer Interrupt
      uint8_t IF = this->memory.read(0xFF0F);
      this->memory.write(0xFF0F, IF |= 0x04);

      // Set TIMA = TAC
      TIMA = this->memory.read(0xFF06);
    }


    this->memory.write(0xFF05, TIMA);
  }


}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x20, %rsp
movb %sil, %al
movq %rdi, -0x8(%rbp)
movb %al, -0x9(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0x18(%rbp)
movzbl -0x9(%rbp), %eax
addl 0x120(%rdi), %eax
movl %eax, 0x120(%rdi)
addq $0x130, %rdi            # imm = 0x130
movl $0xff07, %esi           # imm = 0xFF07
callq 0xbc0c0
movb %al, %cl
movq -0x18(%rbp), %rax
movb %cl, -0xa(%rbp)
cmpl $0x40, 0x120(%rax)
jb 0x4c759
movq -0x18(%rbp), %rdi
addq $0x130, %rdi            # imm = 0x130
movl $0xff04, %esi           # imm = 0xFF04
callq 0xbc0c0
movb %al, %cl
movq -0x18(%rbp), %rax
movb %cl, -0xb(%rbp)
movb -0xb(%rbp), %cl
addb $0x1, %cl
movb %cl, -0xb(%rbp)
movb %cl, 0x10054(%rax)
movl 0x120(%rax), %ecx
subl $0x40, %ecx
movl %ecx, 0x120(%rax)
movzbl -0xa(%rbp), %eax
andl $0x4, %eax
cmpl $0x0, %eax
je 0x4c8ef
movq -0x18(%rbp), %rdi
movzbl -0x9(%rbp), %ecx
movl 0x124(%rdi), %eax
addl %ecx, %eax
movl %eax, 0x124(%rdi)
addq $0x130, %rdi            # imm = 0x130
movl $0xff05, %esi           # imm = 0xFF05
callq 0xbc0c0
movb %al, -0xc(%rbp)
movb -0xc(%rbp), %al
movb %al, -0xd(%rbp)
movzbl -0xa(%rbp), %eax
andl $0x3, %eax
movl %eax, %ecx
movq %rcx, -0x20(%rbp)
subl $0x11, %eax
ja 0x4c878
movq -0x20(%rbp), %rax
leaq 0x11e84a(%rip), %rcx    # 0x16b004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x18(%rbp), %rax
cmpl $0x100, 0x124(%rax)     # imm = 0x100
jb 0x4c7f2
movq -0x18(%rbp), %rax
movb -0xd(%rbp), %cl
addb $0x1, %cl
movb %cl, -0xd(%rbp)
movl 0x124(%rax), %ecx
subl $0x100, %ecx            # imm = 0x100
movl %ecx, 0x124(%rax)
jmp 0x4c878
movq -0x18(%rbp), %rax
cmpl $0x4, 0x124(%rax)
jb 0x4c820
movq -0x18(%rbp), %rax
movb -0xd(%rbp), %cl
addb $0x1, %cl
movb %cl, -0xd(%rbp)
movl 0x124(%rax), %ecx
subl $0x4, %ecx
movl %ecx, 0x124(%rax)
jmp 0x4c878
movq -0x18(%rbp), %rax
cmpl $0x10, 0x124(%rax)
jb 0x4c84b
movq -0x18(%rbp), %rax
movb -0xd(%rbp), %cl
addb $0x1, %cl
movb %cl, -0xd(%rbp)
movl 0x124(%rax), %ecx
subl $0x10, %ecx
movl %ecx, 0x124(%rax)
jmp 0x4c878
movq -0x18(%rbp), %rax
cmpl $0x40, 0x124(%rax)
jb 0x4c876
movq -0x18(%rbp), %rax
movb -0xd(%rbp), %cl
addb $0x1, %cl
movb %cl, -0xd(%rbp)
movl 0x124(%rax), %ecx
subl $0x40, %ecx
movl %ecx, 0x124(%rax)
jmp 0x4c878
movzbl -0xd(%rbp), %eax
movzbl -0xc(%rbp), %ecx
cmpl %ecx, %eax
jge 0x4c8d6
movq -0x18(%rbp), %rdi
addq $0x130, %rdi            # imm = 0x130
movl $0xff0f, %esi           # imm = 0xFF0F
callq 0xbc0c0
movq -0x18(%rbp), %rdi
movb %al, -0xe(%rbp)
addq $0x130, %rdi            # imm = 0x130
movzbl -0xe(%rbp), %eax
orl $0x4, %eax
movb %al, -0xe(%rbp)
movl $0xff0f, %esi           # imm = 0xFF0F
movzbl %al, %edx
callq 0xbc150
movq -0x18(%rbp), %rdi
addq $0x130, %rdi            # imm = 0x130
movl $0xff06, %esi           # imm = 0xFF06
callq 0xbc0c0
movb %al, -0xd(%rbp)
movq -0x18(%rbp), %rdi
addq $0x130, %rdi            # imm = 0x130
movl $0xff05, %esi           # imm = 0xFF05
movzbl -0xd(%rbp), %edx
callq 0xbc150
addq $0x20, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)