// File: Ciaxur[P]yagb-emu/src/CPU.cc
// Function: CPU::handleInterrupt()
void CPU::handleInterrupt() {
  if (this->IME) {
    std::cout << "CPU INTERRUPTED!\n";

    // Memory Registers Required
    uint8_t IE = this->memory.read(0xFFFF);
    uint8_t IF = this->memory.read(0xFF0F);
    uint8_t IH = (IE & IF) & 0x1F;

    // Least Significant bit gets highest priority
    if (IH & 0x01) {          // Bit0: V-Blank
      // Basically CALL without the offset
      this->PUSH(&PC);
      PC = 0x0040;

      // Consume CPU Cycles + 2 (internal timing NOPs)
      cyclesLeft -= 5;
      updateTimers(5);

      // Unset Handled Bit
      IF &= ~0x01;

      // Dispatch Handled
      IME = false;
    } else if (IH & 0x02) {   // Bit1: LCD STAT
      this->PUSH(&PC);
      PC = 0x0048;
      cyclesLeft -= 5;
      updateTimers(5);
      IF &= ~0x02;
      IME = false;
    } else if (IH & 0x04) {   // Bit2: Timer
      this->PUSH(&PC);
      PC = 0x0050;
      cyclesLeft -= 5;
      updateTimers(5);
      IF &= ~0x04;
      IME = false;
    } else if (IH & 0x08) {   // Bit3: Serial
      this->PUSH(&PC);
      PC = 0x0058;
      cyclesLeft -= 5;
      updateTimers(5);
      IF &= ~0x08;
      IME = false;
    } else if (IH & 0x10) {   // Bit4: Joypad
      this->PUSH(&PC);
      PC = 0x0060;
      cyclesLeft -= 5;
      updateTimers(5);
      IF &= ~0x10;
      IME = false;
    }

    // Update IF
    this->memory.write(0xFF0F, IF);
  }

  // Check IME Delayed Enable (EI)
  else if (delayed_IME) {
    delayed_IME = false;
    IME = true;
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x20, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x18(%rbp)
testb $0x1, 0x128(%rax)
je 0x4a97c
movq 0x1c3798(%rip), %rdi    # 0x20def0
leaq 0x1276b2(%rip), %rsi    # 0x171e11
callq 0xd5c0
movq -0x18(%rbp), %rdi
addq $0x130, %rdi            # imm = 0x130
movl $0xffff, %esi           # imm = 0xFFFF
callq 0xbc0c0
movq -0x18(%rbp), %rdi
movb %al, -0x9(%rbp)
addq $0x130, %rdi            # imm = 0x130
movl $0xff0f, %esi           # imm = 0xFF0F
callq 0xbc0c0
movb %al, -0xa(%rbp)
movzbl -0x9(%rbp), %eax
movzbl -0xa(%rbp), %ecx
andl %ecx, %eax
andl $0x1f, %eax
movb %al, -0xb(%rbp)
movzbl -0xb(%rbp), %eax
andl $0x1, %eax
cmpl $0x0, %eax
je 0x4a7fd
movq -0x18(%rbp), %rdi
movq %rdi, %rsi
addq $0x12c, %rsi            # imm = 0x12C
callq 0xbae20
movq -0x18(%rbp), %rdi
movw $0x40, 0x12c(%rdi)
movl 0x8(%rdi), %eax
subl $0x5, %eax
movl %eax, 0x8(%rdi)
movl $0x5, %esi
callq 0x4c6d0
movq -0x18(%rbp), %rax
movzbl -0xa(%rbp), %ecx
andl $-0x2, %ecx
movb %cl, -0xa(%rbp)
movb $0x0, 0x128(%rax)
jmp 0x4a961
movzbl -0xb(%rbp), %eax
andl $0x2, %eax
cmpl $0x0, %eax
je 0x4a856
movq -0x18(%rbp), %rdi
movq %rdi, %rsi
addq $0x12c, %rsi            # imm = 0x12C
callq 0xbae20
movq -0x18(%rbp), %rdi
movw $0x48, 0x12c(%rdi)
movl 0x8(%rdi), %eax
subl $0x5, %eax
movl %eax, 0x8(%rdi)
movl $0x5, %esi
callq 0x4c6d0
movq -0x18(%rbp), %rax
movzbl -0xa(%rbp), %ecx
andl $-0x3, %ecx
movb %cl, -0xa(%rbp)
movb $0x0, 0x128(%rax)
jmp 0x4a95f
movzbl -0xb(%rbp), %eax
andl $0x4, %eax
cmpl $0x0, %eax
je 0x4a8af
movq -0x18(%rbp), %rdi
movq %rdi, %rsi
addq $0x12c, %rsi            # imm = 0x12C
callq 0xbae20
movq -0x18(%rbp), %rdi
movw $0x50, 0x12c(%rdi)
movl 0x8(%rdi), %eax
subl $0x5, %eax
movl %eax, 0x8(%rdi)
movl $0x5, %esi
callq 0x4c6d0
movq -0x18(%rbp), %rax
movzbl -0xa(%rbp), %ecx
andl $-0x5, %ecx
movb %cl, -0xa(%rbp)
movb $0x0, 0x128(%rax)
jmp 0x4a95d
movzbl -0xb(%rbp), %eax
andl $0x8, %eax
cmpl $0x0, %eax
je 0x4a905
movq -0x18(%rbp), %rdi
movq %rdi, %rsi
addq $0x12c, %rsi            # imm = 0x12C
callq 0xbae20
movq -0x18(%rbp), %rdi
movw $0x58, 0x12c(%rdi)
movl 0x8(%rdi), %eax
subl $0x5, %eax
movl %eax, 0x8(%rdi)
movl $0x5, %esi
callq 0x4c6d0
movq -0x18(%rbp), %rax
movzbl -0xa(%rbp), %ecx
andl $-0x9, %ecx
movb %cl, -0xa(%rbp)
movb $0x0, 0x128(%rax)
jmp 0x4a95b
movzbl -0xb(%rbp), %eax
andl $0x10, %eax
cmpl $0x0, %eax
je 0x4a959
movq -0x18(%rbp), %rdi
movq %rdi, %rsi
addq $0x12c, %rsi            # imm = 0x12C
callq 0xbae20
movq -0x18(%rbp), %rdi
movw $0x60, 0x12c(%rdi)
movl 0x8(%rdi), %eax
subl $0x5, %eax
movl %eax, 0x8(%rdi)
movl $0x5, %esi
callq 0x4c6d0
movq -0x18(%rbp), %rax
movzbl -0xa(%rbp), %ecx
andl $-0x11, %ecx
movb %cl, -0xa(%rbp)
movb $0x0, 0x128(%rax)
jmp 0x4a95b
jmp 0x4a95d
jmp 0x4a95f
jmp 0x4a961
movq -0x18(%rbp), %rdi
addq $0x130, %rdi            # imm = 0x130
movl $0xff0f, %esi           # imm = 0xFF0F
movzbl -0xa(%rbp), %edx
callq 0xbc150
jmp 0x4a99d
movq -0x18(%rbp), %rax
testb $0x1, 0x129(%rax)
je 0x4a99b
movq -0x18(%rbp), %rax
movb $0x0, 0x129(%rax)
movb $0x1, 0x128(%rax)
jmp 0x4a99d
addq $0x20, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)