   *(cycletable + 0x0D) = 4;
   *(cycletable + 0x0E) = 8;
   *(cycletable + 0x0F) = 4;
+
+  *(cycletable + 0x20) = 8;  //  +4 IFF
+  *(cycletable + 0x21) = 12;
+  *(cycletable + 0x22) = 8;
+  *(cycletable + 0x23) = 8;
+  *(cycletable + 0x24) = 4;
+  *(cycletable + 0x25) = 4;
+  *(cycletable + 0x26) = 8;
+  *(cycletable + 0x27) = 4;
+  *(cycletable + 0x28) = 8;  //  +4 IFF
+  *(cycletable + 0x29) = 8;
+  *(cycletable + 0x2A) = 8;
+  *(cycletable + 0x2B) = 8;
+  *(cycletable + 0x2C) = 4;
+  *(cycletable + 0x2D) = 4;
+  *(cycletable + 0x2E) = 8;
+  *(cycletable + 0x2F) = 4;
+
+  *(cycletable + 0x30) = 8;  //  +4 IFF
+  *(cycletable + 0x31) = 12;
+  *(cycletable + 0x32) = 8;
+  *(cycletable + 0x33) = 8;
+  *(cycletable + 0x34) = 12;
+  *(cycletable + 0x35) = 12;
+  *(cycletable + 0x36) = 12;
+  *(cycletable + 0x37) = 4;
+  *(cycletable + 0x38) = 8;  //  +4 IFF
+  *(cycletable + 0x39) = 8;
+  *(cycletable + 0x3A) = 8;
+  *(cycletable + 0x3B) = 8;
+  *(cycletable + 0x3C) = 4;
+  *(cycletable + 0x3D) = 4;
+  *(cycletable + 0x3E) = 8;
+  *(cycletable + 0x3F) = 4;
+
+  *(cycletable + 0xC0) = 8;   // +12 IFF
+  *(cycletable + 0xC1) = 12;
+  *(cycletable + 0xC2) = 12;  //  +4 IFF
+  *(cycletable + 0xC3) = 16;
+  *(cycletable + 0xC4) = 12;  // +12 IFF
+  *(cycletable + 0xC5) = 16;
+  *(cycletable + 0xC6) = 8;
+  *(cycletable + 0xC7) = 16;
+  *(cycletable + 0xC8) = 8;   // +12 IFF
+  *(cycletable + 0xC9) = 16;
+  *(cycletable + 0xCA) = 12;  //  +4 IFF
+  *(cycletable + 0xCC) = 12;  // +12 IFF
+  *(cycletable + 0xCD) = 24;
+  *(cycletable + 0xCE) = 8;
+  *(cycletable + 0xCF) = 16;
+
+  *(cycletable + 0xE0) = 12;
+  *(cycletable + 0xE1) = 12;
+  *(cycletable + 0xE2) = 8;
+  // *(cycletable + 0xE3) = _
+  // *(cycletable + 0xE4) = _
+  *(cycletable + 0xE5) = 16;
+  *(cycletable + 0xE6) = 8;
+  *(cycletable + 0xE7) = 16;
+  *(cycletable + 0xE8) = 16;
+  *(cycletable + 0xE9) = 4;
+  *(cycletable + 0xEA) = 16;
+  // *(cycletable + 0xEB) = _
+  // *(cycletable + 0xEC) = _
+  // *(cycletable + 0xED) = _
+  *(cycletable + 0xEE) = 8;
+  *(cycletable + 0xEF) = 16;
+
+  *(cycletable + 0xF0) = 12;
+  *(cycletable + 0xF1) = 12;
+  *(cycletable + 0xF2) = 8;
+  *(cycletable + 0xF3) = 4;
+  // *(cycletable + 0xF4) = _
+  *(cycletable + 0xF5) = 16;
+  *(cycletable + 0xF6) = 8;
+  *(cycletable + 0xF7) = 16;
+  *(cycletable + 0xF8) = 12;
+  *(cycletable + 0xF9) = 8;
+  *(cycletable + 0xFA) = 16;
+  *(cycletable + 0xFB) = 4;
+  // *(cycletable + 0xFC) = _
+  // *(cycletable + 0xFD) = _
+  *(cycletable + 0xFE) = 8;
+  *(cycletable + 0xFF) = 16;
 }
 
 def fini_cycletable() {
   free(cycletable as *uint8);
+}
+
+// =============================================================================
+// [FL] Flag
+// =============================================================================
+type Flag = uint8;
+
+let FLAG_Z: Flag = 0b1000_0000;
+let FLAG_N: Flag = 0b0100_0000;
+let FLAG_H: Flag = 0b0010_0000;
+let FLAG_C: Flag = 0b0001_0000;
+
+def flag_set(flag: Flag, value: bool) {
+  if value { *F |=  uint8(flag); }
+  else     { *F &= ~uint8(flag); }
+}
+
+def flag_get(flag: Flag): bool {
+  return *F & uint8(flag) != 0;
+}
+
+def flag_geti(flag: Flag): uint8 {
+  return if flag_get(flag) { 1; } else { 0; };
+}
+
+// =============================================================================
+// [OM] Operation Mnemonics
+// =============================================================================
+
+// Increment 8-bit Register
+def om_inc8(r: *uint8) {
+  flag_set(FLAG_H, (((*r & 0xF) + (1 & 0xF)) & 0x10) > 0);
+
+  *r += 1;
+
+  flag_set(FLAG_Z, *r == 0);
+  flag_set(FLAG_N, false);
+}
+
+// Decrement 8-bit Register
+def om_dec8(r: *uint8) {
+  flag_set(FLAG_H, (((*r & 0xF) - (1 & 0xF)) & 0x10) < 0);
+
+  *r -= 1;
+
+  flag_set(FLAG_Z, *r == 0);
+  flag_set(FLAG_N, true);
+}
+
+// Increment 16-bit Register
+def om_inc16(r: *uint16) {
+  *r += 1;
+}
+
+// Decrement 16-bit Register
+def om_dec16(r: *uint16) {
+  *r -= 1;
+}
+
+// And 8-bit value
+def om_and8(a: uint8, b: uint8): uint8 {
+  let r = a & b;
+
+  flag_set(FLAG_Z, r == 0);
+  flag_set(FLAG_N, false);
+  flag_set(FLAG_H, true);
+  flag_set(FLAG_C, false);
+
+  return r;
+}
+
+// Or 8-bit value
+def om_or8(a: uint8, b: uint8): uint8 {
+  let r = a & b;
+
+  flag_set(FLAG_Z, r == 0);
+  flag_set(FLAG_N, false);
+  flag_set(FLAG_H, false);
+  flag_set(FLAG_C, false);
+
+  return r;
+}
+
+// Xor 8-bit value
+def om_xor8(a: uint8, b: uint8): uint8 {
+  let r = a ^ b;
+
+  flag_set(FLAG_Z, r == 0);
+  flag_set(FLAG_N, false);
+  flag_set(FLAG_H, false);
+  flag_set(FLAG_C, false);
+
+  return r;
+}
+
+// Add 8-bit value
+def om_add8(a: uint8, b: uint8): uint8 {
+  flag_set(FLAG_H, (((a & 0xF) + (b & 0xF)) & 0x10) > 0);
+
+  let r = uint16(a) + uint16(b);
+
+  flag_set(FLAG_C, r > 0xFFFF);
+  flag_set(FLAG_Z, r == 0);
+  flag_set(FLAG_N, false);
+
+  return uint8(r & 0xFF);
+}
+
+// Add 8-bit value w/carry
+def om_adc8(a: uint8, b: uint8): uint8 {
+  return om_add8(a, b + uint8(flag_geti(FLAG_C)));
+}
+
+// Subtract 8-bit value
+def om_sub8(a: uint8, b: uint8): uint8 {
+  let r = om_add8(a, ~b);
+
+  flag_set(FLAG_N, true);
+
+  return r;
+}
+
+// Subtract 8-bit value w/carry
+def om_sbc8(a: uint8, b: uint8): uint8 {
+  let r = om_adc8(a, ~b);
+
+  flag_set(FLAG_N, true);
+
+  return r;
+}
+
+// Add 16-bit value
+def om_add16(a: uint16, b: uint16): uint16 {
+  flag_set(FLAG_H, (((a & 0xFF) + (b & 0xFF)) & 0x100) > 0);
+
+  let r = uint32(a) + uint32(b);
+
+  flag_set(FLAG_C, r > 0xFFFF);
+  flag_set(FLAG_N, false);
+
+  return uint16(r & 0xFFFF);
+}
+
+// Add 16-bit value w/carry
+def om_adc16(a: uint16, b: uint16): uint16 {
+  return om_add16(a, b + uint16(flag_geti(FLAG_C)));
+}
+
+// Subtract 16-bit value
+def om_sub16(a: uint16, b: uint16): uint16 {
+  let r = om_add16(a, ~b);
+
+  flag_set(FLAG_N, true);
+
+  return r;
+}
+
+// Subtract 16-bit value w/carry
+def om_sbc16(a: uint16, b: uint16): uint16 {
+  let r = om_adc16(a, ~b);
+
+  flag_set(FLAG_N, true);
+
+  return r;
+}
+
+// Push 16-bit value
+def om_push16(r: *uint16) {
+  SP -= 2;
+  mmu_write16(SP, *r);
+}
+
+// Pop 16-bit value
+def om_pop16(r: *uint16) {
+  *r = mmu_read16(SP);
+  SP += 2;
+}
+
+// Jump
+def om_jp(address: uint16) {
+  PC = address;
+}
+
+// Call
+def om_call(address: uint16) {
+  om_push16(&PC);
+  om_jp(address);
+}
+
+// Return
+def om_ret() {
+  om_pop16(&PC);
+}
+
+// Return (and enable interrupts)
+def om_reti() {
+  IME = true;
+  om_ret();
 }
 
 // =============================================================================


// [03] INC BC
def op_03() {
  *BC += 1;

  flag_set(FLAG_Z, *BC == 0);
  flag_set(FLAG_N, 0);
  flag_set(FLAG_H, ..);
}

// [04] INC B
def op_04() {
  *B += 1;
  // TODO: Flags
}

// [05] DEC B
def op_05() {
  *B -= 1;
  // TODO: Flags
}


// [06]
// [07]
// [08]
// [09]
// [0A]
// [0B]
// [0C]
// [0D]
// [0E]
// [0F]


def init_cycletable() {
  cycletable = malloc(0x1_00) as *uint8;
  memset(cycletable as *uint8, 0, 0x1_00);

  *(cycletable + 0x00) = 4;
  *(cycletable + 0x01) = 12;
