gameboy wormboy manboy gameworm gameman wormgame mangame manworm

Dependencies:   mbed SDFileSystem2

Revision:
17:c9afe1a7b423
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cpu.cpp	Sun Jan 13 19:00:10 2019 +0000
@@ -0,0 +1,2921 @@
+// Implementation of OPCODES and cpu step function
+
+#define NDEBUG
+#include <assert.h>
+
+#include "cpu.h"
+#include "mem.h"
+
+// cpu registers, halted state, and timers
+CpuState globalState;
+
+typedef void OpcodeHandler(u8 opcode);
+
+// the GB has several invalid opcodes
+void invHandler(u8 opcode) {
+  printf("got invalid opcode 0x%x\n", opcode);
+  assert(false);
+}
+
+////////////////////////////////
+// CB Opcode Helper Functions //
+////////////////////////////////
+
+u8 rlcReg(u8 value, bool isA) {
+  u8 result = value;
+  clearAllFlags();
+  if((result & 0x80) != 0) {
+    setCarryFlag();
+    result <<= 1;
+    result |= 0x1;
+  } else {
+    result <<= 1;
+  }
+  if(!isA) {
+    if((u8)result == 0) {
+      setZeroFlag();
+    }
+  }
+  return result;
+}
+
+u8 rlReg(u8 value, bool isA) {
+  u8 carry = getCarryFlag() ? (u8)1 : (u8)0;
+  u8 result = value;
+  clearAllFlags();
+  if((result & 0x80) != 0) {
+    setCarryFlag();
+  }
+  result <<= 1;
+  result |= carry;
+  if(!isA) {
+    if((u8)result == 0) {
+      setZeroFlag();
+    }
+  }
+  return result;
+}
+
+u8 rrc(u8 value, bool isA) {
+  u8 result = value;
+  clearAllFlags();
+  if((result & 1) != 0) {
+    setCarryFlag();
+    result >>= 1;
+    result |= 0x80;
+  } else {
+    result >>= 1;
+  }
+  if(!isA) {
+    if((u8)result == 0) {
+      setZeroFlag();
+    }
+  }
+  return result;
+}
+
+u8 rr(u8 value, bool isA) {
+  u8 carry = getCarryFlag() ? (u8)0x80 : (u8)0x00;
+  u8 result = value;
+  clearAllFlags();
+  if((result & 1) != 0) {
+    setCarryFlag();
+  }
+  result >>= 1;
+  result |= carry;
+  if(!isA) {
+    if((u8)result == 0) {
+      setZeroFlag();
+    }
+  }
+  return result;
+}
+
+u8 srl(u8 value) {
+  u8 result = value;
+  clearAllFlags();
+  if(result & 1) {
+    setCarryFlag();
+  }
+  result >>= 1;
+  if(result == 0) {
+    setZeroFlag();
+  }
+  return result;
+}
+
+u8 sla(u8 value) {
+  clearAllFlags();
+  if(value & 0x80) {
+    setCarryFlag();
+  }
+  u8 result = value << 1;
+  if(result == 0) {
+    setZeroFlag();
+  }
+  return result;
+}
+
+u8 sra(u8 value) {
+  u8 result = value;
+  clearAllFlags();
+  if(result & 1) {
+    setCarryFlag();
+  }
+  if((result & 0x80)) {
+    result >>= 1;
+    result |= 0x80;
+  } else {
+    result >>= 1;
+  }
+  if(result == 0) {
+    setZeroFlag();
+  }
+  return result;
+}
+
+u8 swapRegister(u8 value) {
+  u8 low = value & 0xf;
+  u8 hi = (value >> 4) & 0xf;
+  u8 result = (low << 4) + hi;
+  clearAllFlags();
+  if((u8)result == 0) {
+    setZeroFlag();
+  }
+  return result;
+}
+
+
+////////////////////////////////
+// CB Opcodes                 //
+////////////////////////////////
+
+void SLA_A(u8 opcode) { // 0x27
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = sla(globalState.a);
+}
+
+void SLA_B(u8 opcode) { // 0x20
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.hi = sla(globalState.bc.hi);
+}
+
+void SLA_C(u8 opcode) { // 0x21
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.lo = sla(globalState.bc.lo);
+}
+
+void SLA_D(u8 opcode) { // 0x22
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.hi = sla(globalState.de.hi);
+}
+
+void SLA_E(u8 opcode) { // 0x23
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.lo = sla(globalState.de.lo);
+}
+
+void SLA_H(u8 opcode) { // 0x24
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.hi = sla(globalState.hl.hi);
+}
+
+void SLA_L(u8 opcode) { // 0x25
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.lo = sla(globalState.hl.lo);
+}
+
+void SLA_DHL(u8 opcode) { // 0x26
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  writeByte(sla(readByte(globalState.hl.v)), globalState.hl.v);
+}
+
+void SRA_A(u8 opcode) { // 0x2f
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = sra(globalState.a);
+}
+
+void SRA_B(u8 opcode) { // 0x28
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.hi = sra(globalState.bc.hi);
+}
+
+void SRA_C(u8 opcode) { // 0x29
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.lo = sra(globalState.bc.lo);
+}
+
+void SRA_D(u8 opcode) { // 0x2a
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.hi = sra(globalState.de.hi);
+}
+
+void SRA_E(u8 opcode) { // 0x2b
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.lo = sra(globalState.de.lo);
+}
+
+void SRA_H(u8 opcode) { // 0x2c
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.hi = sra(globalState.hl.hi);
+}
+
+void SRA_L(u8 opcode) { // 0x2d
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.lo = sra(globalState.hl.lo);
+}
+
+void SRA_DHL(u8 opcode) { // 0x2e
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  writeByte(sra(readByte(globalState.hl.v)), globalState.hl.v);
+}
+
+
+void SRL_A(u8 opcode) { // 0x3f
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = srl(globalState.a);
+}
+
+void SRL_B(u8 opcode) { // 0x38
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.hi = srl(globalState.bc.hi);
+}
+
+void SRL_C(u8 opcode) { // 0x39
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.lo = srl(globalState.bc.lo);
+}
+
+void SRL_D(u8 opcode) { // 0x3a
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.hi = srl(globalState.de.hi);
+}
+
+void SRL_E(u8 opcode) { // 0x3b
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.lo = srl(globalState.de.lo);
+}
+
+void SRL_H(u8 opcode) { // 0x3c
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.hi = srl(globalState.hl.hi);
+}
+
+void SRL_L(u8 opcode) { // 0x3d
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.lo = srl(globalState.hl.lo);
+}
+
+void SRL_DHL(u8 opcode) { // 0x3e
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  writeByte(srl(readByte(globalState.hl.v)), globalState.hl.v);
+}
+
+void RR_A(u8 opcode) { // 0x1f
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = rr(globalState.a, false);
+}
+
+void RR_B(u8 opcode) { // 0x18
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.hi = rr(globalState.bc.hi, false);
+}
+
+void RR_C(u8 opcode) { // 0x19
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.lo = rr(globalState.bc.lo, false);
+}
+
+void RR_D(u8 opcode) { // 0x1a
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.hi = rr(globalState.de.hi, false);
+}
+
+void RR_E(u8 opcode) { // 0x1b
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.lo = rr(globalState.de.lo, false);
+}
+
+void RR_H(u8 opcode) { // 0x1c
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.hi = rr(globalState.hl.hi, false);
+}
+
+void RR_L(u8 opcode) { // 0x1d
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.lo = rr(globalState.hl.lo, false);
+}
+
+void RR_DHL(u8 opcode) { // 0x1e
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  writeByte(rr(readByte(globalState.hl.v), false), globalState.hl.v);
+}
+
+void RL_A(u8 opcode) { // 0x17
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = rlReg(globalState.a, false);
+}
+
+void RL_B(u8 opcode) { // 0x10
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.hi = rlReg(globalState.bc.hi, false);
+}
+
+void RL_C(u8 opcode) { // 0x11
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.lo = rlReg(globalState.bc.lo, false);
+}
+
+void RL_D(u8 opcode) { // 0x12
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.hi = rlReg(globalState.de.hi, false);
+}
+
+void RL_E(u8 opcode) { // 0x13
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.lo = rlReg(globalState.de.lo, false);
+}
+
+void RL_H(u8 opcode) { // 0x14
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.hi = rlReg(globalState.hl.hi, false);
+}
+
+void RL_L(u8 opcode) { // 0x15
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.lo = rlReg(globalState.hl.lo, false);
+}
+
+void RL_DHL(u8 opcode) { // 0x16
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  writeByte(rlReg(readByte(globalState.hl.v), false), globalState.hl.v);
+}
+
+void SWAP_A(u8 opcode) { // 37
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = swapRegister(globalState.a);
+}
+
+void SWAP_B(u8 opcode) { // 30
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.hi = swapRegister(globalState.bc.hi);
+}
+
+void SWAP_C(u8 opcode) { // 31
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.lo = swapRegister(globalState.bc.lo);
+}
+
+void SWAP_D(u8 opcode) { // 32
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.hi = swapRegister(globalState.de.hi);
+}
+
+void SWAP_E(u8 opcode) { // 33
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.lo = swapRegister(globalState.de.lo);
+}
+
+void SWAP_H(u8 opcode) { // 34
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.hi = swapRegister(globalState.hl.hi);
+}
+
+void SWAP_L(u8 opcode) { // 35
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.lo = swapRegister(globalState.hl.lo);
+}
+
+void SWAP_DHL(u8 opcode) { // 36
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  writeByte(swapRegister(readByte(globalState.hl.v)), globalState.hl.v);
+}
+
+void RLC_A(u8 opcode) { // 07
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = rlcReg(globalState.a, false);
+}
+
+void RLC_B(u8 opcode) { // 00
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.hi = rlcReg(globalState.bc.hi, false);
+}
+
+void RLC_C(u8 opcode) { // 01
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.lo = rlcReg(globalState.bc.lo, false);
+}
+
+void RLC_D(u8 opcode) { // 02
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.hi = rlcReg(globalState.de.hi, false);
+}
+
+void RLC_E(u8 opcode) { // 03
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.lo = rlcReg(globalState.de.lo, false);
+}
+
+void RLC_H(u8 opcode) { // 04
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.hi = rlcReg(globalState.hl.hi, false);
+}
+
+void RLC_L(u8 opcode) { // 05
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.lo = rlcReg(globalState.hl.lo, false);
+}
+
+void RLC_DHL(u8 opcode) { // 06
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  u8 result = rlcReg(readByte(globalState.hl.v), false);
+  writeByte(result, globalState.hl.v);
+}
+
+
+void RRC_A(u8 opcode) { // 0f
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = rrc(globalState.a, false);
+}
+
+void RRC_B(u8 opcode) { // 08
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.hi = rrc(globalState.bc.hi, false);
+}
+
+void RRC_C(u8 opcode) { // 09
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.lo = rrc(globalState.bc.lo, false);
+}
+
+void RRC_D(u8 opcode) { // 0a
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.hi = rrc(globalState.de.hi, false);
+}
+
+void RRC_E(u8 opcode) { // 0b
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.lo = rrc(globalState.de.lo, false);
+}
+
+void RRC_H(u8 opcode) { // 0c
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.hi = rrc(globalState.hl.hi, false);
+}
+
+void RRC_L(u8 opcode) { // 0d
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.lo = rrc(globalState.hl.lo, false);
+}
+
+void RRC_DHL(u8 opcode) { // 0e
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  u8 result = rrc(readByte(globalState.hl.v), false);
+  writeByte(result, globalState.hl.v);
+}
+
+
+void bit_B_set(u8 opcode) {
+  u8 bitID = (opcode - (u8)0xC0) >> 3;
+  assert(bitID < 8);
+  globalState.bc.hi |= (1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_C_set(u8 opcode) {
+  u8 bitID = (opcode - (u8)0xC1) >> 3;
+  assert(bitID < 8);
+  globalState.bc.lo |= (1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_D_set(u8 opcode) {
+  u8 bitID = (opcode - (u8)0xC2) >> 3;
+  assert(bitID < 8);
+  globalState.de.hi |= (1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_E_set(u8 opcode) {
+  u8 bitID = (opcode - (u8)0xC3) >> 3;
+  assert(bitID < 8);
+  globalState.de.lo |= (1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_H_set(u8 opcode) {
+  u8 bitID = (opcode - (u8)0xC4) >> 3;
+  assert(bitID < 8);
+  globalState.hl.hi |= (1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_L_set(u8 opcode) {
+  u8 bitID = (opcode - (u8)0xC5) >> 3;
+  assert(bitID < 8);
+  globalState.hl.lo |= (1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_DHL_set(u8 opcode) {
+  u8 bitID = (opcode - (u8)0xC6) >> 3;
+  assert(bitID < 8);
+  u8 value = readByte(globalState.hl.v);
+  value |= (1 << bitID);
+  writeByte(value, globalState.hl.v);
+  globalState.pc += 1;
+  globalState.cycleCount += 16;
+}
+
+void bit_A_set(u8 opcode) {
+  u8 bitID = (opcode - (u8)0xC7) >> 3;
+  assert(bitID < 8);
+  globalState.a |= (1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_B_res(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x80) >> 3;
+  assert(bitID < 8);
+  globalState.bc.hi &= ~(1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_C_res(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x81) >> 3;
+  assert(bitID < 8);
+  globalState.bc.lo &= ~(1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_D_res(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x82) >> 3;
+  assert(bitID < 8);
+  globalState.de.hi &= ~(1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_E_res(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x83) >> 3;
+  assert(bitID < 8);
+  globalState.de.lo &= ~(1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_H_res(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x84) >> 3;
+  assert(bitID < 8);
+  globalState.hl.hi &= ~(1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_L_res(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x85) >> 3;
+  assert(bitID < 8);
+  globalState.hl.lo &= ~(1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_DHL_res(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x86) >> 3;
+  assert(bitID < 8);
+  u8 value = readByte(globalState.hl.v);
+  value &= ~(1 << bitID);
+  writeByte(value, globalState.hl.v);
+  globalState.pc += 1;
+  globalState.cycleCount += 16;
+}
+
+void bit_A_res(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x87) >> 3;
+  assert(bitID < 8);
+  globalState.a &= ~(1 << bitID);
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_A_test(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x47) >> 3;
+  assert(bitID < 8);
+  //printf("check bit %d of A\n", bitID);
+  u8 val = globalState.a;
+  if(((val >> bitID) & 1) == 0) {
+    setZeroFlag();
+  } else {
+    clearZeroFlag();
+  }
+  setHalfCarryFlag();
+  clearSubtractFlag();
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_B_test(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x40) >> 3;
+  //printf("B opcode 0x%x bitId %d\n", opcode, bitID);
+  assert(bitID < 8);
+  //printf("check bit %d of B\n", bitID);
+  u8 val = globalState.bc.hi;
+  if(((val >> bitID) & 1) == 0) {
+    setZeroFlag();
+  } else {
+    clearZeroFlag();
+  }
+  setHalfCarryFlag();
+  clearSubtractFlag();
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+
+void bit_C_test(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x41) >> 3;
+  assert(bitID < 8);
+  //printf("check bit %d of C\n", bitID);
+  u8 val = globalState.bc.lo;
+  if(((val >> bitID) & 1) == 0) {
+    setZeroFlag();
+  } else {
+    clearZeroFlag();
+  }
+  setHalfCarryFlag();
+  clearSubtractFlag();
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_D_test(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x42) >> 3;
+  assert(bitID < 8);
+  //printf("check bit %d of D\n", bitID);
+  u8 val = globalState.de.hi;
+  if(((val >> bitID) & 1) == 0) {
+    setZeroFlag();
+  } else {
+    clearZeroFlag();
+  }
+  setHalfCarryFlag();
+  clearSubtractFlag();
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_E_test(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x43) >> 3;
+  assert(bitID < 8);
+  //printf("check bit %d of E\n", bitID);
+  u8 val = globalState.de.lo;
+  if(((val >> bitID) & 1) == 0) {
+    setZeroFlag();
+  } else {
+    clearZeroFlag();
+  }
+  setHalfCarryFlag();
+  clearSubtractFlag();
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_H_test(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x44) >> 3;
+  assert(bitID < 8);
+  //printf("check bit %d of H\n", bitID);
+  u8 val = globalState.hl.hi;
+  if(((val >> bitID) & 1) == 0) {
+    setZeroFlag();
+  } else {
+    clearZeroFlag();
+  }
+  setHalfCarryFlag();
+  clearSubtractFlag();
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_L_test(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x45) >> 3;
+  assert(bitID < 8);
+  //printf("check bit %d of L\n", bitID);
+  u8 val = globalState.hl.lo;
+  if(((val >> bitID) & 1) == 0) {
+    setZeroFlag();
+  } else {
+    clearZeroFlag();
+  }
+  setHalfCarryFlag();
+  clearSubtractFlag();
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+void bit_DHL_test(u8 opcode) {
+  u8 bitID = (opcode - (u8)0x45) >> 3;
+  assert(bitID < 8);
+  //printf("check bit %d of L\n", bitID);
+  u8 val = readByte(globalState.hl.v);
+  if(((val >> bitID) & 1) == 0) {
+    setZeroFlag();
+  } else {
+    clearZeroFlag();
+  }
+  setHalfCarryFlag();
+  clearSubtractFlag();
+  globalState.pc += 1;
+  globalState.cycleCount += 16;
+}
+
+// CB-prefixed opcode handler table
+static OpcodeHandler* opcode_cbs[256] =
+        {RLC_B,          RLC_C,          RLC_D,          RLC_E,          RLC_H,          RLC_L,          RLC_DHL,        RLC_A,          // 0x0 - 0x7
+         RRC_B,          RRC_C,          RRC_D,          RRC_E,          RRC_H,          RRC_L,          RRC_DHL,        RRC_A,          // 0x8 - 0xf
+         RL_B,           RL_C,           RL_D,           RL_E,           RL_H,           RL_L,           RL_DHL,         RL_A,           // 0x10 - 0x17
+         RR_B,           RR_C,           RR_D,           RR_E,           RR_H,           RR_L,           RR_DHL,         RR_A,           // 0x18 - 0x1f
+         SLA_B,          SLA_C,          SLA_D,          SLA_E,          SLA_H,          SLA_L,          SLA_DHL,        SLA_A,          // 0x20 - 0x27
+         SRA_B,          SRA_C,          SRA_D,          SRA_E,          SRA_H,          SRA_L,          SRA_DHL,        SRA_A,          // 0x28 - 0x2f
+         SWAP_B,         SWAP_C,         SWAP_D,         SWAP_E,         SWAP_H,         SWAP_L,         SWAP_DHL,       SWAP_A,         // 0x30 - 0x37
+         SRL_B,          SRL_C,          SRL_D,          SRL_E,          SRL_H,          SRL_L,          SRL_DHL,        SRL_A,          // 0x38 - 0x3f
+         bit_B_test,     bit_C_test,     bit_D_test,     bit_E_test,     bit_H_test,     bit_L_test,     bit_DHL_test,   bit_A_test,     // 0x40 - 0x47
+         bit_B_test,     bit_C_test,     bit_D_test,     bit_E_test,     bit_H_test,     bit_L_test,     bit_DHL_test,   bit_A_test,     // 0x48 - 0x4f
+         bit_B_test,     bit_C_test,     bit_D_test,     bit_E_test,     bit_H_test,     bit_L_test,     bit_DHL_test,   bit_A_test,     // 0x50 - 0x57
+         bit_B_test,     bit_C_test,     bit_D_test,     bit_E_test,     bit_H_test,     bit_L_test,     bit_DHL_test,   bit_A_test,     // 0x58 - 0x5f
+         bit_B_test,     bit_C_test,     bit_D_test,     bit_E_test,     bit_H_test,     bit_L_test,     bit_DHL_test,   bit_A_test,     // 0x60 - 0x67
+         bit_B_test,     bit_C_test,     bit_D_test,     bit_E_test,     bit_H_test,     bit_L_test,     bit_DHL_test,   bit_A_test,     // 0x68 - 0x6f
+         bit_B_test,     bit_C_test,     bit_D_test,     bit_E_test,     bit_H_test,     bit_L_test,     bit_DHL_test,   bit_A_test,     // 0x70 - 0x77
+         bit_B_test,     bit_C_test,     bit_D_test,     bit_E_test,     bit_H_test,     bit_L_test,     bit_DHL_test,   bit_A_test,     // 0x78 - 0x7f
+         bit_B_res,      bit_C_res,      bit_D_res,      bit_E_res,      bit_H_res,      bit_L_res,      bit_DHL_res,    bit_A_res,      // 0x80 - 0x8
+         bit_B_res,      bit_C_res,      bit_D_res,      bit_E_res,      bit_H_res,      bit_L_res,      bit_DHL_res,    bit_A_res,      // 0x88 - 0x8f
+         bit_B_res,      bit_C_res,      bit_D_res,      bit_E_res,      bit_H_res,      bit_L_res,      bit_DHL_res,    bit_A_res,      // 0x90 - 0x97
+         bit_B_res,      bit_C_res,      bit_D_res,      bit_E_res,      bit_H_res,      bit_L_res,      bit_DHL_res,    bit_A_res,      // 0x98 - 0x9f
+         bit_B_res,      bit_C_res,      bit_D_res,      bit_E_res,      bit_H_res,      bit_L_res,      bit_DHL_res,    bit_A_res,      // 0xa0 - 0xa7
+         bit_B_res,      bit_C_res,      bit_D_res,      bit_E_res,      bit_H_res,      bit_L_res,      bit_DHL_res,    bit_A_res,      // 0xa8 - 0xaf
+         bit_B_res,      bit_C_res,      bit_D_res,      bit_E_res,      bit_H_res,      bit_L_res,      bit_DHL_res,    bit_A_res,      // 0xb0 - 0xb7
+         bit_B_res,      bit_C_res,      bit_D_res,      bit_E_res,      bit_H_res,      bit_L_res,      bit_DHL_res,    bit_A_res,      // 0xb8 - 0xbf
+         bit_B_set,      bit_C_set,      bit_D_set,      bit_E_set,      bit_H_set,      bit_L_set,      bit_DHL_set,    bit_A_set     , // 0xc0 - 0xc7
+         bit_B_set,      bit_C_set,      bit_D_set,      bit_E_set,      bit_H_set,      bit_L_set,      bit_DHL_set,    bit_A_set     , // 0xc8 - 0xcf
+         bit_B_set,      bit_C_set,      bit_D_set,      bit_E_set,      bit_H_set,      bit_L_set,      bit_DHL_set,    bit_A_set     , // 0xd0 - 0xd7
+         bit_B_set,      bit_C_set,      bit_D_set,      bit_E_set,      bit_H_set,      bit_L_set,      bit_DHL_set,    bit_A_set     , // 0xd8 - 0xdf
+         bit_B_set,      bit_C_set,      bit_D_set,      bit_E_set,      bit_H_set,      bit_L_set,      bit_DHL_set,    bit_A_set     , // 0xe0 - 0xe7
+         bit_B_set,      bit_C_set,      bit_D_set,      bit_E_set,      bit_H_set,      bit_L_set,      bit_DHL_set,    bit_A_set     , // 0xe8 - 0xef
+         bit_B_set,      bit_C_set,      bit_D_set,      bit_E_set,      bit_H_set,      bit_L_set,      bit_DHL_set,    bit_A_set     , // 0xf0 - 0xf7
+         bit_B_set,      bit_C_set,      bit_D_set,      bit_E_set,      bit_H_set,      bit_L_set,      bit_DHL_set,    bit_A_set     }; // 0xf8 - 0xff
+
+
+////////////////////////////////
+// Opcodes                    //
+////////////////////////////////
+void LD_B_n(u8 opocde) { // 06
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.bc.hi = imm;
+  globalState.cycleCount += 8;
+}
+
+void LD_C_n(u8 opocde) { // 0E
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.bc.lo = imm;
+  globalState.cycleCount += 8;
+}
+
+void LD_D_n(u8 opocde) { // 16
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.de.hi = imm;
+  globalState.cycleCount += 8;
+}
+
+void LD_E_n(u8 opocde) { // 1e
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.de.lo = imm;
+  globalState.cycleCount += 8;
+}
+
+void LD_H_n(u8 opocde) { // 26
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.hl.hi = imm;
+  globalState.cycleCount += 8;
+}
+
+void LD_L_n(u8 opocde) { // 2e
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.hl.lo = imm;
+  globalState.cycleCount += 8;
+}
+
+// REGISTER-REGISTER LOADS (REGISTER A)
+void LD_A_A(u8 opcode) { // 0x7f
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.a = globalState.a;
+}
+
+void LD_A_B(u8 opcode) { // 0x78
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.a = globalState.bc.hi;
+}
+
+void LD_A_C(u8 opcode) { // 0x79
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.a = globalState.bc.lo;
+}
+
+void LD_A_D(u8 opcode) { // 0x7a
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.a = globalState.de.hi;
+}
+
+void LD_A_E(u8 opcode) { // 0x7b
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.a = globalState.de.lo;
+}
+
+void LD_A_H(u8 opcode) { // 0x7c
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.a = globalState.hl.hi;
+}
+
+void LD_A_L(u8 opcode) { // 0x7d
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.a = globalState.hl.lo;
+}
+
+void LD_A_DHL(u8 opcode) { // 0x7e
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = readByte(globalState.hl.v);
+}
+
+
+
+// REGISTER-REGISTER LOADS (REGISTER B)
+void LD_B_B(u8 opcode) { // 0x40
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.hi = globalState.bc.hi;
+}
+
+void LD_B_C(u8 opcode) { // 0x41
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.hi = globalState.bc.lo;
+}
+
+void LD_B_D(u8 opcode) { // 0x42
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.hi = globalState.de.hi;
+}
+
+void LD_B_E(u8 opcode) { // 0x43
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.hi = globalState.de.lo;
+}
+
+void LD_B_H(u8 opcode) { // 0x44
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.hi = globalState.hl.hi;
+}
+
+void LD_B_L(u8 opcode) { // 0x45
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.hi = globalState.hl.lo;
+}
+
+void LD_B_DHL(u8 opcode) { // 0x46
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.hi = readByte(globalState.hl.v);
+}
+
+
+
+// REGISTER-REGISTER LOADS (REGISTER C)
+void LD_C_B(u8 opcode) { // 0x48
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.lo = globalState.bc.hi;
+}
+
+void LD_C_C(u8 opcode) { // 0x49
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.lo = globalState.bc.lo;
+}
+
+void LD_C_D(u8 opcode) { // 0x4a
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.lo = globalState.de.hi;
+}
+
+void LD_C_E(u8 opcode) { // 0x4b
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.lo = globalState.de.lo;
+}
+
+void LD_C_H(u8 opcode) { // 0x4c
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.lo = globalState.hl.hi;
+}
+
+void LD_C_L(u8 opcode) { // 0x4d
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.lo = globalState.hl.lo;
+}
+
+void LD_C_DHL(u8 opcode) { // 0x4e
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.lo = readByte(globalState.hl.v);
+}
+
+
+
+// REGISTER-REGISTER LOADS (REGISTER D)
+void LD_D_B(u8 opcode) { // 0x50
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.hi = globalState.bc.hi;
+}
+
+void LD_D_C(u8 opcode) { // 0x51
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.hi = globalState.bc.lo;
+}
+
+void LD_D_D(u8 opcode) { // 0x52
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.hi = globalState.de.hi;
+}
+
+void LD_D_E(u8 opcode) { // 0x53
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.hi = globalState.de.lo;
+}
+
+void LD_D_H(u8 opcode) { // 0x54
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.hi = globalState.hl.hi;
+}
+
+void LD_D_L(u8 opcode) { // 0x55
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.hi = globalState.hl.lo;
+}
+
+void LD_D_DHL(u8 opcode) { // 0x56
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.hi = readByte(globalState.hl.v);
+}
+
+
+// REGISTER-REGISTER LOADS (REGISTER E)
+void LD_E_B(u8 opcode) { // 0x58
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.lo = globalState.bc.hi;
+}
+
+void LD_E_C(u8 opcode) { // 0x59
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.lo = globalState.bc.lo;
+}
+
+void LD_E_D(u8 opcode) { // 0x5a
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.lo = globalState.de.hi;
+}
+
+void LD_E_E(u8 opcode) { // 0x5b
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.lo = globalState.de.lo;
+}
+
+void LD_E_H(u8 opcode) { // 0x5c
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.lo = globalState.hl.hi;
+}
+
+void LD_E_L(u8 opcode) { // 0x5d
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.lo = globalState.hl.lo;
+}
+
+void LD_E_DHL(u8 opcode) { // 0x5e
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.lo = readByte(globalState.hl.v);
+}
+
+// REGISTER-REGISTER LOADS (REGISTER H)
+void LD_H_B(u8 opcode) { // 0x60
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.hi = globalState.bc.hi;
+}
+
+void LD_H_C(u8 opcode) { // 0x61
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.hi = globalState.bc.lo;
+}
+
+void LD_H_D(u8 opcode) { // 0x62
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.hi = globalState.de.hi;
+}
+
+void LD_H_E(u8 opcode) { // 0x63
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.hi = globalState.de.lo;
+}
+
+void LD_H_H(u8 opcode) { // 0x64
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.hi = globalState.hl.hi;
+}
+
+void LD_H_L(u8 opcode) { // 0x65
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.hi = globalState.hl.lo;
+}
+
+void LD_H_DHL(u8 opcode) { // 0x66
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.hi = readByte(globalState.hl.v);
+}
+
+// REGISTER-REGISTER LOADS (REGISTER L)
+void LD_L_B(u8 opcode) { // 0x60
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.lo = globalState.bc.hi;
+}
+
+void LD_L_C(u8 opcode) { // 0x61
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.lo = globalState.bc.lo;
+}
+
+void LD_L_D(u8 opcode) { // 0x62
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.lo = globalState.de.hi;
+}
+
+void LD_L_E(u8 opcode) { // 0x63
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.lo = globalState.de.lo;
+}
+
+void LD_L_H(u8 opcode) { // 0x64
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.lo = globalState.hl.hi;
+}
+
+void LD_L_L(u8 opcode) { // 0x65
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.lo = globalState.hl.lo;
+}
+
+void LD_L_DHL(u8 opcode) { // 0x66
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.lo = readByte(globalState.hl.v);
+}
+
+// REGISTER-REGISTER LOADS (REGISTER (HL))
+void LD_DHL_B(u8 opcode) { // 0x70
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  writeByte(globalState.bc.hi, globalState.hl.v);
+}
+
+void LD_DHL_C(u8 opcode) { // 0x71
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  writeByte(globalState.bc.lo, globalState.hl.v);
+}
+
+void LD_DHL_D(u8 opcode) { // 0x72
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  writeByte(globalState.de.hi, globalState.hl.v);
+}
+
+void LD_DHL_E(u8 opcode) { // 0x73
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  writeByte(globalState.de.lo, globalState.hl.v);
+}
+
+void LD_DHL_H(u8 opcode) { // 0x74
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  writeByte(globalState.hl.hi, globalState.hl.v);
+}
+
+void LD_DHL_L(u8 opcode) { // 0x75
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  writeByte(globalState.hl.lo, globalState.hl.v);
+}
+
+// Random
+void LD_DHL_n(u8 opcode) { // 0x36
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.cycleCount += 12;
+  writeByte(imm, globalState.hl.v);
+}
+
+// Load Into Register A Specials
+void LD_A_DBC(u8 opcode) { // 0A
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = readByte(globalState.bc.v);
+}
+
+void LD_A_DDE(u8 opcode) { // 1A
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = readByte(globalState.de.v);
+}
+
+
+void LD_A_Dnn(u8 opcode) { // FA
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  globalState.a = readByte(readU16(globalState.pc));
+  globalState.pc += 2;
+}
+
+void LD_A_n(u8 opocde) { // 0x3e
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.a = imm;
+  globalState.cycleCount += 8;
+}
+
+// LOAD FROM REGISTER A
+void LD_B_A(u8 opcode) { // 0x47
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.hi = globalState.a;
+}
+
+void LD_C_A(u8 opcode) { // 0x4f
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.bc.lo = globalState.a;
+}
+
+void LD_D_A(u8 opcode) { // 0x57
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.hi = globalState.a;
+}
+
+void LD_E_A(u8 opcode) { // 0x5f
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.de.lo = globalState.a;
+}
+
+void LD_H_A(u8 opcode) { // 0x67
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.hi = globalState.a;
+}
+
+void LD_L_A(u8 opcode) { // 0x6f
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.hl.lo = globalState.a;
+}
+
+void LD_DBC_A(u8 opcode) { // 0x02
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  writeByte(globalState.a, globalState.bc.v);
+}
+
+void LD_DDE_A(u8 opcode) { // 0x12
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  writeByte(globalState.a, globalState.de.v);
+}
+
+void LD_DHL_A(u8 opcode) { // 0x77
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  writeByte(globalState.a, globalState.hl.v);
+}
+
+void LD_Dnn_A(u8 opcode) { // 0xea
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  writeByte(globalState.a, readU16(globalState.pc));
+  globalState.pc += 2;
+}
+
+// Load A with memory offset from 0xff00
+void LD_A_FF00_C(u8 opcode) { //0xf2
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = readByte((u16)0xff00 + globalState.bc.lo);
+}
+
+// Store A with memory offset from 0xff00
+void LD_FF00_C_A(u8 opcode) { // 0xe2
+  globalState.pc++;
+  writeByte(globalState.a, (u16)0xff00 + globalState.bc.lo);
+  globalState.cycleCount += 8;
+}
+
+// Load (HL) into A, decrement HL
+void LDD_A_DHL(u8 opcode) { // 0x3a
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.a = readByte(globalState.hl.v);
+  globalState.hl.v--;
+}
+
+// Load A into (HL), decrement HL
+void LDD_DHL_A(u8 opcode) { // 0x32
+  writeByte(globalState.a, globalState.hl.v);
+  globalState.hl.v--;
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+
+// Load (HL) into A, increment HL
+void LDI_A_DHL(u8 opcode){ // 0x2a
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+  globalState.a = readByte(globalState.hl.v);
+  globalState.hl.v++;
+}
+
+// Load A into (HL), increment HL
+void LDI_DHL_A(u8 opcode) { // 0x22
+  writeByte(globalState.a, globalState.hl.v);
+  globalState.hl.v++;
+  globalState.pc += 1;
+  globalState.cycleCount += 8;
+}
+// page 75
+
+// Store A into FF00 + n
+void LD_FF00_n_A(u8 opcode) { //0xe0
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  writeByte(globalState.a, (u16)0xff00 + imm);
+  globalState.cycleCount += 12;
+}
+
+// Load A with FF00 + n
+void LD_A_FF00_n(u8 opcode) { // 0xf0
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.a = readByte((u16)0xff00 + imm);
+  globalState.cycleCount += 12;
+}
+
+// 16-bit loads
+void LD_BC_nn(u8 opcode) { // 0x01
+  u16 imm = readU16(globalState.pc + (u16)1);
+  globalState.bc.v = imm;
+  globalState.pc += 3;
+  globalState.cycleCount += 12;
+}
+
+void LD_DE_nn(u8 opcode) { // 0x11
+  u16 imm = readU16(globalState.pc + (u16)1);
+  globalState.de.v = imm;
+  globalState.pc += 3;
+  globalState.cycleCount += 12;
+}
+
+void LD_HL_nn(u8 opcode) { // 0x21
+  u16 imm = readU16(globalState.pc + (u16)1);
+  globalState.hl.v = imm;
+  globalState.pc += 3;
+  globalState.cycleCount += 12;
+}
+
+void LD_SP_nn(u8 opcode) { // 0x31
+  u16 imm = readU16(globalState.pc + (u16)1);
+  globalState.sp = imm;
+  globalState.pc += 3;
+  globalState.cycleCount += 12;
+}
+
+void LD_SP_HL(u8 opcode) { // 0xf9
+  globalState.sp = globalState.hl.v;
+  globalState.pc++;
+  globalState.cycleCount += 8;
+}
+
+// load effective address relative to stack pointer
+void LD_HL_SP_n(u8 opcode) { //0xf8
+  globalState.pc++;
+  globalState.cycleCount += 12;
+  s8 imm = readByte(globalState.pc);
+  globalState.pc++;
+  clearAllFlags();
+  u16 result = globalState.sp + imm;
+  if(((globalState.sp ^ imm ^ result) & 0x100) == 0x100) {
+    setCarryFlag();
+  }
+  if(((globalState.sp ^ imm ^ result) & 0x10) == 0x10) {
+    setHalfCarryFlag();
+  }
+  globalState.hl.v = result;
+}
+
+// store stack pointer
+void LD_Dnn_SP(u8 opcode) { // 08
+  globalState.pc++;
+  u16 addr = readU16(globalState.pc);
+  globalState.pc+=2;
+  globalState.cycleCount += 20;
+  writeU16(globalState.sp, addr);
+}
+
+// push U16 register onto stack
+void PUSH_AF(u8 opcode) { // 0xf5
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  writeU16(globalState.f + (((u16)globalState.a) << 8), globalState.sp - (u16)2);
+  globalState.sp -= 2;
+}
+
+void PUSH_BC(u8 opcode) { // 0xc5
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  writeU16(globalState.bc.v, globalState.sp - (u16)2);
+  globalState.sp -= 2;
+}
+
+void PUSH_DE(u8 opcode) { // 0xd5
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  writeU16(globalState.de.v, globalState.sp - (u16)2);
+  globalState.sp -= 2;
+}
+
+void PUSH_HL(u8 opcode) { // 0xe5
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  writeU16(globalState.hl.v, globalState.sp - (u16)2);
+  globalState.sp -= 2;
+}
+
+// POP U16 register from stack
+void POP_AF(u8 opcode) { // 0xf1
+  globalState.pc++;
+  globalState.cycleCount += 12;
+  u16 v = readU16(globalState.sp);
+  globalState.sp += 2;
+  globalState.a = (u8)(v >> 8);
+  globalState.f = (u8)(v & 0xf0);
+}
+
+void POP_BC(u8 opcode) { // 0xc1
+  globalState.pc++;
+  globalState.cycleCount += 12;
+  u16 v = readU16(globalState.sp);
+  globalState.sp += 2;
+  globalState.bc.v = v;
+}
+
+void POP_DE(u8 opcode) { // 0xd1
+  globalState.pc++;
+  globalState.cycleCount += 12;
+  u16 v = readU16(globalState.sp);
+  globalState.sp += 2;
+  globalState.de.v = v;
+}
+
+void POP_HL(u8 opcode) { // 0xe1
+  globalState.pc++;
+  globalState.cycleCount += 12;
+  u16 v = readU16(globalState.sp);
+  globalState.sp += 2;
+  globalState.hl.v = v;
+}
+
+void addToA(u8 number) {
+  int result = globalState.a + number;
+  int carryBits = globalState.a ^ number ^ result;
+  globalState.a = (u8)result;
+  clearAllFlags();
+
+  if((u8)result == 0){
+    setZeroFlag();
+  }
+
+  if((carryBits & 0x100) != 0) {
+    setCarryFlag();
+  }
+  if((carryBits & 0x10) != 0) {
+    setHalfCarryFlag();
+  }
+}
+
+// ADD Opcodes
+void ADD_A(u8 opcode) { // 0x87
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  addToA(globalState.a);
+}
+
+void ADD_B(u8 opcode) { // 0x80
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  addToA(globalState.bc.hi);
+}
+
+void ADD_C(u8 opcode) { // 0x81
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  addToA(globalState.bc.lo);
+}
+
+void ADD_D(u8 opcode) { // 0x82
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  addToA(globalState.de.hi);
+}
+
+void ADD_E(u8 opcode) { // 0x83
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  addToA(globalState.de.lo);
+}
+
+void ADD_H(u8 opcode) { // 0x84
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  addToA(globalState.hl.hi);
+}
+
+void ADD_L(u8 opcode) { // 0x85
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  addToA(globalState.hl.lo);
+}
+
+void ADD_DHL(u8 opcode) { // 0x86
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  addToA(readByte(globalState.hl.v));
+}
+
+void ADD_n(u8 opcode) { // 0xC6
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  addToA(imm);
+}
+
+void adcToA(u8 number) {
+  int carry = getCarryFlag() ? 1 : 0;
+  int result = globalState.a + number + carry;
+  clearAllFlags();
+  if((u8)result == 0) {
+    setZeroFlag();
+  }
+  if(result > 0xff) {
+    setCarryFlag();
+  }
+  if(((globalState.a & 0xf) + (number & 0xf) + carry) > 0xf) {
+    setHalfCarryFlag();
+  }
+  globalState.a = (u8) result;
+}
+
+// ADC Opcodes
+void ADC_A(u8 opcode) { // 0x8f
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  adcToA(globalState.a);
+}
+
+void ADC_B(u8 opcode) { // 0x88
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  adcToA(globalState.bc.hi);
+}
+
+void ADC_C(u8 opcode) { // 0x89
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  adcToA(globalState.bc.lo);
+}
+
+void ADC_D(u8 opcode) { // 0x8a
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  adcToA(globalState.de.hi);
+}
+
+void ADC_E(u8 opcode) { // 0x8b
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  adcToA(globalState.de.lo);
+}
+
+void ADC_H(u8 opcode) { // 0x8c
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  adcToA(globalState.hl.hi);
+}
+
+void ADC_L(u8 opcode) { // 0x8d
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  adcToA(globalState.hl.lo);
+}
+
+void ADC_DHL(u8 opcode) { // 0x8e
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  adcToA(readByte(globalState.hl.v));
+}
+
+void ADC_n(u8 opcode) { // 0xCe
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  adcToA(imm);
+}
+
+void subToA(u8 number) {
+  int result = globalState.a - number;
+  int carryBits = globalState.a ^ number ^ result;
+  globalState.a = (u8)result;
+  clearAllFlags();
+  setSubtractFlag();
+  if((u8)result == 0) {
+    setZeroFlag();
+  }
+  if((carryBits & 0x100) != 0) {
+    setCarryFlag();
+  }
+  if((carryBits & 0x10) != 0) {
+    setHalfCarryFlag();
+  }
+}
+
+// SUB Opcodes
+void SUB_A(u8 opcode) { // 0x97
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  subToA(globalState.a);
+}
+
+void SUB_B(u8 opcode) { // 0x90
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  subToA(globalState.bc.hi);
+}
+
+void SUB_C(u8 opcode) { // 0x91
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  subToA(globalState.bc.lo);
+}
+
+void SUB_D(u8 opcode) { // 0x92
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  subToA(globalState.de.hi);
+}
+
+void SUB_E(u8 opcode) { // 0x93
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  subToA(globalState.de.lo);
+}
+
+void SUB_H(u8 opcode) { // 0x94
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  subToA(globalState.hl.hi);
+}
+
+void SUB_L(u8 opcode) { // 0x95
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  subToA(globalState.hl.lo);
+}
+
+void SUB_DHL(u8 opcode) { // 0x96
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  subToA(readByte(globalState.hl.v));
+}
+
+void SUB_n(u8 opcode) { // 0xD6
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  subToA(imm);
+}
+
+void sbcToA(u8 number) {
+  int carry = getCarryFlag() ? 1 : 0;
+  int result = globalState.a - number - carry;
+  clearAllFlags();
+  setSubtractFlag();
+  if((u8)result == 0) {
+    setZeroFlag();
+  }
+  if(result < 0) {
+    setCarryFlag();
+  }
+  if(((globalState.a & 0xf) - (number & 0xf) - carry) < 0) {
+    setHalfCarryFlag();
+  }
+  globalState.a = (u8)result;
+}
+
+// SBC Opcodes
+void SBC_A(u8 opcode) { // 0x9f
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  sbcToA(globalState.a);
+}
+
+void SBC_B(u8 opcode) { // 0x98
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  sbcToA(globalState.bc.hi);
+}
+
+void SBC_C(u8 opcode) { // 0x99
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  sbcToA(globalState.bc.lo);
+}
+
+void SBC_D(u8 opcode) { // 0x9a
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  sbcToA(globalState.de.hi);
+}
+
+void SBC_E(u8 opcode) { // 0x9b
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  sbcToA(globalState.de.lo);
+}
+
+void SBC_H(u8 opcode) { // 0x9c
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  sbcToA(globalState.hl.hi);
+}
+
+void SBC_L(u8 opcode) { // 0x9d
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  sbcToA(globalState.hl.lo);
+}
+
+void SBC_DHL(u8 opcode) { // 0x9e
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  sbcToA(readByte(globalState.hl.v));
+}
+
+void SBC_n(u8 opcode) { // 0xDe
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  sbcToA(imm);
+}
+
+void andtoA(u8 number) {
+  u8 result = globalState.a & number;
+  globalState.a = result;
+  clearAllFlags();
+  setHalfCarryFlag();
+  if((u8)result == 0) {
+    setZeroFlag();
+  }
+}
+
+// AND Opcodes
+void AND_A(u8 opcode) { // 0xa7
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  andtoA(globalState.a);
+}
+
+void AND_B(u8 opcode) { // 0xa0
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  andtoA(globalState.bc.hi);
+}
+
+void AND_C(u8 opcode) { // 0xa1
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  andtoA(globalState.bc.lo);
+}
+
+void AND_D(u8 opcode) { // 0xa2
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  andtoA(globalState.de.hi);
+}
+
+void AND_E(u8 opcode) { // 0xa3
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  andtoA(globalState.de.lo);
+}
+
+void AND_H(u8 opcode) { // 0xa4
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  andtoA(globalState.hl.hi);
+}
+
+void AND_L(u8 opcode) { // 0xa5
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  andtoA(globalState.hl.lo);
+}
+
+void AND_DHL(u8 opcode) { // 0xa6
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  andtoA(readByte(globalState.hl.v));
+}
+
+void AND_n(u8 opcode) { // 0xe6
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  andtoA(imm);
+}
+
+void xorToA(u8 number) {
+  u8 result = globalState.a ^ number;
+  globalState.a = result;
+  clearAllFlags();
+  if((u8)result == 0) {
+    setZeroFlag();
+  }
+}
+
+// XOR Opcodes
+void XOR_A(u8 opcode) { // 0xaf
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  xorToA(globalState.a);
+}
+
+void XOR_B(u8 opcode) { // 0xa8
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  xorToA(globalState.bc.hi);
+}
+
+void XOR_C(u8 opcode) { // 0xa9
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  xorToA(globalState.bc.lo);
+}
+
+void XOR_D(u8 opcode) { // 0xaa
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  xorToA(globalState.de.hi);
+}
+
+void XOR_E(u8 opcode) { // 0xab
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  xorToA(globalState.de.lo);
+}
+
+void XOR_H(u8 opcode) { // 0xac
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  xorToA(globalState.hl.hi);
+}
+
+void XOR_L(u8 opcode) { // 0xad
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  xorToA(globalState.hl.lo);
+}
+
+void XOR_DHL(u8 opcode) { // 0xae
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  xorToA(readByte(globalState.hl.v));
+}
+
+void XOR_n(u8 opcode) { // 0xee
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  xorToA(imm);
+}
+
+void orToA(u8 number) {
+  u8 result = globalState.a | number;
+  globalState.a = result;
+  clearAllFlags();
+  if((u8)result == 0) {
+    setZeroFlag();
+  }
+}
+
+// OR Opcodes
+void OR_A(u8 opcode) { // 0xb7
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  orToA(globalState.a);
+}
+
+void OR_B(u8 opcode) { // 0xb0
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  orToA(globalState.bc.hi);
+}
+
+void OR_C(u8 opcode) { // 0xb1
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  orToA(globalState.bc.lo);
+}
+
+void OR_D(u8 opcode) { // 0xb2
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  orToA(globalState.de.hi);
+}
+
+void OR_E(u8 opcode) { // 0xb3
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  orToA(globalState.de.lo);
+}
+
+void OR_H(u8 opcode) { // 0xb4
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  orToA(globalState.hl.hi);
+}
+
+void OR_L(u8 opcode) { // 0xb5
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  orToA(globalState.hl.lo);
+}
+
+void OR_DHL(u8 opcode) { // 0xb6
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  orToA(readByte(globalState.hl.v));
+}
+
+void OR_n(u8 opcode) { // 0xf6
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  orToA(imm);
+}
+
+void cpToA(u8 number) {
+  clearAllFlags();
+  setSubtractFlag();
+  if(globalState.a < number) {
+    setCarryFlag();
+  }
+  if(globalState.a == number) {
+    setZeroFlag();
+  }
+  if(((globalState.a - number) & 0xf) > (globalState.a & 0xf)) {
+    setHalfCarryFlag();
+  }
+}
+
+// CP Opcodes
+void CP_A(u8 opcode) { // 0xbf
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  cpToA(globalState.a);
+}
+
+void CP_B(u8 opcode) { // 0xb8
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  cpToA(globalState.bc.hi);
+}
+
+void CP_C(u8 opcode) { // 0xb9
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  cpToA(globalState.bc.lo);
+}
+
+void CP_D(u8 opcode) { // 0xba
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  cpToA(globalState.de.hi);
+}
+
+void CP_E(u8 opcode) { // 0xbb
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  cpToA(globalState.de.lo);
+}
+
+void CP_H(u8 opcode) { // 0xbc
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  cpToA(globalState.hl.hi);
+}
+
+void CP_L(u8 opcode) { // 0xbd
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  cpToA(globalState.hl.lo);
+}
+
+void CP_DHL(u8 opcode) { // 0xbe
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  cpToA(readByte(globalState.hl.v));
+}
+
+void CP_n(u8 opcode) { // 0xfe
+  u8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  cpToA(imm);
+}
+
+void DecodeCB(u8 opcode) {
+  globalState.pc += 1;
+  u8 newOpcode = readByte(globalState.pc);
+  opcode_cbs[newOpcode](newOpcode);
+}
+
+u8 increment(u8 in) {
+  u8 result = in + (u8)1;
+  if(getCarryFlag()) {
+    clearAllFlags();
+    setCarryFlag();
+  } else {
+    clearAllFlags();
+  }
+  if(result == 0) {
+    setZeroFlag();
+  }
+  if((result & 0x0f) == 0x00) {
+    setHalfCarryFlag();
+  }
+  return result;
+}
+
+void INC_A(u8 opcode) { // 0x3c
+  globalState.a = increment(globalState.a);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void INC_B(u8 opcode) { // 0x04
+  globalState.bc.hi = increment(globalState.bc.hi);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void INC_C(u8 opcode) { // 0x0c
+  globalState.bc.lo = increment(globalState.bc.lo);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void INC_D(u8 opcode) { // 0x14
+  globalState.de.hi = increment(globalState.de.hi);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void INC_E(u8 opcode) { // 0x1c
+  globalState.de.lo = increment(globalState.de.lo);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void INC_H(u8 opcode) { // 0x24
+  globalState.hl.hi = increment(globalState.hl.hi);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void INC_L(u8 opcode) { // 0x2c
+  globalState.hl.lo = increment(globalState.hl.lo);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void INC_DHL(u8 opcode) { // 0x34
+  // todo this one is hard.
+  u8 v = readByte(globalState.hl.v);
+  writeByte(increment(v), globalState.hl.v);
+  globalState.pc++;
+  globalState.cycleCount += 12;
+}
+
+u8 decrement(u8 in) {
+  u8 result = in - (u8)1;
+  if(getCarryFlag()) {
+    clearAllFlags();
+    setCarryFlag();
+  } else {
+    clearAllFlags();
+  }
+  setSubtractFlag();
+  if(result == 0) {
+    setZeroFlag();
+  }
+  if((result & 0xf) == 0xf) {
+    setHalfCarryFlag();
+  }
+  return result;
+}
+
+void DEC_A(u8 opcode) { // 0x3d
+  globalState.a = decrement(globalState.a);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void DEC_B(u8 opcode) { // 0x05
+  globalState.bc.hi = decrement(globalState.bc.hi);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void DEC_C(u8 opcode) { // 0x0d
+  globalState.bc.lo = decrement(globalState.bc.lo);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void DEC_D(u8 opcode) { // 0x15
+  globalState.de.hi = decrement(globalState.de.hi);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void DEC_E(u8 opcode) { // 0x1d
+  globalState.de.lo = decrement(globalState.de.lo);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void DEC_H(u8 opcode) { // 0x25
+  globalState.hl.hi = decrement(globalState.hl.hi);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void DEC_L(u8 opcode) { // 0x2d
+  globalState.hl.lo = decrement(globalState.hl.lo);
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+void DEC_DHL(u8 opcode) { // 0x35
+  // todo this one is hard.
+  u8 v = readByte(globalState.hl.v);
+  writeByte(decrement(v), globalState.hl.v);
+  globalState.pc++;
+  globalState.cycleCount += 12;
+}
+
+void addToHl(u16 number) {
+  int result = globalState.hl.v + number;
+  if(getZeroFlag()) {
+    clearAllFlags();
+    setZeroFlag();
+  } else {
+    clearAllFlags();
+  }
+  if(result & 0x10000) {
+    setCarryFlag();
+  }
+  if((globalState.hl.v ^ number ^ (result & 0xffff)) & 0x1000) {
+    setHalfCarryFlag();
+  }
+  globalState.hl.v = (u16)result;
+}
+
+void ADD_HL_BC(u8 opcode) { // 09
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  addToHl(globalState.bc.v);
+}
+
+void ADD_HL_DE(u8 opcode) { // 19
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  addToHl(globalState.de.v);
+}
+
+void ADD_HL_HL(u8 opcode) { // 29
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  addToHl(globalState.hl.v);
+}
+
+void ADD_HL_SP(u8 opcode) { // 39
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  addToHl(globalState.sp);
+}
+
+void ADD_SP_n(u8 opcode) { // E8
+  s8 number = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.cycleCount += 16;
+  int result = globalState.sp + number;
+  clearAllFlags();
+  if(((globalState.sp ^ number ^ (result & 0xffff)) & 0x100) == 0x100) {
+    setCarryFlag();
+  }
+  if(((globalState.sp ^ number ^ (result & 0xffff)) & 0x10) == 0x10) {
+    setHalfCarryFlag();
+  }
+  globalState.sp = (u16)result;
+}
+
+// 16 bit incs
+void INC_BC(u8 opcode) { // 03
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.v++;
+}
+
+void INC_DE(u8 opcode) { // 13
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.v++;
+}
+
+void INC_HL(u8 opcode) { // 23
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.v++;
+}
+
+void INC_SP(u8 opcode) { // 33
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.sp++;
+}
+
+// 16 bit decs
+void DEC_BC(u8 opcode) { // 0B
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.bc.v--;
+}
+
+void DEC_DE(u8 opcode) { // 1B
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.de.v--;
+}
+
+void DEC_HL(u8 opcode) { // 2B
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.hl.v--;
+}
+
+void DEC_SP(u8 opcode) { // 3B
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.sp--;
+}
+
+void DAA(u8 opcode) { // 0x27
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  u8 a = globalState.a;
+
+  if(!getSubtractFlag()) {
+    if(getCarryFlag() || a > 0x99) {
+      a += 0x60;
+      setCarryFlag();
+    }
+    if(getHalfCarryFlag() || (a & 0x0f) > 0x09) {
+      a += 0x6;
+    }
+  } else {
+    if(getCarryFlag()) {
+      a -= 0x60;
+    }
+    if(getHalfCarryFlag()) {
+      a -= 0x6;
+    }
+  }
+  clearZeroFlag();
+  clearHalfCarryFlag();
+  if(a == 0) {
+    setZeroFlag();
+  }
+  globalState.a = (u8)a;
+}
+
+void CPL(u8 opcode) { // 0x2f
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.a = ~globalState.a;
+  setHalfCarryFlag();
+  setSubtractFlag();
+}
+
+void CCF(u8 opcode) { // 0x3f
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  if(getCarryFlag()) {
+    clearCarryFlag();
+  } else {
+    setCarryFlag();
+  }
+  clearHalfCarryFlag();
+  clearSubtractFlag();
+}
+
+void SCF(u8 opcode) { // 0x37
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  clearHalfCarryFlag();
+  clearSubtractFlag();
+  setCarryFlag();
+}
+
+void NOP(u8 opcode) { // 00
+  globalState.pc++;
+  globalState.cycleCount += 4;
+}
+
+
+void HALT(u8 opcode) { // 76
+  globalState.cycleCount += 4;
+  globalState.pc++;
+  //if(globalState.ime) {
+    globalState.halt = true;
+  //}
+
+}
+
+void STOP(u8 opcode) { // 10 (00)
+  printf("stop not yet implemented\n");
+  assert(false);
+}
+
+void DI(u8 opcode) { // F3
+  // todo instruction after bs
+  globalState.ime = 0;
+  globalState.cycleCount += 4;
+  globalState.pc++;
+//  printf("di not yet implemented\n");
+//  assert(false);
+}
+
+void EI(u8 opcode) { // FB
+  globalState.ime = 1;
+  globalState.cycleCount += 4;
+  globalState.pc++;
+}
+
+void RLCA(u8 opcode) { // 07
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.a = rlcReg(globalState.a, true);
+}
+
+void RLA(u8 opcode) { // 17
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.a = rlReg(globalState.a, true);
+}
+
+void RRCA(u8 opcode) { // 0x0f
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.a = rrc(globalState.a, true);
+}
+
+void RRA(u8 opcode) { // 0x1f
+  globalState.pc++;
+  globalState.cycleCount += 4;
+  globalState.a = rr(globalState.a, true);
+}
+
+void JP_nn(u8 opcodes) { // 0xc3
+  globalState.pc++;
+  u16 addr = readU16(globalState.pc);
+  globalState.pc += 2;
+  globalState.cycleCount += 12;
+  globalState.pc = addr;
+}
+
+void JP_NZ_nn(u8 opcodes) { // 0xc2
+  globalState.pc++;
+  u16 addr = readU16(globalState.pc);
+  globalState.pc += 2;
+  if(!getZeroFlag()) {
+    globalState.pc = addr;
+  }
+  globalState.cycleCount += 12;
+}
+
+void JP_Z_nn(u8 opcodes) { // 0xca
+  globalState.pc++;
+  u16 addr = readU16(globalState.pc);
+  globalState.pc += 2;
+  if(getZeroFlag()) {
+    globalState.pc = addr;
+  }
+  globalState.cycleCount += 12;
+}
+
+void JP_NC_nn(u8 opcodes) { // 0xd2
+  globalState.pc++;
+  u16 addr = readU16(globalState.pc);
+  globalState.pc += 2;
+  if(!getCarryFlag()) {
+    globalState.pc = addr;
+  }
+  globalState.cycleCount += 12;
+}
+
+void JP_C_nn(u8 opcodes) { // 0xda
+  globalState.pc++;
+  u16 addr = readU16(globalState.pc);
+  globalState.pc += 2;
+  if(getCarryFlag()) {
+    globalState.pc = addr;
+  }
+  globalState.cycleCount += 12;
+}
+
+void JP_HL(u8 opcodes) { // 0xe9
+  globalState.pc = globalState.hl.v;
+  globalState.cycleCount += 4;
+}
+
+void JR_n(u8 opcode) { // 18
+  s8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  globalState.pc += imm;
+  globalState.cycleCount += 8;
+}
+
+void JR_NZ(u8 opcode) { // 20
+  s8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  if(!getZeroFlag()){
+    globalState.pc += imm;
+  }
+  globalState.cycleCount += 8;
+}
+
+void JR_Z(u8 opcode) { // 28
+  s8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  if(getZeroFlag()){
+    globalState.pc += imm;
+  }
+  globalState.cycleCount += 8;
+}
+
+void JR_NC(u8 opcode) {  // 30
+  s8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  if(!getCarryFlag()){
+    globalState.pc += imm;
+  }
+  globalState.cycleCount += 8;
+}
+
+void JR_C(u8 opcode) { // 38
+  s8 imm = readByte(++globalState.pc);
+  globalState.pc++;
+  if(getCarryFlag()){
+    globalState.pc += imm;
+  }
+  globalState.cycleCount += 8;
+}
+
+
+void CALL_nn(u8 opcode) { // 0xCD
+  globalState.pc++;
+  u16 addr = readU16(globalState.pc);
+  //printf("call address 0x%x\n", addr);
+  globalState.pc += 2;
+  writeU16(globalState.pc, globalState.sp - (u16)2);
+  globalState.sp -= 2;
+  globalState.pc = addr;
+  globalState.cycleCount += 12;
+}
+
+void CALL_NZ(u8 opcode) { // 0xC4
+  globalState.pc++;
+  u16 addr = readU16(globalState.pc);
+  globalState.pc += 2;
+  if(!getZeroFlag()) {
+    writeU16(globalState.pc, globalState.sp - (u16)2);
+    globalState.sp -= 2;
+    globalState.pc = addr;
+  }
+  globalState.cycleCount += 12;
+}
+
+void CALL_Z(u8 opcode) { // 0xCc
+  globalState.pc++;
+  u16 addr = readU16(globalState.pc);
+  globalState.pc += 2;
+  if(getZeroFlag()) {
+    writeU16(globalState.pc, globalState.sp - (u16)2);
+    globalState.sp -= 2;
+    globalState.pc = addr;
+  }
+  globalState.cycleCount += 12;
+}
+
+
+void CALL_NC(u8 opcode) { // 0d4
+  globalState.pc++;
+  u16 addr = readU16(globalState.pc);
+  globalState.pc += 2;
+  if(!getCarryFlag()) {
+    writeU16(globalState.pc, globalState.sp - (u16)2);
+    globalState.sp -= 2;
+    globalState.pc = addr;
+  }
+  globalState.cycleCount += 12;
+}
+
+void CALL_C(u8 opcode) { // 0xdc
+  globalState.pc++;
+  u16 addr = readU16(globalState.pc);
+  globalState.pc += 2;
+  if(getCarryFlag()) {
+    writeU16(globalState.pc, globalState.sp - (u16)2);
+    globalState.sp -= 2;
+    globalState.pc = addr;
+  }
+  globalState.cycleCount += 12;
+}
+
+void REST_00(u8 opcode) { // 0xc7
+  globalState.pc++;
+  writeU16(globalState.pc, globalState.sp - (u16)2);
+  globalState.sp -= 2;
+  globalState.pc = 0x0000;
+  globalState.cycleCount += 32;
+}
+
+void REST_08(u8 opcode) { // 0xcf
+  globalState.pc++;
+  writeU16(globalState.pc, globalState.sp - (u16)2);
+  globalState.sp -= 2;
+  globalState.pc = 0x0008;
+  globalState.cycleCount += 32;
+}
+
+void REST_10(u8 opcode) { // 0xd7
+  globalState.pc++;
+  writeU16(globalState.pc, globalState.sp - (u16)2);
+  globalState.sp -= 2;
+  globalState.pc = 0x0010;
+  globalState.cycleCount += 32;
+}
+
+void REST_18(u8 opcode) { // 0xdf
+  globalState.pc++;
+  writeU16(globalState.pc, globalState.sp - (u16)2);
+  globalState.sp -= 2;
+  globalState.pc = 0x0018;
+  globalState.cycleCount += 32;
+}
+
+void REST_20(u8 opcode) { // 0xe7
+  globalState.pc++;
+  writeU16(globalState.pc, globalState.sp - (u16)2);
+  globalState.sp -= 2;
+  globalState.pc = 0x0020;
+  globalState.cycleCount += 32;
+}
+
+void REST_28(u8 opcode) { // 0xef
+  globalState.pc++;
+  writeU16(globalState.pc, globalState.sp - (u16)2);
+  globalState.sp -= 2;
+  globalState.pc = 0x0028;
+  globalState.cycleCount += 32;
+}
+
+void REST_30(u8 opcode) { // 0xf7
+  globalState.pc++;
+  writeU16(globalState.pc, globalState.sp - (u16)2);
+  globalState.sp -= 2;
+  globalState.pc = 0x0030;
+  globalState.cycleCount += 32;
+}
+
+void REST_38(u8 opcode) { // 0xff
+  globalState.pc++;
+  writeU16(globalState.pc, globalState.sp - (u16)2);
+  globalState.sp -= 2;
+  globalState.pc = 0x0038;
+  globalState.cycleCount += 32;
+}
+
+void RET(u8 opcode) { // 0xc9
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.pc = readU16(globalState.sp);
+  globalState.sp += 2;
+}
+
+void RET_NZ(u8 opcode) { // 0xc0
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  if(!getZeroFlag()) {
+    globalState.pc = readU16(globalState.sp);
+    globalState.sp += 2;
+  }
+}
+
+void RET_Z(u8 opcode) { // 0xc8
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  if(getZeroFlag()) {
+    globalState.pc = readU16(globalState.sp);
+    globalState.sp += 2;
+  }
+}
+
+void RET_NC(u8 opcode) { // 0xd0
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  if(!getCarryFlag()) {
+    globalState.pc = readU16(globalState.sp);
+    globalState.sp += 2;
+  }
+}
+
+void RET_C(u8 opcode) { // 0xd8
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  if(getCarryFlag()) {
+    globalState.pc = readU16(globalState.sp);
+    globalState.sp += 2;
+  }
+}
+
+void RETI(u8 opcode) { // 0xd9
+  globalState.pc++;
+  globalState.cycleCount += 8;
+  globalState.pc = readU16(globalState.sp);
+  globalState.sp += 2;
+  globalState.ime = 1;
+}
+
+// normal opcode handler table
+static OpcodeHandler* opcodes[256] =
+        {NOP,          LD_BC_nn,     LD_DBC_A,     INC_BC,       INC_B,        DEC_B,        LD_B_n,       RLCA,         // 0x0 - 0x7
+         LD_Dnn_SP,    ADD_HL_BC,    LD_A_DBC,     DEC_BC,       INC_C,        DEC_C,        LD_C_n,       RRCA,         // 0x8 - 0xf
+         STOP,         LD_DE_nn,     LD_DDE_A,     INC_DE,       INC_D,        DEC_D,        LD_D_n,       RLA,          // 0x10 - 0x17
+         JR_n,         ADD_HL_DE,    LD_A_DDE,     DEC_DE,       INC_E,        DEC_E,        LD_E_n,       RRA,          // 0x18 - 0x1f
+         JR_NZ,        LD_HL_nn,     LDI_DHL_A,    INC_HL,       INC_H,        DEC_H,        LD_H_n,       DAA,          // 0x20 - 0x27
+         JR_Z,         ADD_HL_HL,    LDI_A_DHL,    DEC_HL,       INC_L,        DEC_L,        LD_L_n,       CPL,          // 0x28 - 0x2f
+         JR_NC,        LD_SP_nn,     LDD_DHL_A,    INC_SP,       INC_DHL,      DEC_DHL,      LD_DHL_n,     SCF,          // 0x30 - 0x37
+         JR_C,         ADD_HL_SP,    LDD_A_DHL,    DEC_SP,       INC_A,        DEC_A,        LD_A_n,       CCF,          // 0x38 - 0x3f
+         LD_B_B,       LD_B_C,       LD_B_D,       LD_B_E,       LD_B_H,       LD_B_L,       LD_B_DHL,     LD_B_A,       // 0x40 - 0x47
+         LD_C_B,       LD_C_C,       LD_C_D,       LD_C_E,       LD_C_H,       LD_C_L,       LD_C_DHL,     LD_C_A,       // 0x48 - 0x4f
+         LD_D_B,       LD_D_C,       LD_D_D,       LD_D_E,       LD_D_H,       LD_D_L,       LD_D_DHL,     LD_D_A,       // 0x50 - 0x57
+         LD_E_B,       LD_E_C,       LD_E_D,       LD_E_E,       LD_E_H,       LD_E_L,       LD_E_DHL,     LD_E_A,       // 0x58 - 0x5f
+         LD_H_B,       LD_H_C,       LD_H_D,       LD_H_E,       LD_H_H,       LD_H_L,       LD_H_DHL,     LD_H_A,       // 0x60 - 0x67
+         LD_L_B,       LD_L_C,       LD_L_D,       LD_L_E,       LD_L_H,       LD_L_L,       LD_L_DHL,     LD_L_A,       // 0x68 - 0x6f
+         LD_DHL_B,     LD_DHL_C,     LD_DHL_D,     LD_DHL_E,     LD_DHL_H,     LD_DHL_L,     HALT,         LD_DHL_A,     // 0x70 - 0x77
+         LD_A_B,       LD_A_C,       LD_A_D,       LD_A_E,       LD_A_H,       LD_A_L,       LD_A_DHL,     LD_A_A      , // 0x78 - 0x7f
+         ADD_B,        ADD_C,        ADD_D,        ADD_E,        ADD_H,        ADD_L,        ADD_DHL,      ADD_A,        // 0x80 - 0x87
+         ADC_B,        ADC_C,        ADC_D,        ADC_E,        ADC_H,        ADC_L,        ADC_DHL,      ADC_A,        // 0x88 - 0x8f
+         SUB_B,        SUB_C,        SUB_D,        SUB_E,        SUB_H,        SUB_L,        SUB_DHL,      SUB_A,        // 0x90 - 0x97
+         SBC_B,        SBC_C,        SBC_D,        SBC_E,        SBC_H,        SBC_L,        SBC_DHL,      SBC_A,        // 0x98 - 0x9f
+         AND_B,        AND_C,        AND_D,        AND_E,        AND_H,        AND_L,        AND_DHL,      AND_A,        // 0xa0 - 0xa7
+         XOR_B,        XOR_C,        XOR_D,        XOR_E,        XOR_H,        XOR_L,        XOR_DHL,      XOR_A,        // 0xa8 - 0xaf
+         OR_B,         OR_C,         OR_D,         OR_E,         OR_H,         OR_L,         OR_DHL,       OR_A,         // 0xb0 - 0xb7
+         CP_B,         CP_C,         CP_D,         CP_E,         CP_H,         CP_L,         CP_DHL,       CP_A,         // 0xb8 - 0xbf
+         RET_NZ,       POP_BC,       JP_NZ_nn,     JP_nn,        CALL_NZ,      PUSH_BC,      ADD_n,        REST_00,      // 0xc0 - 0xc7
+         RET_Z,        RET,          JP_Z_nn,      DecodeCB,     CALL_Z,       CALL_nn,      ADC_n,        REST_08,      // 0xc8 - 0xcf
+         RET_NC,       POP_DE,       JP_NC_nn,     invHandler,   CALL_NC,      PUSH_DE,      SUB_n,        REST_10,      // 0xd0 - 0xd7
+         RET_C,        RETI,         JP_C_nn,      invHandler,   CALL_C,       invHandler,   SBC_n,        REST_18,      // 0xd8 - 0xdf
+         LD_FF00_n_A,  POP_HL,       LD_FF00_C_A,  invHandler,   invHandler,   PUSH_HL,      AND_n,        REST_20,      // 0xe0 - 0xe7
+         ADD_SP_n,     JP_HL,        LD_Dnn_A,     invHandler,   invHandler,   invHandler,   XOR_n,        REST_28,      // 0xe8 - 0xef
+         LD_A_FF00_n,  POP_AF,       LD_A_FF00_C,  DI,           invHandler,   PUSH_AF,      OR_n,         REST_30,      // 0xf0 - 0xf7
+         LD_HL_SP_n,   LD_SP_HL,     LD_A_Dnn,     EI,           invHandler,   invHandler,   CP_n,         REST_38};     // 0xf8 - 0xff
+
+
+// reset the globalState structure, including registers and timers
+void resetCpu() {
+  globalState.f = 0x1; // or 0x11? (
+  globalState.a = 0xb0; // maybe f, a swap??
+  globalState.bc.v = 0x0013;
+  globalState.de.v = 0x00d8;
+  globalState.hl.v = 0x014d;
+  globalState.sp = 0xfffe;
+  globalState.pc = 0x0;
+  globalState.halt = false;
+  globalState.cycleCount = 0;
+  globalState.divOffset = 0;
+  globalState.timSubcount = 0;
+}
+
+// set the globalState so the next call to step() will run an ISR
+void interrupt(u16 addr) {
+  globalState.ime = 0;                                // disable interrupts
+  writeU16(globalState.pc, globalState.sp - (u16)2);  // push pc to stack
+  globalState.sp -= 2;                                // push pc to stack
+  globalState.cycleCount += 12;                       // timing
+  globalState.pc = addr;                              // jump to ISR
+}
+
+// timer speeds: once this number of clock cycles has elapsed, the timer ticks.
+static u32 timReset[4] = {(1 << 10), (1 << 4), (1 << 6), (1 << 8)};
+
+// step the CPU 1 instruction
+// returns number of clock cycles
+u32 cpuStep() {
+  uint64_t oldCycleCount = globalState.cycleCount;
+
+  // update div register
+  globalMemState.ioRegs[IO_DIV] = (u8)((globalState.cycleCount - globalState.divOffset) >> 8);
+
+  // execute, if we aren't halted.
+  if(!globalState.halt) {
+    // fetch opcode
+    u8 opcode = readByte(globalState.pc);
+    // execute opcode
+    opcodes[opcode](opcode);
+  }
+
+    assert(false);
+  // interrupts
+  if(globalState.ime && globalMemState.upperRam[0x7f] && globalMemState.ioRegs[IO_IF]) {
+
+    // mask interrupts with the interrupt enable register at 0xffff.
+    u8 interrupts = globalMemState.upperRam[0x7f] & globalMemState.ioRegs[IO_IF];
+
+    if(interrupts & 0x01) {
+      globalMemState.ioRegs[IO_IF] &= ~1;
+      interrupt(VBLANK_INTERRUPT);
+      globalState.halt = false;
+    } else if(interrupts & 0x02) {
+      globalMemState.ioRegs[IO_IF] &= ~2;
+      interrupt(LCDC_INTERRUPT);
+      globalState.halt = false;
+    } else if(interrupts & 0x04) {
+      globalMemState.ioRegs[IO_IF] &= ~4;
+      interrupt(TIMER_INTERRUPT);
+      globalState.halt = false;
+    } else if(interrupts & 0x08) {
+      globalMemState.ioRegs[IO_IF] &= ~8;
+      interrupt(SERIAL_INTERRUPT);
+      globalState.halt = false;
+    } else if(interrupts & 0x10) {
+      globalMemState.ioRegs[IO_IF] &= ~0x10;
+      interrupt(HIGH_TO_LOW_P10_P13);
+      globalState.halt = false;
+    }
+  }
+
+  // even if we have IME off, and we're halted, we're supposed to check IF and IE register
+  // this won't fire an interrupt, but will get us out of halt
+  // this behavior isn't well documented, but was required to pass cpu_instr.gb
+  // (though none of the games seem to need it...)
+  if(globalState.halt) {
+    globalState.cycleCount += 800; // just to keep ticking the timer...
+    u8 interrupts = globalMemState.upperRam[0x7f] & globalMemState.ioRegs[IO_IF];
+    if(interrupts & 0x01) {
+      globalState.halt = false;
+    } else if(interrupts & 0x02) {
+      globalState.halt = false;
+    } else if(interrupts & 0x04) {
+      globalState.halt = false;
+    } else if(interrupts & 0x08) {
+      globalState.halt = false;
+    } else if(interrupts & 0x10) {
+      globalState.halt = false;
+    }
+  }
+
+
+  // cycle count
+  uint64_t cyclesThisIteration = globalState.cycleCount - oldCycleCount;
+
+  // update timer
+  u8 tac = globalMemState.ioRegs[IO_TAC];
+  bool ten = ((tac >> 2) & 1) != 0; // timer enable?
+  if(ten) {
+    u8 tclk = (tac & (u8)3);     // timer speed
+    globalState.timSubcount += cyclesThisIteration;
+    if(globalState.timSubcount >= timReset[tclk]) { // timer tick
+      globalState.timSubcount = 0;
+      u8 timv = globalMemState.ioRegs[IO_TIMA]; // check for overflow
+      if(timv == 255) {
+        globalMemState.ioRegs[IO_IF] |= 4; // set interrupt
+        globalMemState.ioRegs[IO_TIMA] = globalMemState.ioRegs[IO_TMA]; // reset
+      } else {
+        globalMemState.ioRegs[IO_TIMA] = timv + (u8)1; // increment.
+      }
+    }
+  }
+
+  return (u32)cyclesThisIteration;
+}
+
+bool getZeroFlag() {
+  return (globalState.f & 0x80) != 0;
+}
+
+bool getSubtractFlag() {
+  return (globalState.f & 0x40) != 0;
+}
+
+bool getHalfCarryFlag() {
+  return (globalState.f & 0x20) != 0;
+}
+
+bool getCarryFlag() {
+  return (globalState.f & 0x10) != 0;
+}
+
+void setZeroFlag() {
+  globalState.f = globalState.f | (u8)0x80;
+}
+
+void setSubtractFlag() {
+  globalState.f = globalState.f | (u8)0x40;
+}
+
+void setHalfCarryFlag() {
+  globalState.f = globalState.f | (u8)0x20;
+}
+
+void setCarryFlag() {
+  globalState.f = globalState.f | (u8)0x10;
+}
+
+void clearZeroFlag(){
+  globalState.f = globalState.f & ~((u8)0x80);
+}
+
+void clearSubtractFlag(){
+  globalState.f = globalState.f & ~((u8)0x40);
+}
+
+void clearHalfCarryFlag(){
+  globalState.f = globalState.f & ~((u8)0x20);
+}
+
+void clearCarryFlag(){
+  globalState.f = globalState.f & ~((u8)0x10);
+}
+
+void clearAllFlags() {
+  clearZeroFlag();
+  clearSubtractFlag();
+  clearHalfCarryFlag();
+  clearCarryFlag();
+}
\ No newline at end of file