{"version":3,"sources":["~lib/rt/common.ts","~lib/shared/typeinfo.ts","~lib/rt/pure.ts","~lib/rt/tlsf.ts","~lib/gc.ts","~lib/rt.ts","~lib/util/error.ts","~lib/memory.ts","~lib/util/memory.ts","core/constants.ts","core/config.ts","core/graphics/colors.constants.ts","core/graphics/colors.ts","core/graphics/palette.ts","core/graphics/tiles.ts","core/sound/channel1.ts","core/sound/channel2.ts","core/sound/channel3.ts","core/sound/channel4.ts","core/sound/accumulator.ts","core/sound/sound.ts","core/interrupts/interrupts.ts","core/timers/timers.ts","core/serial/serial.ts","core/joypad/joypad.ts","core/debug/breakpoints.ts","core/graphics/lcd.ts","core/graphics/graphics.ts","core/memory/memory.ts","core/cpu/cpu.ts","core/cycles.ts","core/execute.ts","core/core.ts","core/memory/load.ts","core/memory/memoryMap.ts","core/memory/banking.ts","core/memory/store.ts","core/memory/dma.ts","core/helpers/index.ts","core/cpu/opcodes.ts","core/portable/portable.ts","core/graphics/backgroundWindow.ts","core/graphics/priority.ts","core/graphics/sprites.ts","core/memory/readTraps.ts","core/sound/duty.ts","core/sound/registers.ts","core/memory/writeTraps.ts","core/cpu/flags.ts","core/cpu/instructions.ts","core/cpu/cbOpcodes.ts","core/debug/debug-cpu.ts","core/debug/debug-graphics.ts","core/debug/debug-timer.ts","core/debug/debug-memory.ts"],"names":[],"mappings":"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CD,OACH,IAEE,OACI,OACD,OACH,IAEA,OACI,OACD,OACH,OAIF,OACI,OACD,OACH,IAEE,OACI,OACD,KACH,IAEA,OACI,OACD,MACH,OAIF,OACI,OACD,KACH,IAEE,OACI,OACD,OACH,IAEA,OACI,OACD,MACH,OAIF,OACI,OACD,OACH,IAEE,OACI,OACD,OACH,IAEA,OACI,OACD,OACH,OAIF,OACI,OACD,OACH,IAEE,OACI,OACD,OACH,IAEA,OACI,OACD,OACH,mCAYhB,MADC,EAiBD,QAgBA,OAgBA,QAgBA,QACA,QAgBA,QACA,QAgBA,QACA,QACA,QACA,QAgBA,OACA,QACA,QACA,QAgBA,QAgBA,QAgBA,QAgBA,SAvLc,OACI,OACD,MACH,IAEE,OACI,OACD,MACH,IAEA,OACI,OACD,MACH,OAGF,OACI,OACD,KACH,IAEE,OACI,OACD,OACH,IAEA,OACI,OACD,KACH,OAGF,OACI,OACD,OACH,IAEE,OACI,OACD,MACH,IAEA,OACI,OACD,OACH,OAGF,OACI,OACD,OACH,IAEE,IACI,OACD,OACH,OAEA,IACI,OACD,OACH,UAIF,OACI,OACD,OACH,IAEE,OACI,OACD,OACH,IAEA,OACI,OACD,OACH,QAIF,OACI,OACD,OACH,MAEE,OACI,OACD,OACH,OAEA,OACI,OACD,OACH,OAMF,OACI,OACD,OACH,IAEE,OACI,OACD,OACH,KAEA,OACI,OACD,OACH,OAMF,OACI,OACD,MACH,IAEE,OACI,OACD,OACH,IAEA,KACI,OACD,OACH,SAGF,OACI,OACD,OACH,OAEE,OACI,OACD,OACH,IAEA,OACI,OACD,KACH,OAGF,OACI,OACD,OACH,IAEE,OACI,MACD,OACH,MAEA,OACI,OACD,KACH,OAGF,OACI,OACD,KACH,IAEE,OACI,OACD,OACH,IAEA,OACI,OACD,MACH,OAGF,OACI,OACD,OACH,IAEE,OACI,OACD,OACH,IAEA,OACI,OACD,KACH,UAxdM,IAEzB,OAKA,KACE,AAAC,SAQW,SAAQ,EAAK,MACZ,AAAyB,IAA1C,KADqC,WAOZ,AAD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","sourceRoot":"assemblyscript:///","sourceContents":["// Alignment guarantees\n\n// @ts-ignore: decorator\n@inline export const AL_BITS: u32 = 4; // 16 bytes to fit up to v128\n// @ts-ignore: decorator\n@inline export const AL_SIZE: usize = 1 << <usize>AL_BITS;\n// @ts-ignore: decorator\n@inline export const AL_MASK: usize = AL_SIZE - 1;\n\n// Extra debugging\n\n// @ts-ignore: decorator\n@inline export const DEBUG = true;\n\n// ╒════════════════ Common block layout (32-bit) ═════════════════╕\n//    3                   2                   1\n//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0  bits\n// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤\n// │                           MM info                             │ -16\n// ├───────────────────────────────────────────────────────────────┤\n// │                           GC info                             │ -12\n// ├───────────────────────────────────────────────────────────────┤\n// │                          runtime id                           │ -8\n// ├───────────────────────────────────────────────────────────────┤\n// │                         runtime size                          │ -4\n// ╞═══════════════════════════════════════════════════════════════╡\n// │                              ...                              │ ref\n@unmanaged export class BLOCK {\n  /** Memory manager info. */\n  mmInfo: usize; // WASM64 needs adaption\n  /** Garbage collector info. */\n  gcInfo: u32;\n  /** Runtime class id. */\n  rtId: u32;\n  /** Runtime object size. */\n  rtSize: u32;\n}\n\n// @ts-ignore: decorator\n@inline export const BLOCK_OVERHEAD = (offsetof<BLOCK>() + AL_MASK) & ~AL_MASK;\n\n// @ts-ignore: decorator\n@inline export const BLOCK_MAXSIZE: usize = (1 << 30) - BLOCK_OVERHEAD;\n","// This file is shared with the compiler and must remain portable\n\n// ╒═══════════════════ Typeinfo interpretation ═══════════════════╕\n//    3                   2                   1\n//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0  bits\n// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤ ◄─ __rtti_base\n// │                             count                             │\n// ╞═══════════════════════════════════════════════════════════════╡ ┐\n// │                      Typeinfo#flags [id=0]                    │ id < count\n// ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤\n// │                      Typeinfo#base  [id=0]                    │\n// ├───────────────────────────────────────────────────────────────┤\n// │                              ...                              │\n\n/** Runtime type information data structure. */\n@unmanaged\nexport class Typeinfo {\n  /** Flags describing the shape of this class type. */\n  flags: TypeinfoFlags;\n  /** Base class id or `0` if none. */\n  base: u32;\n}\n\n/** Runtime type information flags. */\nexport const enum TypeinfoFlags {\n  /** No specific flags. */\n  NONE = 0,\n  /** Type is an `ArrayBufferView`. */\n  ARRAYBUFFERVIEW = 1 << 0,\n  /** Type is an `Array`. */\n  ARRAY = 1 << 1,\n  /** Type is a `Set`. */\n  SET = 1 << 2,\n  /** Type is a `Map`. */\n  MAP = 1 << 3,\n  /** Type is inherently acyclic. */\n  ACYCLIC = 1 << 4,\n  /** Value alignment of 1 byte. */\n  VALUE_ALIGN_0 = 1 << 5,\n  /** Value alignment of 2 bytes. */\n  VALUE_ALIGN_1 = 1 << 6,\n  /** Value alignment of 4 bytes. */\n  VALUE_ALIGN_2 = 1 << 7,\n  /** Value alignment of 8 bytes. */\n  VALUE_ALIGN_3 = 1 << 8,\n  /** Value alignment of 16 bytes. */\n  VALUE_ALIGN_4 = 1 << 9,\n  /** Value is a signed type. */\n  VALUE_SIGNED = 1 << 10,\n  /** Value is a float type. */\n  VALUE_FLOAT = 1 << 11,\n  /** Value type is nullable. */\n  VALUE_NULLABLE = 1 << 12,\n  /** Value type is managed. */\n  VALUE_MANAGED = 1 << 13,\n  /** Key alignment of 1 byte. */\n  KEY_ALIGN_0 = 1 << 14,\n  /** Key alignment of 2 bytes. */\n  KEY_ALIGN_1 = 1 << 15,\n  /** Key alignment of 4 bytes. */\n  KEY_ALIGN_2 = 1 << 16,\n  /** Key alignment of 8 bytes. */\n  KEY_ALIGN_3 = 1 << 17,\n  /** Key alignment of 16 bytes. */\n  KEY_ALIGN_4 = 1 << 18,\n  /** Key is a signed type. */\n  KEY_SIGNED = 1 << 19,\n  /** Key is a float type. */\n  KEY_FLOAT = 1 << 20,\n  /** Key type is nullable. */\n  KEY_NULLABLE = 1 << 21,\n  /** Key type is managed. */\n  KEY_MANAGED = 1 << 22\n}\n","import { DEBUG, BLOCK_OVERHEAD } from \"rt/common\";\nimport { Block, freeBlock, ROOT } from \"rt/tlsf\";\nimport { TypeinfoFlags } from \"shared/typeinfo\";\nimport { onincrement, ondecrement, onfree, onalloc } from \"./rtrace\";\n\n/////////////////////////// A Pure Reference Counting Garbage Collector ///////////////////////////\n// see:     https://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon03Pure.pdf\n\n// ╒══════════════════════ GC Info structure ══════════════════════╕\n// │  3                   2                   1                    │\n// │1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0│\n// ├─┼─┴─┴─┼─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤\n// │B│color│                     refCount                          │\n// └─┴─────┴───────────────────────────────────────────────────────┘\n// B: buffered\n\n// @ts-ignore: decorator\n@inline const BUFFERED_MASK: u32 = 1 << ((sizeof<u32>() * 8) - 1);\n// @ts-ignore: decorator\n@inline const COLOR_BITS = 3;\n// @ts-ignore: decorator\n@inline const COLOR_SHIFT: u32 = ctz(BUFFERED_MASK) - COLOR_BITS;\n// @ts-ignore: decorator\n@inline const COLOR_MASK: u32 = ((1 << COLOR_BITS) - 1) << COLOR_SHIFT;\n// @ts-ignore: decorator\n@inline export const REFCOUNT_MASK: u32 = (1 << COLOR_SHIFT) - 1;\n\n// ╒════════╤═══════════════════ Colors ═══════════════════════════╕\n// │ Color  │ Meaning                                              │\n// ├────────┼──────────────────────────────────────────────────────┤\n// │ BLACK  │ In use or free                                       │\n// │ GRAY   │ Possible member of cycle                             │\n// │ WHITE  │ Member of garbage cycle                              │\n// │ PURPLE │ Possible root of cycle                               │\n// │ RED    │ Candidate cycle undergoing Σ-computation *concurrent │\n// │ ORANGE │ Candidate cycle awaiting epoch boundary  *concurrent │\n// └────────┴──────────────────────────────────────────────────────┘\n// Acyclic detection has been decoupled, hence no GREEN.\n\n// @ts-ignore: decorator\n@inline const COLOR_BLACK: u32 = 0 << COLOR_SHIFT;\n// @ts-ignore: decorator\n@inline const COLOR_GRAY: u32 = 1 << COLOR_SHIFT;\n// @ts-ignore: decorator\n@inline const COLOR_WHITE: u32 = 2 << COLOR_SHIFT;\n// @ts-ignore: decorator\n@inline const COLOR_PURPLE: u32 = 3 << COLOR_SHIFT;\n// @ts-ignore: decorator\n// @inline const COLOR_RED: u32 = 4 << COLOR_SHIFT;\n// @ts-ignore: decorator\n// @inline const COLOR_ORANGE: u32 = 5 << COLOR_SHIFT;\n\n// @ts-ignore: decorator\n@inline const VISIT_DECREMENT = 1; // guard 0\n// @ts-ignore: decorator\n@inline const VISIT_MARKGRAY = 2;\n// @ts-ignore: decorator\n@inline const VISIT_SCAN = 3;\n// @ts-ignore: decorator\n@inline const VISIT_SCANBLACK = 4;\n// @ts-ignore: decorator\n@inline const VISIT_COLLECTWHITE = 5;\n\n// @ts-ignore: decorator\n@global @unsafe\nfunction __visit(ref: usize, cookie: i32): void {\n  if (ref < __heap_base) return;\n  var s = changetype<Block>(ref - BLOCK_OVERHEAD);\n  switch (cookie) {\n    case VISIT_DECREMENT: {\n      decrement(s);\n      break;\n    }\n    case VISIT_MARKGRAY: {\n      if (DEBUG) assert((s.gcInfo & REFCOUNT_MASK) > 0);\n      s.gcInfo = s.gcInfo - 1;\n      markGray(s);\n      break;\n    }\n    case VISIT_SCAN: {\n      scan(s);\n      break;\n    }\n    case VISIT_SCANBLACK: {\n      let info = s.gcInfo;\n      assert((info & ~REFCOUNT_MASK) == ((info + 1) & ~REFCOUNT_MASK)); // overflow\n      s.gcInfo = info + 1;\n      if ((info & COLOR_MASK) != COLOR_BLACK) {\n        scanBlack(s);\n      }\n      break;\n    }\n    case VISIT_COLLECTWHITE: {\n      collectWhite(s);\n      break;\n    }\n    default: if (DEBUG) assert(false);\n  }\n}\n\n/** Increments the reference count of the specified block by one.*/\nfunction increment(s: Block): void {\n  var info = s.gcInfo;\n  assert((info & ~REFCOUNT_MASK) == ((info + 1) & ~REFCOUNT_MASK)); // overflow\n  s.gcInfo = info + 1;\n  if (isDefined(ASC_RTRACE)) onincrement(s);\n  if (DEBUG) assert(!(s.mmInfo & 1)); // used\n}\n\n/** Decrements the reference count of the specified block by one, possibly freeing it. */\nfunction decrement(s: Block): void {\n  var info = s.gcInfo;\n  var rc = info & REFCOUNT_MASK;\n  if (isDefined(ASC_RTRACE)) ondecrement(s);\n  if (DEBUG) assert(!(s.mmInfo & 1)); // used\n  if (rc == 1) {\n    __visit_members(changetype<usize>(s) + BLOCK_OVERHEAD, VISIT_DECREMENT);\n    if (!(info & BUFFERED_MASK)) {\n      freeBlock(ROOT, s);\n    } else {\n      s.gcInfo = BUFFERED_MASK | COLOR_BLACK | 0;\n    }\n  } else {\n    if (DEBUG) assert(rc > 0);\n    if (!(__typeinfo(s.rtId) & TypeinfoFlags.ACYCLIC)) {\n      s.gcInfo = BUFFERED_MASK | COLOR_PURPLE | (rc - 1);\n      if (!(info & BUFFERED_MASK)) {\n        appendRoot(s);\n      }\n    } else {\n      s.gcInfo = (info & ~REFCOUNT_MASK) | (rc - 1);\n    }\n  }\n}\n\n/** Buffer of possible roots. */\n// @ts-ignore: decorator\n@lazy var ROOTS: usize;\n/** Current absolute offset into the `ROOTS` buffer. */\n// @ts-ignore: decorator\n@lazy var CUR: usize = 0;\n/** Current absolute end offset into the `ROOTS` buffer. */\n// @ts-ignore: decorator\n@lazy var END: usize = 0;\n\n/** Appends a block to possible roots. */\nfunction appendRoot(s: Block): void {\n  var cur = CUR;\n  if (cur >= END) {\n    growRoots(); // TBD: either that or pick a default and force collection on overflow\n    cur = CUR;\n  }\n  store<Block>(cur, s);\n  CUR = cur + sizeof<usize>();\n}\n\n/** Grows the roots buffer if it ran full. */\nfunction growRoots(): void {\n  var oldRoots = ROOTS;\n  var oldSize = CUR - oldRoots;\n  var newSize = max(oldSize * 2, 64 << alignof<usize>());\n  var newRoots = __alloc(newSize, 0);\n  if (isDefined(ASC_RTRACE)) onfree(changetype<Block>(newRoots - BLOCK_OVERHEAD)); // neglect unmanaged\n  memory.copy(newRoots, oldRoots, oldSize);\n  if (oldRoots) {\n    if (isDefined(ASC_RTRACE)) onalloc(changetype<Block>(oldRoots - BLOCK_OVERHEAD)); // neglect unmanaged\n    __free(oldRoots);\n  }\n  ROOTS = newRoots;\n  CUR = newRoots + oldSize;\n  END = newRoots + newSize;\n}\n\n/** Collects cyclic garbage. */\n// @ts-ignore: decorator\n@global @unsafe\nexport function __collect(): void {\n\n  // markRoots\n  var roots = ROOTS;\n  var cur = roots;\n  for (let pos = cur, end = CUR; pos < end; pos += sizeof<usize>()) {\n    let s = load<Block>(pos);\n    let info = s.gcInfo;\n    if ((info & COLOR_MASK) == COLOR_PURPLE && (info & REFCOUNT_MASK) > 0) {\n      markGray(s);\n      store<Block>(cur, s);\n      cur += sizeof<usize>();\n    } else {\n      if ((info & COLOR_MASK) == COLOR_BLACK && !(info & REFCOUNT_MASK)) {\n        freeBlock(ROOT, s);\n      } else {\n        s.gcInfo = info & ~BUFFERED_MASK;\n      }\n    }\n  }\n  CUR = cur;\n\n  // scanRoots\n  for (let pos = roots; pos < cur; pos += sizeof<usize>()) {\n    scan(load<Block>(pos));\n  }\n\n  // collectRoots\n  for (let pos = roots; pos < cur; pos += sizeof<usize>()) {\n    let s = load<Block>(pos);\n    s.gcInfo = s.gcInfo & ~BUFFERED_MASK;\n    collectWhite(s);\n  }\n  CUR = roots;\n}\n\n/** Marks a block as gray (possible member of cycle) during the collection phase. */\nfunction markGray(s: Block): void {\n  var info = s.gcInfo;\n  if ((info & COLOR_MASK) != COLOR_GRAY) {\n    s.gcInfo = (info & ~COLOR_MASK) | COLOR_GRAY;\n    __visit_members(changetype<usize>(s) + BLOCK_OVERHEAD, VISIT_MARKGRAY);\n  }\n}\n\n/** Scans a block during the collection phase, determining whether it is garbage or not. */\nfunction scan(s: Block): void {\n  var info = s.gcInfo;\n  if ((info & COLOR_MASK) == COLOR_GRAY) {\n    if ((info & REFCOUNT_MASK) > 0) {\n      scanBlack(s);\n    } else {\n      s.gcInfo = (info & ~COLOR_MASK) | COLOR_WHITE;\n      __visit_members(changetype<usize>(s) + BLOCK_OVERHEAD, VISIT_SCAN);\n    }\n  }\n}\n\n/** Marks a block as black (in use) if it was found to be reachable during the collection phase. */\nfunction scanBlack(s: Block): void {\n  s.gcInfo = (s.gcInfo & ~COLOR_MASK) | COLOR_BLACK;\n  __visit_members(changetype<usize>(s) + BLOCK_OVERHEAD, VISIT_SCANBLACK);\n}\n\n/** Collects all white (member of a garbage cycle) nodes when completing the collection phase.  */\nfunction collectWhite(s: Block): void {\n  var info = s.gcInfo;\n  if ((info & COLOR_MASK) == COLOR_WHITE && !(info & BUFFERED_MASK)) {\n    s.gcInfo = (info & ~COLOR_MASK) | COLOR_BLACK;\n    __visit_members(changetype<usize>(s) + BLOCK_OVERHEAD, VISIT_COLLECTWHITE);\n    freeBlock(ROOT, s);\n  }\n}\n\n// @ts-ignore: decorator\n@global @unsafe\nexport function __retain(ref: usize): usize {\n  if (ref > __heap_base) increment(changetype<Block>(ref - BLOCK_OVERHEAD));\n  return ref;\n}\n\n// @ts-ignore: decorator\n@global @unsafe\nexport function __release(ref: usize): void {\n  if (ref > __heap_base) decrement(changetype<Block>(ref - BLOCK_OVERHEAD));\n}\n\n// @ts-ignore: decorator\n@global @unsafe\nexport function __reset(): void {\n}\n","import { AL_BITS, AL_MASK, DEBUG, BLOCK, BLOCK_OVERHEAD, BLOCK_MAXSIZE } from \"rt/common\";\nimport { onfree, onalloc } from \"./rtrace\";\nimport { REFCOUNT_MASK } from \"./pure\";\n\n/////////////////////// The TLSF (Two-Level Segregate Fit) memory allocator ///////////////////////\n//                             see: http://www.gii.upv.es/tlsf/\n\n// - `ffs(x)` is equivalent to `ctz(x)` with x != 0\n// - `fls(x)` is equivalent to `sizeof(x) * 8 - clz(x) - 1`\n\n// ╒══════════════ Block size interpretation (32-bit) ═════════════╕\n//    3                   2                   1\n//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0  bits\n// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┼─┴─┴─┴─╫─┴─┴─┴─┤\n// │ |                    FL                       │ SB = SL + AL  │ ◄─ usize\n// └───────────────────────────────────────────────┴───────╨───────┘\n// FL: first level, SL: second level, AL: alignment, SB: small block\n\n// @ts-ignore: decorator\n@inline const SL_BITS: u32 = 4;\n// @ts-ignore: decorator\n@inline const SL_SIZE: usize = 1 << <usize>SL_BITS;\n\n// @ts-ignore: decorator\n@inline const SB_BITS: usize = <usize>(SL_BITS + AL_BITS);\n// @ts-ignore: decorator\n@inline const SB_SIZE: usize = 1 << <usize>SB_BITS;\n\n// @ts-ignore: decorator\n@inline const FL_BITS: u32 = 31 - SB_BITS;\n\n// [00]: < 256B (SB)  [12]: < 1M\n// [01]: < 512B       [13]: < 2M\n// [02]: < 1K         [14]: < 4M\n// [03]: < 2K         [15]: < 8M\n// [04]: < 4K         [16]: < 16M\n// [05]: < 8K         [17]: < 32M\n// [06]: < 16K        [18]: < 64M\n// [07]: < 32K        [19]: < 128M\n// [08]: < 64K        [20]: < 256M\n// [09]: < 128K       [21]: < 512M\n// [10]: < 256K       [22]: <= 1G - OVERHEAD\n// [11]: < 512K\n// VMs limit to 2GB total (currently), making one 1G block max (or three 512M etc.) due to block overhead\n\n// Tags stored in otherwise unused alignment bits\n\n// @ts-ignore: decorator\n@inline const FREE: usize = 1 << 0;\n// @ts-ignore: decorator\n@inline const LEFTFREE: usize = 1 << 1;\n// @ts-ignore: decorator\n@inline const TAGS_MASK: usize = FREE | LEFTFREE; // <= AL_MASK\n\n// ╒════════════════════ Block layout (32-bit) ════════════════════╕\n//    3                   2                   1\n//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0  bits\n// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┼─┼─┼─┤ overhead   ┐\n// │                          size                           │0│L│F│ ◄─┐ info\n// ├─────────────────────────────────────────────────────────┴─┴─┴─┤   │\n// │                                                               │   │\n// │               ... additional runtime overhead ...             │   │\n// │                                                               │   │\n// ╞═══════════════════════════════════════════════════════════════╡   │      ┐ ┘\n// │                        if free: ◄ prev                        │ ◄─┤ usize\n// ├───────────────────────────────────────────────────────────────┤   │\n// │                        if free: next ►                        │ ◄─┤\n// ├───────────────────────────────────────────────────────────────┤   │\n// │                             ...                               │   │    = 0\n// ├───────────────────────────────────────────────────────────────┤   │\n// │                        if free: back ▲                        │ ◄─┘\n// └───────────────────────────────────────────────────────────────┘ payload  ┘ >= MIN SIZE\n// F: FREE, L: LEFTFREE\n@unmanaged export class Block extends BLOCK {\n\n  /** Previous free block, if any. Only valid if free, otherwise part of payload. */\n  prev: Block | null;\n  /** Next free block, if any. Only valid if free, otherwise part of payload. */\n  next: Block | null;\n\n  // If the block is free, there is a 'back'reference at its end pointing at its start.\n}\n\n// Block constants. A block must have a minimum size of three pointers so it can hold `prev`,\n// `next` and `back` if free.\n\n// @ts-ignore: decorator\n@inline const BLOCK_MINSIZE: usize = (3 * sizeof<usize>() + AL_MASK) & ~AL_MASK; // prev + next + back\n// @ts-ignore: decorator\n// @inline const BLOCK_MAXSIZE: usize = 1 << (FL_BITS + SB_BITS - 1); // exclusive, lives in common.ts\n\n/** Gets the left block of a block. Only valid if the left block is free. */\n// @ts-ignore: decorator\n@inline function GETFREELEFT(block: Block): Block {\n  return load<Block>(changetype<usize>(block) - sizeof<usize>());\n}\n\n/** Gets the right block of of a block by advancing to the right by its size. */\n// @ts-ignore: decorator\n@inline function GETRIGHT(block: Block): Block {\n  return changetype<Block>(changetype<usize>(block) + BLOCK_OVERHEAD + (block.mmInfo & ~TAGS_MASK));\n}\n\n// ╒═════════════════════ Root layout (32-bit) ════════════════════╕\n//    3                   2                   1\n//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0  bits\n// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤          ┐\n// │        0        |           flMap                            S│ ◄────┐\n// ╞═══════════════════════════════════════════════════════════════╡      │\n// │                           slMap[0] S                          │ ◄─┐  │\n// ├───────────────────────────────────────────────────────────────┤   │  │\n// │                           slMap[1]                            │ ◄─┤  │\n// ├───────────────────────────────────────────────────────────────┤  u32 │\n// │                           slMap[22]                           │ ◄─┘  │\n// ╞═══════════════════════════════════════════════════════════════╡    usize\n// │                            head[0]                            │ ◄────┤\n// ├───────────────────────────────────────────────────────────────┤      │\n// │                              ...                              │ ◄────┤\n// ├───────────────────────────────────────────────────────────────┤      │\n// │                           head[367]                           │ ◄────┤\n// ╞═══════════════════════════════════════════════════════════════╡      │\n// │                             tail                              │ ◄────┘\n// └───────────────────────────────────────────────────────────────┘   SIZE   ┘\n// S: Small blocks map\n@unmanaged class Root {\n  /** First level bitmap. */\n  flMap: usize;\n}\n\n// Root constants. Where stuff is stored inside of the root structure.\n\n// @ts-ignore: decorator\n@inline const SL_START = sizeof<usize>();\n// @ts-ignore: decorator\n@inline const SL_END = SL_START + (FL_BITS << alignof<u32>());\n// @ts-ignore: decorator\n@inline const HL_START = (SL_END + AL_MASK) & ~AL_MASK;\n// @ts-ignore: decorator\n@inline const HL_END = HL_START + FL_BITS * SL_SIZE * sizeof<usize>();\n// @ts-ignore: decorator\n@inline const ROOT_SIZE = HL_END + sizeof<usize>();\n\n// @ts-ignore: decorator\n@lazy export var ROOT: Root;\n\n/** Gets the second level map of the specified first level. */\n// @ts-ignore: decorator\n@inline function GETSL(root: Root, fl: usize): u32 {\n  return load<u32>(\n    changetype<usize>(root) + (fl << alignof<u32>()),\n    SL_START\n  );\n}\n\n/** Sets the second level map of the specified first level. */\n// @ts-ignore: decorator\n@inline function SETSL(root: Root, fl: usize, slMap: u32): void {\n  store<u32>(\n    changetype<usize>(root) + (fl << alignof<u32>()),\n    slMap,\n    SL_START\n  );\n}\n\n/** Gets the head of the free list for the specified combination of first and second level. */\n// @ts-ignore: decorator\n@inline function GETHEAD(root: Root, fl: usize, sl: u32): Block | null {\n  return load<Block>(\n    changetype<usize>(root) + (((fl << SL_BITS) + <usize>sl) << alignof<usize>()),\n    HL_START\n  );\n}\n\n/** Sets the head of the free list for the specified combination of first and second level. */\n// @ts-ignore: decorator\n@inline function SETHEAD(root: Root, fl: usize, sl: u32, head: Block | null): void {\n  store<Block>(\n    changetype<usize>(root) + (((fl << SL_BITS) + <usize>sl) << alignof<usize>()),\n    head,\n    HL_START\n  );\n}\n\n/** Gets the tail block.. */\n// @ts-ignore: decorator\n@inline function GETTAIL(root: Root): Block {\n  return load<Block>(\n    changetype<usize>(root),\n    HL_END\n  );\n}\n\n/** Sets the tail block. */\n// @ts-ignore: decorator\n@inline function SETTAIL(root: Root, tail: Block): void {\n  store<Block>(\n    changetype<usize>(root),\n    tail,\n    HL_END\n  );\n}\n\n/** Inserts a previously used block back into the free list. */\nfunction insertBlock(root: Root, block: Block): void {\n  if (DEBUG) assert(block); // cannot be null\n  var blockInfo = block.mmInfo;\n  if (DEBUG) assert(blockInfo & FREE); // must be free\n\n  var right = GETRIGHT(block);\n  var rightInfo = right.mmInfo;\n\n  // merge with right block if also free\n  if (rightInfo & FREE) {\n    let newSize = (blockInfo & ~TAGS_MASK) + BLOCK_OVERHEAD + (rightInfo & ~TAGS_MASK);\n    if (newSize < BLOCK_MAXSIZE) {\n      removeBlock(root, right);\n      block.mmInfo = blockInfo = (blockInfo & TAGS_MASK) | newSize;\n      right = GETRIGHT(block);\n      rightInfo = right.mmInfo;\n      // 'back' is set below\n    }\n  }\n\n  // merge with left block if also free\n  if (blockInfo & LEFTFREE) {\n    let left = GETFREELEFT(block);\n    let leftInfo = left.mmInfo;\n    if (DEBUG) assert(leftInfo & FREE); // must be free according to right tags\n    let newSize = (leftInfo & ~TAGS_MASK) + BLOCK_OVERHEAD + (blockInfo & ~TAGS_MASK);\n    if (newSize < BLOCK_MAXSIZE) {\n      removeBlock(root, left);\n      left.mmInfo = blockInfo = (leftInfo & TAGS_MASK) | newSize;\n      block = left;\n      // 'back' is set below\n    }\n  }\n\n  right.mmInfo = rightInfo | LEFTFREE;\n  // right is no longer used now, hence rightInfo is not synced\n\n  // we now know the size of the block\n  var size = blockInfo & ~TAGS_MASK;\n  if (DEBUG) assert(size >= BLOCK_MINSIZE && size < BLOCK_MAXSIZE); // must be a valid size\n  if (DEBUG) assert(changetype<usize>(block) + BLOCK_OVERHEAD + size == changetype<usize>(right)); // must match\n\n  // set 'back' to itself at the end of block\n  store<Block>(changetype<usize>(right) - sizeof<usize>(), block);\n\n  // mapping_insert\n  var fl: usize, sl: u32;\n  if (size < SB_SIZE) {\n    fl = 0;\n    sl = <u32>(size >> AL_BITS);\n  } else {\n    const inv: usize = sizeof<usize>() * 8 - 1;\n    fl = inv - clz<usize>(size);\n    sl = <u32>((size >> (fl - SL_BITS)) ^ (1 << SL_BITS));\n    fl -= SB_BITS - 1;\n  }\n  if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range\n\n  // perform insertion\n  var head = GETHEAD(root, fl, sl);\n  block.prev = null;\n  block.next = head;\n  if (head) head.prev = block;\n  SETHEAD(root, fl, sl, block);\n\n  // update first and second level maps\n  root.flMap |= (1 << fl);\n  SETSL(root, fl, GETSL(root, fl) | (1 << sl));\n}\n\n/** Removes a free block from internal lists. */\nfunction removeBlock(root: Root, block: Block): void {\n  var blockInfo = block.mmInfo;\n  if (DEBUG) assert(blockInfo & FREE); // must be free\n  var size = blockInfo & ~TAGS_MASK;\n  if (DEBUG) assert(size >= BLOCK_MINSIZE && size < BLOCK_MAXSIZE); // must be valid\n\n  // mapping_insert\n  var fl: usize, sl: u32;\n  if (size < SB_SIZE) {\n    fl = 0;\n    sl = <u32>(size >> AL_BITS);\n  } else {\n    const inv: usize = sizeof<usize>() * 8 - 1;\n    fl = inv - clz<usize>(size);\n    sl = <u32>((size >> (fl - SL_BITS)) ^ (1 << SL_BITS));\n    fl -= SB_BITS - 1;\n  }\n  if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range\n\n  // link previous and next free block\n  var prev = block.prev;\n  var next = block.next;\n  if (prev) prev.next = next;\n  if (next) next.prev = prev;\n\n  // update head if we are removing it\n  if (block == GETHEAD(root, fl, sl)) {\n    SETHEAD(root, fl, sl, next);\n\n    // clear second level map if head is empty now\n    if (!next) {\n      let slMap = GETSL(root, fl);\n      SETSL(root, fl, slMap &= ~(1 << sl));\n\n      // clear first level map if second level is empty now\n      if (!slMap) root.flMap &= ~(1 << fl);\n    }\n  }\n  // note: does not alter left/back because it is likely that splitting\n  // is performed afterwards, invalidating those changes. so, the caller\n  // must perform those updates.\n}\n\n/** Searches for a free block of at least the specified size. */\nfunction searchBlock(root: Root, size: usize): Block | null {\n  // size was already asserted by caller\n\n  // mapping_search\n  var fl: usize, sl: u32;\n  if (size < SB_SIZE) {\n    fl = 0;\n    sl = <u32>(size >> AL_BITS);\n  } else {\n    const halfMaxSize = BLOCK_MAXSIZE >> 1; // don't round last fl\n    const inv: usize = sizeof<usize>() * 8 - 1;\n    const invRound = inv - SL_BITS;\n    let requestSize = size < halfMaxSize\n      ? size + (1 << (invRound - clz<usize>(size))) - 1\n      : size;\n    fl = inv - clz<usize>(requestSize);\n    sl = <u32>((requestSize >> (fl - SL_BITS)) ^ (1 << SL_BITS));\n    fl -= SB_BITS - 1;\n  }\n  if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range\n\n  // search second level\n  var slMap = GETSL(root, fl) & (~0 << sl);\n  var head: Block | null = null;\n  if (!slMap) {\n    // search next larger first level\n    let flMap = root.flMap & (~0 << (fl + 1));\n    if (!flMap) {\n      head = null;\n    } else {\n      fl = ctz<usize>(flMap);\n      slMap = GETSL(root, fl);\n      if (DEBUG) assert(slMap);  // can't be zero if fl points here\n      head = GETHEAD(root, fl, ctz<u32>(slMap));\n    }\n  } else {\n    head = GETHEAD(root, fl, ctz<u32>(slMap));\n  }\n  return head;\n}\n\n/** Prepares the specified block before (re-)use, possibly splitting it. */\nfunction prepareBlock(root: Root, block: Block, size: usize): void {\n  // size was already asserted by caller\n\n  var blockInfo = block.mmInfo;\n  if (DEBUG) assert(!(size & AL_MASK)); // size must be aligned so the new block is\n\n  // split if the block can hold another MINSIZE block incl. overhead\n  var remaining = (blockInfo & ~TAGS_MASK) - size;\n  if (remaining >= BLOCK_OVERHEAD + BLOCK_MINSIZE) {\n    block.mmInfo = size | (blockInfo & LEFTFREE); // also discards FREE\n\n    let spare = changetype<Block>(changetype<usize>(block) + BLOCK_OVERHEAD + size);\n    spare.mmInfo = (remaining - BLOCK_OVERHEAD) | FREE; // not LEFTFREE\n    insertBlock(root, spare); // also sets 'back'\n\n  // otherwise tag block as no longer FREE and right as no longer LEFTFREE\n  } else {\n    block.mmInfo = blockInfo & ~FREE;\n    GETRIGHT(block).mmInfo &= ~LEFTFREE;\n  }\n}\n\n/** Adds more memory to the pool. */\nfunction addMemory(root: Root, start: usize, end: usize): bool {\n  if (DEBUG) {\n    assert(\n      start <= end &&       // must be valid\n      !(start & AL_MASK) && // must be aligned\n      !(end & AL_MASK)      // must be aligned\n    );\n  }\n\n  var tail = GETTAIL(root);\n  var tailInfo: usize = 0;\n  if (tail) { // more memory\n    if (DEBUG) assert(start >= changetype<usize>(tail) + BLOCK_OVERHEAD);\n\n    // merge with current tail if adjacent\n    if (start - BLOCK_OVERHEAD == changetype<usize>(tail)) {\n      start -= BLOCK_OVERHEAD;\n      tailInfo = tail.mmInfo;\n    } else {\n      // We don't do this, but a user might `memory.grow` manually\n      // leading to non-adjacent pages managed by TLSF.\n    }\n\n  } else if (DEBUG) { // first memory\n    assert(start >= changetype<usize>(root) + ROOT_SIZE); // starts after root\n  }\n\n  // check if size is large enough for a free block and the tail block\n  var size = end - start;\n  if (size < BLOCK_OVERHEAD + BLOCK_MINSIZE + BLOCK_OVERHEAD) {\n    return false;\n  }\n\n  // left size is total minus its own and the zero-length tail's header\n  var leftSize = size - (BLOCK_OVERHEAD << 1);\n  var left = changetype<Block>(start);\n  left.mmInfo = leftSize | FREE | (tailInfo & LEFTFREE);\n  left.prev = null;\n  left.next = null;\n\n  // tail is a zero-length used block\n  tail = changetype<Block>(start + size - BLOCK_OVERHEAD);\n  tail.mmInfo = 0 | LEFTFREE;\n  SETTAIL(root, tail);\n\n  insertBlock(root, left); // also merges with free left before tail / sets 'back'\n\n  return true;\n}\n\n/** Grows memory to fit at least another block of the specified size. */\nfunction growMemory(root: Root, size: usize): void {\n  // Here, both rounding performed in searchBlock ...\n  const halfMaxSize = BLOCK_MAXSIZE >> 1;\n  if (size < halfMaxSize) { // don't round last fl\n    const invRound = (sizeof<usize>() * 8 - 1) - SL_BITS;\n    size += (1 << (invRound - clz<usize>(size))) - 1;\n  }\n  // and additional BLOCK_OVERHEAD must be taken into account. If we are going\n  // to merge with the tail block, that's one time, otherwise it's two times.\n  var pagesBefore = memory.size();\n  size += BLOCK_OVERHEAD << usize((<usize>pagesBefore << 16) - BLOCK_OVERHEAD != changetype<usize>(GETTAIL(root)));\n  var pagesNeeded = <i32>(((size + 0xffff) & ~0xffff) >>> 16);\n  var pagesWanted = max(pagesBefore, pagesNeeded); // double memory\n  if (memory.grow(pagesWanted) < 0) {\n    if (memory.grow(pagesNeeded) < 0) unreachable();\n  }\n  var pagesAfter = memory.size();\n  addMemory(root, <usize>pagesBefore << 16, <usize>pagesAfter << 16);\n}\n\n/** Prepares and checks an allocation size. */\nfunction prepareSize(size: usize): usize {\n  if (size >= BLOCK_MAXSIZE) throw new Error(\"allocation too large\");\n  return max<usize>((size + AL_MASK) & ~AL_MASK, BLOCK_MINSIZE); // align and ensure min size\n}\n\n/** Initilizes the root structure. */\nexport function initializeRoot(): void {\n  var rootOffset = (__heap_base + AL_MASK) & ~AL_MASK;\n  var pagesBefore = memory.size();\n  var pagesNeeded = <i32>((((rootOffset + ROOT_SIZE) + 0xffff) & ~0xffff) >>> 16);\n  if (pagesNeeded > pagesBefore && memory.grow(pagesNeeded - pagesBefore) < 0) unreachable();\n  var root = changetype<Root>(rootOffset);\n  root.flMap = 0;\n  SETTAIL(root, changetype<Block>(0));\n  for (let fl: usize = 0; fl < FL_BITS; ++fl) {\n    SETSL(root, fl, 0);\n    for (let sl: u32 = 0; sl < SL_SIZE; ++sl) {\n      SETHEAD(root, fl, sl, null);\n    }\n  }\n  addMemory(root, (rootOffset + ROOT_SIZE + AL_MASK) & ~AL_MASK, memory.size() << 16);\n  ROOT = root;\n}\n\n// @ts-ignore: decorator\n@lazy\nvar collectLock: bool = false;\n\n/** Allocates a block of the specified size. */\nexport function allocateBlock(root: Root, size: usize): Block {\n  if (DEBUG) assert(!collectLock); // must not allocate while collecting\n  var payloadSize = prepareSize(size);\n  var block = searchBlock(root, payloadSize);\n  if (!block) {\n    if (gc.auto) {\n      if (DEBUG) collectLock = true;\n      __collect();\n      if (DEBUG) collectLock = false;\n      block = searchBlock(root, payloadSize);\n      if (!block) {\n        growMemory(root, payloadSize);\n        block = <Block>searchBlock(root, payloadSize);\n        if (DEBUG) assert(block); // must be found now\n      }\n    } else {\n      growMemory(root, payloadSize);\n      block = <Block>searchBlock(root, payloadSize);\n      if (DEBUG) assert(block); // must be found now\n    }\n  }\n  if (DEBUG) assert((block.mmInfo & ~TAGS_MASK) >= payloadSize); // must fit\n  block.gcInfo = 0; // RC=0\n  // block.rtId = 0; // set by the caller (__alloc)\n  block.rtSize = size;\n  removeBlock(root, <Block>block);\n  prepareBlock(root, <Block>block, payloadSize);\n  if (isDefined(ASC_RTRACE)) onalloc(<Block>block);\n  return <Block>block;\n}\n\n/** Reallocates a block to the specified size. */\nexport function reallocateBlock(root: Root, block: Block, size: usize): Block {\n  var payloadSize = prepareSize(size);\n  var blockInfo = block.mmInfo;\n  if (DEBUG) {\n    assert(\n      !(blockInfo & FREE) &&           // must be used\n      !(block.gcInfo & ~REFCOUNT_MASK) // not buffered or != BLACK\n    );\n  }\n\n  // possibly split and update runtime size if it still fits\n  if (payloadSize <= (blockInfo & ~TAGS_MASK)) {\n    prepareBlock(root, block, payloadSize);\n    block.rtSize = size;\n    return block;\n  }\n\n  // merge with right free block if merger is large enough\n  var right = GETRIGHT(block);\n  var rightInfo = right.mmInfo;\n  if (rightInfo & FREE) {\n    let mergeSize = (blockInfo & ~TAGS_MASK) + BLOCK_OVERHEAD + (rightInfo & ~TAGS_MASK);\n    if (mergeSize >= payloadSize) {\n      removeBlock(root, right);\n      // TODO: this can yield an intermediate block larger than BLOCK_MAXSIZE, which\n      // is immediately split though. does this trigger any assertions / issues?\n      block.mmInfo = (blockInfo & TAGS_MASK) | mergeSize;\n      block.rtSize = size;\n      prepareBlock(root, block, payloadSize);\n      return block;\n    }\n  }\n\n  // otherwise move the block\n  var newBlock = allocateBlock(root, size);\n  newBlock.rtId = block.rtId;\n  memory.copy(changetype<usize>(newBlock) + BLOCK_OVERHEAD, changetype<usize>(block) + BLOCK_OVERHEAD, size);\n  block.mmInfo = blockInfo | FREE;\n  insertBlock(root, block);\n  if (isDefined(ASC_RTRACE)) onfree(block);\n  return newBlock;\n}\n\n/** Frees a block. */\nexport function freeBlock(root: Root, block: Block): void {\n  var blockInfo = block.mmInfo;\n  assert(!(blockInfo & FREE)); // must be used (user might call through to this)\n  block.mmInfo = blockInfo | FREE;\n  insertBlock(root, block);\n  if (isDefined(ASC_RTRACE)) onfree(block);\n}\n\n// @ts-ignore: decorator\n@global @unsafe\nexport function __alloc(size: usize, id: u32): usize {\n  var root = ROOT;\n  if (!root) {\n    initializeRoot();\n    root = ROOT;\n  }\n  var block = allocateBlock(root, size);\n  block.rtId = id;\n  return changetype<usize>(block) + BLOCK_OVERHEAD;\n}\n\n// @ts-ignore: decorator\n@global @unsafe\nexport function __realloc(ref: usize, size: usize): usize {\n  if (DEBUG) assert(ROOT); // must be initialized\n  assert(ref != 0 && !(ref & AL_MASK)); // must exist and be aligned\n  return changetype<usize>(reallocateBlock(ROOT, changetype<Block>(ref - BLOCK_OVERHEAD), size)) + BLOCK_OVERHEAD;\n}\n\n// @ts-ignore: decorator\n@global @unsafe\nexport function __free(ref: usize): void {\n  if (DEBUG) assert(ROOT); // must be initialized\n  assert(ref != 0 && !(ref & AL_MASK)); // must exist and be aligned\n  freeBlock(ROOT, changetype<Block>(ref - BLOCK_OVERHEAD));\n}\n","/// <reference path=\"./rt/index.d.ts\" />\n\n/** Garbage collector interface. */\nexport namespace gc {\n\n  /** Can be set to `false` to disable automatic collection. Defaults to `true`. */\n  export var auto: bool = true;\n\n  /** Performs a full garbage collection cycle. */\n  export function collect(): void {\n    __collect();\n  }\n}\n","import { Typeinfo, TypeinfoFlags } from \"./shared/typeinfo\";\nimport { E_INDEXOUTOFRANGE } from \"./util/error\";\nimport { BLOCK, BLOCK_OVERHEAD } from \"./rt/common\";\nimport { ArrayBufferView } from \"./arraybuffer\";\n\n// @ts-ignore: decorator\n@builtin\nexport declare const __rtti_base: usize;\n\n// @ts-ignore: decorator\n@builtin @unsafe\nexport declare function __visit_globals(cookie: u32): void;\n\n// @ts-ignore: decorator\n@builtin @unsafe\nexport declare function __visit_members(ref: usize, cookie: u32): void;\n\n// @ts-ignore: decorator\n@unsafe\nexport function __typeinfo(id: u32): TypeinfoFlags {\n  var ptr = __rtti_base;\n  if (id > load<u32>(ptr)) throw new Error(E_INDEXOUTOFRANGE);\n  return changetype<Typeinfo>(ptr + sizeof<u32>() + id * offsetof<Typeinfo>()).flags;\n}\n\n// @ts-ignore: decorator\n@unsafe\nexport function __instanceof(ref: usize, superId: u32): bool { // keyword\n  var id = changetype<BLOCK>(ref - BLOCK_OVERHEAD).rtId;\n  var ptr = __rtti_base;\n  if (id <= load<u32>(ptr)) {\n    do if (id == superId) return true;\n    while (id = changetype<Typeinfo>(ptr + sizeof<u32>() + id * offsetof<Typeinfo>()).base);\n  }\n  return false;\n}\n\n// @ts-ignore: decorator\n@unsafe\nexport function __allocArray(length: i32, alignLog2: usize, id: u32, data: usize = 0): usize {\n  var array = __alloc(offsetof<i32[]>(), id);\n  var bufferSize = <usize>length << alignLog2;\n  var buffer = __alloc(bufferSize, idof<ArrayBuffer>());\n  store<usize>(array, __retain(buffer), offsetof<ArrayBufferView>(\"buffer\"));\n  store<usize>(array, buffer, offsetof<ArrayBufferView>(\"dataStart\"));\n  store<u32>(array, bufferSize, offsetof<ArrayBufferView>(\"byteLength\"));\n  store<i32>(changetype<usize>(array), length, offsetof<i32[]>(\"length_\"));\n  if (data) memory.copy(buffer, data, bufferSize);\n  return array;\n}\n\n// These are provided by the respective implementation, included as another entry file by asc:\n\n// @builtin @unsafe\n// export declare function __alloc(size: usize, id: u32): usize;\n\n// // @ts-ignore: decorator\n// @builtin @unsafe\n// export declare function __realloc(ref: usize, size: usize): usize;\n\n// // @ts-ignore: decorator\n// @builtin @unsafe\n// export declare function __free(ref: usize): void;\n\n// // @ts-ignore: decorator\n// @builtin @unsafe\n// export declare function __retain(ref: usize): usize;\n\n// // @ts-ignore: decorator\n// @builtin @unsafe\n// export declare function __release(ref: usize): void;\n\n// // @ts-ignore: decorator\n// @builtin @unsafe\n// export declare function __collect(): void;\n\n// // @ts-ignore: decorator\n// @builtin @unsafe\n// export declare function __visit(ref: usize, cookie: u32): void;\n","// Common error messages for use accross the standard library. Keeping error messages compact\n// and reusing them where possible ensures minimal static data in binaries.\n\n// @ts-ignore: decorator\n@lazy @inline\nexport const E_INDEXOUTOFRANGE: string = \"Index out of range\";\n\n// @ts-ignore: decorator\n@lazy @inline\nexport const E_INVALIDLENGTH: string = \"Invalid length\";\n\n// @ts-ignore: decorator\n@lazy @inline\nexport const E_EMPTYARRAY: string = \"Array is empty\";\n\n// @ts-ignore: decorator\n@lazy @inline\nexport const E_HOLEYARRAY: string = \"Element type must be nullable if array is holey\";\n\n// @ts-ignore: decorator\n@lazy @inline\nexport const E_NOTIMPLEMENTED: string = \"Not implemented\";\n\n// @ts-ignore: decorator\n@lazy @inline\nexport const E_KEYNOTFOUND: string = \"Key does not exist\";\n","import { memcmp, memmove, memset } from \"./util/memory\";\nimport { E_NOTIMPLEMENTED } from \"./util/error\";\n\n/** Memory manager interface. */\nexport namespace memory {\n\n  /** Gets the size of the memory in pages. */\n  // @ts-ignore: decorator\n  @builtin\n  export declare function size(): i32;\n\n  /** Grows the memory by the given size in pages and returns the previous size in pages. */\n  // @ts-ignore: decorator\n  @unsafe @builtin\n  export declare function grow(pages: i32): i32;\n\n  /** Fills a section in memory with the specified byte value. */\n  // @ts-ignore: decorator\n  @unsafe @builtin\n  export function fill(dst: usize, c: u8, n: usize): void {\n    memset(dst, c, n); // fallback if \"bulk-memory\" isn't enabled\n  }\n\n  /** Copies a section of memory to another. Has move semantics. */\n  // @ts-ignore: decorator\n  @unsafe @builtin\n  export function copy(dst: usize, src: usize, n: usize): void {\n    memmove(dst, src, n); // fallback if \"bulk-memory\" isn't enabled\n  }\n\n  /** Initializes a memory segment. */\n  // @ts-ignore: decorator\n  @unsafe\n  export function init(segmentIndex: u32, srcOffset: usize, dstOffset: usize, n: usize): void {\n    throw new Error(E_NOTIMPLEMENTED);\n  }\n\n  /** Drops a memory segment. */\n  // @ts-ignore: decorator\n  @unsafe\n  export function drop(segmentIndex: u32): void {\n    throw new Error(E_NOTIMPLEMENTED);\n  }\n\n  /** Repeats a section of memory at a specific address. */\n  // @ts-ignore: decorator\n  @unsafe\n  export function repeat(dst: usize, src: usize, srcLength: usize, count: usize): void {\n    var index: usize = 0;\n    var total = srcLength * count;\n    while (index < total) {\n      memory.copy(dst + index, src, srcLength);\n      index += srcLength;\n    }\n  }\n\n  /** Compares a section of memory to another. */\n  // @ts-ignore: decorator\n  @inline\n  export function compare(vl: usize, vr: usize, n: usize): i32 {\n    return memcmp(vl, vr, n);\n  }\n}\n","export function memcpy(dest: usize, src: usize, n: usize): void { // see: musl/src/string/memcpy.c\n  if (ASC_SHRINK_LEVEL > 1) {\n    while (n) {\n      store<u8>(dest++, load<u8>(src++));\n      --n;\n    }\n  } else {\n    let w: u32, x: u32;\n\n    // copy 1 byte each until src is aligned to 4 bytes\n    while (n && (src & 3)) {\n      store<u8>(dest++, load<u8>(src++));\n      n--;\n    }\n\n    // if dst is aligned to 4 bytes as well, copy 4 bytes each\n    if ((dest & 3) == 0) {\n      while (n >= 16) {\n        store<u32>(dest     , load<u32>(src     ));\n        store<u32>(dest +  4, load<u32>(src +  4));\n        store<u32>(dest +  8, load<u32>(src +  8));\n        store<u32>(dest + 12, load<u32>(src + 12));\n        src += 16; dest += 16; n -= 16;\n      }\n      if (n & 8) {\n        store<u32>(dest    , load<u32>(src    ));\n        store<u32>(dest + 4, load<u32>(src + 4));\n        dest += 8; src += 8;\n      }\n      if (n & 4) {\n        store<u32>(dest, load<u32>(src));\n        dest += 4; src += 4;\n      }\n      if (n & 2) { // drop to 2 bytes each\n        store<u16>(dest, load<u16>(src));\n        dest += 2; src += 2;\n      }\n      if (n & 1) { // drop to 1 byte\n        store<u8>(dest++, load<u8>(src++));\n      }\n      return;\n    }\n\n    // if dst is not aligned to 4 bytes, use alternating shifts to copy 4 bytes each\n    // doing shifts if faster when copying enough bytes (here: 32 or more)\n    if (n >= 32) {\n      switch (dest & 3) {\n        // known to be != 0\n        case 1: {\n          w = load<u32>(src);\n          store<u8>(dest++, load<u8>(src++));\n          store<u8>(dest++, load<u8>(src++));\n          store<u8>(dest++, load<u8>(src++));\n          n -= 3;\n          while (n >= 17) {\n            x = load<u32>(src + 1);\n            store<u32>(dest, w >> 24 | x << 8);\n            w = load<u32>(src + 5);\n            store<u32>(dest + 4, x >> 24 | w << 8);\n            x = load<u32>(src + 9);\n            store<u32>(dest + 8, w >> 24 | x << 8);\n            w = load<u32>(src + 13);\n            store<u32>(dest + 12, x >> 24 | w << 8);\n            src += 16; dest += 16; n -= 16;\n          }\n          break;\n        }\n        case 2: {\n          w = load<u32>(src);\n          store<u8>(dest++, load<u8>(src++));\n          store<u8>(dest++, load<u8>(src++));\n          n -= 2;\n          while (n >= 18) {\n            x = load<u32>(src + 2);\n            store<u32>(dest, w >> 16 | x << 16);\n            w = load<u32>(src + 6);\n            store<u32>(dest + 4, x >> 16 | w << 16);\n            x = load<u32>(src + 10);\n            store<u32>(dest + 8, w >> 16 | x << 16);\n            w = load<u32>(src + 14);\n            store<u32>(dest + 12, x >> 16 | w << 16);\n            src += 16; dest += 16; n -= 16;\n          }\n          break;\n        }\n        case 3: {\n          w = load<u32>(src);\n          store<u8>(dest++, load<u8>(src++));\n          n -= 1;\n          while (n >= 19) {\n            x = load<u32>(src + 3);\n            store<u32>(dest, w >> 8 | x << 24);\n            w = load<u32>(src + 7);\n            store<u32>(dest + 4, x >> 8 | w << 24);\n            x = load<u32>(src + 11);\n            store<u32>(dest + 8, w >> 8 | x << 24);\n            w = load<u32>(src + 15);\n            store<u32>(dest + 12, x >> 8 | w << 24);\n            src += 16; dest += 16; n -= 16;\n          }\n          break;\n        }\n      }\n    }\n\n    // copy remaining bytes one by one\n    if (n & 16) {\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n    }\n    if (n & 8) {\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n    }\n    if (n & 4) {\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n    }\n    if (n & 2) {\n      store<u8>(dest++, load<u8>(src++));\n      store<u8>(dest++, load<u8>(src++));\n    }\n    if (n & 1) {\n      store<u8>(dest++, load<u8>(src++));\n    }\n  }\n}\n\n// @ts-ignore: decorator\n@inline\nexport function memmove(dest: usize, src: usize, n: usize): void { // see: musl/src/string/memmove.c\n  if (dest === src) return;\n  if (ASC_SHRINK_LEVEL < 1) {\n    if (src + n <= dest || dest + n <= src) {\n      memcpy(dest, src, n);\n      return;\n    }\n  }\n  if (dest < src) {\n    if ((src & 7) == (dest & 7)) {\n      while (dest & 7) {\n        if (!n) return;\n        --n;\n        store<u8>(dest++, load<u8>(src++));\n      }\n      while (n >= 8) {\n        store<u64>(dest, load<u64>(src));\n        n    -= 8;\n        dest += 8;\n        src  += 8;\n      }\n    }\n    while (n) {\n      store<u8>(dest++, load<u8>(src++));\n      --n;\n    }\n  } else {\n    if ((src & 7) == (dest & 7)) {\n      while ((dest + n) & 7) {\n        if (!n) return;\n        store<u8>(dest + --n, load<u8>(src + n));\n      }\n      while (n >= 8) {\n        n -= 8;\n        store<u64>(dest + n, load<u64>(src + n));\n      }\n    }\n    while (n) {\n      store<u8>(dest + --n, load<u8>(src + n));\n    }\n  }\n}\n\n// @ts-ignore: decorator\n@inline\nexport function memset(dest: usize, c: u8, n: usize): void { // see: musl/src/string/memset\n  if (ASC_SHRINK_LEVEL > 1) {\n    while (n) {\n      store<u8>(dest++, c);\n      --n;\n    }\n  } else {\n    // fill head and tail with minimal branching\n    if (!n) return;\n    store<u8>(dest, c);\n    store<u8>(dest + n - 1, c);\n    if (n <= 2) return;\n\n    store<u8>(dest + 1, c);\n    store<u8>(dest + 2, c);\n    store<u8>(dest + n - 2, c);\n    store<u8>(dest + n - 3, c);\n    if (n <= 6) return;\n    store<u8>(dest + 3, c);\n    store<u8>(dest + n - 4, c);\n    if (n <= 8) return;\n\n    // advance pointer to align it at 4-byte boundary\n    let k: usize = -dest & 3;\n    dest += k;\n    n -= k;\n    n &= -4;\n\n    let c32: u32 = <u32>-1 / 255 * c;\n\n    // fill head/tail up to 28 bytes each in preparation\n    store<u32>(dest, c32);\n    store<u32>(dest + n - 4, c32);\n    if (n <= 8) return;\n    store<u32>(dest + 4, c32);\n    store<u32>(dest + 8, c32);\n    store<u32>(dest + n - 12, c32);\n    store<u32>(dest + n - 8, c32);\n    if (n <= 24) return;\n    store<u32>(dest + 12, c32);\n    store<u32>(dest + 16, c32);\n    store<u32>(dest + 20, c32);\n    store<u32>(dest + 24, c32);\n    store<u32>(dest + n - 28, c32);\n    store<u32>(dest + n - 24, c32);\n    store<u32>(dest + n - 20, c32);\n    store<u32>(dest + n - 16, c32);\n\n    // align to a multiple of 8\n    k = 24 + (dest & 4);\n    dest += k;\n    n -= k;\n\n    // copy 32 bytes each\n    let c64: u64 = <u64>c32 | (<u64>c32 << 32);\n    while (n >= 32) {\n      store<u64>(dest, c64);\n      store<u64>(dest + 8, c64);\n      store<u64>(dest + 16, c64);\n      store<u64>(dest + 24, c64);\n      n -= 32;\n      dest += 32;\n    }\n  }\n}\n\n// @ts-ignore: decorator\n@inline\nexport function memcmp(vl: usize, vr: usize, n: usize): i32 {\n  if (vl == vr) return 0;\n  if (ASC_SHRINK_LEVEL < 2) {\n    if ((vl & 7) == (vr & 7)) {\n      while (vl & 7) {\n        if (!n) return 0;\n        let a = <i32>load<u8>(vl);\n        let b = <i32>load<u8>(vr);\n        if (a != b) return a - b;\n        n--; vl++; vr++;\n      }\n      while (n >= 8) {\n        if (load<u64>(vl) != load<u64>(vr)) break;\n        vl += 8;\n        vr += 8;\n        n  -= 8;\n      }\n    }\n  }\n  while (n--) {\n    let a = <i32>load<u8>(vl);\n    let b = <i32>load<u8>(vr);\n    if (a != b) return a - b;\n    vl++; vr++;\n  }\n  return 0;\n}\n","// Constants that will be shared by the wasm core of the emulator\n// And libraries built around the wasm (such as the official JS), or @CryZe wasmboy-rs\n\n// ----------------------------------\n// Wasmboy Memory Map\n// https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit?usp=sharing\n// ----------------------------------\n\n// AssemblyScript\nexport const ASSEMBLYSCRIPT_MEMORY_LOCATION: i32 = 0x000000;\nexport const ASSEMBLYSCRIPT_MEMORY_SIZE: i32 = 0x000400;\n\n// WasmBoy States\nexport const WASMBOY_STATE_LOCATION: i32 = ASSEMBLYSCRIPT_MEMORY_LOCATION + ASSEMBLYSCRIPT_MEMORY_SIZE;\nexport const WASMBOY_STATE_SIZE: i32 = 0x000400;\n\n// Gameboy Internal Memory\nexport const VIDEO_RAM_LOCATION: i32 = WASMBOY_STATE_LOCATION + WASMBOY_STATE_SIZE;\nexport const VIDEO_RAM_SIZE: i32 = 0x004000;\n\nexport const WORK_RAM_LOCATION: i32 = VIDEO_RAM_LOCATION + VIDEO_RAM_SIZE;\nexport const WORK_RAM_SIZE: i32 = 0x008000;\n\nexport const OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION: i32 = WORK_RAM_LOCATION + WORK_RAM_SIZE;\nexport const OTHER_GAMEBOY_INTERNAL_MEMORY_SIZE: i32 = 0x004000;\n\n// General Gameboy Internal Memory\nexport const GAMEBOY_INTERNAL_MEMORY_LOCATION: i32 = VIDEO_RAM_LOCATION;\nexport const GAMEBOY_INTERNAL_MEMORY_SIZE: i32 =\n  OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION - VIDEO_RAM_LOCATION + OTHER_GAMEBOY_INTERNAL_MEMORY_SIZE;\n\n// Graphics Output\nexport const GBC_PALETTE_LOCATION: i32 = OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION + OTHER_GAMEBOY_INTERNAL_MEMORY_SIZE;\nexport const GBC_PALETTE_SIZE: i32 = 0x000080;\n\nexport const BG_PRIORITY_MAP_LOCATION: i32 = GBC_PALETTE_LOCATION + GBC_PALETTE_SIZE;\nexport const BG_PRIORITY_MAP_SIZE: i32 = 0x005c00;\n\nexport const FRAME_LOCATION: i32 = BG_PRIORITY_MAP_LOCATION + BG_PRIORITY_MAP_SIZE;\nexport const FRAME_SIZE: i32 = 0x016c00;\n\nexport const BACKGROUND_MAP_LOCATION: i32 = FRAME_LOCATION + FRAME_SIZE;\nexport const BACKGROUND_MAP_SIZE: i32 = 0x030000;\n\nexport const TILE_DATA_LOCATION: i32 = BACKGROUND_MAP_LOCATION + BACKGROUND_MAP_SIZE;\nexport const TILE_DATA_SIZE: i32 = 0x024000;\n\nexport const OAM_TILES_LOCATION: i32 = TILE_DATA_LOCATION + TILE_DATA_SIZE;\nexport const OAM_TILES_SIZE: i32 = 0x003c00;\n\n// General Graphics Output\nexport const GRAPHICS_OUTPUT_LOCATION: i32 = GBC_PALETTE_LOCATION;\nexport const GRAPHICS_OUTPUT_SIZE: i32 = OAM_TILES_LOCATION - GBC_PALETTE_LOCATION + OAM_TILES_SIZE;\n\n// Audio Output\nexport const CHANNEL_1_BUFFER_LOCATION: i32 = OAM_TILES_LOCATION + OAM_TILES_SIZE;\nexport const CHANNEL_1_BUFFER_SIZE: i32 = 0x020000;\n\nexport const CHANNEL_2_BUFFER_LOCATION: i32 = CHANNEL_1_BUFFER_LOCATION + CHANNEL_1_BUFFER_SIZE;\nexport const CHANNEL_2_BUFFER_SIZE: i32 = 0x020000;\n\nexport const CHANNEL_3_BUFFER_LOCATION: i32 = CHANNEL_2_BUFFER_LOCATION + CHANNEL_2_BUFFER_SIZE;\nexport const CHANNEL_3_BUFFER_SIZE: i32 = 0x020000;\n\nexport const CHANNEL_4_BUFFER_LOCATION: i32 = CHANNEL_3_BUFFER_LOCATION + CHANNEL_3_BUFFER_SIZE;\nexport const CHANNEL_4_BUFFER_SIZE: i32 = 0x020000;\n\nexport const AUDIO_BUFFER_LOCATION: i32 = CHANNEL_4_BUFFER_LOCATION + CHANNEL_4_BUFFER_SIZE;\nexport const AUDIO_BUFFER_SIZE: i32 = 0x020000;\n\n// Catridge Ram\nexport const CARTRIDGE_RAM_LOCATION: i32 = AUDIO_BUFFER_LOCATION + AUDIO_BUFFER_SIZE;\nexport const CARTRIDGE_RAM_SIZE: i32 = 0x020000;\n\n// Boot ROM\n// http://gbdev.gg8.se/files/roms/bootroms/\n// Largest Boot rom is GBC, at 2.5KB\nexport const BOOT_ROM_LOCATION: i32 = CARTRIDGE_RAM_LOCATION + CARTRIDGE_RAM_SIZE;\nexport const BOOT_ROM_SIZE: i32 = 0x000a00;\n\n// Cartridge ROM\nexport const CARTRIDGE_ROM_LOCATION: i32 = BOOT_ROM_LOCATION + BOOT_ROM_SIZE;\nexport const CARTRIDGE_ROM_SIZE: i32 = 0x7e0400;\n\n// Debug Memory\nexport const DEBUG_GAMEBOY_MEMORY_LOCATION: i32 = CARTRIDGE_ROM_LOCATION + CARTRIDGE_ROM_SIZE;\nexport const DEBUG_GAMEBOY_MEMORY_SIZE: i32 = 0xffff;\n\n// Final General Size\nexport const WASMBOY_MEMORY_LOCATION: i32 = 0x000000;\nexport const WASMBOY_MEMORY_SIZE: i32 = DEBUG_GAMEBOY_MEMORY_LOCATION + DEBUG_GAMEBOY_MEMORY_SIZE + 1;\nexport const WASMBOY_WASM_PAGES: i32 = ceil(WASMBOY_MEMORY_SIZE / 1024 / 64) + 1;\n","export class Config {\n  // Boot Rom\n  static enableBootRom: boolean = false;\n\n  // GBC Options\n  static useGbcWhenAvailable: boolean = true;\n\n  // Batch Processing\n  static audioBatchProcessing: boolean = false;\n  static graphicsBatchProcessing: boolean = false;\n  static timersBatchProcessing: boolean = false;\n\n  // Scanline Rendering\n  static graphicsDisableScanlineRendering: boolean = false;\n\n  // Acumulate Sound Samples\n  static audioAccumulateSamples: boolean = false;\n\n  // Tile Rednering\n  static tileRendering: boolean = false;\n  static tileCaching: boolean = false;\n\n  // Audio Debugging\n  static enableAudioDebugging: boolean = false;\n}\n","// File for all of the colors for different GB Palletes\n// https://i.imgur.com/HupBY.png\n// https://www.libretro.com/index.php/gambatte-progress-report/\n// https://tcrf.net/Notes:Game_Boy_Color_Bootstrap_ROM\n\n// Our default wasmboy gb colors\nexport class WasmBoyGBColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xf2f2f2;\n  static readonly bgLightGrey: i32 = 0xa0a0a0;\n  static readonly bgDarkGrey: i32 = 0x585858;\n  static readonly bgBlack: i32 = 0x080808;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xf2f2f2;\n  static readonly obj0LightGrey: i32 = 0xa0a0a0;\n  static readonly obj0DarkGrey: i32 = 0x585858;\n  static readonly obj0Black: i32 = 0x080808;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xf2f2f2;\n  static readonly obj1LightGrey: i32 = 0xa0a0a0;\n  static readonly obj1DarkGrey: i32 = 0x585858;\n  static readonly obj1Black: i32 = 0x080808;\n}\n\n// Action Button: Right\nexport class GreenColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0x52ff00;\n  static readonly bgDarkGrey: i32 = 0xff4200;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0x52ff00;\n  static readonly obj0DarkGrey: i32 = 0xff4200;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x52ff00;\n  static readonly obj1DarkGrey: i32 = 0xff4200;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: A + Down\nexport class OrangeColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xffff00;\n  static readonly bgDarkGrey: i32 = 0xff0000;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xffff00;\n  static readonly obj0DarkGrey: i32 = 0xff0000;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xffff00;\n  static readonly obj1DarkGrey: i32 = 0xff0000;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: Up\nexport class BrownColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xffad63;\n  static readonly bgDarkGrey: i32 = 0x843100;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xffad63;\n  static readonly obj0DarkGrey: i32 = 0x843100;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xffad63;\n  static readonly obj1DarkGrey: i32 = 0x843100;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: B + Right\nexport class InvertedColors {\n  //Bg\n  static readonly bgWhite: i32 = 0x000000;\n  static readonly bgLightGrey: i32 = 0x008484;\n  static readonly bgDarkGrey: i32 = 0xffde00;\n  static readonly bgBlack: i32 = 0xffffff;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0x000000;\n  static readonly obj0LightGrey: i32 = 0x008484;\n  static readonly obj0DarkGrey: i32 = 0xffde00;\n  static readonly obj0Black: i32 = 0xffffff;\n\n  // Obj1\n  static readonly obj1White: i32 = 0x000000;\n  static readonly obj1LightGrey: i32 = 0x008484;\n  static readonly obj1DarkGrey: i32 = 0xffde00;\n  static readonly obj1Black: i32 = 0xffffff;\n}\n\n// Action Button: B + Left\nexport class GrayscaleColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xa5a5a5;\n  static readonly bgDarkGrey: i32 = 0x525252;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xa5a5a5;\n  static readonly obj0DarkGrey: i32 = 0x525252;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xa5a5a5;\n  static readonly obj1DarkGrey: i32 = 0x525252;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: Down\nexport class PastelMixColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffa5;\n  static readonly bgLightGrey: i32 = 0xff9494;\n  static readonly bgDarkGrey: i32 = 0x9494ff;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffa5;\n  static readonly obj0LightGrey: i32 = 0xff9494;\n  static readonly obj0DarkGrey: i32 = 0x9494ff;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffa5;\n  static readonly obj1LightGrey: i32 = 0xff9494;\n  static readonly obj1DarkGrey: i32 = 0x9494ff;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: B + Up\nexport class DarkBrownColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffe6c5;\n  static readonly bgLightGrey: i32 = 0xce9c84;\n  static readonly bgDarkGrey: i32 = 0x846b29;\n  static readonly bgBlack: i32 = 0x5a3108;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xffad63;\n  static readonly obj0DarkGrey: i32 = 0x843100;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xffad63;\n  static readonly obj1DarkGrey: i32 = 0x843100;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: A + Right\nexport class DarkGreenColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0x7bff31;\n  static readonly bgDarkGrey: i32 = 0x0063c5;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xff8484;\n  static readonly obj0DarkGrey: i32 = 0x943a3a;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xff8484;\n  static readonly obj1DarkGrey: i32 = 0x943a3a;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: A + Left\nexport class DarkBlueColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0x8c8cde;\n  static readonly bgDarkGrey: i32 = 0x52528c;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xff8484;\n  static readonly obj0DarkGrey: i32 = 0x943a3a;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xffad63;\n  static readonly obj1DarkGrey: i32 = 0x843100;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: A + Up\nexport class RedColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xff8484;\n  static readonly bgDarkGrey: i32 = 0x943a3a;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0x7bff31;\n  static readonly obj0DarkGrey: i32 = 0x008400;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x63a5ff;\n  static readonly obj1DarkGrey: i32 = 0x0000ff;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: Left\nexport class BlueColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0x63a5ff;\n  static readonly bgDarkGrey: i32 = 0x0000ff;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xff8484;\n  static readonly obj0DarkGrey: i32 = 0x943a3a;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x7bff31;\n  static readonly obj1DarkGrey: i32 = 0x008400;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: B + Down\nexport class YellowColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xffff00;\n  static readonly bgDarkGrey: i32 = 0x7b4a00;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0x63a5ff;\n  static readonly obj0DarkGrey: i32 = 0x0000ff;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x7bff31;\n  static readonly obj1DarkGrey: i32 = 0x008400;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Assigned Color Palettes\n\n// Alleyway\nexport class Table00Entry08Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xa59cff;\n  static readonly bgLightGrey: i32 = 0xffff00;\n  static readonly bgDarkGrey: i32 = 0x006300;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xa59cff;\n  static readonly obj0LightGrey: i32 = 0xffff00;\n  static readonly obj0DarkGrey: i32 = 0x006300;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xa59cff;\n  static readonly obj1LightGrey: i32 = 0xffff00;\n  static readonly obj1DarkGrey: i32 = 0x006300;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Pokemon Blue\nexport class Table01Entry0BColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0x63a5ff;\n  static readonly bgDarkGrey: i32 = 0x0000ff;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xff8484;\n  static readonly obj0DarkGrey: i32 = 0x943a3a;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x63a5ff;\n  static readonly obj1DarkGrey: i32 = 0x0000ff;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Pokemon Red\nexport class Table01Entry10Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xff8484;\n  static readonly bgDarkGrey: i32 = 0x943a3a;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0x7bff31;\n  static readonly obj0DarkGrey: i32 = 0x008400;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xff8484;\n  static readonly obj1DarkGrey: i32 = 0x943a3a;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Super Mario Land\nexport class Table03Entry0AColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xb5b5ff;\n  static readonly bgLightGrey: i32 = 0xffff94;\n  static readonly bgDarkGrey: i32 = 0xad5a42;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0x000000;\n  static readonly obj0LightGrey: i32 = 0xffffff;\n  static readonly obj0DarkGrey: i32 = 0xff8484;\n  static readonly obj0Black: i32 = 0x943a3a;\n\n  // Obj1\n  static readonly obj1White: i32 = 0x000000;\n  static readonly obj1LightGrey: i32 = 0xffffff;\n  static readonly obj1DarkGrey: i32 = 0xff8484;\n  static readonly obj1Black: i32 = 0x943a3a;\n}\n\n// Super Mario Land 3 - WarioLand\nexport class Table05Entry00Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xadad84;\n  static readonly bgDarkGrey: i32 = 0x42737b;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xff7300;\n  static readonly obj0DarkGrey: i32 = 0x944200;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x5abdff;\n  static readonly obj1DarkGrey: i32 = 0xff0000;\n  static readonly obj1Black: i32 = 0x0000ff;\n}\n\n// Donkey Kong\nexport class Table05Entry01Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffff9c;\n  static readonly bgLightGrey: i32 = 0x94b5ff;\n  static readonly bgDarkGrey: i32 = 0x639473;\n  static readonly bgBlack: i32 = 0x003a3a;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffc542;\n  static readonly obj0LightGrey: i32 = 0xffd600;\n  static readonly obj0DarkGrey: i32 = 0x943a00;\n  static readonly obj0Black: i32 = 0x4a0000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xff8484;\n  static readonly obj1DarkGrey: i32 = 0x943a3a;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Tennis\nexport class Table05Entry02Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0x6bff00;\n  static readonly bgLightGrey: i32 = 0xffffff;\n  static readonly bgDarkGrey: i32 = 0xff524a;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xffffff;\n  static readonly obj0DarkGrey: i32 = 0x63a5ff;\n  static readonly obj0Black: i32 = 0x0000ff;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xffad63;\n  static readonly obj1DarkGrey: i32 = 0x843100;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Kirby's Dream Land\nexport class Table05Entry08Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xa59cff;\n  static readonly bgLightGrey: i32 = 0xffff00;\n  static readonly bgDarkGrey: i32 = 0x006300;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xff6352;\n  static readonly obj0LightGrey: i32 = 0xd60000;\n  static readonly obj0DarkGrey: i32 = 0x630000;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0x0000ff;\n  static readonly obj1LightGrey: i32 = 0xffffff;\n  static readonly obj1DarkGrey: i32 = 0xffff7b;\n  static readonly obj1Black: i32 = 0x0084ff;\n}\n\n// Super Mario Land 2 BAYYYBEEE\nexport class Table05Entry09Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffce;\n  static readonly bgLightGrey: i32 = 0x63efef;\n  static readonly bgDarkGrey: i32 = 0x9c8431;\n  static readonly bgBlack: i32 = 0x5a5a5a;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xff7300;\n  static readonly obj0DarkGrey: i32 = 0x944200;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x63a5ff;\n  static readonly obj1DarkGrey: i32 = 0x0000ff;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Link's Awakening\nexport class Table05Entry11Colors {\n  // Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xff8484;\n  static readonly bgDarkGrey: i32 = 0x943a3a;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0x00ff00;\n  static readonly obj0DarkGrey: i32 = 0x318400;\n  static readonly obj0Black: i32 = 0x004a00;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x63a5ff;\n  static readonly obj1DarkGrey: i32 = 0x0000ff;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Metroid 2\nexport class Table05Entry14Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0x63a5ff;\n  static readonly bgDarkGrey: i32 = 0x0000ff;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffff00;\n  static readonly obj0LightGrey: i32 = 0xff0000;\n  static readonly obj0DarkGrey: i32 = 0x630000;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x7bff31;\n  static readonly obj1DarkGrey: i32 = 0x008400;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// WarioLand 2\nexport class Table05Entry15Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xadad84;\n  static readonly bgDarkGrey: i32 = 0x42737b;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xffad63;\n  static readonly obj0DarkGrey: i32 = 0xffad63;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x63a5ff;\n  static readonly obj1DarkGrey: i32 = 0x0000ff;\n  static readonly obj1Black: i32 = 0x000000;\n}\n","// File for all of the logic of setting gameboy color plaettes\n\nimport {\n  WasmBoyGBColors,\n  BrownColors,\n  RedColors,\n  DarkBrownColors,\n  GreenColors,\n  DarkGreenColors,\n  InvertedColors,\n  PastelMixColors,\n  OrangeColors,\n  YellowColors,\n  BlueColors,\n  DarkBlueColors,\n  GrayscaleColors,\n  Table00Entry08Colors,\n  Table01Entry0BColors,\n  Table01Entry10Colors,\n  Table03Entry0AColors,\n  Table05Entry00Colors,\n  Table05Entry01Colors,\n  Table05Entry02Colors,\n  Table05Entry08Colors,\n  Table05Entry09Colors,\n  Table05Entry11Colors,\n  Table05Entry14Colors,\n  Table05Entry15Colors\n} from './colors.constants';\nimport { Cpu } from '../cpu/cpu';\nimport { eightBitLoadFromGBMemory } from '../memory/index';\n\n// Current / exported color\nexport class Colors {\n  //Bg\n  static bgWhite: i32 = WasmBoyGBColors.bgWhite;\n  static bgLightGrey: i32 = WasmBoyGBColors.bgLightGrey;\n  static bgDarkGrey: i32 = WasmBoyGBColors.bgDarkGrey;\n  static bgBlack: i32 = WasmBoyGBColors.bgBlack;\n\n  // Obj 0\n  static obj0White: i32 = WasmBoyGBColors.obj0White;\n  static obj0LightGrey: i32 = WasmBoyGBColors.obj0LightGrey;\n  static obj0DarkGrey: i32 = WasmBoyGBColors.obj0DarkGrey;\n  static obj0Black: i32 = WasmBoyGBColors.obj0Black;\n\n  // Obj1\n  static obj1White: i32 = WasmBoyGBColors.obj1White;\n  static obj1LightGrey: i32 = WasmBoyGBColors.obj1LightGrey;\n  static obj1DarkGrey: i32 = WasmBoyGBColors.obj1DarkGrey;\n  static obj1Black: i32 = WasmBoyGBColors.obj1Black;\n}\n\n// Inlined because closure compiler inlines\nexport function initializeColors(): void {\n  setManualColorizationPalette(0);\n\n  if (Cpu.GBCEnabled) {\n    // Don't need to continue this if a GBC game\n    return;\n  }\n\n  if (Cpu.BootROMEnabled) {\n    if (!Cpu.GBCEnabled) {\n      // GB\n      return;\n    }\n  }\n\n  // Do some automatic color palette swapping if we have a loaded ROM\n  let titleChecksum: i32 = 0x00;\n  for (let i: i32 = 0x0134; i <= 0x0143; i++) {\n    titleChecksum += eightBitLoadFromGBMemory(i);\n  }\n\n  // Set the colorization for the game automatically if assigned\n  // https://tcrf.net/Notes:Game_Boy_Color_Bootstrap_ROM\n  let hash: i32 = titleChecksum & 0xff;\n  setHashColorizationPalette(hash);\n}\n\nexport function getRedFromHexColor(color: i32): i32 {\n  return (color & 0xff0000) >> 16;\n}\n\nexport function getGreenFromHexColor(color: i32): i32 {\n  return (color & 0x00ff00) >> 8;\n}\n\nexport function getBlueFromHexColor(color: i32): i32 {\n  return color & 0x0000ff;\n}\n\n// Function to set the colorization\n// By manually pressing buttons\nexport function setManualColorizationPalette(colorizationId: i32): void {\n  // Set the colorizationId clockwise according to:\n  // https://en.wikipedia.org/wiki/Game_Boy_Color\n  switch (colorizationId) {\n    case 0:\n      Colors.bgWhite = WasmBoyGBColors.bgWhite;\n      Colors.bgLightGrey = WasmBoyGBColors.bgLightGrey;\n      Colors.bgDarkGrey = WasmBoyGBColors.bgDarkGrey;\n      Colors.bgBlack = WasmBoyGBColors.bgBlack;\n\n      Colors.obj0White = WasmBoyGBColors.obj0White;\n      Colors.obj0LightGrey = WasmBoyGBColors.obj0LightGrey;\n      Colors.obj0DarkGrey = WasmBoyGBColors.obj0DarkGrey;\n      Colors.obj0Black = WasmBoyGBColors.obj0Black;\n\n      Colors.obj1White = WasmBoyGBColors.obj1White;\n      Colors.obj1LightGrey = WasmBoyGBColors.obj1LightGrey;\n      Colors.obj1DarkGrey = WasmBoyGBColors.obj1DarkGrey;\n      Colors.obj1Black = WasmBoyGBColors.obj1Black;\n      break;\n    case 1:\n      // Up, Brown\n      Colors.bgWhite = BrownColors.bgWhite;\n      Colors.bgLightGrey = BrownColors.bgLightGrey;\n      Colors.bgDarkGrey = BrownColors.bgDarkGrey;\n      Colors.bgBlack = BrownColors.bgBlack;\n\n      Colors.obj0White = BrownColors.obj0White;\n      Colors.obj0LightGrey = BrownColors.obj0LightGrey;\n      Colors.obj0DarkGrey = BrownColors.obj0DarkGrey;\n      Colors.obj0Black = BrownColors.obj0Black;\n\n      Colors.obj1White = BrownColors.obj1White;\n      Colors.obj1LightGrey = BrownColors.obj1LightGrey;\n      Colors.obj1DarkGrey = BrownColors.obj1DarkGrey;\n      Colors.obj1Black = BrownColors.obj1Black;\n      break;\n    case 2:\n      // Up + A, Red\n      Colors.bgWhite = RedColors.bgWhite;\n      Colors.bgLightGrey = RedColors.bgLightGrey;\n      Colors.bgDarkGrey = RedColors.bgDarkGrey;\n      Colors.bgBlack = RedColors.bgBlack;\n\n      Colors.obj0White = RedColors.obj0White;\n      Colors.obj0LightGrey = RedColors.obj0LightGrey;\n      Colors.obj0DarkGrey = RedColors.obj0DarkGrey;\n      Colors.obj0Black = RedColors.obj0Black;\n\n      Colors.obj1White = RedColors.obj1White;\n      Colors.obj1LightGrey = RedColors.obj1LightGrey;\n      Colors.obj1DarkGrey = RedColors.obj1DarkGrey;\n      Colors.obj1Black = RedColors.obj1Black;\n      break;\n    case 3:\n      // Up + B, DarkBrown\n      Colors.bgWhite = DarkBrownColors.bgWhite;\n      Colors.bgLightGrey = DarkBrownColors.bgLightGrey;\n      Colors.bgDarkGrey = DarkBrownColors.bgDarkGrey;\n      Colors.bgBlack = DarkBrownColors.bgBlack;\n\n      Colors.obj0White = DarkBrownColors.obj0White;\n      Colors.obj0LightGrey = DarkBrownColors.obj0LightGrey;\n      Colors.obj0DarkGrey = DarkBrownColors.obj0DarkGrey;\n      Colors.obj0Black = DarkBrownColors.obj0Black;\n\n      Colors.obj1White = DarkBrownColors.obj1White;\n      Colors.obj1LightGrey = DarkBrownColors.obj1LightGrey;\n      Colors.obj1DarkGrey = DarkBrownColors.obj1DarkGrey;\n      Colors.obj1Black = DarkBrownColors.obj1Black;\n      break;\n    case 4:\n      // Right, Green\n      Colors.bgWhite = GreenColors.bgWhite;\n      Colors.bgLightGrey = GreenColors.bgLightGrey;\n      Colors.bgDarkGrey = GreenColors.bgDarkGrey;\n      Colors.bgBlack = GreenColors.bgBlack;\n\n      Colors.obj0White = GreenColors.obj0White;\n      Colors.obj0LightGrey = GreenColors.obj0LightGrey;\n      Colors.obj0DarkGrey = GreenColors.obj0DarkGrey;\n      Colors.obj0Black = GreenColors.obj0Black;\n\n      Colors.obj1White = GreenColors.obj1White;\n      Colors.obj1LightGrey = GreenColors.obj1LightGrey;\n      Colors.obj1DarkGrey = GreenColors.obj1DarkGrey;\n      Colors.obj1Black = GreenColors.obj1Black;\n      break;\n    case 5:\n      // Right + A, DarkGreenColors\n      Colors.bgWhite = DarkGreenColors.bgWhite;\n      Colors.bgLightGrey = DarkGreenColors.bgLightGrey;\n      Colors.bgDarkGrey = DarkGreenColors.bgDarkGrey;\n      Colors.bgBlack = DarkGreenColors.bgBlack;\n\n      Colors.obj0White = DarkGreenColors.obj0White;\n      Colors.obj0LightGrey = DarkGreenColors.obj0LightGrey;\n      Colors.obj0DarkGrey = DarkGreenColors.obj0DarkGrey;\n      Colors.obj0Black = DarkGreenColors.obj0Black;\n\n      Colors.obj1White = DarkGreenColors.obj1White;\n      Colors.obj1LightGrey = DarkGreenColors.obj1LightGrey;\n      Colors.obj1DarkGrey = DarkGreenColors.obj1DarkGrey;\n      Colors.obj1Black = DarkGreenColors.obj1Black;\n      break;\n    case 6:\n      // Right + B, InvertedColors\n      Colors.bgWhite = InvertedColors.bgWhite;\n      Colors.bgLightGrey = InvertedColors.bgLightGrey;\n      Colors.bgDarkGrey = InvertedColors.bgDarkGrey;\n      Colors.bgBlack = InvertedColors.bgBlack;\n\n      Colors.obj0White = InvertedColors.obj0White;\n      Colors.obj0LightGrey = InvertedColors.obj0LightGrey;\n      Colors.obj0DarkGrey = InvertedColors.obj0DarkGrey;\n      Colors.obj0Black = InvertedColors.obj0Black;\n\n      Colors.obj1White = InvertedColors.obj1White;\n      Colors.obj1LightGrey = InvertedColors.obj1LightGrey;\n      Colors.obj1DarkGrey = InvertedColors.obj1DarkGrey;\n      Colors.obj1Black = InvertedColors.obj1Black;\n      break;\n    case 7:\n      // Down, PastelMixColors\n      Colors.bgWhite = PastelMixColors.bgWhite;\n      Colors.bgLightGrey = PastelMixColors.bgLightGrey;\n      Colors.bgDarkGrey = PastelMixColors.bgDarkGrey;\n      Colors.bgBlack = PastelMixColors.bgBlack;\n\n      Colors.obj0White = PastelMixColors.obj0White;\n      Colors.obj0LightGrey = PastelMixColors.obj0LightGrey;\n      Colors.obj0DarkGrey = PastelMixColors.obj0DarkGrey;\n      Colors.obj0Black = PastelMixColors.obj0Black;\n\n      Colors.obj1White = PastelMixColors.obj1White;\n      Colors.obj1LightGrey = PastelMixColors.obj1LightGrey;\n      Colors.obj1DarkGrey = PastelMixColors.obj1DarkGrey;\n      Colors.obj1Black = PastelMixColors.obj1Black;\n      break;\n    case 8:\n      // Down + A, Orange\n      Colors.bgWhite = OrangeColors.bgWhite;\n      Colors.bgLightGrey = OrangeColors.bgLightGrey;\n      Colors.bgDarkGrey = OrangeColors.bgDarkGrey;\n      Colors.bgBlack = OrangeColors.bgBlack;\n\n      Colors.obj0White = OrangeColors.obj0White;\n      Colors.obj0LightGrey = OrangeColors.obj0LightGrey;\n      Colors.obj0DarkGrey = OrangeColors.obj0DarkGrey;\n      Colors.obj0Black = OrangeColors.obj0Black;\n\n      Colors.obj1White = OrangeColors.obj1White;\n      Colors.obj1LightGrey = OrangeColors.obj1LightGrey;\n      Colors.obj1DarkGrey = OrangeColors.obj1DarkGrey;\n      Colors.obj1Black = OrangeColors.obj1Black;\n      break;\n    case 9:\n      // Down + B, Yellow\n      Colors.bgWhite = YellowColors.bgWhite;\n      Colors.bgLightGrey = YellowColors.bgLightGrey;\n      Colors.bgDarkGrey = YellowColors.bgDarkGrey;\n      Colors.bgBlack = YellowColors.bgBlack;\n\n      Colors.obj0White = YellowColors.obj0White;\n      Colors.obj0LightGrey = YellowColors.obj0LightGrey;\n      Colors.obj0DarkGrey = YellowColors.obj0DarkGrey;\n      Colors.obj0Black = YellowColors.obj0Black;\n\n      Colors.obj1White = YellowColors.obj1White;\n      Colors.obj1LightGrey = YellowColors.obj1LightGrey;\n      Colors.obj1DarkGrey = YellowColors.obj1DarkGrey;\n      Colors.obj1Black = YellowColors.obj1Black;\n      break;\n    case 10:\n      // Left, Blue\n      Colors.bgWhite = BlueColors.bgWhite;\n      Colors.bgLightGrey = BlueColors.bgLightGrey;\n      Colors.bgDarkGrey = BlueColors.bgDarkGrey;\n      Colors.bgBlack = BlueColors.bgBlack;\n\n      Colors.obj0White = BlueColors.obj0White;\n      Colors.obj0LightGrey = BlueColors.obj0LightGrey;\n      Colors.obj0DarkGrey = BlueColors.obj0DarkGrey;\n      Colors.obj0Black = BlueColors.obj0Black;\n\n      Colors.obj1White = BlueColors.obj1White;\n      Colors.obj1LightGrey = BlueColors.obj1LightGrey;\n      Colors.obj1DarkGrey = BlueColors.obj1DarkGrey;\n      Colors.obj1Black = BlueColors.obj1Black;\n      break;\n    case 11:\n      // Left + A, Dark Blue\n      Colors.bgWhite = DarkBlueColors.bgWhite;\n      Colors.bgLightGrey = DarkBlueColors.bgLightGrey;\n      Colors.bgDarkGrey = DarkBlueColors.bgDarkGrey;\n      Colors.bgBlack = DarkBlueColors.bgBlack;\n\n      Colors.obj0White = DarkBlueColors.obj0White;\n      Colors.obj0LightGrey = DarkBlueColors.obj0LightGrey;\n      Colors.obj0DarkGrey = DarkBlueColors.obj0DarkGrey;\n      Colors.obj0Black = DarkBlueColors.obj0Black;\n\n      Colors.obj1White = DarkBlueColors.obj1White;\n      Colors.obj1LightGrey = DarkBlueColors.obj1LightGrey;\n      Colors.obj1DarkGrey = DarkBlueColors.obj1DarkGrey;\n      Colors.obj1Black = DarkBlueColors.obj1Black;\n      break;\n    case 12:\n      // Left + B, GrayScale\n      Colors.bgWhite = GrayscaleColors.bgWhite;\n      Colors.bgLightGrey = GrayscaleColors.bgLightGrey;\n      Colors.bgDarkGrey = GrayscaleColors.bgDarkGrey;\n      Colors.bgBlack = GrayscaleColors.bgBlack;\n\n      Colors.obj0White = GrayscaleColors.obj0White;\n      Colors.obj0LightGrey = GrayscaleColors.obj0LightGrey;\n      Colors.obj0DarkGrey = GrayscaleColors.obj0DarkGrey;\n      Colors.obj0Black = GrayscaleColors.obj0Black;\n\n      Colors.obj1White = GrayscaleColors.obj1White;\n      Colors.obj1LightGrey = GrayscaleColors.obj1LightGrey;\n      Colors.obj1DarkGrey = GrayscaleColors.obj1DarkGrey;\n      Colors.obj1Black = GrayscaleColors.obj1Black;\n      break;\n  }\n}\n\n// Function to set the colorization\n// By checksum of the title\n// https://forums.nesdev.com/viewtopic.php?f=20&t=10226\n// TODO: torch2424 need to find how to get the \"disambiguation\"\n// Inlined because closure compiler inlines\nexport function setHashColorizationPalette(hash: i32): void {\n  switch (hash) {\n    case 0x88:\n      Colors.bgWhite = Table00Entry08Colors.bgWhite;\n      Colors.bgLightGrey = Table00Entry08Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table00Entry08Colors.bgDarkGrey;\n      Colors.bgBlack = Table00Entry08Colors.bgBlack;\n\n      Colors.obj0White = Table00Entry08Colors.obj0White;\n      Colors.obj0LightGrey = Table00Entry08Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table00Entry08Colors.obj0DarkGrey;\n      Colors.obj0Black = Table00Entry08Colors.obj0Black;\n\n      Colors.obj1White = Table00Entry08Colors.obj1White;\n      Colors.obj1LightGrey = Table00Entry08Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table00Entry08Colors.obj1DarkGrey;\n      Colors.obj1Black = Table00Entry08Colors.obj1Black;\n      break;\n    case 0x61:\n      Colors.bgWhite = Table01Entry0BColors.bgWhite;\n      Colors.bgLightGrey = Table01Entry0BColors.bgLightGrey;\n      Colors.bgDarkGrey = Table01Entry0BColors.bgDarkGrey;\n      Colors.bgBlack = Table01Entry0BColors.bgBlack;\n\n      Colors.obj0White = Table01Entry0BColors.obj0White;\n      Colors.obj0LightGrey = Table01Entry0BColors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table01Entry0BColors.obj0DarkGrey;\n      Colors.obj0Black = Table01Entry0BColors.obj0Black;\n\n      Colors.obj1White = Table01Entry0BColors.obj1White;\n      Colors.obj1LightGrey = Table01Entry0BColors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table01Entry0BColors.obj1DarkGrey;\n      Colors.obj1Black = Table01Entry0BColors.obj1Black;\n      break;\n    case 0x14:\n      Colors.bgWhite = Table01Entry10Colors.bgWhite;\n      Colors.bgLightGrey = Table01Entry10Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table01Entry10Colors.bgDarkGrey;\n      Colors.bgBlack = Table01Entry10Colors.bgBlack;\n\n      Colors.obj0White = Table01Entry10Colors.obj0White;\n      Colors.obj0LightGrey = Table01Entry10Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table01Entry10Colors.obj0DarkGrey;\n      Colors.obj0Black = Table01Entry10Colors.obj0Black;\n\n      Colors.obj1White = Table01Entry10Colors.obj1White;\n      Colors.obj1LightGrey = Table01Entry10Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table01Entry10Colors.obj1DarkGrey;\n      Colors.obj1Black = Table01Entry10Colors.obj1Black;\n      break;\n    case 0x46:\n      Colors.bgWhite = Table03Entry0AColors.bgWhite;\n      Colors.bgLightGrey = Table03Entry0AColors.bgLightGrey;\n      Colors.bgDarkGrey = Table03Entry0AColors.bgDarkGrey;\n      Colors.bgBlack = Table03Entry0AColors.bgBlack;\n\n      Colors.obj0White = Table03Entry0AColors.obj0White;\n      Colors.obj0LightGrey = Table03Entry0AColors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table03Entry0AColors.obj0DarkGrey;\n      Colors.obj0Black = Table03Entry0AColors.obj0Black;\n\n      Colors.obj1White = Table03Entry0AColors.obj1White;\n      Colors.obj1LightGrey = Table03Entry0AColors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table03Entry0AColors.obj1DarkGrey;\n      Colors.obj1Black = Table03Entry0AColors.obj1Black;\n      break;\n    case 0x59:\n    case 0xc6:\n      Colors.bgWhite = Table05Entry00Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry00Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry00Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry00Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry00Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry00Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry00Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry00Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry00Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry00Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry00Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry00Colors.obj1Black;\n      break;\n    case 0x86:\n    case 0xa8:\n      Colors.bgWhite = Table05Entry01Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry01Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry01Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry01Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry01Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry01Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry01Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry01Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry01Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry01Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry01Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry01Colors.obj1Black;\n      break;\n    case 0xbf:\n    case 0xce:\n    case 0xd1:\n    case 0xf0:\n      Colors.bgWhite = Table05Entry02Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry02Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry02Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry02Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry02Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry02Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry02Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry02Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry02Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry02Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry02Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry02Colors.obj1Black;\n      break;\n    case 0x27:\n    case 0x49:\n    case 0x5c:\n    case 0xb3:\n      Colors.bgWhite = Table05Entry08Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry08Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry08Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry08Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry08Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry08Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry08Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry08Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry08Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry08Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry08Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry08Colors.obj1Black;\n      break;\n    case 0xc9:\n      Colors.bgWhite = Table05Entry09Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry09Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry09Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry09Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry09Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry09Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry09Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry09Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry09Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry09Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry09Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry09Colors.obj1Black;\n      break;\n    case 0x70:\n      Colors.bgWhite = Table05Entry11Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry11Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry11Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry11Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry11Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry11Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry11Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry11Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry11Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry11Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry11Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry11Colors.obj1Black;\n      break;\n    case 0x46:\n      Colors.bgWhite = Table05Entry14Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry14Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry14Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry14Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry14Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry14Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry14Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry14Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry14Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry14Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry14Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry14Colors.obj1Black;\n      break;\n    case 0xd3:\n      Colors.bgWhite = Table05Entry15Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry15Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry15Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry15Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry15Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry15Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry15Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry15Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry15Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry15Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry15Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry15Colors.obj1Black;\n      break;\n  }\n}\n","import { GBC_PALETTE_LOCATION } from '../constants';\nimport { Cpu } from '../cpu/index';\nimport { eightBitLoadFromGBMemory, eightBitStoreIntoGBMemory } from '../memory/index';\nimport { checkBitOnByte, resetBitOnByte, setBitOnByte, concatenateBytes } from '../helpers/index';\n\nimport { Colors } from './colors';\n\n// Class for GBC Color palletes\n// http://gbdev.gg8.se/wiki/articles/Video_Display#FF68_-_BCPS.2FBGPI_-_CGB_Mode_Only_-_Background_Palette_Index\nexport class Palette {\n  static memoryLocationBackgroundPaletteIndex: i32 = 0xff68;\n  static memoryLocationBackgroundPaletteData: i32 = 0xff69;\n  static memoryLocationSpritePaletteIndex: i32 = 0xff6a;\n  static memoryLocationSpritePaletteData: i32 = 0xff6b;\n\n  // Palettes\n  static readonly memoryLocationBackgroundPalette: i32 = 0xff47;\n  static readonly memoryLocationSpritePaletteOne: i32 = 0xff48;\n  static readonly memoryLocationSpritePaletteTwo: i32 = 0xff49;\n}\n\n// Inlined because closure compiler inlines\nexport function initializePalette(): void {\n  if (Cpu.GBCEnabled) {\n    // GBC Palettes\n    eightBitStoreIntoGBMemory(0xff68, 0xc0);\n    eightBitStoreIntoGBMemory(0xff69, 0xff);\n    eightBitStoreIntoGBMemory(0xff6a, 0xc1);\n    eightBitStoreIntoGBMemory(0xff6b, 0x0d);\n  } else {\n    // GBC Palettes\n    eightBitStoreIntoGBMemory(0xff68, 0xff);\n    eightBitStoreIntoGBMemory(0xff69, 0xff);\n    eightBitStoreIntoGBMemory(0xff6a, 0xff);\n    eightBitStoreIntoGBMemory(0xff6b, 0xff);\n  }\n\n  // Override some values if using the bootrom\n  if (Cpu.BootROMEnabled && Cpu.GBCEnabled) {\n    // GBC Palettes\n    eightBitStoreIntoGBMemory(0xff69, 0x20);\n    eightBitStoreIntoGBMemory(0xff6b, 0x8a);\n  }\n}\n\n// Simple get pallete color or monochrome GB\n// shouldRepresentColorByColorId is good for debugging tile data for GBC games that don't have\n// monochromePalettes\n// Inlined because closure compiler inlines\nexport function getMonochromeColorFromPalette(\n  colorId: i32,\n  paletteMemoryLocation: i32,\n  shouldRepresentColorByColorId: boolean = false\n): i32 {\n  // Shift our paletteByte, 2 times for each color ID\n  // And off any extra bytes\n  // Return our Color (00 - white, 01 - light grey, 10 Dark grey, or 11 - Black)\n  let color = colorId;\n  if (!shouldRepresentColorByColorId) {\n    color = ((<i32>eightBitLoadFromGBMemory(paletteMemoryLocation)) >> (colorId << 1)) & 0x03;\n  }\n\n  // Since our max is 254, and max is 3.\n  // monochrome color palette is modified from bgb\n  // TODO: Make these colors into a constant\n  let rgbColor = 242;\n\n  switch (color) {\n    case 0:\n      break;\n    case 1:\n      rgbColor = 160;\n      break;\n    case 2:\n      rgbColor = 88;\n      break;\n    case 3:\n      rgbColor = 8;\n      break;\n  }\n\n  return rgbColor;\n}\n\n// Function to returns the Colorized color for a GB games\nexport function getColorizedGbHexColorFromPalette(colorId: i32, paletteMemoryLocation: i32): i32 {\n  // Shift our paletteByte, 2 times for each color ID\n  // And off any extra bytes\n  // Return our Color (00 - white, 01 - light grey, 10 Dark grey, or 11 - Black)\n  let color = ((<i32>eightBitLoadFromGBMemory(paletteMemoryLocation)) >> (colorId * 2)) & 0x03;\n\n  // Check which palette we got, to apply the right color layer\n  let hexColor = 0;\n  if (paletteMemoryLocation === Palette.memoryLocationSpritePaletteOne) {\n    hexColor = Colors.obj0White;\n\n    switch (color) {\n      case 0:\n        break;\n      case 1:\n        hexColor = Colors.obj0LightGrey;\n        break;\n      case 2:\n        hexColor = Colors.obj0DarkGrey;\n        break;\n      case 3:\n        hexColor = Colors.obj0Black;\n        break;\n    }\n  } else if (paletteMemoryLocation === Palette.memoryLocationSpritePaletteTwo) {\n    hexColor = Colors.obj1White;\n\n    switch (color) {\n      case 0:\n        break;\n      case 1:\n        hexColor = Colors.obj1LightGrey;\n        break;\n      case 2:\n        hexColor = Colors.obj1DarkGrey;\n        break;\n      case 3:\n        hexColor = Colors.obj1Black;\n        break;\n    }\n  } else {\n    hexColor = Colors.bgWhite;\n\n    switch (color) {\n      case 0:\n        break;\n      case 1:\n        hexColor = Colors.bgLightGrey;\n        break;\n      case 2:\n        hexColor = Colors.bgDarkGrey;\n        break;\n      case 3:\n        hexColor = Colors.bgBlack;\n        break;\n    }\n  }\n\n  return hexColor;\n}\n\n// Inlined because closure compiler inlines\nexport function writeColorPaletteToMemory(offset: i32, value: i32): void {\n  // FF68\n  //  Bit 0-5   Index (00-3F)\n  let memoryLocationSpritePaletteData = Palette.memoryLocationSpritePaletteData;\n  if (offset === Palette.memoryLocationBackgroundPaletteData || offset === memoryLocationSpritePaletteData) {\n    // Get the palette index\n    let paletteIndex: i32 = eightBitLoadFromGBMemory(offset - 1);\n\n    // Clear the 6th bit, as it does nothing\n    paletteIndex = resetBitOnByte(6, paletteIndex);\n\n    // Check if we are changing the sprite pallete data\n    let isSprite = offset === memoryLocationSpritePaletteData;\n    storePaletteByteInWasmMemory(paletteIndex, value, isSprite);\n    incrementPaletteIndexIfSet(paletteIndex, offset - 1);\n  }\n}\n\n// Functions to Handle Write to pallete data registers\n// http://gbdev.gg8.se/wiki/articles/Video_Display#FF68_-_BCPS.2FBGPI_-_CGB_Mode_Only_-_Background_Palette_Index\n// Function to handle incrementing the pallete index if required\n// Inlined because closure compiler inlines\nfunction incrementPaletteIndexIfSet(paletteIndex: i32, offset: i32): void {\n  // Check ther auto increment box\n  if (checkBitOnByte(7, paletteIndex)) {\n    // Increment the index, and return the value before the increment\n    // Ensure we don't ouverflow our auto increment bit\n    paletteIndex += 1;\n    paletteIndex = setBitOnByte(7, paletteIndex);\n\n    eightBitStoreIntoGBMemory(offset, paletteIndex);\n  }\n}\n\n// FF68\n// Bit 0-5   Index (00-3F)\n// Bit 7     Auto Increment  (0=Disabled, 1=Increment after Writing)\n// Index is 00-0x3F because the means 0 - 63 (64),\n// and apparently there are 8 bytes per pallete to describe Color 0-3 (4 colors),\n// and 0-7 (8 palltetes). Therefore, 64!\nexport function getRgbColorFromPalette(paletteId: i32, colorId: i32, isSprite: boolean): i32 {\n  // Each Pallete takes 8 bytes, so multiply by 8 to get the pallete\n  // And Each color takes 2 bytes, therefore, multiple by 2 for the correct color bytes in the palette\n  let paletteIndex = paletteId * 8 + colorId * 2;\n\n  // Load the Color that is seperated into two bytes\n  let paletteHighByte: i32 = loadPaletteByteFromWasmMemory(paletteIndex + 1, isSprite);\n  let paletteLowByte: i32 = loadPaletteByteFromWasmMemory(paletteIndex, isSprite);\n\n  // Return the concatenated color byte\n  return <i32>concatenateBytes(paletteHighByte, paletteLowByte);\n}\n\n// Function to return the color from a passed 16 bit color pallette\nexport function getColorComponentFromRgb(colorId: i32, colorRgb: i32): i32 {\n  // Get our bitmask for the color ID\n  // bit mask tested good :)\n  colorId *= 5;\n  let bitMask = 0x1f << colorId;\n  let colorValue = (colorRgb & bitMask) >> colorId;\n\n  // Goal is to reach 254 for each color, so 255 / 31 (0x1F) ~8 TODO: Make exact\n  // Want 5 bits for each\n  return colorValue * 8;\n}\n\n// Function to load a byte from our Gbc Palette memory\nexport function loadPaletteByteFromWasmMemory(paletteIndexByte: i32, isSprite: boolean): u8 {\n  // Clear the top two bits to just get the bottom palette Index\n  let paletteIndex = paletteIndexByte & 0x3f;\n\n  // Move over the palette index to not overlap the background has 0x3F, so Zero for Sprites is 0x40)\n  if (isSprite) {\n    paletteIndex += 0x40;\n  }\n\n  return load<u8>(GBC_PALETTE_LOCATION + paletteIndex);\n}\n\n// Function to store a byte to our Gbc Palette memory\n// Inlined because closure compiler inlines\nexport function storePaletteByteInWasmMemory(paletteIndexByte: i32, value: i32, isSprite: boolean): void {\n  // Clear the top two bits to just get the bottom palette Index\n  let paletteIndex = paletteIndexByte & 0x3f;\n\n  // Move over the palette index to not overlap the background (has 0x3F, so Zero for Sprites is 0x40)\n  if (isSprite) {\n    paletteIndex += 0x40;\n  }\n\n  store<u8>(GBC_PALETTE_LOCATION + paletteIndex, <u8>value);\n}\n","// Functions for performance hacks, and debugging tiles\n\nimport { Cpu } from '../cpu/index';\nimport { Graphics, loadFromVramBank } from './graphics';\nimport {\n  getMonochromeColorFromPalette,\n  getColorizedGbHexColorFromPalette,\n  getRgbColorFromPalette,\n  getColorComponentFromRgb\n} from './palette';\nimport { getRedFromHexColor, getGreenFromHexColor, getBlueFromHexColor } from './colors';\nimport { addPriorityforPixel } from './priority';\n// Assembly script really not feeling the reexport\n// using Skip Traps, because LCD has unrestricted access\n// http://gbdev.gg8.se/wiki/articles/Video_Display#LCD_OAM_DMA_Transfers\nimport { checkBitOnByte } from '../helpers/index';\nimport { i8Portable } from '../portable/portable';\n\nexport class TileCache {\n  static tileId: i32 = -1;\n  static horizontalFlip: boolean = false;\n  static nextXIndexToPerformCacheCheck: i32 = -1;\n}\n\n// Inlined because closure compiler inlines\nexport function resetTileCache(): void {\n  TileCache.tileId = -1;\n  TileCache.nextXIndexToPerformCacheCheck = -1;\n}\n\nexport function drawPixelsFromLineOfTile(\n  tileId: i32,\n  tileDataMemoryLocation: i32,\n  vramBankId: i32,\n  tileLineXStart: i32,\n  tileLineXEnd: i32,\n  tileLineY: i32,\n  outputLineX: i32,\n  outputLineY: i32,\n  outputWidth: i32,\n  wasmMemoryStart: i32,\n  shouldRepresentMonochromeColorByColorId: boolean,\n  paletteLocation: i32,\n  bgMapAttributes: i32,\n  spriteAttributes: i32\n): i32 {\n  // Get our number of pixels drawn\n  let pixelsDrawn = 0;\n\n  // Get our tile data address\n  let tileDataAddress = getTileDataAddress(tileDataMemoryLocation, tileId);\n\n  // Get the bytes for our tile\n  let byteOneForLineOfTilePixels = loadFromVramBank(tileDataAddress + tileLineY * 2, vramBankId);\n  let byteTwoForLineOfTilePixels = loadFromVramBank(tileDataAddress + tileLineY * 2 + 1, vramBankId);\n\n  // Loop through our X values to draw\n  for (let x = tileLineXStart; x <= tileLineXEnd; ++x) {\n    // First find where we are going to do our final output x\n    // And don't allow any width overflow\n    let iteratedOutputX = outputLineX + (x - tileLineXStart);\n    if (iteratedOutputX < outputWidth) {\n      // However, We need to reverse our byte (if not horizontally flipped),\n      // As pixel 0 is on byte 7, and pixel 1 is on byte 6, etc...\n      // Therefore, is pixelX was 2, then really is need to be 5\n      // So 2 - 7 = -5, * 1 = 5\n      // Or to simplify, 7 - 2 = 5 haha!\n      let pixelXInTile = x;\n      if (bgMapAttributes < 0 || !checkBitOnByte(5, bgMapAttributes)) {\n        pixelXInTile = 7 - pixelXInTile;\n      }\n\n      // Get our pallete colors for the tile\n      let paletteColorId = 0;\n      if (checkBitOnByte(pixelXInTile, byteTwoForLineOfTilePixels)) {\n        // Byte one represents the second bit in our color id, so bit shift\n        paletteColorId += 1;\n        paletteColorId = paletteColorId << 1;\n      }\n      if (checkBitOnByte(pixelXInTile, byteOneForLineOfTilePixels)) {\n        paletteColorId += 1;\n      }\n\n      // Get the pallete\n      let red = 0;\n      let green = 0;\n      let blue = 0;\n\n      // Check if we should draw color or not\n      if (Cpu.GBCEnabled && (bgMapAttributes >= 0 || spriteAttributes >= 0)) {\n        // Draw C O L O R\n\n        let isSprite = spriteAttributes >= 0;\n\n        // Call the helper function to grab the correct color from the palette\n        // Get the palette index byte\n        let bgPalette = bgMapAttributes & 0x07;\n        if (isSprite) {\n          bgPalette = spriteAttributes & 0x07;\n        }\n        let rgbColorPalette = getRgbColorFromPalette(bgPalette, paletteColorId, isSprite);\n\n        // Split off into red green and blue\n        red = getColorComponentFromRgb(0, rgbColorPalette);\n        green = getColorComponentFromRgb(1, rgbColorPalette);\n        blue = getColorComponentFromRgb(2, rgbColorPalette);\n      } else {\n        // Draw Monochrome\n\n        // Get the default palette if none\n        if (paletteLocation <= 0) {\n          paletteLocation = Graphics.memoryLocationBackgroundPalette;\n        }\n\n        if (shouldRepresentMonochromeColorByColorId) {\n          let monochromeColor = getMonochromeColorFromPalette(paletteColorId, paletteLocation, shouldRepresentMonochromeColorByColorId);\n          red = monochromeColor;\n          green = monochromeColor;\n          blue = monochromeColor;\n        } else {\n          let hexColor = getColorizedGbHexColorFromPalette(paletteColorId, paletteLocation);\n          red = getRedFromHexColor(hexColor);\n          green = getGreenFromHexColor(hexColor);\n          blue = getBlueFromHexColor(hexColor);\n        }\n      }\n\n      // Finally Lets place a pixel in memory\n      // Find where our tile line would start\n      let pixelStart = getTilePixelStart(iteratedOutputX, outputLineY, outputWidth);\n\n      // Can not optimize wasmMemoryStart any further, as this is in a loop.\n      store<u8>(wasmMemoryStart + pixelStart + 0, <u8>red);\n      store<u8>(wasmMemoryStart + pixelStart + 1, <u8>green);\n      store<u8>(wasmMemoryStart + pixelStart + 2, <u8>blue);\n\n      let gbcBgPriority: boolean = false;\n      if (bgMapAttributes >= 0) {\n        gbcBgPriority = checkBitOnByte(7, bgMapAttributes);\n      }\n\n      // Lastly, add the pixel to our background priority map\n      // https://github.com/torch2424/wasmBoy/issues/51\n      // Bits 0 & 1 will represent the color Id drawn by the BG/Window\n      // Bit 2 will represent if the Bg/Window has GBC priority.\n      addPriorityforPixel(iteratedOutputX, outputLineY, paletteColorId, gbcBgPriority);\n\n      pixelsDrawn++;\n    }\n  }\n\n  return pixelsDrawn;\n}\n\n// Inlined because closure compiler inlines\nexport function getTilePixelStart(outputLineX: i32, outputLineY: i32, outputWidth: i32): i32 {\n  // Finally Lets place a pixel in memory\n  let pixelStart = outputLineY * outputWidth + outputLineX;\n\n  // Each pixel takes 3 slots, therefore, multiply by 3!\n  return pixelStart * 3;\n}\n\nexport function getTileDataAddress(tileDataMemoryLocation: i32, tileIdFromTileMap: i32): i32 {\n  // Watch this part of The ultimate gameboy talk: https://youtu.be/HyzD8pNlpwI?t=30m50s\n  // A line of 8 pixels on a single tile, is represented by 2 bytes.\n  // since a single tile is 8x8 pixels, 8 * 2 = 16 bytes\n\n  // Get the tile ID's tile addess from tile data.\n  // For instance, let's say our first line of tile data represents tiles for letters:\n  // a b c d e f g\n  // And we have tileId 0x02. That means we want the tile for the 'c' character\n  // Since each tile is 16 bytes, it would be the starting tileDataAddress + (tileId * tileSize), to skip over tiles we dont want\n  // The whole signed thing is weird, and has something to do how the second set of tile data is stored :p\n  if (tileDataMemoryLocation === Graphics.memoryLocationTileDataSelectZeroStart) {\n    // Treat the tile Id as a signed int, subtract an offset of 128\n    // if the tileId was 0 then the tile would be in memory region 0x9000-0x900F\n    if (checkBitOnByte(7, tileIdFromTileMap)) {\n      tileIdFromTileMap -= 128;\n    } else {\n      tileIdFromTileMap += 128;\n    }\n  }\n\n  // if the background layout gave us the tileId 0, then the tile data would be between 0x8000-0x800F.\n  return tileDataMemoryLocation + tileIdFromTileMap * 16;\n}\n","// NOTE: Tons of Copy-pasta btween channels, because Classes cannot be instantiated yet in assemblyscript\n\n// Square Channel with Frequency Sweep\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Square_Wave\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Frequency_Sweep\nimport { getSaveStateMemoryOffset } from '../core';\nimport { Sound } from './sound';\nimport { isDutyCycleClockPositiveOrNegativeForWaveform } from './duty';\nimport { Cpu } from '../cpu/index';\nimport {\n  eightBitLoadFromGBMemory,\n  eightBitStoreIntoGBMemory,\n  loadBooleanDirectlyFromWasmMemory,\n  storeBooleanDirectlyToWasmMemory\n} from '../memory/index';\nimport { checkBitOnByte, log, logTimeout } from '../helpers/index';\n\nexport class Channel1 {\n  // Cycle Counter for our sound accumulator\n  static cycleCounter: i32 = 0;\n\n  // Max Length of our Length Load\n  static MAX_LENGTH: i32 = 64;\n\n  // Squarewave channel with volume envelope and frequency sweep functions.\n  // NR10 -> Sweep Register R/W\n  static readonly memoryLocationNRx0: i32 = 0xff10;\n  // -PPP NSSS Sweep period, negate, shift\n  static NRx0SweepPeriod: i32 = 0;\n  static NRx0Negate: boolean = false;\n  static NRx0SweepShift: i32 = 0;\n  static updateNRx0(value: i32): void {\n    let oldSweepNegate = Channel1.NRx0Negate;\n\n    Channel1.NRx0SweepPeriod = (value & 0x70) >> 4;\n    Channel1.NRx0Negate = checkBitOnByte(3, value);\n    Channel1.NRx0SweepShift = value & 0x07;\n\n    // Obscure Behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware\n    // Clearing the sweep negate mode bit in NR10 after at least one sweep calculation has been made,\n    // using the negate mode since the last trigger causes the channel to be immediately disabled.\n    // This prevents you from having the sweep lower the frequency then raise the frequency without a trigger inbetween.\n    if (oldSweepNegate && (!Channel1.NRx0Negate && Channel1.sweepNegateShouldDisableChannelOnClear)) {\n      Channel1.isEnabled = false;\n    }\n  }\n\n  // NR11 -> Sound length/Wave pattern duty (R/W)\n  static readonly memoryLocationNRx1: i32 = 0xff11;\n  // DDLL LLLL Duty, Length load (64-L)\n  static NRx1Duty: i32 = 0;\n  static NRx1LengthLoad: i32 = 0;\n  static updateNRx1(value: i32): void {\n    Channel1.NRx1Duty = (value >> 6) & 0x03;\n    Channel1.NRx1LengthLoad = value & 0x3f;\n\n    // Also need to set our length counter. Taken from the old, setChannelLengthCounter\n    // Channel length is determined by 64 (or 256 if channel 3), - the length load\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n    // Note, this will be different for channel 3\n    Channel1.lengthCounter = Channel1.MAX_LENGTH - Channel1.NRx1LengthLoad;\n  }\n\n  // NR12 -> Volume Envelope (R/W)\n  static readonly memoryLocationNRx2: i32 = 0xff12;\n  // VVVV APPP Starting volume, Envelope add mode, period\n  static NRx2StartingVolume: i32 = 0;\n  static NRx2EnvelopeAddMode: boolean = false;\n  static NRx2EnvelopePeriod: i32 = 0;\n  static updateNRx2(value: i32): void {\n    // Handle \"Zombie Mode\" Obscure behavior\n    // https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    if (Channel1.isEnabled) {\n      // If the old envelope period was zero and the envelope is still doing automatic updates,\n      // volume is incremented by 1, otherwise if the envelope was in subtract mode,\n      // volume is incremented by 2.\n      // NOTE: However, from my testing, it ALWAYS increments by one. This was determined\n      // by my testing for prehistoric man\n      if (Channel1.NRx2EnvelopePeriod === 0 && Channel1.isEnvelopeAutomaticUpdating) {\n        // Volume can't be more than 4 bits\n        Channel1.volume = (Channel1.volume + 1) & 0x0f;\n      }\n\n      // If the mode was changed (add to subtract or subtract to add),\n      // volume is set to 16-volume. But volume cant be more than 4 bits\n      if (Channel1.NRx2EnvelopeAddMode !== checkBitOnByte(3, value)) {\n        Channel1.volume = (16 - Channel1.volume) & 0x0f;\n      }\n    }\n\n    // Handle the regular write\n    Channel1.NRx2StartingVolume = (value >> 4) & 0x0f;\n    Channel1.NRx2EnvelopeAddMode = checkBitOnByte(3, value);\n    Channel1.NRx2EnvelopePeriod = value & 0x07;\n\n    // Also, get our channel is dac enabled\n    let isDacEnabled = (value & 0xf8) > 0;\n    Channel1.isDacEnabled = isDacEnabled;\n\n    // Blargg length test\n    // Disabling DAC should disable channel immediately\n    if (!isDacEnabled) {\n      Channel1.isEnabled = false;\n    }\n  }\n\n  // NR13 -> Frequency lo (W)\n  static readonly memoryLocationNRx3: i32 = 0xff13;\n  // FFFF FFFF Frequency LSB\n  static NRx3FrequencyLSB: i32 = 0;\n  static updateNRx3(value: i32): void {\n    Channel1.NRx3FrequencyLSB = value;\n\n    // Update Channel Frequency\n    Channel1.frequency = (Channel1.NRx4FrequencyMSB << 8) | value;\n  }\n\n  // NR14 -> Frequency hi (R/W)\n  static readonly memoryLocationNRx4: i32 = 0xff14;\n  // TL-- -FFF Trigger, Length enable, Frequency MSB\n  static NRx4LengthEnabled: boolean = false;\n  static NRx4FrequencyMSB: i32 = 0;\n  // NOTE: Order in which these events happen are very particular\n  // And globals can be affected by other functions\n  // Thus, optimizations here should be extremely careful\n  static updateNRx4(value: i32): void {\n    // Handle our Channel frequency first\n    // As this is modified if we trigger for length.\n    let frequencyMSB = value & 0x07;\n    Channel1.NRx4FrequencyMSB = frequencyMSB;\n    Channel1.frequency = (frequencyMSB << 8) | Channel1.NRx3FrequencyLSB;\n\n    // Obscure behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    // Also see blargg's cgb sound test\n    // Extra length clocking occurs when writing to NRx4,\n    // when the frame sequencer's next step is one that,\n    // doesn't clock the length counter.\n    let frameSequencer = Sound.frameSequencer;\n    let doesNextFrameSequencerUpdateLength = (frameSequencer & 1) === 1;\n    let isBeingLengthEnabled = !Channel1.NRx4LengthEnabled && checkBitOnByte(6, value);\n    if (!doesNextFrameSequencerUpdateLength) {\n      // Check lengthEnable\n      if (Channel1.lengthCounter > 0 && isBeingLengthEnabled) {\n        Channel1.lengthCounter -= 1;\n\n        if (!checkBitOnByte(7, value) && Channel1.lengthCounter === 0) {\n          Channel1.isEnabled = false;\n        }\n      }\n    }\n\n    // Set the length enabled from the value\n    Channel1.NRx4LengthEnabled = checkBitOnByte(6, value);\n\n    // Trigger out channel, unfreeze length if frozen\n    // Triggers should happen after obscure behavior\n    // See test 11 for trigger\n    if (checkBitOnByte(7, value)) {\n      Channel1.trigger();\n\n      // When we trigger on the obscure behavior, and we reset the length Counter to max\n      // We need to clock\n      if (!doesNextFrameSequencerUpdateLength && Channel1.lengthCounter === Channel1.MAX_LENGTH && Channel1.NRx4LengthEnabled) {\n        Channel1.lengthCounter -= 1;\n      }\n    }\n  }\n\n  // Channel Properties\n  static readonly channelNumber: i32 = 1;\n  static isEnabled: boolean = false;\n  static isDacEnabled: boolean = false;\n  static frequency: i32 = 0;\n  static frequencyTimer: i32 = 0x00;\n  static envelopeCounter: i32 = 0x00;\n  static isEnvelopeAutomaticUpdating: boolean = false;\n  static lengthCounter: i32 = 0x00;\n  static volume: i32 = 0x00;\n\n  // Square Wave properties\n  static dutyCycle: i32 = 0x00;\n  static waveFormPositionOnDuty: i32 = 0x00;\n\n  // Channel 1 Sweep\n  static isSweepEnabled: boolean = false;\n  static sweepCounter: i32 = 0x00;\n  static sweepShadowFrequency: i32 = 0x00;\n  static sweepNegateShouldDisableChannelOnClear: boolean = false;\n\n  // Save States\n  static readonly saveStateSlot: i32 = 7;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x00, Channel1.saveStateSlot), Channel1.isEnabled);\n    store<i32>(getSaveStateMemoryOffset(0x01, Channel1.saveStateSlot), Channel1.frequencyTimer);\n    store<i32>(getSaveStateMemoryOffset(0x05, Channel1.saveStateSlot), Channel1.envelopeCounter);\n    store<i32>(getSaveStateMemoryOffset(0x09, Channel1.saveStateSlot), Channel1.lengthCounter);\n    store<i32>(getSaveStateMemoryOffset(0x0e, Channel1.saveStateSlot), Channel1.volume);\n\n    store<u8>(getSaveStateMemoryOffset(0x13, Channel1.saveStateSlot), Channel1.dutyCycle);\n    store<u8>(getSaveStateMemoryOffset(0x14, Channel1.saveStateSlot), <u8>Channel1.waveFormPositionOnDuty);\n\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x19, Channel1.saveStateSlot), Channel1.isSweepEnabled);\n    store<i32>(getSaveStateMemoryOffset(0x1a, Channel1.saveStateSlot), Channel1.sweepCounter);\n    store<u16>(getSaveStateMemoryOffset(0x1f, Channel1.saveStateSlot), Channel1.sweepShadowFrequency);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x21, Channel1.saveStateSlot), Channel1.isEnvelopeAutomaticUpdating);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    Channel1.isEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x00, Channel1.saveStateSlot));\n    Channel1.frequencyTimer = load<i32>(getSaveStateMemoryOffset(0x01, Channel1.saveStateSlot));\n    Channel1.envelopeCounter = load<i32>(getSaveStateMemoryOffset(0x05, Channel1.saveStateSlot));\n    Channel1.lengthCounter = load<i32>(getSaveStateMemoryOffset(0x09, Channel1.saveStateSlot));\n    Channel1.volume = load<i32>(getSaveStateMemoryOffset(0x0e, Channel1.saveStateSlot));\n\n    Channel1.dutyCycle = load<u8>(getSaveStateMemoryOffset(0x13, Channel1.saveStateSlot));\n    Channel1.waveFormPositionOnDuty = load<u8>(getSaveStateMemoryOffset(0x14, Channel1.saveStateSlot));\n\n    Channel1.isSweepEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x19, Channel1.saveStateSlot));\n    Channel1.sweepCounter = load<i32>(getSaveStateMemoryOffset(0x1a, Channel1.saveStateSlot));\n    Channel1.sweepShadowFrequency = load<u16>(getSaveStateMemoryOffset(0x1f, Channel1.saveStateSlot));\n    Channel1.isEnvelopeAutomaticUpdating = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x21, Channel1.saveStateSlot));\n  }\n\n  static initialize(): void {\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx0, 0x80);\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx1, 0xbf);\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx2, 0xf3);\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx3, 0xc1);\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx4, 0xbf);\n\n    // Override/reset some variables if the boot ROM is enabled\n    // For GBC and GB\n    if (Cpu.BootROMEnabled) {\n      eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx1, 0x3f);\n      eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx2, 0x00);\n      eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx3, 0x00);\n      eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx4, 0xb8);\n    }\n  }\n\n  // Function to get a sample using the cycle counter on the channel\n  static getSampleFromCycleCounter(): i32 {\n    let accumulatedCycles = Channel1.cycleCounter;\n    Channel1.cycleCounter = 0;\n    return Channel1.getSample(accumulatedCycles);\n  }\n\n  // Function to reset our timer, useful for GBC double speed mode\n  static resetTimer(): void {\n    let frequencyTimer = (2048 - Channel1.frequency) << 2;\n\n    // TODO: Ensure this is correct for GBC Double Speed Mode\n    if (Cpu.GBCDoubleSpeed) {\n      frequencyTimer = frequencyTimer << 2;\n    }\n    Channel1.frequencyTimer = frequencyTimer;\n  }\n\n  static getSample(numberOfCycles: i32): i32 {\n    // Decrement our channel timer\n    let frequencyTimer = Channel1.frequencyTimer;\n    frequencyTimer -= numberOfCycles;\n    while (frequencyTimer <= 0) {\n      // Get the amount that overflowed so we don't drop cycles\n      let overflowAmount = abs(frequencyTimer);\n\n      // Reset our timer\n      // A square channel's frequency timer period is set to (2048-frequency)*4.\n      // Four duty cycles are available, each waveform taking 8 frequency timer clocks to cycle through:\n      Channel1.resetTimer();\n      frequencyTimer = Channel1.frequencyTimer;\n      frequencyTimer -= overflowAmount;\n\n      // Also increment our duty cycle\n      // What is duty? https://en.wikipedia.org/wiki/Duty_cycle\n      // Duty cycle for square wave: http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Square_Wave\n      Channel1.waveFormPositionOnDuty = (Channel1.waveFormPositionOnDuty + 1) & 7;\n    }\n\n    Channel1.frequencyTimer = frequencyTimer;\n\n    // Get our ourput volume\n    let outputVolume = 0;\n\n    // Finally to set our output volume, the channel must be enabled,\n    // Our channel DAC must be enabled, and we must be in an active state\n    // Of our duty cycle\n    if (Channel1.isEnabled && Channel1.isDacEnabled) {\n      // Volume can't be more than 4 bits.\n      // Volume should never be more than 4 bits, but doing a check here\n      outputVolume = Channel1.volume & 0x0f;\n    } else {\n      // Return silence\n      // Since range from -15 - 15, or 0 to 30 for our unsigned\n      return 15;\n    }\n\n    // Get the current sampleValue\n    let sample = 1;\n    if (!isDutyCycleClockPositiveOrNegativeForWaveform(Channel1.NRx1Duty, Channel1.waveFormPositionOnDuty)) {\n      sample = -sample;\n    }\n\n    sample *= outputVolume;\n\n    // Square Waves Can range from -15 - 15. Therefore simply add 15\n    sample += 15;\n    return sample;\n  }\n\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Trigger_Event\n  static trigger(): void {\n    Channel1.isEnabled = true;\n    // Set length to maximum done in write\n    if (Channel1.lengthCounter === 0) {\n      Channel1.lengthCounter = Channel1.MAX_LENGTH;\n    }\n\n    // Reset our timer\n    // A square channel's frequency timer period is set to (2048-frequency)*4.\n    // Four duty cycles are available, each waveform taking 8 frequency timer clocks to cycle through:\n    Channel1.resetTimer();\n\n    // The volume envelope and sweep timers treat a period of 0 as 8.\n    // Meaning, if the period is zero, set it to the max (8).\n    if (Channel1.NRx2EnvelopePeriod === 0) {\n      Channel1.envelopeCounter = 8;\n    } else {\n      Channel1.envelopeCounter = Channel1.NRx2EnvelopePeriod;\n    }\n    Channel1.isEnvelopeAutomaticUpdating = true;\n\n    Channel1.volume = Channel1.NRx2StartingVolume;\n\n    // Handle Channel Sweep\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware\n    Channel1.sweepShadowFrequency = Channel1.frequency;\n\n    // Reset back to the sweep period\n    // Obscure behavior\n    // Sweep timers treat a period o 0 as 8\n    if (Channel1.NRx0SweepPeriod === 0) {\n      Channel1.sweepCounter = 8;\n    } else {\n      Channel1.sweepCounter = Channel1.NRx0SweepPeriod;\n    }\n\n    // The internal enabled flag is set if either the sweep period or shift are non-zero, cleared otherwise.\n    Channel1.isSweepEnabled = Channel1.NRx0SweepPeriod > 0 || Channel1.NRx0SweepShift > 0;\n\n    Channel1.sweepNegateShouldDisableChannelOnClear = false;\n\n    // If the sweep shift is non-zero, frequency calculation and the overflow check are performed immediately.\n    // NOTE: The double calculation thing for the sweep does not happen here.\n    if (Channel1.NRx0SweepShift > 0 && didCalculatedSweepOverflow(calculateSweep())) {\n      Channel1.isEnabled = false;\n    }\n\n    // Finally if DAC is off, channel is still disabled\n    if (!Channel1.isDacEnabled) {\n      Channel1.isEnabled = false;\n    }\n  }\n\n  // Function to determine if the current channel would update when getting the sample\n  // This is used to accumulate samples\n  static willChannelUpdate(numberOfCycles: i32): boolean {\n    //Increment our cycle counter\n    let cycleCounter = Channel1.cycleCounter + numberOfCycles;\n    Channel1.cycleCounter = cycleCounter;\n\n    // Dac enabled status cached by accumulator\n    return !(Channel1.frequencyTimer - cycleCounter > 0);\n  }\n\n  static updateSweep(): void {\n    // Dont update period if not enabled\n    if (!Channel1.isEnabled || !Channel1.isSweepEnabled) {\n      return;\n    }\n\n    // Decrement the sweep counter\n    let sweepCounter = Channel1.sweepCounter - 1;\n    if (sweepCounter <= 0) {\n      // Reset back to the sweep period\n      // Obscure behavior\n      // Sweep timers treat a period of 0 as 8 (They reset back to the max)\n      if (Channel1.NRx0SweepPeriod === 0) {\n        // Sweep isn't calculated when the period is 0\n        Channel1.sweepCounter = 8;\n      } else {\n        // Reset our sweep counter to its period\n        Channel1.sweepCounter = Channel1.NRx0SweepPeriod;\n\n        // Calculate our sweep\n        // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware\n        // When it generates a clock and the sweep's internal enabled flag is set and the sweep period is not zero,\n        // a new frequency is calculated and the overflow check is performed. If the new frequency is 2047 or less,\n        // and the sweep shift is not zero, this new frequency is written back to the shadow frequency,\n        // and square 1's frequency in NR13 and NR14, then frequency calculation,\n        // and overflow check are run AGAIN immediately using this new value,\n        // but this second new frequency is not written back.\n        let newFrequency = calculateSweep();\n        if (didCalculatedSweepOverflow(newFrequency)) {\n          Channel1.isEnabled = false;\n        }\n\n        if (Channel1.NRx0SweepShift > 0) {\n          Channel1.setFrequency(newFrequency);\n\n          if (didCalculatedSweepOverflow(calculateSweep())) {\n            Channel1.isEnabled = false;\n          }\n        }\n      }\n    } else {\n      Channel1.sweepCounter = sweepCounter;\n    }\n  }\n\n  static updateLength(): void {\n    let lengthCounter = Channel1.lengthCounter;\n    if (lengthCounter > 0 && Channel1.NRx4LengthEnabled) {\n      lengthCounter -= 1;\n\n      if (lengthCounter === 0) {\n        Channel1.isEnabled = false;\n      }\n    }\n    Channel1.lengthCounter = lengthCounter;\n  }\n\n  static updateEnvelope(): void {\n    let envelopeCounter = Channel1.envelopeCounter - 1;\n    if (envelopeCounter <= 0) {\n      // Reset back to the sweep period\n      // Obscure behavior\n      // Envelopes treat a period of 0 as 8 (They reset back to the max)\n      if (Channel1.NRx2EnvelopePeriod === 0) {\n        envelopeCounter = 8;\n      } else {\n        envelopeCounter = Channel1.NRx2EnvelopePeriod;\n\n        // When the timer generates a clock and the envelope period is NOT zero, a new volume is calculated\n        // NOTE: There is some weiirrdd obscure behavior where zero can equal 8, so watch out for that\n        // If notes are sustained for too long, this is probably why\n        if (envelopeCounter !== 0 && Channel1.isEnvelopeAutomaticUpdating) {\n          let volume = Channel1.volume;\n\n          // Increment the volume\n          if (Channel1.NRx2EnvelopeAddMode) {\n            volume += 1;\n          } else {\n            volume -= 1;\n          }\n\n          // Don't allow the volume to go above 4 bits.\n          volume = volume & 0x0f;\n\n          // Check if we are below the max\n          if (volume < 15) {\n            Channel1.volume = volume;\n          } else {\n            Channel1.isEnvelopeAutomaticUpdating = false;\n          }\n        }\n      }\n    }\n    Channel1.envelopeCounter = envelopeCounter;\n  }\n\n  static setFrequency(frequency: i32): void {\n    // Set our shadowFrequency\n    Channel1.sweepShadowFrequency = frequency;\n\n    // Get the high and low bits\n    let passedFrequencyHighBits = (frequency >> 8) & 0x07;\n    let passedFrequencyLowBits = frequency & 0xff;\n\n    // Get the new register 4\n    let register4 = eightBitLoadFromGBMemory(Channel1.memoryLocationNRx4);\n    // Knock off lower 3 bits, and Or on our high bits\n    let newRegister4 = register4 & 0xf8;\n    newRegister4 = newRegister4 | passedFrequencyHighBits;\n\n    // Set the registers\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx3, passedFrequencyLowBits);\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx4, newRegister4);\n\n    // Save the frequency for ourselves without triggering memory traps\n    Channel1.NRx3FrequencyLSB = passedFrequencyLowBits;\n    Channel1.NRx4FrequencyMSB = passedFrequencyHighBits;\n    Channel1.frequency = (Channel1.NRx4FrequencyMSB << 8) | Channel1.NRx3FrequencyLSB;\n  }\n  // Done!\n}\n\n// Sweep Specific functions\n// Function to determing a new sweep in the current context\nfunction calculateSweep(): i32 {\n  // Start our new frequency, by making it equal to the \"shadow frequency\"\n  let oldFrequency = Channel1.sweepShadowFrequency;\n  let newFrequency = oldFrequency >> Channel1.NRx0SweepShift;\n\n  // Check for sweep negation\n  if (Channel1.NRx0Negate) {\n    Channel1.sweepNegateShouldDisableChannelOnClear = true;\n    newFrequency = oldFrequency - newFrequency;\n  } else {\n    newFrequency = oldFrequency + newFrequency;\n  }\n\n  return newFrequency;\n}\n\n// Function to check if a calculated sweep overflowed\nfunction didCalculatedSweepOverflow(calculatedSweep: i32): boolean {\n  // 7FF is the highest value of the frequency: 111 1111 1111\n  // if it overflows, should disable the channel (handled by the caller)\n  if (calculatedSweep > 0x7ff) {\n    return true;\n  }\n\n  return false;\n}\n","// NOTE: Tons of Copy-pasta btween channels, because Classes cannot be instantiated yet in assemblyscript\n\n// Simple Square Channel\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Square_Wave\nimport { getSaveStateMemoryOffset } from '../core';\nimport { Sound } from './sound';\nimport { isDutyCycleClockPositiveOrNegativeForWaveform } from './duty';\nimport { Cpu } from '../cpu/index';\nimport {\n  eightBitLoadFromGBMemory,\n  eightBitStoreIntoGBMemory,\n  loadBooleanDirectlyFromWasmMemory,\n  storeBooleanDirectlyToWasmMemory\n} from '../memory/index';\nimport { checkBitOnByte, log, logTimeout } from '../helpers/index';\n\nexport class Channel2 {\n  // Cycle Counter for our sound accumulator\n  static cycleCounter: i32 = 0;\n\n  // Max Length of our Length Load\n  static MAX_LENGTH: i32 = 64;\n\n  // Squarewave channel with volume envelope functions only.\n\n  // Only used by register reading\n  static readonly memoryLocationNRx0: i32 = 0xff15;\n\n  // NR21 -> Sound length/Wave pattern duty (R/W)\n  static readonly memoryLocationNRx1: i32 = 0xff16;\n  // DDLL LLLL Duty, Length load (64-L)\n  static NRx1Duty: i32 = 0;\n  static NRx1LengthLoad: i32 = 0;\n  static updateNRx1(value: i32): void {\n    Channel2.NRx1Duty = (value >> 6) & 0x03;\n    Channel2.NRx1LengthLoad = value & 0x3f;\n\n    // Also need to set our length counter. Taken from the old, setChannelLengthCounter\n    // Channel length is determined by 64 (or 256 if channel 3), - the length load\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n    // Note, this will be different for channel 3\n    Channel2.lengthCounter = Channel2.MAX_LENGTH - Channel2.NRx1LengthLoad;\n  }\n\n  // NR22 -> Volume Envelope (R/W)\n  static readonly memoryLocationNRx2: i32 = 0xff17;\n  // VVVV APPP Starting volume, Envelope add mode, period\n  static NRx2StartingVolume: i32 = 0;\n  static NRx2EnvelopeAddMode: boolean = false;\n  static NRx2EnvelopePeriod: i32 = 0;\n  static updateNRx2(value: i32): void {\n    // Handle \"Zombie Mode\" Obscure behavior\n    // https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    if (Channel2.isEnabled) {\n      // If the old envelope period was zero and the envelope is still doing automatic updates,\n      // volume is incremented by 1, otherwise if the envelope was in subtract mode,\n      // volume is incremented by 2.\n      // NOTE: However, from my testing, it ALWAYS increments by one. This was determined\n      // by my testing for prehistoric man\n      if (Channel2.NRx2EnvelopePeriod === 0 && Channel2.isEnvelopeAutomaticUpdating) {\n        // Volume can't be more than 4 bits\n        Channel2.volume = (Channel2.volume + 1) & 0x0f;\n      }\n\n      // If the mode was changed (add to subtract or subtract to add),\n      // volume is set to 16-volume. But volume cant be more than 4 bits\n      if (Channel2.NRx2EnvelopeAddMode !== checkBitOnByte(3, value)) {\n        Channel2.volume = (16 - Channel2.volume) & 0x0f;\n      }\n    }\n\n    Channel2.NRx2StartingVolume = (value >> 4) & 0x0f;\n    Channel2.NRx2EnvelopeAddMode = checkBitOnByte(3, value);\n    Channel2.NRx2EnvelopePeriod = value & 0x07;\n\n    // Also, get our channel is dac enabled\n    let isDacEnabled = (value & 0xf8) > 0;\n    Channel2.isDacEnabled = isDacEnabled;\n\n    // Blargg length test\n    // Disabling DAC should disable channel immediately\n    if (!isDacEnabled) {\n      Channel2.isEnabled = isDacEnabled;\n    }\n  }\n\n  // NR23 -> Frequency lo (W)\n  static readonly memoryLocationNRx3: i32 = 0xff18;\n  // FFFF FFFF Frequency LSB\n  static NRx3FrequencyLSB: i32 = 0;\n  static updateNRx3(value: i32): void {\n    Channel2.NRx3FrequencyLSB = value;\n\n    // Update Channel Frequency\n    Channel2.frequency = (Channel2.NRx4FrequencyMSB << 8) | value;\n  }\n\n  // NR24 -> Frequency hi (R/W)\n  static readonly memoryLocationNRx4: i32 = 0xff19;\n  // TL-- -FFF Trigger, Length enable, Frequency MSB\n  static NRx4LengthEnabled: boolean = false;\n  static NRx4FrequencyMSB: i32 = 0;\n  static updateNRx4(value: i32): void {\n    // Handle our Channel frequency first\n    // As this is modified if we trigger for length.\n    let frequencyMSB = value & 0x07;\n    Channel2.NRx4FrequencyMSB = frequencyMSB;\n    Channel2.frequency = (frequencyMSB << 8) | Channel2.NRx3FrequencyLSB;\n\n    // Obscure behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    // Also see blargg's cgb sound test\n    // Extra length clocking occurs when writing to NRx4,\n    // when the frame sequencer's next step is one that,\n    // doesn't clock the length counter.\n    let frameSequencer = Sound.frameSequencer;\n    let doesNextFrameSequencerUpdateLength = (frameSequencer & 1) === 1;\n    let isBeingLengthEnabled = !Channel2.NRx4LengthEnabled && checkBitOnByte(6, value);\n    if (!doesNextFrameSequencerUpdateLength) {\n      if (Channel2.lengthCounter > 0 && isBeingLengthEnabled) {\n        Channel2.lengthCounter -= 1;\n\n        if (!checkBitOnByte(7, value) && Channel2.lengthCounter === 0) {\n          Channel2.isEnabled = false;\n        }\n      }\n    }\n\n    // Set the length enabled from the value\n    Channel2.NRx4LengthEnabled = checkBitOnByte(6, value);\n\n    // Trigger out channel, unfreeze length if frozen\n    // Triggers should happen after obscure behavior\n    // See test 11 for trigger\n    if (checkBitOnByte(7, value)) {\n      Channel2.trigger();\n\n      // When we trigger on the obscure behavior, and we reset the length Counter to max\n      // We need to clock\n      if (!doesNextFrameSequencerUpdateLength && Channel2.lengthCounter === Channel2.MAX_LENGTH && Channel2.NRx4LengthEnabled) {\n        Channel2.lengthCounter -= 1;\n      }\n    }\n  }\n\n  // Channel Properties\n  static readonly channelNumber: i32 = 2;\n  static isEnabled: boolean = false;\n  static isDacEnabled: boolean = false;\n  static frequency: i32 = 0;\n  static frequencyTimer: i32 = 0x00;\n  static envelopeCounter: i32 = 0x00;\n  static isEnvelopeAutomaticUpdating: boolean = false;\n  static lengthCounter: i32 = 0x00;\n  static volume: i32 = 0x00;\n\n  // Square Wave properties\n  static dutyCycle: i32 = 0x00;\n  static waveFormPositionOnDuty: i32 = 0x00;\n\n  // Save States\n\n  static readonly saveStateSlot: i32 = 8;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x00, Channel2.saveStateSlot), Channel2.isEnabled);\n    store<i32>(getSaveStateMemoryOffset(0x01, Channel2.saveStateSlot), Channel2.frequencyTimer);\n    store<i32>(getSaveStateMemoryOffset(0x05, Channel2.saveStateSlot), Channel2.envelopeCounter);\n    store<i32>(getSaveStateMemoryOffset(0x09, Channel2.saveStateSlot), Channel2.lengthCounter);\n    store<i32>(getSaveStateMemoryOffset(0x0e, Channel2.saveStateSlot), Channel2.volume);\n\n    store<u8>(getSaveStateMemoryOffset(0x13, Channel2.saveStateSlot), Channel2.dutyCycle);\n    store<u8>(getSaveStateMemoryOffset(0x14, Channel2.saveStateSlot), <u8>Channel2.waveFormPositionOnDuty);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x15, Channel2.saveStateSlot), Channel2.isEnvelopeAutomaticUpdating);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    Channel2.isEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x00, Channel2.saveStateSlot));\n    Channel2.frequencyTimer = load<i32>(getSaveStateMemoryOffset(0x01, Channel2.saveStateSlot));\n    Channel2.envelopeCounter = load<i32>(getSaveStateMemoryOffset(0x05, Channel2.saveStateSlot));\n    Channel2.lengthCounter = load<i32>(getSaveStateMemoryOffset(0x09, Channel2.saveStateSlot));\n    Channel2.volume = load<i32>(getSaveStateMemoryOffset(0x0e, Channel2.saveStateSlot));\n\n    Channel2.dutyCycle = load<u8>(getSaveStateMemoryOffset(0x13, Channel2.saveStateSlot));\n    Channel2.waveFormPositionOnDuty = load<u8>(getSaveStateMemoryOffset(0x14, Channel2.saveStateSlot));\n    Channel2.isEnvelopeAutomaticUpdating = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x21, Channel2.saveStateSlot));\n  }\n\n  static initialize(): void {\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx1 - 1, 0xff);\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx1, 0x3f);\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx2, 0x00);\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx3, 0x00);\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx4, 0xb8);\n  }\n\n  // Function to get a sample using the cycle counter on the channel\n  static getSampleFromCycleCounter(): i32 {\n    let accumulatedCycles = Channel2.cycleCounter;\n    Channel2.cycleCounter = 0;\n    return Channel2.getSample(accumulatedCycles);\n  }\n\n  // Function to reset our timer, useful for GBC double speed mode\n  static resetTimer(): void {\n    let frequencyTimer = (2048 - Channel2.frequency) << 2;\n\n    // TODO: Ensure this is correct for GBC Double Speed Mode\n    Channel2.frequencyTimer = frequencyTimer << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  static getSample(numberOfCycles: i32): i32 {\n    // Decrement our channel timer\n    let frequencyTimer = Channel2.frequencyTimer;\n    frequencyTimer -= numberOfCycles;\n    while (frequencyTimer <= 0) {\n      // Get the amount that overflowed so we don't drop cycles\n      let overflowAmount = abs(frequencyTimer);\n\n      // Reset our timer\n      // A square channel's frequency timer period is set to (2048-frequency)*4.\n      // Four duty cycles are available, each waveform taking 8 frequency timer clocks to cycle through:\n      Channel2.resetTimer();\n      frequencyTimer = Channel2.frequencyTimer;\n      frequencyTimer -= overflowAmount;\n\n      // Also increment our duty cycle\n      // What is duty? https://en.wikipedia.org/wiki/Duty_cycle\n      // Duty cycle for square wave: http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Square_Wave\n      Channel2.waveFormPositionOnDuty = (Channel2.waveFormPositionOnDuty + 1) & 7;\n    }\n\n    Channel2.frequencyTimer = frequencyTimer;\n\n    // Get our ourput volume\n    let outputVolume = 0;\n\n    // Finally to set our output volume, the channel must be enabled,\n    // Our channel DAC must be enabled, and we must be in an active state\n    // Of our duty cycle\n    if (Channel2.isEnabled && Channel2.isDacEnabled) {\n      // Volume can't be more than 4 bits.\n      // Volume should never be more than 4 bits, but doing a check here\n      outputVolume = Channel2.volume & 0x0f;\n    } else {\n      // Return silence\n      // Since range from -15 - 15, or 0 to 30 for our unsigned\n      return 15;\n    }\n\n    // Get the current sampleValue\n    let sample = 1;\n    if (!isDutyCycleClockPositiveOrNegativeForWaveform(Channel2.NRx1Duty, Channel2.waveFormPositionOnDuty)) {\n      sample = -sample;\n    }\n\n    sample = sample * outputVolume;\n\n    // Square Waves Can range from -15 - 15. Therefore simply add 15\n    sample += 15;\n    return sample;\n  }\n\n  //http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Trigger_Event\n  static trigger(): void {\n    Channel2.isEnabled = true;\n    // Set length to maximum done in write\n    if (Channel2.lengthCounter === 0) {\n      Channel2.lengthCounter = Channel2.MAX_LENGTH;\n    }\n\n    // Reset our timer\n    // A square channel's frequency timer period is set to (2048-frequency)*4.\n    // Four duty cycles are available, each waveform taking 8 frequency timer clocks to cycle through:\n    Channel2.resetTimer();\n\n    // The volume envelope and sweep timers treat a period of 0 as 8.\n    // Meaning, if the period is zero, set it to the max (8).\n    if (Channel2.NRx2EnvelopePeriod === 0) {\n      Channel2.envelopeCounter = 8;\n    } else {\n      Channel2.envelopeCounter = Channel2.NRx2EnvelopePeriod;\n    }\n    Channel2.isEnvelopeAutomaticUpdating = true;\n\n    Channel2.volume = Channel2.NRx2StartingVolume;\n\n    // Finally if DAC is off, channel is still disabled\n    if (!Channel2.isDacEnabled) {\n      Channel2.isEnabled = false;\n    }\n  }\n\n  // Function to determine if the current channel would update when getting the sample\n  // This is used to accumulate samples\n  static willChannelUpdate(numberOfCycles: i32): boolean {\n    //Increment our cycle counter\n    let cycleCounter = Channel2.cycleCounter + numberOfCycles;\n    Channel2.cycleCounter = cycleCounter;\n\n    // Dac enabled status cached by accumulator\n    return !(Channel2.frequencyTimer - cycleCounter > 0);\n  }\n\n  static updateLength(): void {\n    let lengthCounter = Channel2.lengthCounter;\n    if (lengthCounter > 0 && Channel2.NRx4LengthEnabled) {\n      lengthCounter -= 1;\n    }\n\n    if (lengthCounter === 0) {\n      Channel2.isEnabled = false;\n    }\n    Channel2.lengthCounter = lengthCounter;\n  }\n\n  static updateEnvelope(): void {\n    let envelopeCounter = Channel2.envelopeCounter - 1;\n    if (envelopeCounter <= 0) {\n      // Reset back to the sweep period\n      // Obscure behavior\n      // Envelopes treat a period of 0 as 8 (They reset back to the max)\n      if (Channel2.NRx2EnvelopePeriod === 0) {\n        envelopeCounter = 8;\n      } else {\n        envelopeCounter = Channel2.NRx2EnvelopePeriod;\n\n        // When the timer generates a clock and the envelope period is NOT zero, a new volume is calculated\n        // NOTE: There is some weiirrdd obscure behavior where zero can equal 8, so watch out for that\n        if (envelopeCounter !== 0 && Channel2.isEnvelopeAutomaticUpdating) {\n          let volume = Channel2.volume;\n\n          // Increment the volume\n          if (Channel2.NRx2EnvelopeAddMode) {\n            volume += 1;\n          } else {\n            volume -= 1;\n          }\n\n          // Don't allow the volume to go above 4 bits.\n          volume = volume & 0x0f;\n\n          // Check if we are below the max\n          if (volume < 15) {\n            Channel2.volume = volume;\n          } else {\n            Channel2.isEnvelopeAutomaticUpdating = false;\n          }\n        }\n      }\n    }\n    Channel2.envelopeCounter = envelopeCounter;\n  }\n\n  static setFrequency(frequency: i32): void {\n    // Get the high and low bits\n    let passedFrequencyHighBits = frequency >> 8;\n    let passedFrequencyLowBits = frequency & 0xff;\n\n    // Get the new register 4\n    let register4 = eightBitLoadFromGBMemory(Channel2.memoryLocationNRx4);\n    // Knock off lower 3 bits, and Or on our high bits\n    let newRegister4 = register4 & 0xf8;\n    newRegister4 = newRegister4 | passedFrequencyHighBits;\n\n    // Set the registers\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx3, passedFrequencyLowBits);\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx4, newRegister4);\n\n    // Save the frequency for ourselves without triggering memory traps\n    Channel2.NRx3FrequencyLSB = passedFrequencyLowBits;\n    Channel2.NRx4FrequencyMSB = passedFrequencyHighBits;\n    Channel2.frequency = (passedFrequencyHighBits << 8) | passedFrequencyLowBits;\n  }\n  // Done!\n}\n","// NOTE: Tons of Copy-pasta btween channels, because Classes cannot be instantiated yet in assemblyscript\n\n// How to Search for similar things in binjgb\n// Wave channel trigger : APU_NR34_ADDR\n// Wave Channel getSample : update_wave\n\n// Wave Channel\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Wave_Channel\nimport { getSaveStateMemoryOffset } from '../core';\nimport { Sound } from './sound';\nimport { Cpu } from '../cpu/index';\nimport {\n  eightBitLoadFromGBMemory,\n  eightBitStoreIntoGBMemory,\n  loadBooleanDirectlyFromWasmMemory,\n  storeBooleanDirectlyToWasmMemory\n} from '../memory/index';\nimport { checkBitOnByte, log } from '../helpers/index';\nimport { i32Portable } from '../portable/portable';\n\nexport class Channel3 {\n  // Cycle Counter for our sound accumulator\n  static cycleCounter: i32 = 0;\n\n  // Max Length of our Length Load\n  static MAX_LENGTH: i32 = 256;\n\n  // Voluntary Wave channel with 32 4-bit programmable samples, played in sequence.\n  // NR30 -> Sound on/off (R/W)\n  static readonly memoryLocationNRx0: i32 = 0xff1a;\n  // E--- ---- DAC power\n  static updateNRx0(value: i32): void {\n    let isDacEnabled = checkBitOnByte(7, value);\n\n    // Sample buffer reset to zero when powered on\n    if (!Channel3.isDacEnabled && isDacEnabled) {\n      Channel3.sampleBuffer = 0x00;\n    }\n\n    Channel3.isDacEnabled = isDacEnabled;\n\n    // Blargg length test\n    // Disabling DAC should disable channel immediately\n    if (!isDacEnabled) {\n      Channel3.isEnabled = isDacEnabled;\n    }\n  }\n\n  // NR31 -> Sound length (R/W)\n  static readonly memoryLocationNRx1: i32 = 0xff1b;\n  // LLLL LLLL Length load (256-L)\n  static NRx1LengthLoad: i32 = 0;\n  static updateNRx1(value: i32): void {\n    Channel3.NRx1LengthLoad = value;\n\n    // Also need to set our length counter. Taken from the old, setChannelLengthCounter\n    // Channel length is determined by 64 (or 256 if channel 3), - the length load\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n    // Note, this will be different for channel 3\n    // Supposed to be 256, so subtracting 255 and then adding 1 if that makes sense\n    Channel3.lengthCounter = Channel3.MAX_LENGTH - Channel3.NRx1LengthLoad;\n  }\n\n  // NR32 -> Select ouput level (R/W)\n  static readonly memoryLocationNRx2: i32 = 0xff1c;\n  // -VV- ---- Volume code (00=0%, 01=100%, 10=50%, 11=25%)\n  static NRx2VolumeCode: i32 = 0;\n  static updateNRx2(value: i32): void {\n    Channel3.NRx2VolumeCode = (value >> 5) & 0x0f;\n  }\n\n  // NR33 -> Frequency lower data (W)\n  static readonly memoryLocationNRx3: i32 = 0xff1d;\n  // FFFF FFFF Frequency LSB\n  static NRx3FrequencyLSB: i32 = 0;\n  static updateNRx3(value: i32): void {\n    Channel3.NRx3FrequencyLSB = value;\n\n    // Update Channel Frequency\n    Channel3.frequency = (Channel3.NRx4FrequencyMSB << 8) | value;\n  }\n\n  // NR34 -> Frequency higher data (R/W)\n  static readonly memoryLocationNRx4: i32 = 0xff1e;\n  // TL-- -FFF Trigger, Length enable, Frequency MSB\n  static NRx4LengthEnabled: boolean = false;\n  static NRx4FrequencyMSB: i32 = 0;\n  static updateNRx4(value: i32): void {\n    // Handle our frequency\n    // Must be done first for our upcoming trigger\n    // To correctly reset timing\n    let frequencyMSB = value & 0x07;\n    Channel3.NRx4FrequencyMSB = frequencyMSB;\n    Channel3.frequency = (frequencyMSB << 8) | Channel3.NRx3FrequencyLSB;\n\n    // Obscure behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    // Also see blargg's cgb sound test\n    // Extra length clocking occurs when writing to NRx4,\n    // when the frame sequencer's next step is one that,\n    // doesn't clock the length counter.\n    let frameSequencer = Sound.frameSequencer;\n    let doesNextFrameSequencerUpdateLength = (frameSequencer & 1) === 1;\n    let isBeingLengthEnabled = false;\n    if (!doesNextFrameSequencerUpdateLength) {\n      // Check lengthEnable\n      isBeingLengthEnabled = !Channel3.NRx4LengthEnabled && checkBitOnByte(6, value);\n      if (Channel3.lengthCounter > 0 && isBeingLengthEnabled) {\n        Channel3.lengthCounter -= 1;\n\n        if (!checkBitOnByte(7, value) && Channel3.lengthCounter === 0) {\n          Channel3.isEnabled = false;\n        }\n      }\n    }\n\n    // Set the length enabled from the value\n    Channel3.NRx4LengthEnabled = checkBitOnByte(6, value);\n\n    // Trigger our channel, unfreeze length if frozen\n    // Triggers should happen after obscure behavior\n    // See test 11 for trigger\n    if (checkBitOnByte(7, value)) {\n      Channel3.trigger();\n\n      // When we trigger on the obscure behavior, and we reset the length Counter to max\n      // We need to clock\n      if (!doesNextFrameSequencerUpdateLength && Channel3.lengthCounter === Channel3.MAX_LENGTH && Channel3.NRx4LengthEnabled) {\n        Channel3.lengthCounter -= 1;\n      }\n    }\n  }\n\n  // Our wave table location\n  static readonly memoryLocationWaveTable: i32 = 0xff30;\n\n  // Channel Properties\n  static readonly channelNumber: i32 = 3;\n  static isEnabled: boolean = false;\n  static isDacEnabled: boolean = false;\n  static frequency: i32 = 0;\n  static frequencyTimer: i32 = 0x00;\n  static lengthCounter: i32 = 0x00;\n  static waveTablePosition: i32 = 0x00;\n  static volumeCode: i32 = 0x00;\n  static volumeCodeChanged: boolean = false;\n  static sampleBuffer: i32 = 0x00;\n\n  // Save States\n\n  static readonly saveStateSlot: i32 = 9;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x00, Channel3.saveStateSlot), Channel3.isEnabled);\n    store<i32>(getSaveStateMemoryOffset(0x01, Channel3.saveStateSlot), Channel3.frequencyTimer);\n    store<i32>(getSaveStateMemoryOffset(0x05, Channel3.saveStateSlot), Channel3.lengthCounter);\n    store<u16>(getSaveStateMemoryOffset(0x09, Channel3.saveStateSlot), Channel3.waveTablePosition);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    Channel3.isEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x00, Channel3.saveStateSlot));\n    Channel3.frequencyTimer = load<i32>(getSaveStateMemoryOffset(0x01, Channel3.saveStateSlot));\n    Channel3.lengthCounter = load<i32>(getSaveStateMemoryOffset(0x05, Channel3.saveStateSlot));\n    Channel3.waveTablePosition = load<u16>(getSaveStateMemoryOffset(0x09, Channel3.saveStateSlot));\n  }\n\n  // Memory Read Trap\n  static handleWaveRamRead(): i32 {\n    // Obscure behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware\n    // If the wave channel is enabled, accessing any byte from $FF30-$FF3F is equivalent to,\n    // accessing the current byte selected by the waveform position. Further, on the DMG accesses will only work in this manner,\n    // if made within a couple of clocks of the wave channel accessing wave RAM;\n    // if made at any other time, reads return $FF and writes have no effect.\n\n    // TODO: Handle DMG case\n\n    return readCurrentSampleByteFromWaveRam();\n  }\n\n  // Memory Write Trap\n  static handleWaveRamWrite(value: i32): void {\n    // Obscure behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware\n    // If the wave channel is enabled, accessing any byte from $FF30-$FF3F is equivalent to,\n    // accessing the current byte selected by the waveform position. Further, on the DMG accesses will only work in this manner,\n    // if made within a couple of clocks of the wave channel accessing wave RAM;\n    // if made at any other time, reads return $FF and writes have no effect.\n\n    // Thus we want to write the value to the current sample position\n    // Will Find the position, and knock off any remainder\n    let positionIndexToAdd = i32Portable(Channel3.waveTablePosition >> 1);\n    let memoryLocationWaveSample = Channel3.memoryLocationWaveTable + positionIndexToAdd;\n\n    eightBitStoreIntoGBMemory(memoryLocationWaveSample, value);\n  }\n\n  static initialize(): void {\n    eightBitStoreIntoGBMemory(Channel3.memoryLocationNRx0, 0x7f);\n    eightBitStoreIntoGBMemory(Channel3.memoryLocationNRx1, 0xff);\n    eightBitStoreIntoGBMemory(Channel3.memoryLocationNRx2, 0x9f);\n    eightBitStoreIntoGBMemory(Channel3.memoryLocationNRx3, 0x00);\n    eightBitStoreIntoGBMemory(Channel3.memoryLocationNRx4, 0xb8);\n\n    // The volume code changed\n    Channel3.volumeCodeChanged = true;\n  }\n\n  // Function to get a sample using the cycle counter on the channel\n  static getSampleFromCycleCounter(): i32 {\n    let accumulatedCycles = Channel3.cycleCounter;\n    Channel3.cycleCounter = 0;\n    return Channel3.getSample(accumulatedCycles);\n  }\n\n  // Function to reset our timer, useful for GBC double speed mode\n  static resetTimer(): void {\n    let frequencyTimer = (2048 - Channel3.frequency) << 1;\n\n    // TODO: Ensure this is correct for GBC Double Speed Mode\n    Channel3.frequencyTimer = frequencyTimer << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  static getSample(numberOfCycles: i32): i32 {\n    // Check if we are enabled\n    if (!Channel3.isEnabled || !Channel3.isDacEnabled) {\n      // Return silence\n      // Since range from -15 - 15, or 0 to 30 for our unsigned\n      return 15;\n    }\n\n    // Get our volume code\n    // Need this to compute the sample\n    let volumeCode = Channel3.volumeCode;\n    if (Channel3.volumeCodeChanged) {\n      volumeCode = eightBitLoadFromGBMemory(Channel3.memoryLocationNRx2);\n      volumeCode = volumeCode >> 5;\n      volumeCode = volumeCode & 0x0f;\n      Channel3.volumeCode = volumeCode;\n      Channel3.volumeCodeChanged = false;\n    }\n\n    // Get the current sample\n    let sample = getSampleFromSampleBufferForWaveTablePosition();\n\n    // Shift our sample and set our volume depending on the volume code\n    // Since we can't multiply by float, simply divide by 4, 2, 1\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Wave_Channel\n    let outputVolume = 0;\n    switch (volumeCode) {\n      case 0:\n        sample >>= 4;\n        break;\n      case 1:\n        // Dont Shift sample\n        outputVolume = 1;\n        break;\n      case 2:\n        sample >>= 1;\n        outputVolume = 2;\n        break;\n      default:\n        sample >>= 2;\n        outputVolume = 4;\n        break;\n    }\n\n    // Apply out output volume\n    sample = outputVolume > 0 ? sample / outputVolume : 0;\n    // Square Waves Can range from -15 - 15. Therefore simply add 15\n    sample += 15;\n\n    // Update the sample based on our timer\n    let frequencyTimer = Channel3.frequencyTimer;\n    frequencyTimer -= numberOfCycles;\n    while (frequencyTimer <= 0) {\n      // Get the amount that overflowed so we don't drop cycles\n      let overflowAmount = abs(frequencyTimer);\n\n      // Reset our timer\n      // A wave channel's frequency timer period is set to (2048-frequency) * 2.\n      // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Wave_Channel\n      Channel3.resetTimer();\n      frequencyTimer = Channel3.frequencyTimer;\n      frequencyTimer -= overflowAmount;\n\n      // Update our sample buffer\n      advanceWavePositionAndSampleBuffer();\n    }\n\n    Channel3.frequencyTimer = frequencyTimer;\n\n    // Finally return the sample\n    return sample;\n  }\n\n  //http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Trigger_Event\n  static trigger(): void {\n    Channel3.isEnabled = true;\n    // Length counter maximum handled by write\n    if (Channel3.lengthCounter === 0) {\n      Channel3.lengthCounter = Channel3.MAX_LENGTH;\n    }\n\n    // Reset our timer\n    // A wave channel's frequency timer period is set to (2048-frequency)*2.\n    Channel3.resetTimer();\n\n    // Add some delay to our frequency timer\n    // So Honestly, lifted this from binjgb\n    // https://github.com/binji/binjgb/blob/68eb4b2f6d5d7a98d270e12c4b8ff065c07f5e94/src/emulator.c#L2625\n    // I have no clue why this is, but it passes 09-wave read while on.s\n    // blargg test.\n    // I think this has to do with obscure behavior?\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware\n    // When triggering the wave channel,\n    // the first sample to play is the previous one still in the high nibble of the sample buffer,\n    // and the next sample is the second nibble from the wave table.\n    // This is because it doesn't load the first byte on trigger like it \"should\".\n    // The first nibble from the wave table is thus not played until the waveform loops.\n    Channel3.frequencyTimer += 6;\n\n    // Reset our wave table position\n    Channel3.waveTablePosition = 0;\n\n    // Finally if DAC is off, channel is still disabled\n    if (!Channel3.isDacEnabled) {\n      Channel3.isEnabled = false;\n    }\n  }\n\n  // Function to determine if the current channel would update when getting the sample\n  // This is used to accumulate samples\n  static willChannelUpdate(numberOfCycles: i32): boolean {\n    //Increment our cycle counter\n    Channel3.cycleCounter += numberOfCycles;\n\n    // Dac enabled status cached by accumulator\n    return !(!Channel3.volumeCodeChanged && Channel3.frequencyTimer - Channel3.cycleCounter > 0);\n  }\n\n  static updateLength(): void {\n    let lengthCounter = Channel3.lengthCounter;\n    if (lengthCounter > 0 && Channel3.NRx4LengthEnabled) {\n      lengthCounter -= 1;\n    }\n\n    if (lengthCounter === 0) {\n      Channel3.isEnabled = false;\n    }\n    Channel3.lengthCounter = lengthCounter;\n  }\n}\n\n// Functions specific to wave memory\nfunction advanceWavePositionAndSampleBuffer(): void {\n  // Advance the wave table position, and loop back if needed\n  let waveTablePosition = Channel3.waveTablePosition;\n  waveTablePosition += 1;\n  while (waveTablePosition >= 32) {\n    waveTablePosition -= 32;\n  }\n  Channel3.waveTablePosition = waveTablePosition;\n\n  // Load the next sample byte from wave ram,\n  // into the sample buffer\n  Channel3.sampleBuffer = readCurrentSampleByteFromWaveRam();\n}\n\nfunction readCurrentSampleByteFromWaveRam(): i32 {\n  // Will Find the position, and knock off any remainder\n  let positionIndexToAdd = i32Portable(Channel3.waveTablePosition >> 1);\n  let memoryLocationWaveSample = Channel3.memoryLocationWaveTable + positionIndexToAdd;\n\n  return eightBitLoadFromGBMemory(memoryLocationWaveSample);\n}\n\nfunction getSampleFromSampleBufferForWaveTablePosition(): i32 {\n  let sample = Channel3.sampleBuffer;\n\n  // Need to grab the top or lower half for the correct sample\n  sample >>= (<i32>((Channel3.waveTablePosition & 1) === 0)) << 2;\n  sample &= 0x0f;\n\n  return sample;\n}\n","// NOTE: Tons of Copy-pasta btween channels, because Classes cannot be instantiated yet in assemblyscript\n\n// Noise Channel\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Noise_Channel\nimport { getSaveStateMemoryOffset } from '../core';\nimport { Sound } from './sound';\nimport { Cpu } from '../cpu/index';\nimport { eightBitStoreIntoGBMemory, loadBooleanDirectlyFromWasmMemory, storeBooleanDirectlyToWasmMemory } from '../memory/index';\nimport { checkBitOnByte } from '../helpers/index';\n\nexport class Channel4 {\n  // Cycle Counter for our sound accumulator\n  static cycleCounter: i32 = 0;\n\n  // Max Length of our Length Load\n  static MAX_LENGTH: i32 = 64;\n\n  // Channel 4\n  // 'white noise' channel with volume envelope functions.\n\n  // Only used by register reading\n  static readonly memoryLocationNRx0: i32 = 0xff1f;\n\n  // NR41 -> Sound length (R/W)\n  static readonly memoryLocationNRx1: i32 = 0xff20;\n  // --LL LLLL Length load (64-L)\n  static NRx1LengthLoad: i32 = 0;\n  static updateNRx1(value: i32): void {\n    Channel4.NRx1LengthLoad = value & 0x3f;\n\n    // Also need to set our length counter. Taken from the old, setChannelLengthCounter\n    // Channel length is determined by 64 (or 256 if channel 3), - the length load\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n    // Note, this will be different for channel 3\n    Channel4.lengthCounter = Channel4.MAX_LENGTH - Channel4.NRx1LengthLoad;\n  }\n\n  // NR42 -> Volume Envelope (R/W)\n  static readonly memoryLocationNRx2: i32 = 0xff21;\n  // VVVV APPP Starting volume, Envelope add mode, period\n  static NRx2StartingVolume: i32 = 0;\n  static NRx2EnvelopeAddMode: boolean = false;\n  static NRx2EnvelopePeriod: i32 = 0;\n  static updateNRx2(value: i32): void {\n    // Handle \"Zombie Mode\" Obscure behavior\n    // https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    if (Channel4.isEnabled) {\n      // If the old envelope period was zero and the envelope is still doing automatic updates,\n      // volume is incremented by 1, otherwise if the envelope was in subtract mode,\n      // volume is incremented by 2.\n      // NOTE: However, from my testing, it ALWAYS increments by one. This was determined\n      // by my testing for prehistoric man\n      if (Channel4.NRx2EnvelopePeriod === 0 && Channel4.isEnvelopeAutomaticUpdating) {\n        // Volume can't be more than 4 bits\n        Channel4.volume = (Channel4.volume + 1) & 0x0f;\n      }\n\n      // If the mode was changed (add to subtract or subtract to add),\n      // volume is set to 16-volume. But volume cant be more than 4 bits\n      if (Channel4.NRx2EnvelopeAddMode !== checkBitOnByte(3, value)) {\n        Channel4.volume = (16 - Channel4.volume) & 0x0f;\n      }\n    }\n\n    Channel4.NRx2StartingVolume = (value >> 4) & 0x0f;\n    Channel4.NRx2EnvelopeAddMode = checkBitOnByte(3, value);\n    Channel4.NRx2EnvelopePeriod = value & 0x07;\n\n    // Also, get our channel is dac enabled\n    let isDacEnabled = (value & 0xf8) > 0;\n    Channel4.isDacEnabled = isDacEnabled;\n\n    // Blargg length test\n    // Disabling DAC should disable channel immediately\n    if (!isDacEnabled) {\n      Channel4.isEnabled = isDacEnabled;\n    }\n  }\n\n  // NR43 -> Polynomial Counter (R/W)\n  static readonly memoryLocationNRx3: i32 = 0xff22;\n  // SSSS WDDD Clock shift, Width mode of LFSR, Divisor code\n  static NRx3ClockShift: i32 = 0;\n  static NRx3WidthMode: boolean = false;\n  static NRx3DivisorCode: i32 = 0;\n  static updateNRx3(value: i32): void {\n    let divisorCode = value & 0x07;\n    Channel4.NRx3ClockShift = value >> 4;\n    Channel4.NRx3WidthMode = checkBitOnByte(3, value);\n    Channel4.NRx3DivisorCode = divisorCode;\n    // Also, get our divisor\n    divisorCode <<= 1;\n    if (divisorCode < 1) divisorCode = 1;\n    Channel4.divisor = divisorCode << 3;\n  }\n\n  // NR44 -> Trigger, Length Enable\n  static readonly memoryLocationNRx4: i32 = 0xff23;\n  // TL-- ---- Trigger, Length enable\n  static NRx4LengthEnabled: boolean = false;\n  static updateNRx4(value: i32): void {\n    // Obscure behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    // Also see blargg's cgb sound test\n    // Extra length clocking occurs when writing to NRx4,\n    // when the frame sequencer's next step is one that,\n    // doesn't clock the length counter.\n    let frameSequencer = Sound.frameSequencer;\n    let doesNextFrameSequencerUpdateLength = (frameSequencer & 1) === 1;\n    let isBeingLengthEnabled = !Channel4.NRx4LengthEnabled && checkBitOnByte(6, value);\n    if (!doesNextFrameSequencerUpdateLength) {\n      if (Channel4.lengthCounter > 0 && isBeingLengthEnabled) {\n        Channel4.lengthCounter -= 1;\n\n        if (!checkBitOnByte(7, value) && Channel4.lengthCounter === 0) {\n          Channel4.isEnabled = false;\n        }\n      }\n    }\n\n    // Set the length enabled from the value\n    Channel4.NRx4LengthEnabled = checkBitOnByte(6, value);\n\n    // Trigger out channel, unfreeze length if frozen\n    // Triggers should happen after obscure behavior\n    // See test 11 for trigger\n    if (checkBitOnByte(7, value)) {\n      Channel4.trigger();\n\n      // When we trigger on the obscure behavior, and we reset the length Counter to max\n      // We need to clock\n      if (!doesNextFrameSequencerUpdateLength && Channel4.lengthCounter === Channel4.MAX_LENGTH && Channel4.NRx4LengthEnabled) {\n        Channel4.lengthCounter -= 1;\n      }\n    }\n  }\n\n  // Channel Properties\n  static readonly channelNumber: i32 = 4;\n  static isEnabled: boolean = false;\n  static isDacEnabled: boolean = false;\n  static frequencyTimer: i32 = 0x00;\n  static envelopeCounter: i32 = 0x00;\n  static isEnvelopeAutomaticUpdating: boolean = false;\n  static lengthCounter: i32 = 0x00;\n  static volume: i32 = 0x00;\n  static divisor: i32 = 0;\n\n  // Noise properties\n  // NOTE: Is only 15 bits\n  static linearFeedbackShiftRegister: i32 = 0x00;\n\n  // Save States\n\n  static readonly saveStateSlot: i32 = 10;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x00, Channel4.saveStateSlot), Channel4.isEnabled);\n    store<i32>(getSaveStateMemoryOffset(0x01, Channel4.saveStateSlot), Channel4.frequencyTimer);\n    store<i32>(getSaveStateMemoryOffset(0x05, Channel4.saveStateSlot), Channel4.envelopeCounter);\n    store<i32>(getSaveStateMemoryOffset(0x09, Channel4.saveStateSlot), Channel4.lengthCounter);\n    store<i32>(getSaveStateMemoryOffset(0x0e, Channel4.saveStateSlot), Channel4.volume);\n    store<u16>(getSaveStateMemoryOffset(0x13, Channel4.saveStateSlot), Channel4.linearFeedbackShiftRegister);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x15, Channel4.saveStateSlot), Channel4.isEnvelopeAutomaticUpdating);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    Channel4.isEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x00, Channel4.saveStateSlot));\n    Channel4.frequencyTimer = load<i32>(getSaveStateMemoryOffset(0x01, Channel4.saveStateSlot));\n    Channel4.envelopeCounter = load<i32>(getSaveStateMemoryOffset(0x05, Channel4.saveStateSlot));\n    Channel4.lengthCounter = load<i32>(getSaveStateMemoryOffset(0x09, Channel4.saveStateSlot));\n    Channel4.volume = load<i32>(getSaveStateMemoryOffset(0x0e, Channel4.saveStateSlot));\n    Channel4.linearFeedbackShiftRegister = load<u16>(getSaveStateMemoryOffset(0x13, Channel4.saveStateSlot));\n    Channel4.isEnvelopeAutomaticUpdating = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x15, Channel4.saveStateSlot));\n  }\n\n  static initialize(): void {\n    eightBitStoreIntoGBMemory(Channel4.memoryLocationNRx1 - 1, 0xff);\n    eightBitStoreIntoGBMemory(Channel4.memoryLocationNRx1, 0xff);\n    eightBitStoreIntoGBMemory(Channel4.memoryLocationNRx2, 0x00);\n    eightBitStoreIntoGBMemory(Channel4.memoryLocationNRx3, 0x00);\n    eightBitStoreIntoGBMemory(Channel4.memoryLocationNRx4, 0xbf);\n  }\n\n  // Function to get a sample using the cycle counter on the channel\n  static getSampleFromCycleCounter(): i32 {\n    let accumulatedCycles = Channel4.cycleCounter;\n    Channel4.cycleCounter = 0;\n    return Channel4.getSample(accumulatedCycles);\n  }\n\n  static getSample(numberOfCycles: i32): i32 {\n    // Decrement our channel timer\n    let frequencyTimer = Channel4.frequencyTimer;\n    frequencyTimer -= numberOfCycles;\n\n    // TODO: This can't be a while loop to use up all the cycles,\n    // Since noise is psuedo random and the period can be anything\n    if (frequencyTimer <= 0) {\n      // Get the amount that overflowed so we don't drop cycles\n      let overflowAmount = abs(frequencyTimer);\n\n      // Reset our timer\n      frequencyTimer = Channel4.getNoiseChannelFrequencyPeriod();\n      frequencyTimer -= overflowAmount;\n\n      // Do some cool stuff with lfsr\n      // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Noise_Channel\n\n      // First XOR bit zero and one\n      let linearFeedbackShiftRegister = Channel4.linearFeedbackShiftRegister;\n      let lfsrBitZero = linearFeedbackShiftRegister & 0x01;\n      let lfsrBitOne = linearFeedbackShiftRegister >> 1;\n      lfsrBitOne = lfsrBitOne & 0x01;\n      let xorLfsrBitZeroOne = lfsrBitZero ^ lfsrBitOne;\n\n      // Shift all lsfr bits by one\n      linearFeedbackShiftRegister = linearFeedbackShiftRegister >> 1;\n\n      // Place the XOR result on bit 15\n      linearFeedbackShiftRegister = linearFeedbackShiftRegister | (xorLfsrBitZeroOne << 14);\n\n      // If the width mode is set, set xor on bit 6, and make lfsr 7 bit\n      if (Channel4.NRx3WidthMode) {\n        // Make 7 bit, by knocking off lower bits. Want to keeps bits 8 - 16, and then or on 7\n        linearFeedbackShiftRegister = linearFeedbackShiftRegister & ~0x40;\n        linearFeedbackShiftRegister = linearFeedbackShiftRegister | (xorLfsrBitZeroOne << 6);\n      }\n      Channel4.linearFeedbackShiftRegister = linearFeedbackShiftRegister;\n    }\n\n    // Make sure period never becomes negative\n    if (frequencyTimer < 0) {\n      frequencyTimer = 0;\n    }\n\n    Channel4.frequencyTimer = frequencyTimer;\n\n    // Get our ourput volume, set to zero for silence\n    let outputVolume = 0;\n\n    // Finally to set our output volume, the channel must be enabled,\n    // Our channel DAC must be enabled, and we must be in an active state\n    // Of our duty cycle\n    if (Channel4.isEnabled && Channel4.isDacEnabled) {\n      // Volume can't be more than 4 bits.\n      // Volume should never be more than 4 bits, but doing a check here\n      outputVolume = Channel4.volume & 0x0f;\n    } else {\n      // Return silence\n      // Since range from -15 - 15, or 0 to 30 for our unsigned\n      return 15;\n    }\n\n    // Declare our sample\n    let sample = 0;\n\n    // Wave form output is bit zero of lfsr, INVERTED\n    sample = !checkBitOnByte(0, Channel4.linearFeedbackShiftRegister) ? 1 : -1;\n    sample = sample * outputVolume;\n\n    // Noise Can range from -15 - 15. Therefore simply add 15\n    sample = sample + 15;\n    return <i32>sample;\n  }\n\n  //http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Trigger_Event\n  static trigger(): void {\n    Channel4.isEnabled = true;\n    // Length counter maximum handled by write\n    if (Channel4.lengthCounter === 0) {\n      Channel4.lengthCounter = Channel4.MAX_LENGTH;\n    }\n\n    // Reset our timers\n    Channel4.frequencyTimer = Channel4.getNoiseChannelFrequencyPeriod();\n\n    // The volume envelope and sweep timers treat a period of 0 as 8.\n    // Meaning, if the period is zero, set it to the max (8).\n    if (Channel4.NRx2EnvelopePeriod === 0) {\n      Channel4.envelopeCounter = 8;\n    } else {\n      Channel4.envelopeCounter = Channel4.NRx2EnvelopePeriod;\n    }\n    Channel4.isEnvelopeAutomaticUpdating = true;\n\n    Channel4.volume = Channel4.NRx2StartingVolume;\n\n    // Noise channel's LFSR bits are all set to 1.\n    Channel4.linearFeedbackShiftRegister = 0x7fff;\n\n    // Finally if DAC is off, channel is still disabled\n    if (!Channel4.isDacEnabled) {\n      Channel4.isEnabled = false;\n    }\n  }\n\n  // Function to determine if the current channel would update when getting the sample\n  // This is used to accumulate samples\n  static willChannelUpdate(numberOfCycles: i32): boolean {\n    //Increment our cycle counter\n    Channel4.cycleCounter += numberOfCycles;\n\n    // Dac enabled status cached by accumulator\n    return !(Channel4.frequencyTimer - Channel4.cycleCounter > 0);\n  }\n\n  static getNoiseChannelFrequencyPeriod(): i32 {\n    // Get our divisor from the divisor code, and shift by the clock shift\n    let response = Channel4.divisor << Channel4.NRx3ClockShift;\n    return response << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  static updateLength(): void {\n    let lengthCounter = Channel4.lengthCounter;\n    if (lengthCounter > 0 && Channel4.NRx4LengthEnabled) {\n      lengthCounter -= 1;\n    }\n\n    if (lengthCounter === 0) {\n      Channel4.isEnabled = false;\n    }\n    Channel4.lengthCounter = lengthCounter;\n  }\n\n  static updateEnvelope(): void {\n    let envelopeCounter = Channel4.envelopeCounter - 1;\n    if (envelopeCounter <= 0) {\n      // Reset back to the sweep period\n      // Obscure behavior\n      // Envelopes treat a period of 0 as 8 (They reset back to the max)\n      if (Channel4.NRx2EnvelopePeriod === 0) {\n        envelopeCounter = 8;\n      } else {\n        envelopeCounter = Channel4.NRx2EnvelopePeriod;\n\n        // When the timer generates a clock and the envelope period is NOT zero, a new volume is calculated\n        // NOTE: There is some weiirrdd obscure behavior where zero can equal 8, so watch out for that\n        if (envelopeCounter !== 0 && Channel4.isEnvelopeAutomaticUpdating) {\n          let volume = Channel4.volume;\n\n          // Increment the volume\n          if (Channel4.NRx2EnvelopeAddMode) {\n            volume += 1;\n          } else {\n            volume -= 1;\n          }\n\n          // Don't allow the volume to go above 4 bits.\n          volume = volume & 0x0f;\n\n          // Check if we are below the max\n          if (volume < 15) {\n            Channel4.volume = volume;\n          } else {\n            Channel4.isEnvelopeAutomaticUpdating = false;\n          }\n        }\n      }\n    }\n    Channel4.envelopeCounter = envelopeCounter;\n  }\n  // Done!\n}\n","import { Sound, mixChannelSamples, setLeftAndRightOutputForAudioQueue } from './sound';\nimport { Channel1 } from './channel1';\nimport { Channel2 } from './channel2';\nimport { Channel3 } from './channel3';\nimport { Channel4 } from './channel4';\nimport { i32Portable } from '../portable/portable';\nimport { AUDIO_BUFFER_LOCATION } from '../constants';\n\n// Another class simply for accumulating samples\n// Default everything to silence\nexport class SoundAccumulator {\n  static channel1Sample: i32 = 15;\n  static channel2Sample: i32 = 15;\n  static channel3Sample: i32 = 15;\n  static channel4Sample: i32 = 15;\n  static channel1DacEnabled: boolean = false;\n  static channel2DacEnabled: boolean = false;\n  static channel3DacEnabled: boolean = false;\n  static channel4DacEnabled: boolean = false;\n  static leftChannelSampleUnsignedByte: i32 = 127;\n  static rightChannelSampleUnsignedByte: i32 = 127;\n  static mixerVolumeChanged: boolean = false;\n  static mixerEnabledChanged: boolean = false;\n\n  //If a channel was updated, need to also track if we need to need to mix them again\n  static needToRemixSamples: boolean = false;\n}\n\n// Inlined because closure compiler inlines\nexport function initializeSoundAccumulator(): void {\n  SoundAccumulator.channel1Sample = 15;\n  SoundAccumulator.channel2Sample = 15;\n  SoundAccumulator.channel3Sample = 15;\n  SoundAccumulator.channel4Sample = 15;\n  SoundAccumulator.channel1DacEnabled = false;\n  SoundAccumulator.channel2DacEnabled = false;\n  SoundAccumulator.channel3DacEnabled = false;\n  SoundAccumulator.channel4DacEnabled = false;\n  SoundAccumulator.leftChannelSampleUnsignedByte = 127;\n  SoundAccumulator.rightChannelSampleUnsignedByte = 127;\n  SoundAccumulator.mixerVolumeChanged = true;\n  SoundAccumulator.mixerEnabledChanged = true;\n  SoundAccumulator.needToRemixSamples = false;\n}\n\n// Inlined because closure compiler inlines\nexport function accumulateSound(numberOfCycles: i32): void {\n  // Check if any of the individual channels will update\n  let channel1WillUpdate = Channel1.willChannelUpdate(numberOfCycles) || didChannelDacChange(Channel1.channelNumber);\n  let channel2WillUpdate = Channel2.willChannelUpdate(numberOfCycles) || didChannelDacChange(Channel2.channelNumber);\n  let channel3WillUpdate = Channel3.willChannelUpdate(numberOfCycles) || didChannelDacChange(Channel3.channelNumber);\n  let channel4WillUpdate = Channel4.willChannelUpdate(numberOfCycles) || didChannelDacChange(Channel4.channelNumber);\n\n  if (channel1WillUpdate) {\n    SoundAccumulator.channel1Sample = Channel1.getSampleFromCycleCounter();\n  }\n  if (channel2WillUpdate) {\n    SoundAccumulator.channel2Sample = Channel2.getSampleFromCycleCounter();\n  }\n  if (channel3WillUpdate) {\n    SoundAccumulator.channel3Sample = Channel3.getSampleFromCycleCounter();\n  }\n  if (channel4WillUpdate) {\n    SoundAccumulator.channel4Sample = Channel4.getSampleFromCycleCounter();\n  }\n\n  // If any channel updated, we need to re-mix our samples\n  if (channel1WillUpdate || channel2WillUpdate || channel3WillUpdate || channel4WillUpdate) {\n    SoundAccumulator.needToRemixSamples = true;\n  }\n\n  // Do Some downsampling magic\n  let downSampleCycleCounter = Sound.downSampleCycleCounter;\n  downSampleCycleCounter += numberOfCycles;\n  let maxDownSampleCycles = Sound.maxDownSampleCycles();\n  if (downSampleCycleCounter >= maxDownSampleCycles) {\n    // Reset the downsample counter\n    // Don't set to zero to catch overflowed cycles\n    downSampleCycleCounter -= maxDownSampleCycles;\n\n    if (SoundAccumulator.needToRemixSamples || SoundAccumulator.mixerVolumeChanged || SoundAccumulator.mixerEnabledChanged) {\n      mixChannelSamples(\n        SoundAccumulator.channel1Sample,\n        SoundAccumulator.channel2Sample,\n        SoundAccumulator.channel3Sample,\n        SoundAccumulator.channel4Sample\n      );\n    } else {\n      Sound.downSampleCycleCounter = downSampleCycleCounter;\n    }\n\n    // Finally Simply place the accumulated sample in memory\n    // Set our volumes in memory\n    // +1 so it can not be zero\n    setLeftAndRightOutputForAudioQueue(\n      SoundAccumulator.leftChannelSampleUnsignedByte + 1,\n      SoundAccumulator.rightChannelSampleUnsignedByte + 1,\n      AUDIO_BUFFER_LOCATION\n    );\n    let audioQueueIndex = Sound.audioQueueIndex + 1;\n    // Don't allow our audioQueueIndex to overflow into other parts of the wasmBoy memory map\n    // https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit#gid=0\n    // Not 0xFFFF because we need half of 64kb since we store left and right channel\n    let maxIndex = i32Portable(Sound.wasmBoyMemoryMaxBufferSize >> 1) - 1;\n    if (audioQueueIndex >= maxIndex) {\n      audioQueueIndex -= 1;\n    }\n    Sound.audioQueueIndex = audioQueueIndex;\n  }\n\n  Sound.downSampleCycleCounter = downSampleCycleCounter;\n}\n\n// Function used by SoundAccumulator to find out if a channel Dac Changed\nfunction didChannelDacChange(channelNumber: i32): boolean {\n  switch (channelNumber) {\n    case Channel1.channelNumber: {\n      let isDacEnabled = Channel1.isDacEnabled;\n      let channel1EnabledChanged = SoundAccumulator.channel1DacEnabled !== isDacEnabled;\n      SoundAccumulator.channel1DacEnabled = isDacEnabled;\n      return channel1EnabledChanged;\n    }\n    case Channel2.channelNumber: {\n      let isDacEnabled = Channel2.isDacEnabled;\n      let channel2EnabledChanged = SoundAccumulator.channel2DacEnabled !== isDacEnabled;\n      SoundAccumulator.channel2DacEnabled = isDacEnabled;\n      return channel2EnabledChanged;\n    }\n    case Channel3.channelNumber: {\n      let isDacEnabled = Channel3.isDacEnabled;\n      let channel3EnabledChanged = SoundAccumulator.channel3DacEnabled !== isDacEnabled;\n      SoundAccumulator.channel3DacEnabled = isDacEnabled;\n      return channel3EnabledChanged;\n    }\n    case Channel4.channelNumber: {\n      let isDacEnabled = Channel4.isDacEnabled;\n      let channel4EnabledChanged = SoundAccumulator.channel4DacEnabled !== isDacEnabled;\n      SoundAccumulator.channel4DacEnabled = isDacEnabled;\n      return channel4EnabledChanged;\n    }\n  }\n  return false;\n}\n","// https://emu-docs.org/Game%20Boy/gb_sound.txt\n// https://www.youtube.com/watch?v=HyzD8pNlpwI\n// https://gist.github.com/drhelius/3652407\n\n// For our wasm -> JS, we will be passing in our -1.0 to 1.0 volume\n// As an unsigned byte. Each channel will give 0 (representing -1.0), to\n// 30 (representing 1.0), and will be added together. in the fucntion\n// getSampleAsUnsignedByte() will do the conversion of getting the total\n// of all the channels, times the (mixer volume + 1), to give us an unsigned\n// byte from 0 (-1.0) to 254 (1.0)\nimport {\n  AUDIO_BUFFER_LOCATION,\n  CHANNEL_1_BUFFER_LOCATION,\n  CHANNEL_2_BUFFER_LOCATION,\n  CHANNEL_3_BUFFER_LOCATION,\n  CHANNEL_4_BUFFER_LOCATION\n} from '../constants';\nimport { getSaveStateMemoryOffset } from '../core';\nimport { SoundAccumulator, initializeSoundAccumulator, accumulateSound } from './accumulator';\nimport { Channel1 } from './channel1';\nimport { Channel2 } from './channel2';\nimport { Channel3 } from './channel3';\nimport { Channel4 } from './channel4';\nimport { Cpu } from '../cpu/index';\nimport { Config } from '../config';\nimport { eightBitStoreIntoGBMemory } from '../memory/index';\nimport { checkBitOnByte, concatenateBytes, splitLowByte, splitHighByte, log } from '../helpers/index';\nimport { i32Portable } from '../portable/portable';\n\nexport class Sound {\n  // Current cycles\n  // This will be used for batch processing\n  // https://github.com/binji/binjgb/commit/e028f45e805bc0b0aa4697224a209f9ae514c954\n  // TODO: May Also need to do this for Reads\n  static currentCycles: i32 = 0;\n\n  // Number of cycles to run in each batch process\n  // This number should be in sync so that sound doesn't run too many cyles at once\n  // and does not exceed the minimum number of cyles for either down sampling, or\n  // How often we change the frame, or a channel's update process\n  // Number of cycles is 87, because:\n  // Number of cycles before downsampling a single sample\n  // TODO: Find out how to make this number bigger\n  // Or, don't call this in syncCycles, and make the lib responsible.\n  static batchProcessCycles(): i32 {\n    // return Cpu.GBCDoubleSpeed ? 174 : 87;\n    return 87 << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  // Channel control / On-OFF / Volume (RW)\n  static readonly memoryLocationNR50: i32 = 0xff24;\n  static NR50LeftMixerVolume: i32 = 0;\n  static NR50RightMixerVolume: i32 = 0;\n  static updateNR50(value: i32): void {\n    Sound.NR50LeftMixerVolume = (value >> 4) & 0x07;\n    Sound.NR50RightMixerVolume = value & 0x07;\n  }\n\n  // 0xFF25 selects which output each channel goes to, Referred to as NR51\n  static readonly memoryLocationNR51: i32 = 0xff25;\n  static NR51IsChannel1EnabledOnLeftOutput: boolean = true;\n  static NR51IsChannel2EnabledOnLeftOutput: boolean = true;\n  static NR51IsChannel3EnabledOnLeftOutput: boolean = true;\n  static NR51IsChannel4EnabledOnLeftOutput: boolean = true;\n  static NR51IsChannel1EnabledOnRightOutput: boolean = true;\n  static NR51IsChannel2EnabledOnRightOutput: boolean = true;\n  static NR51IsChannel3EnabledOnRightOutput: boolean = true;\n  static NR51IsChannel4EnabledOnRightOutput: boolean = true;\n  static updateNR51(value: i32): void {\n    Sound.NR51IsChannel4EnabledOnLeftOutput = checkBitOnByte(7, value);\n    Sound.NR51IsChannel3EnabledOnLeftOutput = checkBitOnByte(6, value);\n    Sound.NR51IsChannel2EnabledOnLeftOutput = checkBitOnByte(5, value);\n    Sound.NR51IsChannel1EnabledOnLeftOutput = checkBitOnByte(4, value);\n    Sound.NR51IsChannel4EnabledOnRightOutput = checkBitOnByte(3, value);\n    Sound.NR51IsChannel3EnabledOnRightOutput = checkBitOnByte(2, value);\n    Sound.NR51IsChannel2EnabledOnRightOutput = checkBitOnByte(1, value);\n    Sound.NR51IsChannel1EnabledOnRightOutput = checkBitOnByte(0, value);\n  }\n\n  // Sound on/off\n  static readonly memoryLocationNR52: i32 = 0xff26;\n  static NR52IsSoundEnabled: boolean = true;\n  static updateNR52(value: i32): void {\n    Sound.NR52IsSoundEnabled = checkBitOnByte(7, value);\n  }\n\n  // $FF30 -- $FF3F is the load register space for the 4-bit samples for channel 3\n  static readonly memoryLocationChannel3LoadRegisterStart: i32 = 0xff30;\n\n  // Need to count how often we need to increment our frame sequencer\n  // Which you can read about below\n  static frameSequenceCycleCounter: i32 = 0x0000;\n  static maxFrameSequenceCycles(): i32 {\n    // return Cpu.GBCDoubleSpeed ? 16384 : 8192;\n    return 8192 << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  // Also need to downsample our audio to average audio qualty\n  // https://www.reddit.com/r/EmuDev/comments/5gkwi5/gb_apu_sound_emulation/\n  // Want to do 44100hz, so CpuRate / Sound Rate, 4194304 / 44100 ~ 91 cycles\n  static downSampleCycleCounter: i32 = 0x00;\n  static sampleRate: i32 = 44100;\n  static maxDownSampleCycles(): i32 {\n    return Cpu.CLOCK_SPEED() / Sound.sampleRate;\n  }\n\n  // Frame sequencer controls what should be updated and and ticked\n  // Every time the sound is updated :) It is updated everytime the\n  // Cycle counter reaches the max cycle\n  static frameSequencer: i32 = 0x00;\n\n  // Our current sample number we are passing back to the wasmboy memory map\n  // Found that a static number of samples doesn't work well on mobile\n  // Will just update the queue index, grab as much as we can whenever we need more audio, then reset\n  // NOTE: Giving a really large sample rate gives more latency, but less pops!\n  //static readonly MAX_NUMBER_OF_SAMPLES: i32 = 4096;\n  static audioQueueIndex: i32 = 0x0000;\n  static wasmBoyMemoryMaxBufferSize: i32 = 0x20000;\n\n  // Save States\n  static readonly saveStateSlot: i32 = 6;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    store<i32>(getSaveStateMemoryOffset(0x00, Sound.saveStateSlot), Sound.frameSequenceCycleCounter);\n    store<u8>(getSaveStateMemoryOffset(0x04, Sound.saveStateSlot), Sound.downSampleCycleCounter);\n    store<u8>(getSaveStateMemoryOffset(0x05, Sound.saveStateSlot), Sound.frameSequencer);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    Sound.frameSequenceCycleCounter = load<i32>(getSaveStateMemoryOffset(0x00, Sound.saveStateSlot));\n    Sound.downSampleCycleCounter = load<u8>(getSaveStateMemoryOffset(0x04, Sound.saveStateSlot));\n    Sound.frameSequencer = load<u8>(getSaveStateMemoryOffset(0x05, Sound.saveStateSlot));\n\n    clearAudioBuffer();\n  }\n}\n\n// Initialize sound registers\n// From: https://emu-docs.org/Game%20Boy/gb_sound.txt\n// Inlined because closure compiler inlines\nexport function initializeSound(): void {\n  // Reset Stateful variables\n  Sound.currentCycles = 0;\n  Sound.NR50LeftMixerVolume = 0;\n  Sound.NR50RightMixerVolume = 0;\n  Sound.NR51IsChannel1EnabledOnLeftOutput = true;\n  Sound.NR51IsChannel2EnabledOnLeftOutput = true;\n  Sound.NR51IsChannel3EnabledOnLeftOutput = true;\n  Sound.NR51IsChannel4EnabledOnLeftOutput = true;\n  Sound.NR51IsChannel1EnabledOnRightOutput = true;\n  Sound.NR51IsChannel2EnabledOnRightOutput = true;\n  Sound.NR51IsChannel3EnabledOnRightOutput = true;\n  Sound.NR51IsChannel4EnabledOnRightOutput = true;\n  Sound.NR52IsSoundEnabled = true;\n  Sound.frameSequenceCycleCounter = 0x0000;\n  Sound.downSampleCycleCounter = 0x00;\n  Sound.frameSequencer = 0x00;\n  Sound.audioQueueIndex = 0x0000;\n\n  // intiialize our channels\n  Channel1.initialize();\n  Channel2.initialize();\n  Channel3.initialize();\n  Channel4.initialize();\n\n  // Other Sound Registers\n  eightBitStoreIntoGBMemory(Sound.memoryLocationNR50, 0x77);\n  Sound.updateNR50(0x77);\n  eightBitStoreIntoGBMemory(Sound.memoryLocationNR51, 0xf3);\n  Sound.updateNR51(0xf3);\n  eightBitStoreIntoGBMemory(Sound.memoryLocationNR52, 0xf1);\n  Sound.updateNR52(0xf1);\n\n  // Override/reset some variables if the boot ROM is enabled\n  // For both GB and GBC\n  if (Cpu.BootROMEnabled) {\n    eightBitStoreIntoGBMemory(Sound.memoryLocationNR50, 0x00);\n    Sound.updateNR50(0x00);\n    eightBitStoreIntoGBMemory(Sound.memoryLocationNR51, 0x00);\n    Sound.updateNR51(0x00);\n    eightBitStoreIntoGBMemory(Sound.memoryLocationNR52, 0x70);\n    Sound.updateNR52(0x70);\n  }\n\n  initializeSoundAccumulator();\n}\n\n// Function to batch process our audio after we skipped so many cycles\nexport function batchProcessAudio(): void {\n  let batchProcessCycles = Sound.batchProcessCycles();\n  let currentCycles = Sound.currentCycles;\n  while (currentCycles >= batchProcessCycles) {\n    updateSound(batchProcessCycles);\n    currentCycles -= batchProcessCycles;\n  }\n  Sound.currentCycles = currentCycles;\n}\n\n// Function for updating sound\nexport function updateSound(numberOfCycles: i32): void {\n  // Check if our frameSequencer updated\n  let frameSequencerUpdated = updateFrameSequencer(numberOfCycles);\n\n  if (Config.audioAccumulateSamples && !frameSequencerUpdated) {\n    accumulateSound(numberOfCycles);\n  } else {\n    calculateSound(numberOfCycles);\n  }\n}\n\n// Funciton to get the current Audio Queue index\nexport function getNumberOfSamplesInAudioBuffer(): i32 {\n  return Sound.audioQueueIndex;\n}\n\n// Function to reset the audio queue\nexport function clearAudioBuffer(): void {\n  Sound.audioQueueIndex = 0;\n}\n\n// Inlined because closure compiler inlines\nfunction calculateSound(numberOfCycles: i32): void {\n  // Update all of our channels\n  // All samples will be returned as 0 to 30\n  // 0 being -1.0, and 30 being 1.0\n  // (see blurb at top)\n  let channel1Sample = i32Portable(Channel1.getSample(numberOfCycles));\n  let channel2Sample = i32Portable(Channel2.getSample(numberOfCycles));\n  let channel3Sample = i32Portable(Channel3.getSample(numberOfCycles));\n  let channel4Sample = i32Portable(Channel4.getSample(numberOfCycles));\n  // TODO: Allow individual channels to be muted\n  // let channel1Sample: i32 = 15;\n  // let channel2Sample: i32 = 15;\n  // let channel3Sample: i32 = 15;\n  // let channel4Sample: i32 = 15;\n\n  // Save the samples in the accumulator\n  SoundAccumulator.channel1Sample = channel1Sample;\n  SoundAccumulator.channel2Sample = channel2Sample;\n  SoundAccumulator.channel3Sample = channel3Sample;\n  SoundAccumulator.channel4Sample = channel4Sample;\n\n  // Do Some downsampling magic\n  let downSampleCycleCounter = Sound.downSampleCycleCounter + numberOfCycles;\n  if (downSampleCycleCounter >= Sound.maxDownSampleCycles()) {\n    // Reset the downsample counter\n    // Don't set to zero to catch overflowed cycles\n    downSampleCycleCounter -= Sound.maxDownSampleCycles();\n\n    // Mix our samples\n    let mixedSample = mixChannelSamples(channel1Sample, channel2Sample, channel3Sample, channel4Sample);\n    let leftChannelSampleUnsignedByte = splitHighByte(mixedSample);\n    let rightChannelSampleUnsignedByte = splitLowByte(mixedSample);\n\n    // Set our volumes in memory\n    // +1 so it can not be zero\n    setLeftAndRightOutputForAudioQueue(leftChannelSampleUnsignedByte + 1, rightChannelSampleUnsignedByte + 1, AUDIO_BUFFER_LOCATION);\n    if (Config.enableAudioDebugging) {\n      // Channel 1\n      mixedSample = mixChannelSamples(channel1Sample, 15, 15, 15);\n      leftChannelSampleUnsignedByte = splitHighByte(mixedSample);\n      rightChannelSampleUnsignedByte = splitLowByte(mixedSample);\n      setLeftAndRightOutputForAudioQueue(leftChannelSampleUnsignedByte + 1, rightChannelSampleUnsignedByte + 1, CHANNEL_1_BUFFER_LOCATION);\n\n      // Channel 2\n      mixedSample = mixChannelSamples(15, channel2Sample, 15, 15);\n      leftChannelSampleUnsignedByte = splitHighByte(mixedSample);\n      rightChannelSampleUnsignedByte = splitLowByte(mixedSample);\n      setLeftAndRightOutputForAudioQueue(leftChannelSampleUnsignedByte + 1, rightChannelSampleUnsignedByte + 1, CHANNEL_2_BUFFER_LOCATION);\n\n      // Channel 3\n      mixedSample = mixChannelSamples(15, 15, channel3Sample, 15);\n      leftChannelSampleUnsignedByte = splitHighByte(mixedSample);\n      rightChannelSampleUnsignedByte = splitLowByte(mixedSample);\n      setLeftAndRightOutputForAudioQueue(leftChannelSampleUnsignedByte + 1, rightChannelSampleUnsignedByte + 1, CHANNEL_3_BUFFER_LOCATION);\n\n      // Channel 4\n      mixedSample = mixChannelSamples(15, 15, 15, channel4Sample);\n      leftChannelSampleUnsignedByte = splitHighByte(mixedSample);\n      rightChannelSampleUnsignedByte = splitLowByte(mixedSample);\n      setLeftAndRightOutputForAudioQueue(leftChannelSampleUnsignedByte + 1, rightChannelSampleUnsignedByte + 1, CHANNEL_4_BUFFER_LOCATION);\n    }\n    let audioQueueIndex = Sound.audioQueueIndex + 1;\n\n    // Don't allow our audioQueueIndex to overflow into other parts of the wasmBoy memory map\n    // https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit#gid=0\n    // Not 0xFFFF because we need half of 64kb since we store left and right channel\n    let maxIndex = i32Portable(Sound.wasmBoyMemoryMaxBufferSize >> 1) - 1;\n    if (audioQueueIndex >= maxIndex) {\n      audioQueueIndex -= 1;\n    }\n    Sound.audioQueueIndex = audioQueueIndex;\n  }\n\n  Sound.downSampleCycleCounter = downSampleCycleCounter;\n}\n\n// Inlined because closure compiler inlines\nfunction updateFrameSequencer(numberOfCycles: i32): boolean {\n  // APU runs at 4194304 / 512\n  // Or Cpu.clockSpeed / 512\n  // Which means, we need to update once every 8192 cycles :)\n  let maxFrameSequenceCycles = Sound.maxFrameSequenceCycles();\n  let frameSequenceCycleCounter = Sound.frameSequenceCycleCounter + numberOfCycles;\n  if (frameSequenceCycleCounter >= maxFrameSequenceCycles) {\n    // Reset the frameSequenceCycleCounter\n    // Not setting to zero as we do not want to drop cycles\n    frameSequenceCycleCounter -= maxFrameSequenceCycles;\n    Sound.frameSequenceCycleCounter = frameSequenceCycleCounter;\n\n    // Update our frame sequencer\n    // https://gist.github.com/drhelius/3652407\n    let frameSequencer = (Sound.frameSequencer + 1) & 7;\n\n    switch (frameSequencer) {\n      case 0:\n        // Update Length on Channels\n        Channel1.updateLength();\n        Channel2.updateLength();\n        Channel3.updateLength();\n        Channel4.updateLength();\n        break;\n      /* Do Nothing on one */\n      case 2:\n        // Update Sweep and Length on Channels\n        Channel1.updateLength();\n        Channel2.updateLength();\n        Channel3.updateLength();\n        Channel4.updateLength();\n\n        Channel1.updateSweep();\n        break;\n      /* Do Nothing on three */\n      case 4:\n        // Update Length on Channels\n        Channel1.updateLength();\n        Channel2.updateLength();\n        Channel3.updateLength();\n        Channel4.updateLength();\n        break;\n      /* Do Nothing on five */\n      case 6:\n        // Update Sweep and Length on Channels\n        Channel1.updateLength();\n        Channel2.updateLength();\n        Channel3.updateLength();\n        Channel4.updateLength();\n\n        Channel1.updateSweep();\n        break;\n      case 7:\n        // Update Envelope on channels\n        Channel1.updateEnvelope();\n        Channel2.updateEnvelope();\n        Channel4.updateEnvelope();\n        break;\n    }\n\n    // Save our frame sequencer\n    Sound.frameSequencer = frameSequencer;\n    return true;\n  } else {\n    Sound.frameSequenceCycleCounter = frameSequenceCycleCounter;\n  }\n\n  return false;\n}\n\nexport function mixChannelSamples(\n  channel1Sample: i32 = 15,\n  channel2Sample: i32 = 15,\n  channel3Sample: i32 = 15,\n  channel4Sample: i32 = 15\n): i32 {\n  // Do Some Cool mixing\n  // NR50 FF24 ALLL BRRR Vin L enable, Left vol, Vin R enable, Right vol\n  // NR51 FF25 NW21 NW21 Left enables, Right enables\n  // NR52 FF26 P--- NW21 Power control/status, Channel length statuses\n  // NW21 = 4 bits on byte\n  // 3 -> Channel 4, 2 -> Channel 3, 1 -> Channel 2, 0 -> Channel 1\n\n  // Matt's Proccess\n  // I push out 1024 samples at a time and use 96000 hz sampling rate, so I guess i'm a bit less than one frame,\n  // but I let the queue fill up with 4 x 1024 samples before I start waiting for the audio\n\n  // TODO: Vin Mixing\n\n  SoundAccumulator.mixerVolumeChanged = false;\n\n  // Get our channel volume for left/right\n  let leftChannelSample = 0;\n  let rightChannelSample = 0;\n\n  // Find the sample for the left if enabled\n  // other wise add silence (15) for the channel\n  leftChannelSample += Sound.NR51IsChannel1EnabledOnLeftOutput ? channel1Sample : 15;\n  leftChannelSample += Sound.NR51IsChannel2EnabledOnLeftOutput ? channel2Sample : 15;\n  leftChannelSample += Sound.NR51IsChannel3EnabledOnLeftOutput ? channel3Sample : 15;\n  leftChannelSample += Sound.NR51IsChannel4EnabledOnLeftOutput ? channel4Sample : 15;\n\n  // Find the sample for the right if enabled\n  // other wise add silence (15) for the channel\n  rightChannelSample += Sound.NR51IsChannel1EnabledOnRightOutput ? channel1Sample : 15;\n  rightChannelSample += Sound.NR51IsChannel2EnabledOnRightOutput ? channel2Sample : 15;\n  rightChannelSample += Sound.NR51IsChannel3EnabledOnRightOutput ? channel3Sample : 15;\n  rightChannelSample += Sound.NR51IsChannel4EnabledOnRightOutput ? channel4Sample : 15;\n\n  // Update our accumulator\n  SoundAccumulator.mixerEnabledChanged = false;\n  SoundAccumulator.needToRemixSamples = false;\n\n  // Finally multiply our volumes by the mixer volume\n  // Mixer volume can be at most 7 + 1\n  // Can be at most 7, because we only have 3 bits, 111 = 7\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Mixer\n  // Done in the getSampleAsUnsignedByte(), since we are doing some weirdness there :)\n\n  // Convert our samples from unsigned 32 to unsigned byte\n  // Reason being, We want to be able to pass in wasm memory as usigned byte. Javascript will handle the conversion back\n  let leftChannelSampleUnsignedByte: i32 = getSampleAsUnsignedByte(leftChannelSample, Sound.NR50LeftMixerVolume + 1);\n  let rightChannelSampleUnsignedByte: i32 = getSampleAsUnsignedByte(rightChannelSample, Sound.NR50RightMixerVolume + 1);\n\n  // Save these samples in the accumulator\n  SoundAccumulator.leftChannelSampleUnsignedByte = leftChannelSampleUnsignedByte;\n  SoundAccumulator.rightChannelSampleUnsignedByte = rightChannelSampleUnsignedByte;\n\n  return concatenateBytes(leftChannelSampleUnsignedByte, rightChannelSampleUnsignedByte);\n}\n\nfunction getSampleAsUnsignedByte(sample: i32, mixerVolume: i32): i32 {\n  // If the sample is silence, return silence as unsigned byte\n  // Silence is common, and should be checked for performance\n  if (sample === 60) {\n    return 127;\n  }\n\n  // convert to a signed, precise scale of -6000 to 6000 (cheap way of -1.0 to 1.0)\n  // Multiply by the mixer volume fraction (to find the actual volume)\n  const precision = 100000;\n  let convertedSample = sample - 60;\n  convertedSample = convertedSample * precision;\n\n  // Multiply by the mixer volume fraction (to find the actual volume)\n  convertedSample = (convertedSample * mixerVolume) >> 3;\n\n  // Convert back to scale of 0 to 120\n  convertedSample = i32Portable(convertedSample / precision) + 60;\n\n  // Finally, convert to an unsigned byte scale\n  // With Four Channels (0 to 30) and no global volume. Max is 120\n  // max unsigned byte goal is 254 (see blurb at top).\n  // 120 / 254 should give the correct conversion\n  // For example, 120 / 254 = 0.47244094488188976\n  // Multiply by 1000 to increase the float into an int\n  // so, 120 * 1000 / (0.47244094488188976 * 1000) should give approximate answer for max mixer volume\n  let maxDivider = i32Portable((120 * precision) / 254);\n  convertedSample = i32Portable((convertedSample * precision) / maxDivider);\n\n  // Ensure we have an i32 and not a float for JS builds\n  convertedSample = i32Portable(convertedSample);\n\n  return convertedSample;\n}\n\n// Function to set our left and right channels at the correct queue index\nexport function setLeftAndRightOutputForAudioQueue(leftVolume: i32, rightVolume: i32, bufferLocation: i32): void {\n  // Get our stereo index\n  let audioQueueOffset = bufferLocation + (Sound.audioQueueIndex << 1);\n\n  // Store our volumes\n  // +1 that way we don't have empty data to ensure that the value is set\n  store<u8>(audioQueueOffset + 0, <u8>(leftVolume + 1));\n  store<u8>(audioQueueOffset + 1, <u8>(rightVolume + 1));\n}\n","import { Cpu } from '../cpu/index';\nimport { getSaveStateMemoryOffset } from '../core';\nimport {\n  eightBitLoadFromGBMemory,\n  eightBitStoreIntoGBMemory,\n  sixteenBitStoreIntoGBMemory,\n  loadBooleanDirectlyFromWasmMemory,\n  storeBooleanDirectlyToWasmMemory\n} from '../memory/index';\nimport { setBitOnByte, resetBitOnByte, checkBitOnByte } from '../helpers/index';\n\nexport class Interrupts {\n  static masterInterruptSwitch: boolean = false;\n  // According to mooneye, interrupts are not handled until AFTER\n  // Next instruction\n  // https://github.com/Gekkio/mooneye-gb/blob/master/docs/accuracy.markdown\n  static masterInterruptSwitchDelay: boolean = false;\n\n  // Biut position for each part of the interrupts HW registers\n  static readonly bitPositionVBlankInterrupt: i32 = 0;\n  static readonly bitPositionLcdInterrupt: i32 = 1;\n  static readonly bitPositionTimerInterrupt: i32 = 2;\n  static readonly bitPositionSerialInterrupt: i32 = 3;\n  static readonly bitPositionJoypadInterrupt: i32 = 4;\n\n  static readonly memoryLocationInterruptEnabled: i32 = 0xffff; // A.K.A interrupt Flag (IE)\n  // Cache which Interrupts are enabled\n  static interruptsEnabledValue: i32 = 0;\n  static isVBlankInterruptEnabled: boolean = false;\n  static isLcdInterruptEnabled: boolean = false;\n  static isTimerInterruptEnabled: boolean = false;\n  static isSerialInterruptEnabled: boolean = false;\n  static isJoypadInterruptEnabled: boolean = false;\n  static updateInterruptEnabled(value: i32): void {\n    Interrupts.isVBlankInterruptEnabled = checkBitOnByte(Interrupts.bitPositionVBlankInterrupt, value);\n    Interrupts.isLcdInterruptEnabled = checkBitOnByte(Interrupts.bitPositionLcdInterrupt, value);\n    Interrupts.isTimerInterruptEnabled = checkBitOnByte(Interrupts.bitPositionTimerInterrupt, value);\n    Interrupts.isSerialInterruptEnabled = checkBitOnByte(Interrupts.bitPositionSerialInterrupt, value);\n    Interrupts.isJoypadInterruptEnabled = checkBitOnByte(Interrupts.bitPositionJoypadInterrupt, value);\n\n    Interrupts.interruptsEnabledValue = value;\n  }\n\n  static readonly memoryLocationInterruptRequest: i32 = 0xff0f; // A.K.A interrupt Flag (IF)\n  // Cache which Interrupts are requested\n  static interruptsRequestedValue: i32 = 0;\n  static isVBlankInterruptRequested: boolean = false;\n  static isLcdInterruptRequested: boolean = false;\n  static isTimerInterruptRequested: boolean = false;\n  static isSerialInterruptRequested: boolean = false;\n  static isJoypadInterruptRequested: boolean = false;\n  static updateInterruptRequested(value: i32): void {\n    Interrupts.isVBlankInterruptRequested = checkBitOnByte(Interrupts.bitPositionVBlankInterrupt, value);\n    Interrupts.isLcdInterruptRequested = checkBitOnByte(Interrupts.bitPositionLcdInterrupt, value);\n    Interrupts.isTimerInterruptRequested = checkBitOnByte(Interrupts.bitPositionTimerInterrupt, value);\n    Interrupts.isSerialInterruptRequested = checkBitOnByte(Interrupts.bitPositionSerialInterrupt, value);\n    Interrupts.isJoypadInterruptRequested = checkBitOnByte(Interrupts.bitPositionJoypadInterrupt, value);\n\n    Interrupts.interruptsRequestedValue = value;\n  }\n\n  // Function to return if we have any pending interrupts\n  static areInterruptsPending(): boolean {\n    return (Interrupts.interruptsRequestedValue & Interrupts.interruptsEnabledValue & 0x1f) > 0;\n  }\n\n  // Save States\n  static readonly saveStateSlot: i32 = 2;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x00, Interrupts.saveStateSlot), Interrupts.masterInterruptSwitch);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x01, Interrupts.saveStateSlot), Interrupts.masterInterruptSwitchDelay);\n\n    // Interrupts enabled and requested are stored in actual GB memory, thus, don't need to be saved\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    Interrupts.masterInterruptSwitch = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x00, Interrupts.saveStateSlot));\n    Interrupts.masterInterruptSwitchDelay = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x01, Interrupts.saveStateSlot));\n\n    Interrupts.updateInterruptEnabled(eightBitLoadFromGBMemory(Interrupts.memoryLocationInterruptEnabled));\n    Interrupts.updateInterruptRequested(eightBitLoadFromGBMemory(Interrupts.memoryLocationInterruptRequest));\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function initializeInterrupts(): void {\n  // Values from BGB\n\n  // IE\n  Interrupts.updateInterruptEnabled(0x00);\n  eightBitStoreIntoGBMemory(Interrupts.memoryLocationInterruptEnabled, Interrupts.interruptsEnabledValue);\n\n  // IF\n  Interrupts.updateInterruptRequested(0xe1);\n  eightBitStoreIntoGBMemory(Interrupts.memoryLocationInterruptRequest, Interrupts.interruptsRequestedValue);\n}\n\n// NOTE: Interrupts should be handled before reading an opcode\n// Inlined because closure compiler inlines\nexport function checkInterrupts(): i32 {\n  // First check for our delay was enabled\n  if (Interrupts.masterInterruptSwitchDelay) {\n    Interrupts.masterInterruptSwitch = true;\n    Interrupts.masterInterruptSwitchDelay = false;\n  }\n\n  // Check if we have an enabled and requested interrupt\n  let isAnInterruptRequestedAndEnabledValue: i32 = Interrupts.interruptsEnabledValue & Interrupts.interruptsRequestedValue & 0x1f;\n\n  if (isAnInterruptRequestedAndEnabledValue > 0) {\n    // Boolean to track if interrupts were handled\n    // Interrupt handling requires 20 cycles\n    // https://github.com/Gekkio/mooneye-gb/blob/master/docs/accuracy.markdown#what-is-the-exact-timing-of-cpu-servicing-an-interrupt\n    let wasInterruptHandled: boolean = false;\n\n    // Service our interrupts, if we have the master switch enabled\n    // https://www.reddit.com/r/EmuDev/comments/5ie3k7/infinite_loop_trying_to_pass_blarggs_interrupt/\n    if (Interrupts.masterInterruptSwitch && !Cpu.isHaltNoJump) {\n      if (Interrupts.isVBlankInterruptEnabled && Interrupts.isVBlankInterruptRequested) {\n        _handleInterrupt(Interrupts.bitPositionVBlankInterrupt);\n        wasInterruptHandled = true;\n      } else if (Interrupts.isLcdInterruptEnabled && Interrupts.isLcdInterruptRequested) {\n        _handleInterrupt(Interrupts.bitPositionLcdInterrupt);\n        wasInterruptHandled = true;\n      } else if (Interrupts.isTimerInterruptEnabled && Interrupts.isTimerInterruptRequested) {\n        _handleInterrupt(Interrupts.bitPositionTimerInterrupt);\n        wasInterruptHandled = true;\n      } else if (Interrupts.isSerialInterruptEnabled && Interrupts.isSerialInterruptRequested) {\n        _handleInterrupt(Interrupts.bitPositionSerialInterrupt);\n        wasInterruptHandled = true;\n      } else if (Interrupts.isJoypadInterruptEnabled && Interrupts.isJoypadInterruptRequested) {\n        _handleInterrupt(Interrupts.bitPositionJoypadInterrupt);\n        wasInterruptHandled = true;\n      }\n    }\n\n    let interuptHandlerCycles: i32 = 0;\n    if (wasInterruptHandled) {\n      // Interrupt handling requires 20 cycles, TCAGBD\n      interuptHandlerCycles = 20;\n      if (Cpu.isHalted()) {\n        // If the CPU was halted, now is the time to un-halt\n        // Should be done here when the jump occurs according to:\n        // https://www.reddit.com/r/EmuDev/comments/6fmjch/gb_glitches_in_links_awakening_and_pok%C3%A9mon_gold/\n        Cpu.exitHaltAndStop();\n        interuptHandlerCycles += 4;\n      }\n    }\n\n    if (Cpu.isHalted()) {\n      Cpu.exitHaltAndStop();\n    }\n\n    return interuptHandlerCycles;\n  }\n\n  return 0;\n}\n\nfunction _handleInterrupt(bitPosition: i32): void {\n  // Disable the master switch\n  setInterrupts(false);\n\n  // Disable the bit on the interruptRequest\n  let interruptRequest = eightBitLoadFromGBMemory(Interrupts.memoryLocationInterruptRequest);\n  interruptRequest = resetBitOnByte(bitPosition, interruptRequest);\n  Interrupts.interruptsRequestedValue = interruptRequest;\n  eightBitStoreIntoGBMemory(Interrupts.memoryLocationInterruptRequest, interruptRequest);\n\n  // Push the programCounter onto the stacks\n  // Push the next instruction, not the halt itself (TCAGBD).\n  Cpu.stackPointer = Cpu.stackPointer - 2;\n  if (Cpu.isHalted()) {\n    // TODO: This breaks Pokemon Yellow, And OG Link's awakening. Find out why...\n    // sixteenBitStoreIntoGBMemory(Cpu.stackPointer, Cpu.programCounter + 1);\n    sixteenBitStoreIntoGBMemory(Cpu.stackPointer, Cpu.programCounter);\n  } else {\n    sixteenBitStoreIntoGBMemory(Cpu.stackPointer, Cpu.programCounter);\n  }\n\n  // Jump to the correct interrupt location\n  // Also piggyback off of the switch to reset our HW Register caching\n  // http://www.codeslinger.co.uk/pages/projects/gameboy/interupts.html\n  switch (bitPosition) {\n    case Interrupts.bitPositionVBlankInterrupt:\n      Interrupts.isVBlankInterruptRequested = false;\n      Cpu.programCounter = 0x40;\n      break;\n    case Interrupts.bitPositionLcdInterrupt:\n      Interrupts.isLcdInterruptRequested = false;\n      Cpu.programCounter = 0x48;\n      break;\n    case Interrupts.bitPositionTimerInterrupt:\n      Interrupts.isTimerInterruptRequested = false;\n      Cpu.programCounter = 0x50;\n      break;\n    case Interrupts.bitPositionSerialInterrupt:\n      Interrupts.isSerialInterruptRequested = false;\n      Cpu.programCounter = 0x58;\n      break;\n    case Interrupts.bitPositionJoypadInterrupt:\n      Interrupts.isJoypadInterruptRequested = false;\n      Cpu.programCounter = 0x60;\n      break;\n  }\n}\n\nfunction _requestInterrupt(bitPosition: i32): void {\n  let interruptRequest = eightBitLoadFromGBMemory(Interrupts.memoryLocationInterruptRequest);\n\n  // Pass to set the correct interrupt bit on interruptRequest\n  interruptRequest = setBitOnByte(bitPosition, interruptRequest);\n\n  Interrupts.interruptsRequestedValue = interruptRequest;\n\n  eightBitStoreIntoGBMemory(Interrupts.memoryLocationInterruptRequest, interruptRequest);\n}\n\nexport function setInterrupts(value: boolean): void {\n  // If we are enabling interrupts,\n  // we want to wait 4 cycles before enabling\n  if (value) {\n    Interrupts.masterInterruptSwitchDelay = true;\n  } else {\n    Interrupts.masterInterruptSwitch = false;\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function requestVBlankInterrupt(): void {\n  Interrupts.isVBlankInterruptRequested = true;\n  _requestInterrupt(Interrupts.bitPositionVBlankInterrupt);\n}\n\n// Inlined because closure compiler inlines\nexport function requestLcdInterrupt(): void {\n  Interrupts.isLcdInterruptRequested = true;\n  _requestInterrupt(Interrupts.bitPositionLcdInterrupt);\n}\n\n// Inlined because closure compiler inlines\nexport function requestTimerInterrupt(): void {\n  Interrupts.isTimerInterruptRequested = true;\n  _requestInterrupt(Interrupts.bitPositionTimerInterrupt);\n}\n\n// Inlined because closure compiler inlines\nexport function requestJoypadInterrupt(): void {\n  Interrupts.isJoypadInterruptRequested = true;\n  _requestInterrupt(Interrupts.bitPositionJoypadInterrupt);\n}\n\n// Inlined because closure compiler inlines\nexport function requestSerialInterrupt(): void {\n  Interrupts.isSerialInterruptRequested = true;\n  _requestInterrupt(Interrupts.bitPositionSerialInterrupt);\n}\n","import { getSaveStateMemoryOffset } from '../core';\nimport { Cpu } from '../cpu/index';\nimport {\n  eightBitLoadFromGBMemory,\n  eightBitStoreIntoGBMemory,\n  loadBooleanDirectlyFromWasmMemory,\n  storeBooleanDirectlyToWasmMemory\n} from '../memory/index';\nimport { requestTimerInterrupt } from '../interrupts/index';\nimport { checkBitOnByte } from '../helpers/index';\n\nexport class Timers {\n  // Current cycles\n  // This will be used for batch processing\n  static currentCycles: i32 = 0;\n\n  // Number of cycles to run in each batch process\n  static batchProcessCycles(): i32 {\n    return 256;\n  }\n\n  // Divider Register = DIV\n  // Divider Register is 16 bits.\n  // Divider Register when read is just the upper 8 bits\n  // But internally is used as the full 16\n  // Essentially dividerRegister is an always counting clock\n  // DIV Drives everything, it is the heart of the timer.\n  // All other timing registers base them selves relative to the DIV register\n  // Think of the div register as like a cycle counter :)\n  // DIV will increment TIMA, whenever there is a falling edge, see below for that.\n  static readonly memoryLocationDividerRegister: i32 = 0xff04; // DIV\n  static dividerRegister: i32 = 0;\n  static updateDividerRegister(): void {\n    let oldDividerRegister = Timers.dividerRegister;\n    Timers.dividerRegister = 0;\n    eightBitStoreIntoGBMemory(Timers.memoryLocationDividerRegister, 0);\n\n    if (Timers.timerEnabled && _checkDividerRegisterFallingEdgeDetector(oldDividerRegister, 0)) {\n      _incrementTimerCounter();\n    }\n  }\n\n  // timerCounter = TIMA\n  // TIMA is the actual counter.\n  // Whenever the DIV gets the falling edge, and other obscure cases,\n  // This is incremented. When this overflows, we need to fire an interrupt.\n  static readonly memoryLocationTimerCounter: i32 = 0xff05;\n  static timerCounter: i32 = 0;\n  static timerCounterOverflowDelay: boolean = false;\n  static timerCounterWasReset: boolean = false;\n  static timerCounterMask: i32 = 0;\n\n  static updateTimerCounter(value: i32): void {\n    if (Timers.timerEnabled) {\n      // From binjgb, dont write TIMA if we were just reset\n      if (Timers.timerCounterWasReset) {\n        return;\n      }\n\n      // Mooneye Test, tima_write_reloading\n      // Writing in this strange delay cycle, will cancel\n      // Both the interrupt and the TMA reload\n      if (Timers.timerCounterOverflowDelay) {\n        Timers.timerCounterOverflowDelay = false;\n      }\n    }\n\n    Timers.timerCounter = value;\n  }\n\n  // Timer Modulo = TMA\n  // TMA is what TIMA (Notice the I :p) is counting from, and TIMA will load\n  // Whenever TIMA overflow.\n  // For instance, we count like 1,2,3,4,5,6,7,8,9, and then overflow to 10.\n  // TMA would be like \"Hey, start counting from 5 whenever we reset\"\n  // Then we would be like 5,6,7,8,9...5,6,7,8,9...etc...\n  static readonly memoryLocationTimerModulo: i32 = 0xff06;\n  static timerModulo: i32 = 0;\n  static updateTimerModulo(value: i32): void {\n    Timers.timerModulo = value;\n\n    // Mooneye Test, tma_write_reloading\n    // Don't update if we were reloading\n    if (Timers.timerEnabled && Timers.timerCounterWasReset) {\n      Timers.timerCounter = value;\n      Timers.timerCounterWasReset = false;\n    }\n  }\n\n  // Timer Control = TAC\n  // TAC Says how fast we are counting.\n  // TAC controls which bit we are watching for the falling edge on the DIV register\n  // And whenever the bit has the falling edge, we increment TIMA (The thing counting).\n  // Therefore, depending on the value, we will either count faster or slower.\n  static readonly memoryLocationTimerControl: i32 = 0xff07;\n  // Bit 2    - Timer Stop  (0=Stop, 1=Start)\n  // Bits 1-0 - Input Clock Select\n  //            00:   4096 Hz    (~4194 Hz SGB) (1024 cycles)\n  //            01: 262144 Hz  (~268400 Hz SGB) (16 cycles)\n  //            10:  65536 Hz   (~67110 Hz SGB) (64 cycles)\n  //            11:  16384 Hz   (~16780 Hz SGB) (256 cycles)\n  static timerEnabled: boolean = false;\n  static timerInputClock: i32 = 0;\n\n  static updateTimerControl(value: i32): void {\n    // Get some initial values\n    let oldTimerEnabled = Timers.timerEnabled;\n    Timers.timerEnabled = checkBitOnByte(2, value);\n    let newTimerInputClock = value & 0x03;\n\n    // Do some obscure behavior for if we should increment TIMA\n    // This does the timer increments from rapid_toggle mooneye tests\n    if (!oldTimerEnabled) {\n      let oldTimerCounterMaskBit = _getTimerCounterMaskBit(Timers.timerInputClock);\n      let newTimerCounterMaskBit = _getTimerCounterMaskBit(newTimerInputClock);\n      let shouldIncrementTimerCounter = false;\n      let dividerRegister = Timers.dividerRegister;\n\n      if (Timers.timerEnabled) {\n        shouldIncrementTimerCounter = checkBitOnByte(oldTimerCounterMaskBit, dividerRegister);\n      } else {\n        shouldIncrementTimerCounter =\n          checkBitOnByte(oldTimerCounterMaskBit, dividerRegister) && checkBitOnByte(newTimerCounterMaskBit, dividerRegister);\n      }\n\n      if (shouldIncrementTimerCounter) {\n        _incrementTimerCounter();\n      }\n    }\n\n    Timers.timerInputClock = newTimerInputClock;\n  }\n\n  // Save States\n  static readonly saveStateSlot: i32 = 5;\n\n  // Function to save the state of the class\n  // TODO: Save state for new properties on Timers\n  static saveState(): void {\n    store<i32>(getSaveStateMemoryOffset(0x00, Timers.saveStateSlot), Timers.currentCycles);\n    store<i32>(getSaveStateMemoryOffset(0x04, Timers.saveStateSlot), Timers.dividerRegister);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x08, Timers.saveStateSlot), Timers.timerCounterOverflowDelay);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0b, Timers.saveStateSlot), Timers.timerCounterWasReset);\n\n    eightBitStoreIntoGBMemory(Timers.memoryLocationTimerCounter, Timers.timerCounter);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    Timers.currentCycles = load<i32>(getSaveStateMemoryOffset(0x00, Timers.saveStateSlot));\n    Timers.dividerRegister = load<i32>(getSaveStateMemoryOffset(0x04, Timers.saveStateSlot));\n    Timers.timerCounterOverflowDelay = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x08, Timers.saveStateSlot));\n    Timers.timerCounterWasReset = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0b, Timers.saveStateSlot));\n\n    Timers.timerCounter = eightBitLoadFromGBMemory(Timers.memoryLocationTimerCounter);\n    Timers.timerModulo = eightBitLoadFromGBMemory(Timers.memoryLocationTimerModulo);\n    Timers.timerInputClock = eightBitLoadFromGBMemory(Timers.memoryLocationTimerControl);\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function initializeTimers(): void {\n  // Reset stateful Variables\n  Timers.currentCycles = 0;\n  Timers.dividerRegister = 0;\n  Timers.timerCounter = 0;\n  Timers.timerModulo = 0;\n  Timers.timerEnabled = false;\n  Timers.timerInputClock = 0;\n  Timers.timerCounterOverflowDelay = false;\n  Timers.timerCounterWasReset = false;\n\n  if (Cpu.GBCEnabled) {\n    // DIV\n    eightBitStoreIntoGBMemory(0xff04, 0x1e);\n    Timers.dividerRegister = 0x1ea0;\n\n    // 0xFF05 -> 0xFF06 = 0x00\n\n    // TAC\n    eightBitStoreIntoGBMemory(0xff07, 0xf8);\n    Timers.timerInputClock = 0xf8;\n  } else {\n    // DIV\n    eightBitStoreIntoGBMemory(0xff04, 0xab);\n    Timers.dividerRegister = 0xabcc;\n\n    // 0xFF05 -> 0xFF06 = 0x00\n\n    // TAC\n    eightBitStoreIntoGBMemory(0xff07, 0xf8);\n    Timers.timerInputClock = 0xf8;\n  }\n\n  // Override/reset some variables if the boot ROM is enabled\n  if (Cpu.BootROMEnabled) {\n    if (Cpu.GBCEnabled) {\n      // GBC\n    } else {\n      // GB\n      // DIV\n      eightBitStoreIntoGBMemory(0xff04, 0x00);\n      Timers.dividerRegister = 0x0004;\n    }\n  }\n}\n\n// Batch Process Timers\n// Only checked on writes\n// Function to batch process our Timers after we skipped so many cycles\nexport function batchProcessTimers(): void {\n  // TODO: Did a timer rewrite, make a proper batch processing\n  // For timers\n  updateTimers(Timers.currentCycles);\n  Timers.currentCycles = 0;\n}\n\nexport function updateTimers(numberOfCycles: i32): void {\n  // Want to increment 4 cycles at a time like an actual GB would\n  let cyclesIncreased = 0;\n  while (cyclesIncreased < numberOfCycles) {\n    let oldDividerRegister = Timers.dividerRegister;\n    let curDividerRegister = oldDividerRegister;\n\n    cyclesIncreased += 4;\n    curDividerRegister += 4;\n    curDividerRegister &= 0xffff;\n\n    Timers.dividerRegister = curDividerRegister;\n\n    if (Timers.timerEnabled) {\n      let timerCounterWasReset = Timers.timerCounterWasReset;\n      if (Timers.timerCounterOverflowDelay) {\n        Timers.timerCounter = Timers.timerModulo;\n        // Fire off timer interrupt\n        requestTimerInterrupt();\n        Timers.timerCounterOverflowDelay = false;\n        Timers.timerCounterWasReset = true;\n      } else if (timerCounterWasReset) {\n        Timers.timerCounterWasReset = false;\n      }\n\n      if (_checkDividerRegisterFallingEdgeDetector(oldDividerRegister, curDividerRegister)) {\n        _incrementTimerCounter();\n      }\n    }\n  }\n}\n\n// Function to increment our Timer Counter\n// This fires off interrupts once we overflow\nfunction _incrementTimerCounter(): void {\n  var counter = Timers.timerCounter;\n  if (++counter > 255) {\n    // Whenever the timer overflows, there is a slight delay (4 cycles)\n    // Of when TIMA gets TMA's value, and the interrupt is fired.\n    // Thus we will set the delay, which can be handled in the update timer or write trap\n    Timers.timerCounterOverflowDelay = true;\n    counter = 0;\n  }\n  Timers.timerCounter = counter;\n}\n\n// Function to act as our falling edge detector\n// Whenever we have a falling edge, we need to increment TIMA\n// http://gbdev.gg8.se/wiki/articles/Timer_Obscure_Behaviour\n// https://github.com/binji/binjgb/blob/master/src/emulator.c#L1944\nfunction _checkDividerRegisterFallingEdgeDetector(oldDividerRegister: i32, newDividerRegister: i32): boolean {\n  // Get our mask\n  let timerCounterMaskBit = _getTimerCounterMaskBit(Timers.timerInputClock);\n\n  // If the old register's watched bit was zero,\n  // but after adding the new registers wastch bit is now 1\n  return checkBitOnByte(timerCounterMaskBit, oldDividerRegister) && !checkBitOnByte(timerCounterMaskBit, newDividerRegister);\n}\n\n// Function to get our current tima mask bit\n// used for our falling edge detector\n// See The docs linked above, or TCAGB for this bit mapping\nfunction _getTimerCounterMaskBit(timerInputClock: i32): i32 {\n  switch (timerInputClock) {\n    case 0x00:\n      return 9;\n    case 0x01:\n      return 3;\n    case 0x02:\n      return 5;\n    case 0x03:\n      return 7;\n  }\n  return 0;\n}\n","// Link cable / serial implementation\n// http://gbdev.gg8.se/wiki/articles/Serial_Data_Transfer_(Link_Cable)\n// See TCAGBD, This is like Timer with the Falling Edge detectors\n\nimport { Cpu } from '../cpu/index';\nimport { eightBitLoadFromGBMemory, eightBitStoreIntoGBMemory } from '../memory/index';\nimport { requestSerialInterrupt } from '../interrupts/index';\nimport { checkBitOnByte, resetBitOnByte } from '../helpers/index';\n\nexport class Serial {\n  // Cycle counter\n  static currentCycles: i32 = 0x00;\n\n  // Register locations\n  static readonly memoryLocationSerialTransferData: i32 = 0xff01; // SB\n  static readonly memoryLocationSerialTransferControl: i32 = 0xff02; // SC\n\n  // Number of bits transferred\n  static numberOfBitsTransferred: i32 = 0;\n\n  // Transfer control variables\n  static isShiftClockInternal: boolean = false;\n  static isClockSpeedFast: boolean = false;\n  static transferStartFlag: boolean = false;\n\n  static updateTransferControl(value: i32): boolean {\n    Serial.isShiftClockInternal = checkBitOnByte(0, value);\n    Serial.isClockSpeedFast = checkBitOnByte(1, value);\n    Serial.transferStartFlag = checkBitOnByte(7, value);\n\n    // Allow the original write, and return since we dont need to look anymore\n    return true;\n  }\n}\n\n// Function to initialize our serial values\n// Inlined because closure compiler inlines\nexport function initializeSerial(): void {\n  Serial.currentCycles = 0x00;\n  Serial.numberOfBitsTransferred = 0;\n\n  if (Cpu.GBCEnabled) {\n    // FF01 = 0x00\n    eightBitStoreIntoGBMemory(0xff02, 0x7c);\n    Serial.updateTransferControl(0x7c);\n  } else {\n    // FF01 = 0x00\n    eightBitStoreIntoGBMemory(0xff02, 0x7e);\n    Serial.updateTransferControl(0x7e);\n  }\n}\n\n// TODO: Finish serial\n// See minimal serial: https://github.com/binji/binjgb/commit/64dece05c4ef5a052c4b9b75eb3ddbbfc6677cbe\n// Inlined because closure compiler inlines\nexport function updateSerial(numberOfCycles: i32): void {\n  // If we aren't starting our transfer, or transferring,\n  // return\n  if (!Serial.transferStartFlag) {\n    return;\n  }\n\n  // Want to increment 4 cycles at a time like an actual GB would\n  let cyclesIncreased: i32 = 0;\n  while (cyclesIncreased < numberOfCycles) {\n    let oldCycles = Serial.currentCycles;\n    let curCycles = oldCycles;\n    cyclesIncreased += 4;\n    curCycles += 4;\n\n    if (curCycles > 0xffff) {\n      curCycles -= 0x10000;\n    }\n\n    Serial.currentCycles = curCycles;\n    if (_checkFallingEdgeDetector(oldCycles, curCycles)) {\n      // TODO: Since no actual connection, always transfer 1\n      // Need to fix this\n      let memoryLocationSerialTransferData = Serial.memoryLocationSerialTransferData;\n      let transferData = eightBitLoadFromGBMemory(memoryLocationSerialTransferData);\n      transferData = (transferData << 1) + 1;\n      transferData = transferData & 0xff;\n      eightBitStoreIntoGBMemory(memoryLocationSerialTransferData, transferData);\n      let numberOfBitsTransferred = Serial.numberOfBitsTransferred;\n\n      if (++numberOfBitsTransferred === 8) {\n        Serial.numberOfBitsTransferred = 0;\n        requestSerialInterrupt();\n\n        // Disable transfer start\n        let memoryLocationSerialTransferControl = Serial.memoryLocationSerialTransferControl;\n        let transferControl = eightBitLoadFromGBMemory(memoryLocationSerialTransferControl);\n        eightBitStoreIntoGBMemory(memoryLocationSerialTransferControl, resetBitOnByte(7, transferControl));\n        Serial.transferStartFlag = false;\n      } else {\n        Serial.numberOfBitsTransferred = numberOfBitsTransferred;\n      }\n    }\n  }\n}\n\n// Inlined because closure compiler inlines\nfunction _checkFallingEdgeDetector(oldCycles: i32, newCycles: i32): boolean {\n  // Get our mask\n  let maskBit = _getFallingEdgeMaskBit();\n\n  // If the old register's watched bit was zero,\n  // but after adding the new registers wastch bit is now 1\n  return checkBitOnByte(maskBit, oldCycles) && !checkBitOnByte(maskBit, newCycles);\n}\n\n// Function to get our current tima mask bit\n// used for our falling edge detector\n// See The docs linked above, or TCAGB for this bit mapping\n// Inlined because closure compiler inlines\nfunction _getFallingEdgeMaskBit(): i32 {\n  return Serial.isClockSpeedFast ? 2 : 7;\n}\n","import { Cpu } from '../cpu/index';\nimport { eightBitLoadFromGBMemory } from '../memory/load';\nimport { requestJoypadInterrupt } from '../interrupts/index';\nimport { checkBitOnByte, setBitOnByte, resetBitOnByte } from '../helpers/index';\n\n// http://www.codeslinger.co.uk/pages/projects/gameboy/joypad.html\n// Joypad Register\n// Taken from pandocs\n// Bit 7 - Not used\n// Bit 6 - Not used\n// Bit 5 - P15 Select Button Keys (0=Select)\n// Bit 4 - P14 Select Direction Keys (0=Select)\n// Bit 3 - P13 Input Down or Start (0=Pressed) (Read Only)\n// Bit 2 - P12 Input Up or Select (0=Pressed) (Read Only)\n// Bit 1 - P11 Input Left or Button B (0=Pressed) (Read Only)\n// Bit 0 - P10 Input Right or Button A (0=Pressed) (Read Only)\n\n// Button Ids will be the following:\n// UP - 0\n// RIGHT - 1\n// DOWN - 2\n// LEFT - 3\n// A - 4\n// B - 5\n// SELECT - 6\n// START - 7\n\nexport class Joypad {\n  static up: boolean = false;\n  static down: boolean = false;\n  static left: boolean = false;\n  static right: boolean = false;\n  static a: boolean = false;\n  static b: boolean = false;\n  static select: boolean = false;\n  static start: boolean = false;\n\n  static readonly memoryLocationJoypadRegister: i32 = 0xff00;\n  // Cache some values on the Joypad register\n  static joypadRegisterFlipped: i32 = 0;\n  static isDpadType: boolean = false;\n  static isButtonType: boolean = false;\n  static updateJoypad(value: i32): void {\n    Joypad.joypadRegisterFlipped = value ^ 0xff;\n    Joypad.isDpadType = checkBitOnByte(4, Joypad.joypadRegisterFlipped);\n    Joypad.isButtonType = checkBitOnByte(5, Joypad.joypadRegisterFlipped);\n  }\n\n  // Save States\n  // Not doing anything for Joypad for now\n\n  static readonly saveStateSlot: i32 = 3;\n\n  // Function to save the state of the class\n  static saveState(): void {}\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    Joypad.updateJoypad(eightBitLoadFromGBMemory(Joypad.memoryLocationJoypadRegister));\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function getJoypadState(): i32 {\n  // Get the joypad register\n  let joypadRegister: i32 = Joypad.joypadRegisterFlipped;\n\n  if (Joypad.isDpadType) {\n    // D-pad buttons\n\n    // Up\n    if (Joypad.up) {\n      joypadRegister = resetBitOnByte(2, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(2, joypadRegister);\n    }\n\n    // Right\n    if (Joypad.right) {\n      joypadRegister = resetBitOnByte(0, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(0, joypadRegister);\n    }\n\n    // Down\n    if (Joypad.down) {\n      joypadRegister = resetBitOnByte(3, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(3, joypadRegister);\n    }\n\n    // Left\n    if (Joypad.left) {\n      joypadRegister = resetBitOnByte(1, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(1, joypadRegister);\n    }\n  } else if (Joypad.isButtonType) {\n    // A\n    if (Joypad.a) {\n      joypadRegister = resetBitOnByte(0, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(0, joypadRegister);\n    }\n\n    // B\n    if (Joypad.b) {\n      joypadRegister = resetBitOnByte(1, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(1, joypadRegister);\n    }\n\n    // Select\n    if (Joypad.select) {\n      joypadRegister = resetBitOnByte(2, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(2, joypadRegister);\n    }\n\n    // Start\n    if (Joypad.start) {\n      joypadRegister = resetBitOnByte(3, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(3, joypadRegister);\n    }\n  }\n\n  // Set the top 4 bits to on\n  joypadRegister = joypadRegister | 0xf0;\n\n  return joypadRegister;\n}\n\nexport function setJoypadState(up: i32, right: i32, down: i32, left: i32, a: i32, b: i32, select: i32, start: i32): void {\n  if (up > 0) {\n    _pressJoypadButton(0);\n  } else {\n    _releaseJoypadButton(0);\n  }\n\n  if (right > 0) {\n    _pressJoypadButton(1);\n  } else {\n    _releaseJoypadButton(1);\n  }\n\n  if (down > 0) {\n    _pressJoypadButton(2);\n  } else {\n    _releaseJoypadButton(2);\n  }\n\n  if (left > 0) {\n    _pressJoypadButton(3);\n  } else {\n    _releaseJoypadButton(3);\n  }\n\n  if (a > 0) {\n    _pressJoypadButton(4);\n  } else {\n    _releaseJoypadButton(4);\n  }\n\n  if (b > 0) {\n    _pressJoypadButton(5);\n  } else {\n    _releaseJoypadButton(5);\n  }\n\n  if (select > 0) {\n    _pressJoypadButton(6);\n  } else {\n    _releaseJoypadButton(6);\n  }\n\n  if (start > 0) {\n    _pressJoypadButton(7);\n  } else {\n    _releaseJoypadButton(7);\n  }\n}\n\nfunction _pressJoypadButton(buttonId: i32): void {\n  // Un stop the CPU\n  Cpu.isStopped = false;\n\n  // Check if the button state changed from not pressed\n  let isButtonStateChanging: boolean = false;\n  if (!_getJoypadButtonStateFromButtonId(buttonId)) {\n    isButtonStateChanging = true;\n  }\n\n  // Set our joypad state\n  _setJoypadButtonStateFromButtonId(buttonId, true);\n\n  // If the button state is changing, check for an interrupt\n  if (isButtonStateChanging) {\n    // Determine if it is a button or a dpad button\n    let isDpadTypeButton = false;\n    if (buttonId <= 3) {\n      isDpadTypeButton = true;\n    }\n\n    // Determine if we should request an interrupt\n    let shouldRequestInterrupt = false;\n\n    // Check if the game is looking for a dpad type button press\n    if (Joypad.isDpadType && isDpadTypeButton) {\n      shouldRequestInterrupt = true;\n    }\n\n    // Check if the game is looking for a button type button press\n    if (Joypad.isButtonType && !isDpadTypeButton) {\n      shouldRequestInterrupt = true;\n    }\n\n    // Finally, request the interrupt, if the button state actually changed\n    if (shouldRequestInterrupt) {\n      requestJoypadInterrupt();\n    }\n  }\n}\n\n// Inlined because closure compiler inlines\nfunction _releaseJoypadButton(buttonId: i32): void {\n  // Set our joypad state\n  _setJoypadButtonStateFromButtonId(buttonId, false);\n}\n\nfunction _getJoypadButtonStateFromButtonId(buttonId: i32): boolean {\n  switch (buttonId) {\n    case 0:\n      return Joypad.up;\n    case 1:\n      return Joypad.right;\n    case 2:\n      return Joypad.down;\n    case 3:\n      return Joypad.left;\n    case 4:\n      return Joypad.a;\n    case 5:\n      return Joypad.b;\n    case 6:\n      return Joypad.select;\n    case 7:\n      return Joypad.start;\n    default:\n      return false;\n  }\n}\n\nfunction _setJoypadButtonStateFromButtonId(buttonId: i32, isPressed: boolean): void {\n  switch (buttonId) {\n    case 0:\n      Joypad.up = isPressed;\n      break;\n    case 1:\n      Joypad.right = isPressed;\n      break;\n    case 2:\n      Joypad.down = isPressed;\n      break;\n    case 3:\n      Joypad.left = isPressed;\n      break;\n    case 4:\n      Joypad.a = isPressed;\n      break;\n    case 5:\n      Joypad.b = isPressed;\n      break;\n    case 6:\n      Joypad.select = isPressed;\n      break;\n    case 7:\n      Joypad.start = isPressed;\n      break;\n  }\n}\n","// Breakpoints for memory / cpu\nexport class Breakpoints {\n  static programCounter: i32 = -1;\n  static readGbMemory: i32 = -1;\n  static writeGbMemory: i32 = -1;\n  static reachedBreakpoint: boolean = false;\n}\n\nexport function breakpoint(): void {\n  Breakpoints.reachedBreakpoint = true;\n}\n\nexport function setProgramCounterBreakpoint(breakpoint: i32): void {\n  Breakpoints.programCounter = breakpoint;\n}\n\nexport function resetProgramCounterBreakpoint(): void {\n  Breakpoints.programCounter = -1;\n}\n\nexport function setReadGbMemoryBreakpoint(breakpoint: i32): void {\n  Breakpoints.readGbMemory = breakpoint;\n}\n\nexport function resetReadGbMemoryBreakpoint(): void {\n  Breakpoints.readGbMemory = -1;\n}\n\nexport function setWriteGbMemoryBreakpoint(breakpoint: i32): void {\n  Breakpoints.writeGbMemory = breakpoint;\n}\n\nexport function resetWriteGbMemoryBreakpoint(): void {\n  Breakpoints.writeGbMemory = -1;\n}\n","// Funcitons for setting and checking the LCD\nimport { Graphics } from './graphics';\n// Assembly script really not feeling the reexport\nimport { eightBitLoadFromGBMemory } from '../memory/load';\nimport { eightBitStoreIntoGBMemory } from '../memory/store';\nimport { updateHblankHdma } from '../memory/index';\nimport { requestLcdInterrupt, requestVBlankInterrupt } from '../interrupts/index';\nimport { checkBitOnByte, setBitOnByte, resetBitOnByte } from '../helpers/index';\nimport { FRAME_LOCATION, FRAME_SIZE } from '../constants';\n\nexport class Lcd {\n  // Memory Locations\n  // Also known at STAT\n  // LCD Status (0xFF41) bits Explanation\n  // 0                0                    000                    0             00\n  //       |Coicedence Interrupt|     |Mode Interrupts|  |coincidence flag|  | Mode |\n  // Modes:\n  // 0 or 00: H-Blank\n  // 1 or 01: V-Blank\n  // 2 or 10: Searching Sprites Atts\n  // 3 or 11: Transfering Data to LCD Driver\n  static readonly memoryLocationLcdStatus: i32 = 0xff41;\n  static currentLcdMode: i32 = 0;\n  // Function called in write traps to update our hardware registers\n  static updateLcdStatus(value: i32): void {\n    // Bottom three bits are read only\n    let currentLcdStatus: i32 = eightBitLoadFromGBMemory(Lcd.memoryLocationLcdStatus);\n    let valueNoBottomBits = value & 0xf8;\n    let lcdStatusOnlyBottomBits = currentLcdStatus & 0x07;\n    value = valueNoBottomBits | lcdStatusOnlyBottomBits;\n\n    // Top bit is always 1\n    value = setBitOnByte(7, value);\n\n    eightBitStoreIntoGBMemory(Lcd.memoryLocationLcdStatus, value);\n  }\n\n  static readonly memoryLocationCoincidenceCompare: i32 = 0xff45;\n  static coincidenceCompare: i32 = 0;\n\n  // Also known as LCDC\n  // http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html\n  // Bit 7 - LCD Display Enable (0=Off, 1=On)\n  // Bit 6 - Window Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)\n  // Bit 5 - Window Display Enable (0=Off, 1=On)\n  // Bit 4 - BG & Window Tile Data Select (0=8800-97FF, 1=8000-8FFF)\n  // Bit 3 - BG Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)\n  // Bit 2 - OBJ (Sprite) Size (0=8x8, 1=8x16)\n  // Bit 1 - OBJ (Sprite) Display Enable (0=Off, 1=On)\n  // Bit 0 - BG Display (for CGB see below) (0=Off, 1=On\n  static readonly memoryLocationLcdControl: i32 = 0xff40;\n  // Decoupled LCDC for caching\n  static enabled: boolean = true;\n  static windowTileMapDisplaySelect: boolean = false;\n  static windowDisplayEnabled: boolean = false;\n  static bgWindowTileDataSelect: boolean = false;\n  static bgTileMapDisplaySelect: boolean = false;\n  static tallSpriteSize: boolean = false;\n  static spriteDisplayEnable: boolean = false;\n  static bgDisplayEnabled: boolean = false;\n\n  // Function called in write traps to update our hardware registers\n  static updateLcdControl(value: i32): void {\n    let wasLcdEnabled = Lcd.enabled;\n\n    Lcd.enabled = checkBitOnByte(7, value);\n    Lcd.windowTileMapDisplaySelect = checkBitOnByte(6, value);\n    Lcd.windowDisplayEnabled = checkBitOnByte(5, value);\n    Lcd.bgWindowTileDataSelect = checkBitOnByte(4, value);\n    Lcd.bgTileMapDisplaySelect = checkBitOnByte(3, value);\n    Lcd.tallSpriteSize = checkBitOnByte(2, value);\n    Lcd.spriteDisplayEnable = checkBitOnByte(1, value);\n    Lcd.bgDisplayEnabled = checkBitOnByte(0, value);\n\n    if (wasLcdEnabled && !Lcd.enabled) {\n      // Disable the LCD\n      resetLcd(true);\n    }\n\n    if (!wasLcdEnabled && Lcd.enabled) {\n      // Re-enable the LCD\n      resetLcd(false);\n    }\n  }\n}\n\nfunction resetLcd(shouldBlankScreen: boolean): void {\n  // Reset scanline cycle counter\n  Graphics.scanlineCycleCounter = 0;\n  Graphics.scanlineRegister = 0;\n  eightBitStoreIntoGBMemory(Graphics.memoryLocationScanlineRegister, 0);\n\n  // Set to mode 0\n  // https://www.reddit.com/r/EmuDev/comments/4w6479/gb_dr_mario_level_generation_issues/\n  let lcdStatus: i32 = eightBitLoadFromGBMemory(Lcd.memoryLocationLcdStatus);\n  lcdStatus = resetBitOnByte(1, lcdStatus);\n  lcdStatus = resetBitOnByte(0, lcdStatus);\n  Lcd.currentLcdMode = 0;\n\n  // Store the status in memory\n  eightBitStoreIntoGBMemory(Lcd.memoryLocationLcdStatus, lcdStatus);\n\n  // Blank the screen\n  if (shouldBlankScreen) {\n    for (let i = 0; i < FRAME_SIZE; ++i) {\n      store<u8>(FRAME_LOCATION + i, 255);\n    }\n  }\n}\n\n// Pass in the lcd status for performance\n// Inlined because closure compiler inlines\nexport function setLcdStatus(): void {\n  // Check if the Lcd was disabled\n  if (!Lcd.enabled) {\n    return;\n  }\n\n  // Get our current scanline, and lcd mode\n  let scanlineRegister: i32 = Graphics.scanlineRegister;\n  let lcdMode: i32 = Lcd.currentLcdMode;\n\n  // Default to  H-Blank\n  let newLcdMode = 0;\n\n  // Find our newLcd mode\n  if (scanlineRegister >= 144) {\n    // VBlank mode\n    newLcdMode = 1;\n  } else {\n    let scanlineCycleCounter = Graphics.scanlineCycleCounter;\n    let MIN_CYCLES_SPRITES_LCD_MODE = Graphics.MIN_CYCLES_SPRITES_LCD_MODE();\n    if (scanlineCycleCounter >= MIN_CYCLES_SPRITES_LCD_MODE) {\n      // Searching Sprites Atts\n      newLcdMode = 2;\n    } else if (scanlineCycleCounter >= MIN_CYCLES_SPRITES_LCD_MODE) {\n      // Transferring data to lcd\n      newLcdMode = 3;\n    }\n  }\n\n  if (lcdMode !== newLcdMode) {\n    // Get our lcd status\n    let lcdStatus: i32 = eightBitLoadFromGBMemory(Lcd.memoryLocationLcdStatus);\n\n    // Save our lcd mode\n    Lcd.currentLcdMode = newLcdMode;\n\n    let shouldRequestInterrupt = false;\n\n    // Set our LCD Status accordingly\n    switch (newLcdMode) {\n      case 0x00:\n        lcdStatus = resetBitOnByte(0, lcdStatus);\n        lcdStatus = resetBitOnByte(1, lcdStatus);\n        shouldRequestInterrupt = checkBitOnByte(3, lcdStatus);\n        break;\n      case 0x01:\n        lcdStatus = resetBitOnByte(1, lcdStatus);\n        lcdStatus = setBitOnByte(0, lcdStatus);\n        shouldRequestInterrupt = checkBitOnByte(4, lcdStatus);\n        break;\n      case 0x02:\n        lcdStatus = resetBitOnByte(0, lcdStatus);\n        lcdStatus = setBitOnByte(1, lcdStatus);\n        shouldRequestInterrupt = checkBitOnByte(5, lcdStatus);\n        break;\n      case 0x03:\n        lcdStatus = setBitOnByte(0, lcdStatus);\n        lcdStatus = setBitOnByte(1, lcdStatus);\n        break;\n    }\n\n    // Check if we want to request an interrupt, and we JUST changed modes\n    if (shouldRequestInterrupt) {\n      requestLcdInterrupt();\n    }\n\n    // Check for updating the Hblank HDMA\n    if (newLcdMode === 0) {\n      // Update the Hblank DMA, will simply return if not active\n      updateHblankHdma();\n    }\n\n    // Check for requesting a VBLANK interrupt\n    if (newLcdMode === 1) {\n      requestVBlankInterrupt();\n    }\n\n    // Check for the coincidence\n    lcdStatus = checkCoincidence(newLcdMode, lcdStatus);\n\n    // Finally, save our status\n    eightBitStoreIntoGBMemory(Lcd.memoryLocationLcdStatus, lcdStatus);\n  } else if (scanlineRegister === 153) {\n    // Special Case, need to check LYC\n    // Fix prehistorik man freeze\n    let lcdStatus: i32 = eightBitLoadFromGBMemory(Lcd.memoryLocationLcdStatus);\n    lcdStatus = checkCoincidence(newLcdMode, lcdStatus);\n    eightBitStoreIntoGBMemory(Lcd.memoryLocationLcdStatus, lcdStatus);\n  }\n}\n\nfunction checkCoincidence(lcdMode: i32, lcdStatus: i32): i32 {\n  // Check for the coincidence flag\n  // Need to check on every mode, and not just HBLANK, as checking on hblank breaks shantae, which checks on vblank\n  if ((lcdMode === 0 || lcdMode === 1) && Graphics.scanlineRegister === Lcd.coincidenceCompare) {\n    lcdStatus = setBitOnByte(2, lcdStatus);\n    if (checkBitOnByte(6, lcdStatus)) {\n      requestLcdInterrupt();\n    }\n  } else {\n    lcdStatus = resetBitOnByte(2, lcdStatus);\n  }\n\n  return lcdStatus;\n}\n","// Main Class and funcitons for rendering the gameboy display\nimport { FRAME_LOCATION, GAMEBOY_INTERNAL_MEMORY_LOCATION } from '../constants';\nimport { getSaveStateMemoryOffset } from '../core';\nimport { Lcd, setLcdStatus } from './lcd';\nimport { renderBackground, renderWindow } from './backgroundWindow';\nimport { renderSprites } from './sprites';\nimport { clearPriorityMap } from './priority';\nimport { resetTileCache } from './tiles';\nimport { initializeColors } from './colors';\nimport { Cpu } from '../cpu/index';\nimport { Config } from '../config';\nimport { Memory, eightBitLoadFromGBMemory, eightBitStoreIntoGBMemory } from '../memory/index';\n\nexport class Graphics {\n  // Current cycles\n  // This will be used for batch processing\n  static currentCycles: i32 = 0;\n\n  // Number of cycles to run in each batch process\n  // This number should be in sync so that graphics doesn't run too many cyles at once\n  // and does not exceed the minimum number of cyles for either scanlines, or\n  // How often we change the frame, or a channel's update process\n  static batchProcessCycles(): i32 {\n    return Graphics.MAX_CYCLES_PER_SCANLINE();\n  }\n\n  // Count the number of cycles to keep synced with cpu cycles\n  // Found GBC cycles by finding clock speed from Gb Cycles\n  // See TCAGBD For cycles\n  static scanlineCycleCounter: i32 = 0x00;\n\n  // TCAGBD says 456 per scanline, but 153 only a handful\n  static MAX_CYCLES_PER_SCANLINE(): i32 {\n    if (Graphics.scanlineRegister === 153) {\n      return 4 << (<i32>Cpu.GBCDoubleSpeed);\n    } else {\n      return 456 << (<i32>Cpu.GBCDoubleSpeed);\n    }\n  }\n\n  static MIN_CYCLES_SPRITES_LCD_MODE(): i32 {\n    // TODO: Confirm these clock cyles, double similar to scanline, which TCAGBD did\n    return 376 << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  static MIN_CYCLES_TRANSFER_DATA_LCD_MODE(): i32 {\n    // TODO: Confirm these clock cyles, double similar to scanline, which TCAGBD did\n    return 249 << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  // LCD\n  // scanlineRegister also known as LY\n  // See: http://bgb.bircd.org/pandocs.txt , and search \" LY \"\n  static readonly memoryLocationScanlineRegister: i32 = 0xff44;\n  static scanlineRegister: i32 = 0;\n  static readonly memoryLocationDmaTransfer: i32 = 0xff46;\n\n  // Scroll and Window\n  static readonly memoryLocationScrollX: i32 = 0xff43;\n  static scrollX: i32 = 0;\n  static readonly memoryLocationScrollY: i32 = 0xff42;\n  static scrollY: i32 = 0;\n  static readonly memoryLocationWindowX: i32 = 0xff4b;\n  static windowX: i32 = 0;\n  static readonly memoryLocationWindowY: i32 = 0xff4a;\n  static windowY: i32 = 0;\n\n  // Tile Maps And Data\n  static readonly memoryLocationTileMapSelectZeroStart: i32 = 0x9800;\n  static readonly memoryLocationTileMapSelectOneStart: i32 = 0x9c00;\n  static readonly memoryLocationTileDataSelectZeroStart: i32 = 0x8800;\n  static readonly memoryLocationTileDataSelectOneStart: i32 = 0x8000;\n\n  // Sprites\n  static readonly memoryLocationSpriteAttributesTable: i32 = 0xfe00;\n\n  // Palettes\n  static readonly memoryLocationBackgroundPalette: i32 = 0xff47;\n  static readonly memoryLocationSpritePaletteOne: i32 = 0xff48;\n  static readonly memoryLocationSpritePaletteTwo: i32 = 0xff49;\n\n  // Screen data needs to be stored in wasm memory\n\n  // Save States\n\n  static readonly saveStateSlot: i32 = 1;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    store<i32>(getSaveStateMemoryOffset(0x00, Graphics.saveStateSlot), Graphics.scanlineCycleCounter);\n    store<u8>(getSaveStateMemoryOffset(0x04, Graphics.saveStateSlot), <u8>Lcd.currentLcdMode);\n\n    eightBitStoreIntoGBMemory(Graphics.memoryLocationScanlineRegister, Graphics.scanlineRegister);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    Graphics.scanlineCycleCounter = load<i32>(getSaveStateMemoryOffset(0x00, Graphics.saveStateSlot));\n    Lcd.currentLcdMode = load<u8>(getSaveStateMemoryOffset(0x04, Graphics.saveStateSlot));\n\n    Graphics.scanlineRegister = eightBitLoadFromGBMemory(Graphics.memoryLocationScanlineRegister);\n    Lcd.updateLcdControl(eightBitLoadFromGBMemory(Lcd.memoryLocationLcdControl));\n  }\n}\n\n// Batch Process Graphics\n// http://gameboy.mongenel.com/dmg/asmmemmap.html and http://gbdev.gg8.se/wiki/articles/Video_Display\n// Function to batch process our graphics after we skipped so many cycles\n// This is not currently checked in memory read/write\nexport function batchProcessGraphics(): void {\n  var batchProcessCycles = Graphics.batchProcessCycles();\n  while (Graphics.currentCycles >= batchProcessCycles) {\n    updateGraphics(batchProcessCycles);\n    Graphics.currentCycles -= batchProcessCycles;\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function initializeGraphics(): void {\n  // Reset Stateful Variables\n  Graphics.currentCycles = 0;\n  Graphics.scanlineCycleCounter = 0x00;\n  Graphics.scanlineRegister = 0;\n  Graphics.scrollX = 0;\n  Graphics.scrollY = 0;\n  Graphics.windowX = 0;\n  Graphics.windowY = 0;\n\n  Graphics.scanlineRegister = 0x90;\n\n  if (Cpu.GBCEnabled) {\n    eightBitStoreIntoGBMemory(0xff41, 0x81);\n    // 0xFF42 -> 0xFF43 = 0x00\n    eightBitStoreIntoGBMemory(0xff44, 0x90);\n    // 0xFF45 -> 0xFF46 = 0x00\n    eightBitStoreIntoGBMemory(0xff47, 0xfc);\n    // 0xFF48 -> 0xFF4B = 0x00\n  } else {\n    eightBitStoreIntoGBMemory(0xff41, 0x85);\n    // 0xFF42 -> 0xFF45 = 0x00\n    eightBitStoreIntoGBMemory(0xff46, 0xff);\n    eightBitStoreIntoGBMemory(0xff47, 0xfc);\n    eightBitStoreIntoGBMemory(0xff48, 0xff);\n    eightBitStoreIntoGBMemory(0xff49, 0xff);\n    // 0xFF4A -> 0xFF4B = 0x00\n    // GBC VRAM Banks (Handled by Memory, initializeCartridge)\n  }\n\n  // Scanline\n  // Bgb says LY is 90 on boot\n  Graphics.scanlineRegister = 0x90;\n  eightBitStoreIntoGBMemory(0xff40, 0x90);\n\n  // GBC VRAM Banks\n  eightBitStoreIntoGBMemory(0xff4f, 0x00);\n  eightBitStoreIntoGBMemory(0xff70, 0x01);\n\n  // Override/reset some variables if the boot ROM is enabled\n  if (Cpu.BootROMEnabled) {\n    if (Cpu.GBCEnabled) {\n      // GBC\n      Graphics.scanlineRegister = 0x00;\n      eightBitStoreIntoGBMemory(0xff40, 0x00);\n      eightBitStoreIntoGBMemory(0xff41, 0x80);\n      eightBitStoreIntoGBMemory(0xff44, 0x00);\n    } else {\n      // GB\n      Graphics.scanlineRegister = 0x00;\n      eightBitStoreIntoGBMemory(0xff40, 0x00);\n      eightBitStoreIntoGBMemory(0xff41, 0x84);\n    }\n  }\n\n  initializeColors();\n}\n\nexport function updateGraphics(numberOfCycles: i32): void {\n  if (Lcd.enabled) {\n    Graphics.scanlineCycleCounter += numberOfCycles;\n\n    let graphicsDisableScanlineRendering = Config.graphicsDisableScanlineRendering;\n\n    while (Graphics.scanlineCycleCounter >= Graphics.MAX_CYCLES_PER_SCANLINE()) {\n      // Reset the scanlineCycleCounter\n      // Don't set to zero to catch extra cycles\n      Graphics.scanlineCycleCounter -= Graphics.MAX_CYCLES_PER_SCANLINE();\n\n      // Move to next scanline\n      // let scanlineRegister: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationScanlineRegister);\n      let scanlineRegister = Graphics.scanlineRegister;\n\n      // Check if we've reached the last scanline\n      if (scanlineRegister === 144) {\n        // Draw the scanline\n        if (!graphicsDisableScanlineRendering) {\n          _drawScanline(scanlineRegister);\n        } else {\n          _renderEntireFrame();\n        }\n\n        // Clear the priority map\n        clearPriorityMap();\n\n        // Reset the tile cache\n        resetTileCache();\n      } else if (scanlineRegister < 144) {\n        // Draw the scanline\n        if (!graphicsDisableScanlineRendering) {\n          _drawScanline(scanlineRegister);\n        }\n      }\n\n      // Post increment the scanline register after drawing\n      // TODO: Need to fix graphics timing\n      if (scanlineRegister > 153) {\n        // Check if we overflowed scanlines\n        // if so, reset our scanline number\n        scanlineRegister = 0;\n      } else {\n        scanlineRegister += 1;\n      }\n\n      // Store our new scanline value\n      Graphics.scanlineRegister = scanlineRegister;\n      // eightBitStoreIntoGBMemory(Graphics.memoryLocationScanlineRegister, scanlineRegister);\n    }\n  }\n\n  // Games like Pokemon crystal want the vblank right as it turns to the value, and not have it increment after\n  // It will break and lead to an infinite loop in crystal\n  // Therefore, we want to be checking/Setting our LCD status after the scanline updates\n  setLcdStatus();\n}\n\n// TODO: Make this a _drawPixelOnScanline, as values can be updated while drawing a scanline\nfunction _drawScanline(scanlineRegister: i32): void {\n  // Get our seleted tile data memory location\n  let tileDataMemoryLocation = Graphics.memoryLocationTileDataSelectZeroStart;\n  if (Lcd.bgWindowTileDataSelect) {\n    tileDataMemoryLocation = Graphics.memoryLocationTileDataSelectOneStart;\n  }\n\n  // Check if the background is enabled\n  // NOTE: On Gameboy color, Pandocs says this does something completely different\n  // LCDC.0 - 2) CGB in CGB Mode: BG and Window Master Priority\n  // When Bit 0 is cleared, the background and window lose their priority -\n  // the sprites will be always displayed on top of background and window,\n  // independently of the priority flags in OAM and BG Map attributes.\n  // TODO: Enable this different feature for GBC\n  if (Cpu.GBCEnabled || Lcd.bgDisplayEnabled) {\n    // Get our map memory location\n    let tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectZeroStart;\n    if (Lcd.bgTileMapDisplaySelect) {\n      tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectOneStart;\n    }\n\n    // Finally, pass everything to draw the background\n    renderBackground(scanlineRegister, tileDataMemoryLocation, tileMapMemoryLocation);\n  }\n\n  // Check if the window is enabled, and we are currently\n  // Drawing lines on the window\n  if (Lcd.windowDisplayEnabled) {\n    // Get our map memory location\n    let tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectZeroStart;\n    if (Lcd.windowTileMapDisplaySelect) {\n      tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectOneStart;\n    }\n\n    // Finally, pass everything to draw the background\n    renderWindow(scanlineRegister, tileDataMemoryLocation, tileMapMemoryLocation);\n  }\n\n  if (Lcd.spriteDisplayEnable) {\n    // Sprites are enabled, render them!\n    renderSprites(scanlineRegister, Lcd.tallSpriteSize);\n  }\n}\n\n// Function to render everything for a frame at once\n// This is to improve performance\n// See above for comments on how things are donw\nfunction _renderEntireFrame(): void {\n  // Scanline needs to be in sync while we draw, thus, we can't shortcut anymore than here\n  for (let i = 0; i <= 144; ++i) {\n    _drawScanline(<u8>i);\n  }\n}\n\n// Function to get the start of a RGB pixel (R, G, B)\n// Inlined because closure compiler inlines\nexport function getRgbPixelStart(x: i32, y: i32): i32 {\n  // Get the pixel number\n  // let pixelNumber: i32 = (y * 160) + x;\n  // Each pixel takes 3 slots, therefore, multiply by 3!\n  return (y * 160 + x) * 3;\n}\n\n// Also need to store current frame in memory to be read by JS\nexport function setPixelOnFrame(x: i32, y: i32, colorId: i32, color: i32): void {\n  // Currently only supports 160x144\n  // Storing in X, then y\n  // So need an offset\n  store<u8>(FRAME_LOCATION + getRgbPixelStart(x, y) + colorId, color);\n}\n\n// Function to shortcut the memory map, and load directly from the VRAM Bank\nexport function loadFromVramBank(gameboyOffset: i32, vramBankId: i32): u8 {\n  let wasmBoyAddress = gameboyOffset - Memory.videoRamLocation + GAMEBOY_INTERNAL_MEMORY_LOCATION + 0x2000 * (vramBankId & 0x01);\n  return load<u8>(wasmBoyAddress);\n}\n","// WasmBoy memory map:\n// https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit?usp=sharing\nimport { getSaveStateMemoryOffset } from '../core';\nimport { eightBitLoadFromGBMemory, loadBooleanDirectlyFromWasmMemory } from './load';\nimport { eightBitStoreIntoGBMemory, storeBooleanDirectlyToWasmMemory } from './store';\n\nexport class Memory {\n  // ----------------------------------\n  // Gameboy Memory Map\n  // ----------------------------------\n  // https://github.com/AntonioND/giibiiadvance/blob/master/docs/TCAGBD.pdf\n  // http://gameboy.mongenel.com/dmg/asmmemmap.html\n  // using Arrays, first index is start, second is end\n  static readonly cartridgeRomLocation: i32 = 0x0000;\n\n  static readonly switchableCartridgeRomLocation: i32 = 0x4000;\n\n  static readonly videoRamLocation: i32 = 0x8000;\n\n  static readonly cartridgeRamLocation: i32 = 0xa000;\n\n  static readonly internalRamBankZeroLocation: i32 = 0xc000;\n\n  // This ram bank is switchable\n  static readonly internalRamBankOneLocation: i32 = 0xd000;\n\n  static readonly echoRamLocation: i32 = 0xe000;\n\n  static readonly spriteInformationTableLocation: i32 = 0xfe00;\n\n  static readonly spriteInformationTableLocationEnd: i32 = 0xfe9f;\n\n  static readonly unusableMemoryLocation: i32 = 0xfea0;\n  static readonly unusableMemoryEndLocation: i32 = 0xfeff;\n\n  // Hardware I/O, 0xFF00 -> 0xFF7F\n  // Zero Page, 0xFF80 -> 0xFFFE\n  // Intterupt Enable Flag, 0xFFFF\n\n  // ----------------------------------\n  // Rom/Ram Banking\n  // ----------------------------------\n  // http://gbdev.gg8.se/wiki/articles/Memory_Bank_Controllers#MBC3_.28max_2MByte_ROM_and.2For_32KByte_RAM_and_Timer.29\n  // http://www.codeslinger.co.uk/pages/projects/gameboy/banking.html\n  static currentRomBank: i32 = 0x00;\n  static currentRamBank: i32 = 0x00;\n  static isRamBankingEnabled: boolean = false;\n  static isMBC1RomModeEnabled: boolean = true;\n\n  // Cartridge Types\n  // http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header\n  static isRomOnly: boolean = true;\n  static isMBC1: boolean = false;\n  static isMBC2: boolean = false;\n  static isMBC3: boolean = false;\n  static isMBC5: boolean = false;\n\n  // DMA\n  static memoryLocationHdmaSourceHigh: i32 = 0xff51;\n  static memoryLocationHdmaSourceLow: i32 = 0xff52;\n  static memoryLocationHdmaDestinationHigh: i32 = 0xff53;\n  static memoryLocationHdmaDestinationLow: i32 = 0xff54;\n  static memoryLocationHdmaTrigger: i32 = 0xff55;\n  // Cycles accumulated for DMA\n  static DMACycles: i32 = 0;\n  // Boolean we will mirror to indicate if Hdma is active\n  static isHblankHdmaActive: boolean = false;\n  static hblankHdmaTransferLengthRemaining: i32 = 0x00;\n  // Store the source and destination for performance, and update as needed\n  static hblankHdmaSource: i32 = 0x00;\n  static hblankHdmaDestination: i32 = 0x00;\n\n  // GBC Registers\n  static memoryLocationGBCVRAMBank: i32 = 0xff4f;\n  static memoryLocationGBCWRAMBank: i32 = 0xff70;\n\n  // Save States\n\n  static readonly saveStateSlot: i32 = 4;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    store<u16>(getSaveStateMemoryOffset(0x00, Memory.saveStateSlot), Memory.currentRomBank);\n    store<u16>(getSaveStateMemoryOffset(0x02, Memory.saveStateSlot), Memory.currentRamBank);\n\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x04, Memory.saveStateSlot), Memory.isRamBankingEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x05, Memory.saveStateSlot), Memory.isMBC1RomModeEnabled);\n\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x06, Memory.saveStateSlot), Memory.isRomOnly);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x07, Memory.saveStateSlot), Memory.isMBC1);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x08, Memory.saveStateSlot), Memory.isMBC2);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x09, Memory.saveStateSlot), Memory.isMBC3);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0a, Memory.saveStateSlot), Memory.isMBC5);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    Memory.currentRomBank = load<u16>(getSaveStateMemoryOffset(0x00, Memory.saveStateSlot));\n    Memory.currentRamBank = load<u16>(getSaveStateMemoryOffset(0x02, Memory.saveStateSlot));\n\n    Memory.isRamBankingEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x04, Memory.saveStateSlot));\n    Memory.isMBC1RomModeEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x05, Memory.saveStateSlot));\n\n    Memory.isRomOnly = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x06, Memory.saveStateSlot));\n    Memory.isMBC1 = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x07, Memory.saveStateSlot));\n    Memory.isMBC2 = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x08, Memory.saveStateSlot));\n    Memory.isMBC3 = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x09, Memory.saveStateSlot));\n    Memory.isMBC5 = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0a, Memory.saveStateSlot));\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function initializeCartridge(): void {\n  // Reset stateful variables\n  Memory.isRamBankingEnabled = false;\n  Memory.isMBC1RomModeEnabled = true;\n\n  // Get our game MBC type from the cartridge header\n  // http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header\n  let cartridgeType = eightBitLoadFromGBMemory(0x0147);\n\n  // Reset our Cartridge types\n  Memory.isRomOnly = cartridgeType === 0x00;\n  Memory.isMBC1 = cartridgeType >= 0x01 && cartridgeType <= 0x03;\n  Memory.isMBC2 = cartridgeType >= 0x05 && cartridgeType <= 0x06;\n  Memory.isMBC3 = cartridgeType >= 0x0f && cartridgeType <= 0x13;\n  Memory.isMBC5 = cartridgeType >= 0x19 && cartridgeType <= 0x1e;\n\n  Memory.currentRomBank = 0x01;\n  Memory.currentRamBank = 0x00;\n\n  // Set our GBC Banks\n  eightBitStoreIntoGBMemory(Memory.memoryLocationGBCVRAMBank, 0x00);\n  eightBitStoreIntoGBMemory(Memory.memoryLocationGBCWRAMBank, 0x01);\n}\n","import { getSaveStateMemoryOffset } from '../core';\nimport { loadBooleanDirectlyFromWasmMemory, storeBooleanDirectlyToWasmMemory } from '../memory/index';\nimport { Interrupts } from '../interrupts/index';\n\n// Everything Static as class instances just aren't quite there yet\n// https://github.com/AssemblyScript/assemblyscript/blob/master/tests/compiler/showcase.ts\nexport class Cpu {\n  // Status to track if we are currently executing the boot rom\n  static readonly memoryLocationBootROMSwitch: u16 = 0xff50;\n  static BootROMEnabled: boolean = false;\n\n  // Status to track if we are in Gameboy Color Mode, and GBC State\n  static GBCEnabled: boolean = false;\n\n  // Memory Location for the GBC Speed switch\n  // And the current status\n  static readonly memoryLocationSpeedSwitch: u16 = 0xff4d;\n  static GBCDoubleSpeed: boolean = false;\n\n  // 8-bit Cpu.registers\n  static registerA: u8 = 0;\n  static registerB: u8 = 0;\n  static registerC: u8 = 0;\n  static registerD: u8 = 0;\n  static registerE: u8 = 0;\n  static registerH: u8 = 0;\n  static registerL: u8 = 0;\n  static registerF: u8 = 0;\n\n  // 16-bit Cpu.registers\n  static stackPointer: u16 = 0;\n  // Boot rom from 0x00 to 0x99, all games start at 0x100\n  static programCounter: u16 = 0x00;\n\n  // Current number of cycles, shouldn't execeed max number of cycles\n  static currentCycles: i32 = 0;\n  static CLOCK_SPEED(): i32 {\n    // 2^23, thanks binji!\n    // return Cpu.GBCDoubleSpeed ? 8388608 : 4194304;\n    return 4194304 << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  // Cycles Per Frame = Clock Speed / fps\n  // So: 4194304 / 59.73\n  static MAX_CYCLES_PER_FRAME(): i32 {\n    // return Cpu.GBCDoubleSpeed ? 140448 : 70224;\n    return 70224 << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  // HALT and STOP instructions need to stop running opcodes, but simply check timers\n  // https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js\n  // Matt said is should work to, so it must work!\n  // TCAGBD shows three different HALT states. Therefore, we need to handle each\n  static isHaltNormal: boolean = false;\n  static isHaltNoJump: boolean = false;\n  static isHaltBug: boolean = false;\n  static isStopped: boolean = false;\n\n  // See section 4.10 of TCAGBD\n  // Cpu Halting explained: https://www.reddit.com/r/EmuDev/comments/5ie3k7/infinite_loop_trying_to_pass_blarggs_interrupt/db7xnbe/\n  static enableHalt(): void {\n    if (Interrupts.masterInterruptSwitch) {\n      Cpu.isHaltNormal = true;\n      return;\n    }\n\n    let haltTypeValue = Interrupts.interruptsEnabledValue & Interrupts.interruptsRequestedValue & 0x1f;\n\n    if (haltTypeValue === 0) {\n      Cpu.isHaltNoJump = true;\n      return;\n    }\n\n    Cpu.isHaltBug = true;\n  }\n\n  static exitHaltAndStop(): void {\n    Cpu.isHaltNoJump = false;\n    Cpu.isHaltNormal = false;\n    Cpu.isHaltBug = false;\n    Cpu.isStopped = false;\n  }\n\n  static isHalted(): boolean {\n    return Cpu.isHaltNormal || Cpu.isHaltNoJump;\n  }\n\n  // Save States\n  static readonly saveStateSlot: u16 = 0;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    // Registers\n    store<u8>(getSaveStateMemoryOffset(0x00, Cpu.saveStateSlot), Cpu.registerA);\n    store<u8>(getSaveStateMemoryOffset(0x01, Cpu.saveStateSlot), Cpu.registerB);\n    store<u8>(getSaveStateMemoryOffset(0x02, Cpu.saveStateSlot), Cpu.registerC);\n    store<u8>(getSaveStateMemoryOffset(0x03, Cpu.saveStateSlot), Cpu.registerD);\n    store<u8>(getSaveStateMemoryOffset(0x04, Cpu.saveStateSlot), Cpu.registerE);\n    store<u8>(getSaveStateMemoryOffset(0x05, Cpu.saveStateSlot), Cpu.registerH);\n    store<u8>(getSaveStateMemoryOffset(0x06, Cpu.saveStateSlot), Cpu.registerL);\n    store<u8>(getSaveStateMemoryOffset(0x07, Cpu.saveStateSlot), Cpu.registerF);\n\n    store<u16>(getSaveStateMemoryOffset(0x08, Cpu.saveStateSlot), Cpu.stackPointer);\n    store<u16>(getSaveStateMemoryOffset(0x0a, Cpu.saveStateSlot), Cpu.programCounter);\n\n    store<i32>(getSaveStateMemoryOffset(0x0c, Cpu.saveStateSlot), Cpu.currentCycles);\n\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x11, Cpu.saveStateSlot), Cpu.isHaltNormal);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x12, Cpu.saveStateSlot), Cpu.isHaltNoJump);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x13, Cpu.saveStateSlot), Cpu.isHaltBug);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x14, Cpu.saveStateSlot), Cpu.isStopped);\n\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x15, Cpu.saveStateSlot), Cpu.BootROMEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x16, Cpu.saveStateSlot), Cpu.GBCEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x17, Cpu.saveStateSlot), Cpu.GBCDoubleSpeed);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    // Registers\n    Cpu.registerA = load<u8>(getSaveStateMemoryOffset(0x00, Cpu.saveStateSlot));\n    Cpu.registerB = load<u8>(getSaveStateMemoryOffset(0x01, Cpu.saveStateSlot));\n    Cpu.registerC = load<u8>(getSaveStateMemoryOffset(0x02, Cpu.saveStateSlot));\n    Cpu.registerD = load<u8>(getSaveStateMemoryOffset(0x03, Cpu.saveStateSlot));\n    Cpu.registerE = load<u8>(getSaveStateMemoryOffset(0x04, Cpu.saveStateSlot));\n    Cpu.registerH = load<u8>(getSaveStateMemoryOffset(0x05, Cpu.saveStateSlot));\n    Cpu.registerL = load<u8>(getSaveStateMemoryOffset(0x06, Cpu.saveStateSlot));\n    Cpu.registerF = load<u8>(getSaveStateMemoryOffset(0x07, Cpu.saveStateSlot));\n\n    Cpu.stackPointer = load<u16>(getSaveStateMemoryOffset(0x08, Cpu.saveStateSlot));\n    Cpu.programCounter = load<u16>(getSaveStateMemoryOffset(0x0a, Cpu.saveStateSlot));\n\n    Cpu.currentCycles = load<i32>(getSaveStateMemoryOffset(0x0c, Cpu.saveStateSlot));\n\n    Cpu.isHaltNormal = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x11, Cpu.saveStateSlot));\n    Cpu.isHaltNoJump = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x12, Cpu.saveStateSlot));\n    Cpu.isHaltBug = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x13, Cpu.saveStateSlot));\n    Cpu.isStopped = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x14, Cpu.saveStateSlot));\n\n    Cpu.BootROMEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x15, Cpu.saveStateSlot));\n    Cpu.GBCEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x16, Cpu.saveStateSlot));\n    Cpu.GBCDoubleSpeed = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x17, Cpu.saveStateSlot));\n  }\n}\n\n// Inlined because closure compiler does so\nexport function initializeCpu(): void {\n  // Reset all stateful Cpu variables\n  // Cpu.GBCEnabled is done by core/initialize\n  Cpu.GBCDoubleSpeed = false;\n  Cpu.registerA = 0;\n  Cpu.registerB = 0;\n  Cpu.registerC = 0;\n  Cpu.registerD = 0;\n  Cpu.registerE = 0;\n  Cpu.registerH = 0;\n  Cpu.registerL = 0;\n  Cpu.registerF = 0;\n  Cpu.stackPointer = 0;\n  Cpu.programCounter = 0x00;\n  Cpu.currentCycles = 0;\n  Cpu.isHaltNormal = false;\n  Cpu.isHaltNoJump = false;\n  Cpu.isHaltBug = false;\n  Cpu.isStopped = false;\n\n  // Everything is done by Boot ROM is enabled.\n  if (Cpu.BootROMEnabled) {\n    return;\n  }\n\n  if (Cpu.GBCEnabled) {\n    // CPU Registers\n    Cpu.registerA = 0x11;\n    Cpu.registerF = 0x80;\n    Cpu.registerB = 0x00;\n    Cpu.registerC = 0x00;\n    Cpu.registerD = 0xff;\n    Cpu.registerE = 0x56;\n    Cpu.registerH = 0x00;\n    Cpu.registerL = 0x0d;\n  } else {\n    // Cpu Registers\n    Cpu.registerA = 0x01;\n    Cpu.registerF = 0xb0;\n    Cpu.registerB = 0x00;\n    Cpu.registerC = 0x13;\n    Cpu.registerD = 0x00;\n    Cpu.registerE = 0xd8;\n    Cpu.registerH = 0x01;\n    Cpu.registerL = 0x4d;\n  }\n\n  // Cpu Control Flow\n  Cpu.programCounter = 0x100;\n  Cpu.stackPointer = 0xfffe;\n}\n","// Syncing and Tracking executed cycles\n\nimport { Config } from './config';\nimport { Cpu } from './cpu/index';\nimport { Graphics, updateGraphics, batchProcessGraphics } from './graphics/index';\nimport { Memory } from './memory/index';\nimport { Timers, updateTimers, batchProcessTimers } from './timers/index';\nimport { Sound, updateSound, batchProcessAudio } from './sound/index';\nimport { updateSerial } from './serial/serial';\n\nexport class Cycles {\n  // An even number below the max 32 bit integer\n  static cyclesPerCycleSet: i32 = 2000000000;\n  static cycleSets: i32 = 0;\n  static cycles: i32 = 0;\n}\n\nexport function getCyclesPerCycleSet(): i32 {\n  return Cycles.cyclesPerCycleSet;\n}\n\nexport function getCycleSets(): i32 {\n  return Cycles.cycleSets;\n}\n\nexport function getCycles(): i32 {\n  return Cycles.cycles;\n}\n\n// Inlined because closure compiler inlines\nfunction trackCyclesRan(numberOfCycles: i32): void {\n  let cycles = Cycles.cycles;\n  cycles += numberOfCycles;\n  if (cycles >= Cycles.cyclesPerCycleSet) {\n    Cycles.cycleSets += 1;\n    cycles -= Cycles.cyclesPerCycleSet;\n  }\n  Cycles.cycles = cycles;\n}\n\n// Inlined because closure compiler inlines\nexport function resetCycles(): void {\n  Cycles.cyclesPerCycleSet = 2000000000;\n  Cycles.cycleSets = 0;\n  Cycles.cycles = 0;\n}\n\n// Sync other GB Components with the number of cycles\nexport function syncCycles(numberOfCycles: i32): void {\n  // Check if we did a DMA TRansfer, if we did add the cycles\n  if (Memory.DMACycles > 0) {\n    numberOfCycles += Memory.DMACycles;\n    Memory.DMACycles = 0;\n  }\n\n  // Finally, Add our number of cycles to the CPU Cycles\n  Cpu.currentCycles += numberOfCycles;\n\n  // Check other Gameboy components\n  if (!Cpu.isStopped) {\n    if (Config.graphicsBatchProcessing) {\n      // Need to do this, since a lot of things depend on the scanline\n      // Batch processing will simply return if the number of cycles is too low\n      Graphics.currentCycles += numberOfCycles;\n      batchProcessGraphics();\n    } else {\n      updateGraphics(numberOfCycles);\n    }\n\n    if (Config.audioBatchProcessing) {\n      Sound.currentCycles += numberOfCycles;\n      batchProcessAudio();\n    } else {\n      updateSound(numberOfCycles);\n    }\n\n    updateSerial(numberOfCycles);\n  }\n\n  if (Config.timersBatchProcessing) {\n    // Batch processing will simply return if the number of cycles is too low\n    Timers.currentCycles += numberOfCycles;\n    batchProcessTimers();\n  } else {\n    updateTimers(numberOfCycles);\n  }\n\n  trackCyclesRan(numberOfCycles);\n}\n","// Functions involving executing/running the emulator after initializtion\n\nimport { setHasCoreStarted } from './core';\nimport { syncCycles } from './cycles';\nimport { Cpu, executeOpcode } from './cpu/index';\nimport { checkInterrupts } from './interrupts/index';\nimport { eightBitLoadFromGBMemory } from './memory/index';\nimport { getNumberOfSamplesInAudioBuffer } from './sound/index';\nimport { u16Portable } from './portable/portable';\n\nimport { Breakpoints } from './debug/breakpoints';\n\nexport class Execute {\n  // An even number bewlow the max 32 bit integer\n  static stepsPerStepSet: i32 = 2000000000;\n  static stepSets: i32 = 0;\n  static steps: i32 = 0;\n\n  // Response Codes from Execute Conditions\n  static RESPONSE_CONDITION_ERROR: i32 = -1;\n  static RESPONSE_CONDITION_FRAME: i32 = 0;\n  static RESPONSE_CONDITION_AUDIO: i32 = 1;\n  static RESPONSE_CONDITION_BREAKPOINT: i32 = 2;\n}\n\nexport function getStepsPerStepSet(): i32 {\n  return Execute.stepsPerStepSet;\n}\n\nexport function getStepSets(): i32 {\n  return Execute.stepSets;\n}\n\nexport function getSteps(): i32 {\n  return Execute.steps;\n}\n\n// Inlined because closure compiler inlines\nfunction trackStepsRan(steps: i32): void {\n  let esteps = Execute.steps;\n  esteps += steps;\n  if (esteps >= Execute.stepsPerStepSet) {\n    Execute.stepSets += 1;\n    esteps -= Execute.stepsPerStepSet;\n  }\n  Execute.steps = esteps;\n}\n\n// Inlined because closure compiler inlines\nexport function resetSteps(): void {\n  Execute.stepsPerStepSet = 2000000000;\n  Execute.stepSets = 0;\n  Execute.steps = 0;\n}\n\n// // Public funciton to run frames until,\n// the specified number of frames have run or error.\n// Return values:\n// -1 = error\n// 0 = render a frame\nexport function executeMultipleFrames(numberOfFrames: i32): i32 {\n  let frameResponse = 0;\n  let framesRun = 0;\n  while (framesRun < numberOfFrames && frameResponse >= 0) {\n    frameResponse = executeFrame();\n    framesRun += 1;\n  }\n\n  if (frameResponse < 0) {\n    return frameResponse;\n  }\n\n  return 0;\n}\n\n// Public funciton to run opcodes until,\n// a frame is ready, or error.\n// Return values:\n// -1 = error\n// 0 = render a frame\nexport function executeFrame(): i32 {\n  return executeUntilCondition(true, -1);\n}\n\n// Public Function to run opcodes until,\n// a frame is ready, audio bufer is filled, or error\nexport function executeFrameAndCheckAudio(maxAudioBuffer: i32 = 0): i32 {\n  return executeUntilCondition(true, maxAudioBuffer);\n}\n\n// Base function that executes steps, and checks conditions\n// Return values:\nexport function executeUntilCondition(checkMaxCyclesPerFrame: boolean = true, maxAudioBuffer: i32 = -1): i32 {\n  // Common tracking variables\n  let numberOfCycles = -1;\n  let audioBufferSize = 1024;\n\n  if (maxAudioBuffer > 0) {\n    audioBufferSize = maxAudioBuffer;\n  } else if (maxAudioBuffer < 0) {\n    audioBufferSize = -1;\n  }\n\n  let errorCondition: boolean = false;\n  let frameCondition: boolean = false;\n  let audioBufferCondition: boolean = false;\n\n  while (!errorCondition && !frameCondition && !audioBufferCondition && !Breakpoints.reachedBreakpoint) {\n    numberOfCycles = executeStep();\n\n    // Error Condition\n    if (numberOfCycles < 0) {\n      errorCondition = true;\n    } else if (Cpu.currentCycles >= Cpu.MAX_CYCLES_PER_FRAME()) {\n      frameCondition = true;\n    } else if (audioBufferSize > -1 && getNumberOfSamplesInAudioBuffer() >= audioBufferSize) {\n      audioBufferCondition = true;\n    }\n  }\n\n  // Find our exit reason\n  if (frameCondition) {\n    // Render a frame\n\n    // Reset our currentCycles\n    Cpu.currentCycles -= Cpu.MAX_CYCLES_PER_FRAME();\n\n    return Execute.RESPONSE_CONDITION_FRAME;\n  }\n\n  if (audioBufferCondition) {\n    return Execute.RESPONSE_CONDITION_AUDIO;\n  }\n\n  if (Breakpoints.reachedBreakpoint) {\n    Breakpoints.reachedBreakpoint = false;\n    return Execute.RESPONSE_CONDITION_BREAKPOINT;\n  }\n\n  // TODO: Boot ROM handling\n\n  // There was an error, return -1, and push the program counter back to grab the error opcode\n  Cpu.programCounter = u16Portable(Cpu.programCounter - 1);\n  return -1;\n}\n\n// Function to execute an opcode, and update other gameboy hardware.\n// http://www.codeslinger.co.uk/pages/projects/gameboy/beginning.html\nexport function executeStep(): i32 {\n  // Set has started to 1 since we ran a emulation step\n  setHasCoreStarted(true);\n\n  // Check if we are in the halt bug\n  if (Cpu.isHaltBug) {\n    // Need to not increment program counter,\n    // thus, running the next opcode twice\n\n    // E.g\n    // 0x76 - halt\n    // FA 34 12 - ld a,(1234)\n    // Becomes\n    // FA FA 34 ld a,(34FA)\n    // 12 ld (de),a\n\n    let haltBugOpcode: i32 = <u8>eightBitLoadFromGBMemory(Cpu.programCounter);\n    // Execute opcode will handle the actual PC behavior\n    let haltBugCycles: i32 = executeOpcode(haltBugOpcode);\n    syncCycles(haltBugCycles);\n    Cpu.exitHaltAndStop();\n  }\n\n  // Interrupts should be handled before reading an opcode\n  // https://github.com/Gekkio/mooneye-gb/blob/master/docs/accuracy.markdown#what-is-the-exact-timing-of-cpu-servicing-an-interrupt\n  let interruptCycles: i32 = checkInterrupts();\n  if (interruptCycles > 0) {\n    syncCycles(interruptCycles);\n  }\n\n  // Get the opcode, and additional bytes to be handled\n  // Number of cycles defaults to 4, because while we're halted, we run 4 cycles (according to matt :))\n  let numberOfCycles = 4;\n  let opcode = 0;\n\n  // If we are not halted or stopped, run instructions\n  // If we are halted, this will be skipped and just sync the 4 cycles\n  if (!Cpu.isHalted() && !Cpu.isStopped) {\n    opcode = <u8>eightBitLoadFromGBMemory(Cpu.programCounter);\n    numberOfCycles = executeOpcode(opcode);\n  }\n\n  // blarggFixes, don't allow register F to have the bottom nibble\n  Cpu.registerF = Cpu.registerF & 0xf0;\n\n  // Check if there was an error decoding the opcode\n  if (numberOfCycles <= 0) {\n    return numberOfCycles;\n  }\n\n  // Sync other GB Components with the number of cycles\n  syncCycles(numberOfCycles);\n\n  // Update our steps\n  trackStepsRan(1);\n\n  // Check if we reached the CPU breakpoint\n  if (Cpu.programCounter === Breakpoints.programCounter) {\n    Breakpoints.reachedBreakpoint = true;\n  }\n\n  return numberOfCycles;\n}\n","// Imports\nimport { WASMBOY_WASM_PAGES, WASMBOY_STATE_LOCATION } from './constants';\nimport { Config } from './config';\nimport { resetCycles } from './cycles';\nimport { resetSteps } from './execute';\nimport { Cpu, initializeCpu } from './cpu/index';\nimport { Graphics, initializeGraphics, initializePalette } from './graphics/index';\nimport { Interrupts, initializeInterrupts } from './interrupts/index';\nimport { Joypad } from './joypad/index';\nimport { Memory, initializeCartridge, initializeDma, eightBitStoreIntoGBMemory, eightBitLoadFromGBMemory } from './memory/index';\nimport { Timers, initializeTimers } from './timers/index';\nimport { Sound, initializeSound, Channel1, Channel2, Channel3, Channel4 } from './sound/index';\nimport { initializeSerial } from './serial/serial';\n\n// Grow our memory to the specified size\nif (memory.size() < WASMBOY_WASM_PAGES) {\n  memory.grow(WASMBOY_WASM_PAGES - memory.size());\n}\n\n// Function to track if the core has started\nlet hasStarted: boolean = false;\nexport function setHasCoreStarted(value: boolean): void {\n  hasStarted = value;\n}\n\nexport function hasCoreStarted(): i32 {\n  return <i32>hasStarted;\n}\n\n// Function to configure & initialize wasmboy\nexport function config(\n  enableBootRom: i32,\n  useGbcWhenAvailable: i32,\n  audioBatchProcessing: i32,\n  graphicsBatchProcessing: i32,\n  timersBatchProcessing: i32,\n  graphicsDisableScanlineRendering: i32,\n  audioAccumulateSamples: i32,\n  tileRendering: i32,\n  tileCaching: i32,\n  enableAudioDebugging: i32\n): void {\n  // TODO: depending on the boot rom, initialization may be different\n  // From: http://www.codeslinger.co.uk/pages/projects/gameboy/hardware.html\n  // All values default to zero in memory, so not setting them yet\n  // log('initializing (includeBootRom=$0)', 1, enableBootRom);\n\n  Config.enableBootRom = enableBootRom > 0;\n  Config.useGbcWhenAvailable = useGbcWhenAvailable > 0;\n  Config.audioBatchProcessing = audioBatchProcessing > 0;\n  Config.graphicsBatchProcessing = graphicsBatchProcessing > 0;\n  Config.timersBatchProcessing = timersBatchProcessing > 0;\n  Config.graphicsDisableScanlineRendering = graphicsDisableScanlineRendering > 0;\n  Config.audioAccumulateSamples = audioAccumulateSamples > 0;\n  Config.tileRendering = tileRendering > 0;\n  Config.tileCaching = tileCaching > 0;\n  Config.enableAudioDebugging = enableAudioDebugging > 0;\n\n  initialize();\n}\n\n// Function to initiialize the core\nfunction initialize(): void {\n  // Initialization variables from BGB\n\n  // First, try to switch to Gameboy Color Mode\n  // Get our GBC support from the cartridge header\n  // http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header\n  let gbcType = eightBitLoadFromGBMemory(0x0143);\n\n  // Detecting GBC http://bgb.bircd.org/pandocs.htm#cgbregisters\n  if (gbcType === 0xc0 || (Config.useGbcWhenAvailable && gbcType === 0x80)) {\n    Cpu.GBCEnabled = true;\n  } else {\n    Cpu.GBCEnabled = false;\n  }\n\n  // Reset hasStarted, since we are now reset\n  setHasCoreStarted(false);\n\n  // Reset our cycles ran\n  resetCycles();\n  resetSteps();\n\n  if (Config.enableBootRom) {\n    Cpu.BootROMEnabled = true;\n  } else {\n    Cpu.BootROMEnabled = false;\n  }\n\n  // Call our respective classes intialization\n  // NOTE: Boot ROM Only handles some initialization, thus we need to check in each one\n  // respecitvely :p\n  initializeCpu();\n  initializeCartridge();\n  initializeDma();\n  initializeGraphics();\n  initializePalette();\n  initializeSound();\n  initializeInterrupts();\n  initializeTimers();\n  initializeSerial();\n  initializeVarious();\n}\n\nfunction initializeVarious(): void {\n  // Various Other Registers\n  if (Cpu.GBCEnabled) {\n    // Various other registers\n    eightBitStoreIntoGBMemory(0xff70, 0xf8);\n    eightBitStoreIntoGBMemory(0xff4f, 0xfe);\n    eightBitStoreIntoGBMemory(0xff4d, 0x7e);\n    eightBitStoreIntoGBMemory(0xff00, 0xcf);\n\n    eightBitStoreIntoGBMemory(0xff0f, 0xe1);\n    // 0xFFFF = 0x00\n\n    // Undocumented from Pandocs\n    eightBitStoreIntoGBMemory(0xff6c, 0xfe);\n    eightBitStoreIntoGBMemory(0xff75, 0x8f);\n  } else {\n    eightBitStoreIntoGBMemory(0xff70, 0xff);\n    eightBitStoreIntoGBMemory(0xff4f, 0xff);\n    eightBitStoreIntoGBMemory(0xff4d, 0xff);\n    eightBitStoreIntoGBMemory(0xff00, 0xcf);\n\n    eightBitStoreIntoGBMemory(0xff0f, 0xe1);\n    // 0xFFFF = 0x00\n  }\n}\n\n// Function to return if we are currently playing a GBC ROM\nexport function isGBC(): i32 {\n  return <i32>Cpu.GBCEnabled;\n}\n\n// Function to return an address to store into save state memory\n// this is to regulate our 20 slots\n// https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit?usp=sharing\n// Inlined because closure compiler inlines\nexport function getSaveStateMemoryOffset(offset: i32, saveStateSlot: i32): i32 {\n  // 50 bytes per save state memory partiton sli32\n  return WASMBOY_STATE_LOCATION + offset + 50 * saveStateSlot;\n}\n\n// Function to save state to memory for all of our classes\nexport function saveState(): void {\n  Cpu.saveState();\n  Graphics.saveState();\n  Interrupts.saveState();\n  Joypad.saveState();\n  Memory.saveState();\n  Timers.saveState();\n  Sound.saveState();\n  Channel1.saveState();\n  Channel2.saveState();\n  Channel3.saveState();\n  Channel4.saveState();\n\n  // Reset hasStarted, since we are now reset\n  setHasCoreStarted(false);\n\n  // Don't want to reset cycles here, as this does not reset the emulator\n}\n\n// Function to load state from memory for all of our classes\nexport function loadState(): void {\n  Cpu.loadState();\n  Graphics.loadState();\n  Interrupts.loadState();\n  Joypad.loadState();\n  Memory.loadState();\n  Timers.loadState();\n  Sound.loadState();\n  Channel1.loadState();\n  Channel2.loadState();\n  Channel3.loadState();\n  Channel4.loadState();\n\n  // Reset hasStarted, since we are now reset\n  setHasCoreStarted(false);\n\n  // Reset our cycles ran\n  resetCycles();\n  resetSteps();\n}\n","// Load/Read functionality for memory\nimport { checkReadTraps } from './readTraps';\nimport { getWasmBoyOffsetFromGameBoyOffset } from './memoryMap';\nimport { concatenateBytes } from '../helpers/index';\nimport { Breakpoints } from '../debug/breakpoints';\n\nexport function eightBitLoadFromGBMemory(gameboyOffset: i32): i32 {\n  return <i32>load<u8>(getWasmBoyOffsetFromGameBoyOffset(gameboyOffset));\n}\n\nexport function eightBitLoadFromGBMemoryWithTraps(offset: i32): i32 {\n  if (offset === Breakpoints.readGbMemory) {\n    Breakpoints.reachedBreakpoint = true;\n  }\n\n  let readTrapResult = checkReadTraps(offset);\n  return readTrapResult === -1 ? eightBitLoadFromGBMemory(offset) : <u8>readTrapResult;\n}\n\n// TODO: Rename this to sixteenBitLoadFromGBMemoryWithTraps\n// Inlined because closure compiler inlines\nexport function sixteenBitLoadFromGBMemory(offset: i32): i32 {\n  // Get our low byte\n  let lowByteReadTrapResult = checkReadTraps(offset);\n  let lowByte = lowByteReadTrapResult === -1 ? eightBitLoadFromGBMemory(offset) : lowByteReadTrapResult;\n\n  // Get the next offset for the second byte\n  let nextOffset = offset + 1;\n\n  // Get our high byte\n  let highByteReadTrapResult = checkReadTraps(nextOffset);\n  let highByte = highByteReadTrapResult === -1 ? eightBitLoadFromGBMemory(nextOffset) : highByteReadTrapResult;\n\n  // Concatenate the bytes and return\n  return concatenateBytes(highByte, lowByte);\n}\n\nexport function loadBooleanDirectlyFromWasmMemory(offset: i32): boolean {\n  return <i32>load<u8>(offset) > 0;\n}\n","// WasmBoy memory map:\n// https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit?usp=sharing\nimport {\n  VIDEO_RAM_LOCATION,\n  WORK_RAM_LOCATION,\n  OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION,\n  CARTRIDGE_RAM_LOCATION,\n  BOOT_ROM_LOCATION,\n  CARTRIDGE_ROM_LOCATION\n} from '../constants';\nimport { Memory } from './memory';\nimport { eightBitLoadFromGBMemory } from './load';\nimport { getRomBankAddress, getRamBankAddress } from './banking';\nimport { Cpu } from '../cpu/index';\n\n// Private function to translate a offset meant for the gameboy memory map\n// To the wasmboy memory map\n// Following: http://gameboy.mongenel.com/dmg/asmmemmap.html\n// And https://github.com/Dooskington/GameLad/wiki/Part-11---Memory-Bank-Controllers\n// Performance help from @dcodeIO, and awesome-gbdev\nexport function getWasmBoyOffsetFromGameBoyOffset(gameboyOffset: i32): i32 {\n  // Get the top byte and switch\n  let gameboyOffsetHighByte = gameboyOffset >> 12;\n  switch (gameboyOffsetHighByte) {\n    case 0x00:\n      // Check if we are currently executing the boot rom\n      // Otherwise, bottom 0x0000 -> 0x03FF is Cartridge ROM Ram Bank 1\n      if (Cpu.BootROMEnabled) {\n        if (Cpu.GBCEnabled) {\n          // See: http://gbdev.gg8.se/wiki/articles/Gameboy_Bootstrap_ROM\n          // \"The rom dump includes the 256 byte rom (0x0000-0x00FF) and the,\n          // 1792 byte rom (0x0200-0x08FF) which Dr. Decapitator observed,\n          // but not the 512 byte rom,\n          // which may be cpu microcode or lcd color lookup related.\"\n\n          // First 0xFF bytes are BOOT rom\n          if (gameboyOffset < 0x0100) {\n            return gameboyOffset + BOOT_ROM_LOCATION;\n          }\n\n          // 0x100 -> 0x1FF is the actual ROM\n\n          // Everything from 0x200 -> 0x8FF is BOOT ROM Again\n          if (gameboyOffset > 0x01ff && gameboyOffset < 0x0900) {\n            return gameboyOffset + BOOT_ROM_LOCATION;\n          }\n        } else if (!Cpu.GBCEnabled && gameboyOffset < 0x0100) {\n          return gameboyOffset + BOOT_ROM_LOCATION;\n        }\n      }\n    case 0x01:\n    case 0x02:\n    case 0x03:\n      // Cartridge ROM - Bank 0 (fixed)\n      // 0x0000 -> 0x0D2400\n      return gameboyOffset + CARTRIDGE_ROM_LOCATION;\n    case 0x04:\n    case 0x05:\n    case 0x06:\n    case 0x07:\n      // Cartridge ROM - Switchable Banks 1-xx\n      // 0x4000 -> (0x0D2400 + 0x4000)\n      return getRomBankAddress(gameboyOffset) + CARTRIDGE_ROM_LOCATION;\n    case 0x08:\n    case 0x09:\n      // Video RAM\n      // 0x8000 -> 0x000400\n      let vramBankId = 0;\n      if (Cpu.GBCEnabled) {\n        // Find our current VRAM Bank\n        vramBankId = eightBitLoadFromGBMemory(Memory.memoryLocationGBCVRAMBank) & 0x01;\n        // Even though We added another 0x2000, the Cartridge ram is pulled out of our Internal Memory Space\n        // Therefore, we do not need to adjust for this extra 0x2000\n      }\n\n      return gameboyOffset - Memory.videoRamLocation + VIDEO_RAM_LOCATION + 0x2000 * vramBankId;\n    case 0x0a:\n    case 0x0b:\n      // Cartridge RAM - A.K.A External RAM\n      // 0xA000 -> 0x008400\n      return getRamBankAddress(gameboyOffset) + CARTRIDGE_RAM_LOCATION;\n    case 0x0c:\n      // Gameboy Ram Bank 0\n      // 0xC000 -> 0x000400\n      // Don't need to add head, since we move out 0x200 from the cartridge ram\n      return gameboyOffset - Memory.internalRamBankZeroLocation + WORK_RAM_LOCATION;\n    case 0x0d:\n      // Gameboy Ram Banks, Switchable in GBC Mode\n      // 0xD000 -> 0x000400\n      // In CGB Mode 32 KBytes internal RAM are available.\n      // This memory is divided into 8 banks of 4 KBytes each.\n      // Bank 0 is always available in memory at C000-CFFF,\n      // Bank 1-7 can be selected into the address space at D000-DFFF.\n      // http://gbdev.gg8.se/wiki/articles/CGB_Registers#FF70_-_SVBK_-_CGB_Mode_Only_-_WRAM_Bank\n      // Get the last 3 bits to find our wram ID\n      let wramBankId = 0;\n      if (Cpu.GBCEnabled) {\n        wramBankId = eightBitLoadFromGBMemory(Memory.memoryLocationGBCWRAMBank) & 0x07;\n      }\n      wramBankId = wramBankId < 1 ? 1 : wramBankId;\n      // (0x1000 * (wramBankId - 1)) -> To find the correct wram bank.\n      // wramBankId - 1, because we alreayd have the space for wramBank 1, and are currently in it\n      // So need to address space for 6 OTHER banks\n      return gameboyOffset - Memory.internalRamBankZeroLocation + WORK_RAM_LOCATION + 0x1000 * (wramBankId - 1);\n    default:\n      // Everything Else after Gameboy Ram Banks\n      // 0xE000 -> 0x000400\n      // 0x6000 For the Extra WRAM Banks\n      return gameboyOffset - Memory.echoRamLocation + OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION;\n  }\n}\n","// Function to handle rom/rambanking\nimport { Memory } from './memory';\nimport { concatenateBytes, checkBitOnByte, splitLowByte } from '../helpers/index';\n\n// Inlined because closure compiler inlines\nexport function handleBanking(offset: i32, value: i32): void {\n  // Is rom Only does not bank\n  if (Memory.isRomOnly) {\n    return;\n  }\n\n  let isMBC1 = Memory.isMBC1;\n  let isMBC2 = Memory.isMBC2;\n\n  // Enable Ram Banking\n  if (offset <= 0x1fff) {\n    if (isMBC2 && !checkBitOnByte(4, <u8>value)) {\n      // Do Nothing\n      return;\n    } else {\n      let romEnableByte = value & 0x0f;\n      if (romEnableByte === 0x00) {\n        Memory.isRamBankingEnabled = false;\n      } else if (romEnableByte === 0x0a) {\n        Memory.isRamBankingEnabled = true;\n      }\n    }\n  } else if (offset <= 0x3fff) {\n    let isMBC5 = Memory.isMBC5;\n    if (!isMBC5 || offset <= 0x2fff) {\n      // Change Low Bits on the Current Rom Bank\n      let currentRomBank = Memory.currentRomBank;\n      if (isMBC2) {\n        currentRomBank = value & 0x0f;\n      }\n\n      // Set the number of bottom bytes from the MBC type\n      let romBankLowerBits = value;\n      if (isMBC1) {\n        // Only want the bottom 5\n        romBankLowerBits = romBankLowerBits & 0x1f;\n        currentRomBank &= 0xe0;\n      } else if (Memory.isMBC3) {\n        // Only Want the bottom 7\n        romBankLowerBits = romBankLowerBits & 0x7f;\n        currentRomBank &= 0x80;\n      } else if (isMBC5) {\n        // Going to switch the whole thing\n        currentRomBank &= 0x00;\n      }\n\n      // Set the lower bytes\n      currentRomBank |= romBankLowerBits;\n      Memory.currentRomBank = currentRomBank;\n      return;\n    } else {\n      // TODO: MBC5 High bits Rom bank, check if this works, not sure about the value\n      let lowByte = splitLowByte(Memory.currentRomBank);\n      let highByte = <i32>(value > 0);\n      Memory.currentRomBank = concatenateBytes(highByte, lowByte);\n    }\n  } else if (!isMBC2 && offset <= 0x5fff) {\n    // ROM / RAM Banking, MBC2 doesn't do this\n    if (isMBC1 && Memory.isMBC1RomModeEnabled) {\n      // Do an upper bit rom bank for MBC 1\n      // Remove upper bits of currentRomBank\n      let currentRomBank = Memory.currentRomBank & 0x1f;\n      let romBankHigherBits = value & 0xe0;\n\n      currentRomBank |= romBankHigherBits;\n      Memory.currentRomBank = currentRomBank;\n      return;\n    }\n\n    if (Memory.isMBC3) {\n      if (value >= 0x08 && value <= 0x0c) {\n        // TODO: MBC3 RTC Register Select\n      }\n    }\n\n    let ramBankBits: i32 = value;\n\n    if (!Memory.isMBC5) {\n      // Get the bottom 2 bits\n      ramBankBits &= 0x03;\n    } else {\n      // Get the bottom nibble\n      ramBankBits &= 0x0f;\n    }\n\n    // Set our ram bank\n    Memory.currentRamBank = ramBankBits;\n    return;\n  } else if (!isMBC2 && offset <= 0x7fff) {\n    if (isMBC1) {\n      Memory.isMBC1RomModeEnabled = checkBitOnByte(0, <u8>value);\n    }\n    // TODO: MBC3 Latch Clock Data\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function getRomBankAddress(gameboyOffset: i32): i32 {\n  let currentRomBank: u32 = Memory.currentRomBank;\n  if (!Memory.isMBC5 && currentRomBank === 0) {\n    currentRomBank = 1;\n  }\n\n  // Adjust our gameboy offset relative to zero for the gameboy memory map\n  return <i32>(0x4000 * currentRomBank + (gameboyOffset - Memory.switchableCartridgeRomLocation));\n}\n\n// Inlined because closure compiler inlines\nexport function getRamBankAddress(gameboyOffset: i32): i32 {\n  // Adjust our gameboy offset relative to zero for the gameboy memory map\n  return <i32>(0x2000 * Memory.currentRamBank + (gameboyOffset - Memory.cartridgeRamLocation));\n}\n","// Store / Write memory access\nimport { checkWriteTraps } from './writeTraps';\nimport { getWasmBoyOffsetFromGameBoyOffset } from './memoryMap';\nimport { splitHighByte, splitLowByte } from '../helpers/index';\nimport { Breakpoints } from '../debug/breakpoints';\n\nexport function eightBitStoreIntoGBMemory(gameboyOffset: i32, value: i32): void {\n  store<u8>(getWasmBoyOffsetFromGameBoyOffset(gameboyOffset), value);\n}\n\nexport function eightBitStoreIntoGBMemoryWithTraps(offset: i32, value: i32): void {\n  if (offset === Breakpoints.writeGbMemory) {\n    Breakpoints.reachedBreakpoint = true;\n  }\n\n  if (checkWriteTraps(offset, value)) {\n    eightBitStoreIntoGBMemory(offset, value);\n  }\n}\n\nexport function sixteenBitStoreIntoGBMemoryWithTraps(offset: i32, value: i32): void {\n  // Dividing into two seperate eight bit calls to help with debugging tilemap overwrites\n  // Split the value into two seperate bytes\n  let highByte = splitHighByte(value);\n  let lowByte = splitLowByte(value);\n\n  if (checkWriteTraps(offset, lowByte)) {\n    eightBitStoreIntoGBMemory(offset, lowByte);\n  }\n\n  let nextOffset = offset + 1;\n  if (checkWriteTraps(nextOffset, highByte)) {\n    eightBitStoreIntoGBMemory(nextOffset, highByte);\n  }\n}\n\nexport function sixteenBitStoreIntoGBMemory(offset: i32, value: i32): void {\n  // Dividing into two seperate eight bit calls to help with debugging tilemap overwrites\n  // Split the value into two seperate bytes\n  let highByte = splitHighByte(value);\n  let lowByte = splitLowByte(value);\n\n  eightBitStoreIntoGBMemory(offset + 0, lowByte);\n  eightBitStoreIntoGBMemory(offset + 1, highByte);\n}\n\nexport function storeBooleanDirectlyToWasmMemory(offset: i32, value: boolean): void {\n  store<u8>(offset, <i32>value);\n}\n","import { Cpu } from '../cpu/index';\nimport { Memory } from './memory';\nimport { eightBitLoadFromGBMemoryWithTraps, eightBitLoadFromGBMemory } from './load';\nimport { eightBitStoreIntoGBMemoryWithTraps, eightBitStoreIntoGBMemory } from './store';\nimport { concatenateBytes, checkBitOnByte, setBitOnByte, resetBitOnByte } from '../helpers/index';\n\n// Inlined because closure compiler inlines\nexport function initializeDma(): void {\n  if (Cpu.GBCEnabled) {\n    // GBC DMA\n    eightBitStoreIntoGBMemory(0xff51, 0xff);\n    eightBitStoreIntoGBMemory(0xff52, 0xff);\n    eightBitStoreIntoGBMemory(0xff53, 0xff);\n    eightBitStoreIntoGBMemory(0xff54, 0xff);\n    eightBitStoreIntoGBMemory(0xff55, 0xff);\n  } else {\n    // GB DMA\n    eightBitStoreIntoGBMemory(0xff51, 0xff);\n    eightBitStoreIntoGBMemory(0xff52, 0xff);\n    eightBitStoreIntoGBMemory(0xff53, 0xff);\n    eightBitStoreIntoGBMemory(0xff54, 0xff);\n    eightBitStoreIntoGBMemory(0xff55, 0xff);\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function startDmaTransfer(sourceAddressOffset: i32): void {\n  let sourceAddress = sourceAddressOffset << 8;\n  for (let i = 0; i <= 0x9f; ++i) {\n    let spriteInformationByte = eightBitLoadFromGBMemory(sourceAddress + i);\n    let spriteInformationAddress = Memory.spriteInformationTableLocation + i;\n    eightBitStoreIntoGBMemory(spriteInformationAddress, spriteInformationByte);\n  }\n\n  // TCAGBD:  This copy (DMA) needs 160 × 4 + 4 clocks to complete in both double speed and single speeds modes\n  // Increment all of our Cycle coiunters in ../cpu/opcodes\n  Memory.DMACycles = 644;\n}\n\n// https://gist.github.com/drhelius/3394856\n// http://bgb.bircd.org/pandocs.htm\n// Inlined because closure compiler inlines\nexport function startHdmaTransfer(hdmaTriggerByteToBeWritten: i32): void {\n  // Check if we are Gbc\n  if (!Cpu.GBCEnabled) {\n    return;\n  }\n\n  // Check if we are trying to terminate an already active HBLANK HDMA\n  if (Memory.isHblankHdmaActive && !checkBitOnByte(7, hdmaTriggerByteToBeWritten)) {\n    // Don't reset anything, just set bit 7 to 1 on the trigger byte\n    Memory.isHblankHdmaActive = false;\n    let hdmaTriggerByte = eightBitLoadFromGBMemory(Memory.memoryLocationHdmaTrigger);\n    eightBitStoreIntoGBMemory(Memory.memoryLocationHdmaTrigger, setBitOnByte(7, hdmaTriggerByte));\n    return;\n  }\n\n  // Get our source and destination for the HDMA\n  let hdmaSource = getHdmaSourceFromMemory();\n  let hdmaDestination = getHdmaDestinationFromMemory();\n\n  // Get the length from the trigger\n  // Lower 7 bits, Add 1, times 16\n  // https://gist.github.com/drhelius/3394856\n  let transferLength = resetBitOnByte(7, hdmaTriggerByteToBeWritten);\n  transferLength = (transferLength + 1) << 4;\n\n  // Get bit 7 of the trigger for the HDMA type\n  if (checkBitOnByte(7, hdmaTriggerByteToBeWritten)) {\n    // H-Blank DMA\n    Memory.isHblankHdmaActive = true;\n    Memory.hblankHdmaTransferLengthRemaining = transferLength;\n    Memory.hblankHdmaSource = hdmaSource;\n    Memory.hblankHdmaDestination = hdmaDestination;\n\n    // This will be handled in updateHblankHdma()\n\n    // Since we return false in write traps, we need to now write the byte\n    // Be sure to reset bit 7, to show that the hdma is active\n    eightBitStoreIntoGBMemory(Memory.memoryLocationHdmaTrigger, resetBitOnByte(7, hdmaTriggerByteToBeWritten));\n  } else {\n    // General DMA\n    hdmaTransfer(hdmaSource, hdmaDestination, transferLength);\n\n    // Stop the DMA\n    eightBitStoreIntoGBMemory(Memory.memoryLocationHdmaTrigger, 0xff);\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function updateHblankHdma(): void {\n  if (!Memory.isHblankHdmaActive) {\n    return;\n  }\n\n  // Get our amount of bytes to transfer (Only 0x10 bytes at a time)\n  let bytesToTransfer = 0x10;\n  let hblankHdmaTransferLengthRemaining = Memory.hblankHdmaTransferLengthRemaining;\n  if (hblankHdmaTransferLengthRemaining < bytesToTransfer) {\n    // Set to the difference\n    bytesToTransfer = hblankHdmaTransferLengthRemaining;\n  }\n\n  // Do the transfer (Only 0x10 bytes at a time)\n  hdmaTransfer(Memory.hblankHdmaSource, Memory.hblankHdmaDestination, bytesToTransfer);\n\n  // Update our source and destination\n  Memory.hblankHdmaSource += bytesToTransfer;\n  Memory.hblankHdmaDestination += bytesToTransfer;\n  hblankHdmaTransferLengthRemaining -= bytesToTransfer;\n  Memory.hblankHdmaTransferLengthRemaining = hblankHdmaTransferLengthRemaining;\n\n  let memoryLocationHdmaTrigger = Memory.memoryLocationHdmaTrigger;\n  if (hblankHdmaTransferLengthRemaining <= 0) {\n    // End the transfer\n    Memory.isHblankHdmaActive = false;\n    // Need to clear the HDMA with 0xFF, which sets bit 7 to 1 to show the HDMA has ended\n    eightBitStoreIntoGBMemory(memoryLocationHdmaTrigger, 0xff);\n  } else {\n    // Set our new transfer length, make sure it is in the weird format,\n    // and make sure bit 7 is 0, to show that the HDMA is Active\n    let remainingTransferLength = hblankHdmaTransferLengthRemaining;\n    let transferLengthAsByte = (remainingTransferLength >> 4) - 1;\n    eightBitStoreIntoGBMemory(memoryLocationHdmaTrigger, resetBitOnByte(7, transferLengthAsByte));\n  }\n}\n\n// Simple Function to transfer the bytes from a destination to a source for a general pourpose or Hblank HDMA\nfunction hdmaTransfer(hdmaSource: i32, hdmaDestination: i32, transferLength: i32): void {\n  for (let i = 0; i < transferLength; ++i) {\n    let sourceByte = eightBitLoadFromGBMemoryWithTraps(hdmaSource + i);\n    // get the hdmaDestination with wrapping\n    // See issue #61: https://github.com/torch2424/wasmBoy/issues/61\n    let hdmaDestinationWithWrapping = hdmaDestination + i;\n    while (hdmaDestinationWithWrapping > 0x9fff) {\n      // Simply clear the top 3 bits\n      hdmaDestinationWithWrapping -= 0x2000;\n    }\n    eightBitStoreIntoGBMemoryWithTraps(hdmaDestinationWithWrapping, sourceByte);\n  }\n\n  // Set our Cycles used for the HDMA\n  // Since DMA in GBC Double Speed Mode takes 80 micro seconds,\n  // And HDMA takes 8 micro seconds per 0x10 bytes in GBC Double Speed mode (and GBC Normal Mode)\n  // Will assume (644 / 10) cycles for GBC Double Speed Mode,\n  // and (644 / 10 / 2) for GBC Normal Mode\n  let hdmaCycles = 32 << (<i32>Cpu.GBCDoubleSpeed);\n  hdmaCycles = hdmaCycles * (transferLength >> 4);\n  Memory.DMACycles += hdmaCycles;\n}\n\n// Function to get our HDMA Source\n// Follows the poan docs\n// Inlined because closure compiler inlines\nfunction getHdmaSourceFromMemory(): i32 {\n  // Get our source for the HDMA\n  let hdmaSourceHigh = eightBitLoadFromGBMemory(Memory.memoryLocationHdmaSourceHigh);\n  let hdmaSourceLow = eightBitLoadFromGBMemory(Memory.memoryLocationHdmaSourceLow);\n\n  let hdmaSource = concatenateBytes(hdmaSourceHigh, hdmaSourceLow);\n\n  // And off the appopriate bits for the source and destination\n  // And off the bottom 4 bits\n  hdmaSource = hdmaSource & 0xfff0;\n\n  return hdmaSource;\n}\n\n// Function to get our HDMA Destination\n// Follows the poan docs\n// Inlined because closure compiler inlines\nfunction getHdmaDestinationFromMemory(): i32 {\n  let hdmaDestinationHigh = eightBitLoadFromGBMemory(Memory.memoryLocationHdmaDestinationHigh);\n  let hdmaDestinationLow = eightBitLoadFromGBMemory(Memory.memoryLocationHdmaDestinationLow);\n\n  let hdmaDestination = concatenateBytes(hdmaDestinationHigh, hdmaDestinationLow);\n\n  // Can only be in VRAM, 0x8000 -> 0x9FF0\n  // Pan docs says to knock off upper 3 bits, and lower 4 bits\n  // Which gives us: 0001111111110000 or 0x1FF0\n  // Meaning we must add 0x8000\n  hdmaDestination = hdmaDestination & 0x1ff0;\n  hdmaDestination += Memory.videoRamLocation;\n\n  return hdmaDestination;\n}\n","import { getCarryFlag } from '../cpu/index';\nimport { u8Portable } from '../portable/portable';\n\n// Grouped registers\n// possible overload these later to performace actions\n// AF, BC, DE, HL\nexport function concatenateBytes(highByte: i32, lowByte: i32): i32 {\n  //https://stackoverflow.com/questions/38298412/convert-two-bytes-into-signed-16-bit-integer-in-javascript\n  return ((highByte & 0xff) << 8) | (lowByte & 0xff);\n}\n\nexport function splitHighByte(groupedByte: i32): i32 {\n  return (groupedByte & 0xff00) >> 8;\n}\n\nexport function splitLowByte(groupedByte: i32): i32 {\n  return groupedByte & 0x00ff;\n}\n\nexport function rotateByteLeft(value: u8): u8 {\n  // Rotate left\n  // https://stackoverflow.com/questions/19204750/how-do-i-perform-a-circular-rotation-of-a-byte\n  // 4-bit example:\n  // 1010 -> 0100 | 0001\n  return u8Portable((value << 1) | (value >> 7));\n}\n\nexport function rotateByteLeftThroughCarry(value: u8): u8 {\n  // Example: https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js\n  // Through carry meaning, instead of raotating the bit that gets dropped off, but the carry there instead\n  return u8Portable((value << 1) | getCarryFlag());\n}\n\nexport function rotateByteRight(value: u8): u8 {\n  // Rotate right\n  // 4-bit example:\n  // 1010 -> 0101 | 0000\n  return u8Portable((value >> 1) | (value << 7));\n}\n\nexport function rotateByteRightThroughCarry(value: u8): u8 {\n  // Example: https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js\n  // Through carry meaning, instead of raotating the bit that gets dropped off, put the carry there instead\n  return u8Portable((value >> 1) | (getCarryFlag() << 7));\n}\n\nexport function setBitOnByte(bitPosition: i32, byte: i32): i32 {\n  return byte | (0x01 << bitPosition);\n}\n\nexport function resetBitOnByte(bitPosition: i32, byte: i32): i32 {\n  return byte & ~(0x01 << bitPosition);\n}\n\nexport function checkBitOnByte(bitPosition: i32, byte: i32): boolean {\n  // Perforamnce improvements\n  // https://github.com/AssemblyScript/assemblyscript/issues/40\n  return (byte & (1 << bitPosition)) != 0;\n}\n\n// Declared importObject functions\ndeclare function consoleLog(arg0: i32, arg1: i32): void;\ndeclare function consoleLogTimeout(arg0: i32, arg1: i32, timeout: i32): void;\n\nexport function log(arg0: i32, arg1: i32): void {\n  consoleLog(arg0, arg1);\n}\n\nexport function logTimeout(arg0: i32, arg1: i32, timeout: i32): void {\n  consoleLogTimeout(arg0, arg1, timeout);\n}\n","// Imports\nimport { Cpu } from './index';\nimport { handleCbOpcode } from './cbOpcodes';\nimport {\n  setZeroFlag,\n  getZeroFlag,\n  setSubtractFlag,\n  getSubtractFlag,\n  setHalfCarryFlag,\n  getHalfCarryFlag,\n  setCarryFlag,\n  getCarryFlag,\n  checkAndSetEightBitHalfCarryFlag,\n  checkAndSetSixteenBitFlagsAddOverflow\n} from './flags';\nimport {\n  addARegister,\n  addAThroughCarryRegister,\n  subARegister,\n  subAThroughCarryRegister,\n  andARegister,\n  xorARegister,\n  orARegister,\n  cpARegister,\n  relativeJump\n} from './instructions';\nimport { syncCycles } from '../cycles';\nimport {\n  rotateByteLeft,\n  rotateByteLeftThroughCarry,\n  rotateByteRight,\n  rotateByteRightThroughCarry,\n  concatenateBytes,\n  splitHighByte,\n  splitLowByte,\n  checkBitOnByte,\n  resetBitOnByte,\n  setBitOnByte\n} from '../helpers/index';\nimport {\n  Memory,\n  eightBitLoadFromGBMemoryWithTraps,\n  eightBitStoreIntoGBMemoryWithTraps,\n  sixteenBitStoreIntoGBMemoryWithTraps,\n  eightBitLoadFromGBMemory,\n  sixteenBitLoadFromGBMemory\n} from '../memory/index';\nimport { setInterrupts } from '../interrupts/index';\nimport { u8Portable, u16Portable, i8Portable } from '../portable/portable';\n\n// Take in any opcode, and decode it, and return the number of cycles\n// Program counter can be gotten from getProgramCounter();\n// Setting return value to i32 instead of u16, as we want to return a negative number on error\n// https://rednex.github.io/rgbds/gbz80.7.html\n// http://pastraiser.com/cpu/gameboy/gameboyopcodes.html\nexport function executeOpcode(opcode: i32): i32 {\n  // Always implement the program counter by one\n  // Any other value can just subtract or add however much offset before reaching this line\n  let programCounter = Cpu.programCounter;\n  programCounter = u16Portable(programCounter + 1);\n\n  // Check if we are in the halt bug\n  if (Cpu.isHaltBug) {\n    // Need to not increment program counter,\n    // thus, running the next opcode twice\n\n    // E.g\n    // 0x76 - halt\n    // FA 34 12 - ld a,(1234)\n    // Becomes\n    // FA FA 34 ld a,(34FA)\n    // 12 ld (de),a\n    programCounter = u16Portable(programCounter - 1);\n  }\n  Cpu.programCounter = programCounter;\n\n  // Split our opcode into a high nibble to speed up performance\n  // Running 255 if statements is slow, even in wasm haha!\n  let opcodeHighNibble = opcode & 0xf0;\n  opcodeHighNibble = opcodeHighNibble >> 4;\n\n  // NOTE: @binji rule of thumb: it takes 4 cpu cycles to read one byte\n  // Therefore isntructions that use more than just the opcode (databyte one and two) will take at least\n  // 8 cyckles to use getDataByteOne(), and two cycles to use the concatented\n\n  // Not using a switch statement to avoid cannot redeclare this variable errors\n  // And it would be a ton of work :p\n\n  switch (opcodeHighNibble) {\n    case 0x00:\n      return handleOpcode0x(opcode);\n    case 0x01:\n      return handleOpcode1x(opcode);\n    case 0x02:\n      return handleOpcode2x(opcode);\n    case 0x03:\n      return handleOpcode3x(opcode);\n    case 0x04:\n      return handleOpcode4x(opcode);\n    case 0x05:\n      return handleOpcode5x(opcode);\n    case 0x06:\n      return handleOpcode6x(opcode);\n    case 0x07:\n      return handleOpcode7x(opcode);\n    case 0x08:\n      return handleOpcode8x(opcode);\n    case 0x09:\n      return handleOpcode9x(opcode);\n    case 0x0a:\n      return handleOpcodeAx(opcode);\n    case 0x0b:\n      return handleOpcodeBx(opcode);\n    case 0x0c:\n      return handleOpcodeCx(opcode);\n    case 0x0d:\n      return handleOpcodeDx(opcode);\n    case 0x0e:\n      return handleOpcodeEx(opcode);\n    default:\n      return handleOpcodeFx(opcode);\n  }\n}\n\n// Wrapper functions around loading and storing memory, and syncing those cycles\nexport function eightBitLoadSyncCycles(gameboyOffset: i32): u8 {\n  syncCycles(4);\n  return <u8>eightBitLoadFromGBMemoryWithTraps(gameboyOffset);\n}\n\nexport function eightBitStoreSyncCycles(gameboyOffset: i32, value: i32): void {\n  syncCycles(4);\n  eightBitStoreIntoGBMemoryWithTraps(gameboyOffset, value);\n}\n\nexport function sixteenBitLoadSyncCycles(gameboyOffset: i32): u16 {\n  syncCycles(8);\n  // sixteen bit load has traps even though it has no label\n  return <u16>sixteenBitLoadFromGBMemory(gameboyOffset);\n}\n\nexport function sixteenBitStoreSyncCycles(gameboyOffset: i32, value: i32): void {\n  syncCycles(8);\n  sixteenBitStoreIntoGBMemoryWithTraps(gameboyOffset, value);\n}\n\n// Functions to access the next operands of a opcode, reffering to them as \"dataBytes\"\nfunction getDataByteOne(): u8 {\n  syncCycles(4);\n  return <u8>eightBitLoadFromGBMemory(Cpu.programCounter);\n}\n\nfunction getDataByteTwo(): u8 {\n  syncCycles(4);\n  return <u8>eightBitLoadFromGBMemory(u16Portable(Cpu.programCounter + 1));\n}\n// Get our concatenated databyte one and getDataByteTwo()\n// Find and replace with : getConcatenatedDataByte()\nfunction getConcatenatedDataByte(): u16 {\n  return <u16>concatenateBytes(getDataByteTwo(), getDataByteOne());\n}\n\nfunction handleOpcode0x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x00:\n      // NOP\n      // 1  4\n      // No Operation\n      return 4;\n    case 0x01: {\n      // LD BC,d16\n      // 3  12\n\n      // 8 cycles\n      let concatenatedDataByte: i32 = getConcatenatedDataByte();\n\n      Cpu.registerB = <u8>splitHighByte(concatenatedDataByte);\n      Cpu.registerC = <u8>splitLowByte(concatenatedDataByte);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n\n      return 4;\n    }\n    case 0x02: {\n      // LD (BC),A\n      // 1  8\n      // () means load into address pointed by BC\n\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerB, Cpu.registerC), Cpu.registerA);\n      return 4;\n    }\n    case 0x03: {\n      // INC BC\n      // 1  8\n      let registerBC3: u16 = <u16>concatenateBytes(Cpu.registerB, Cpu.registerC);\n      registerBC3++;\n      Cpu.registerB = <u8>splitHighByte(registerBC3);\n      Cpu.registerC = <u8>splitLowByte(registerBC3);\n      return 8;\n    }\n    case 0x04: {\n      // INC B\n      // 1  4\n      // Z 0 H -\n      let registerB = Cpu.registerB;\n      checkAndSetEightBitHalfCarryFlag(registerB, 1);\n      registerB = u8Portable(registerB + 1);\n      Cpu.registerB = registerB;\n      setZeroFlag(<i32>(registerB === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x05: {\n      // DEC B\n      // 1  4\n      // Z 1 H -\n      let registerB = Cpu.registerB;\n      checkAndSetEightBitHalfCarryFlag(registerB, -1);\n      registerB = u8Portable(registerB - 1);\n      Cpu.registerB = registerB;\n      setZeroFlag(<i32>(registerB === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x06: {\n      // LD B,d8\n      // 2  8\n\n      // 4 cycles\n      Cpu.registerB = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n\n      return 4;\n    }\n    case 0x07: {\n      // RLCA\n      // 1  4\n      // 0 0 0 C\n      // Check for the carry\n      let registerA = Cpu.registerA;\n      setCarryFlag(<i32>((registerA & 0x80) === 0x80));\n      Cpu.registerA = rotateByteLeft(registerA);\n      // Set all other flags to zero\n      setZeroFlag(0);\n      setSubtractFlag(0);\n      setHalfCarryFlag(0);\n      return 4;\n    }\n    case 0x08: {\n      // LD (a16),SP\n      // 3  20\n      // Load the stack pointer into the 16 bit address represented by the two data bytes\n\n      // 16 cycles, 8 from data byte, 8 from sixteenbit store\n      sixteenBitStoreSyncCycles(getConcatenatedDataByte(), Cpu.stackPointer);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n\n      return 4;\n    }\n    case 0x09: {\n      // ADD HL,BC\n      // 1 8\n      // - 0 H C\n      let registerHL: u16 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      let registerBC9: u16 = <u16>concatenateBytes(Cpu.registerB, Cpu.registerC);\n      checkAndSetSixteenBitFlagsAddOverflow(<u16>registerHL, <u16>registerBC9, false);\n      let result: u16 = u16Portable(<u16>(registerHL + registerBC9));\n      Cpu.registerH = <u8>splitHighByte(<u16>result);\n      Cpu.registerL = <u8>splitLowByte(<u16>result);\n      setSubtractFlag(0);\n      return 8;\n    }\n    case 0x0a: {\n      // LD A,(BC)\n      // 1 8\n\n      // 4 cycles from load\n      Cpu.registerA = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerB, Cpu.registerC));\n      return 4;\n    }\n    case 0x0b: {\n      // DEC BC\n      // 1  8\n      let registerBCB: u16 = <u16>concatenateBytes(Cpu.registerB, Cpu.registerC);\n      registerBCB = u16Portable(registerBCB - 1);\n      Cpu.registerB = <u8>splitHighByte(registerBCB);\n      Cpu.registerC = <u8>splitLowByte(registerBCB);\n      return 8;\n    }\n    case 0x0c: {\n      // INC C\n      // 1  4\n      // Z 0 H -\n      let registerC = Cpu.registerC;\n      checkAndSetEightBitHalfCarryFlag(registerC, 1);\n      registerC = u8Portable(registerC + 1);\n      Cpu.registerC = registerC;\n      setZeroFlag(<i32>(registerC === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x0d: {\n      // DEC C\n      // 1  4\n      // Z 1 H -\n      let registerC = Cpu.registerC;\n      checkAndSetEightBitHalfCarryFlag(registerC, -1);\n      registerC = u8Portable(registerC - 1);\n      Cpu.registerC = registerC;\n      setZeroFlag(<i32>(registerC === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x0e: {\n      // LD C,d8\n      // 2 8\n\n      // 4 cycles\n      Cpu.registerC = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n\n      return 4;\n    }\n    case 0x0f: {\n      // RRCA\n      // 1 4\n      // 0 0 0 C\n      // Check for the last bit, to see if it will be carried\n      let registerA = Cpu.registerA;\n      setCarryFlag(<i32>((registerA & 0x01) > 0));\n      Cpu.registerA = rotateByteRight(registerA);\n      // Set all other flags to zero\n      setZeroFlag(0);\n      setSubtractFlag(0);\n      setHalfCarryFlag(0);\n      return 4;\n    }\n  }\n  return -1;\n}\n\nfunction handleOpcode1x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x10: {\n      // STOP 0\n      // 2 4\n      // Enter CPU very low power mode. Also used to switch between double and normal speed CPU modes in GBC.\n      // Meaning Don't Decode anymore opcodes , or updated the LCD until joypad interrupt (or when button is pressed if I am wrong)\n      // See HALT\n\n      // If we are in gameboy color mode, set the new speed\n      if (Cpu.GBCEnabled) {\n        // 4 cycles\n        let speedSwitch: i32 = eightBitLoadSyncCycles(Cpu.memoryLocationSpeedSwitch);\n        if (checkBitOnByte(0, speedSwitch)) {\n          // Reset the prepare bit\n          speedSwitch = resetBitOnByte(0, speedSwitch);\n\n          // Switch to the new mode, and set the speed switch to the OTHER speed, to represent our new speed\n          if (!checkBitOnByte(7, speedSwitch)) {\n            Cpu.GBCDoubleSpeed = true;\n            speedSwitch = setBitOnByte(7, speedSwitch);\n          } else {\n            Cpu.GBCDoubleSpeed = false;\n            speedSwitch = resetBitOnByte(7, speedSwitch);\n          }\n\n          // Store the final speed switch\n          // 4 cycles\n          eightBitStoreSyncCycles(Cpu.memoryLocationSpeedSwitch, speedSwitch);\n\n          // Cycle accurate gameboy docs says this takes 76 clocks\n          // 76 - 8 cycles (from load/store) = 68\n          return 68;\n        }\n      }\n\n      // NOTE: This breaks Blarggs CPU tests if CGB Stop is not implemented\n      Cpu.isStopped = true;\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x11: {\n      // LD DE,d16\n      // 3  12\n\n      // 8 cycles\n      let concatenatedDataByte = getConcatenatedDataByte();\n\n      Cpu.registerD = <u8>splitHighByte(concatenatedDataByte);\n      Cpu.registerE = <u8>splitLowByte(concatenatedDataByte);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n      return 4;\n    }\n    case 0x12: {\n      // LD (DE),A\n      // 1 8\n\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerD, Cpu.registerE), Cpu.registerA);\n      return 4;\n    }\n    case 0x13: {\n      // INC DE\n      // 1 8\n      let registerDE3 = <u16>concatenateBytes(Cpu.registerD, Cpu.registerE);\n      registerDE3 = u16Portable(registerDE3 + 1);\n      Cpu.registerD = <u8>splitHighByte(registerDE3);\n      Cpu.registerE = <u8>splitLowByte(registerDE3);\n      return 8;\n    }\n    case 0x14: {\n      // INC D\n      // 1  4\n      // Z 0 H -\n      let registerD = Cpu.registerD;\n      checkAndSetEightBitHalfCarryFlag(registerD, 1);\n      registerD = u8Portable(registerD + 1);\n      Cpu.registerD = registerD;\n      setZeroFlag(<i32>(Cpu.registerD === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x15: {\n      // DEC D\n      // 1  4\n      // Z 1 H -\n      let registerD = Cpu.registerD;\n      checkAndSetEightBitHalfCarryFlag(registerD, -1);\n      registerD = u8Portable(registerD - 1);\n      Cpu.registerD = registerD;\n      setZeroFlag(<i32>(Cpu.registerD === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x16: {\n      // LD D,d8\n      // 2 8\n\n      // 4 cycles\n      Cpu.registerD = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x17: {\n      // RLA\n      // 1 4\n      // 0 0 0 C\n      // Check for the carry\n      // setting has first bit since we need to use carry\n      let hasHighbit = (Cpu.registerA & 0x80) === 0x80;\n      Cpu.registerA = rotateByteLeftThroughCarry(Cpu.registerA);\n      // OR the carry flag to the end\n      setCarryFlag(<i32>hasHighbit);\n      // Set all other flags to zero\n      setZeroFlag(0);\n      setSubtractFlag(0);\n      setHalfCarryFlag(0);\n      return 4;\n    }\n    case 0x18: {\n      // JR r8\n      // 2  12\n      // NOTE: Discoved dataByte is signed\n      // However the relative Jump Function handles this\n\n      // 4 cycles\n      relativeJump(getDataByteOne());\n      return 8;\n    }\n    // Relative Jump Function Handles program counter\n    case 0x19: {\n      // ADD HL,DE\n      // 1  8\n      // - 0 H C\n      let registerHL = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      let registerDE9 = <u16>concatenateBytes(Cpu.registerD, Cpu.registerE);\n      checkAndSetSixteenBitFlagsAddOverflow(<u16>registerHL, <u16>registerDE9, false);\n      let result = u16Portable(<u16>(registerHL + registerDE9));\n      Cpu.registerH = <u8>splitHighByte(<u16>result);\n      Cpu.registerL = <u8>splitLowByte(<u16>result);\n      setSubtractFlag(0);\n      return 8;\n    }\n    case 0x1a: {\n      // LD A,(DE)\n      // 1 8\n      let registerDEA = <u16>concatenateBytes(Cpu.registerD, Cpu.registerE);\n      // 4 cycles\n      Cpu.registerA = <u8>eightBitLoadSyncCycles(registerDEA);\n      return 4;\n    }\n    case 0x1b: {\n      // DEC DE\n      // 1 8\n      let registerDEB = <u16>concatenateBytes(Cpu.registerD, Cpu.registerE);\n      registerDEB = u16Portable(registerDEB - 1);\n      Cpu.registerD = <u8>splitHighByte(registerDEB);\n      Cpu.registerE = <u8>splitLowByte(registerDEB);\n      return 8;\n    }\n    case 0x1c: {\n      // INC E\n      // 1  4\n      // Z 0 H -\n      let registerE = Cpu.registerE;\n      checkAndSetEightBitHalfCarryFlag(registerE, 1);\n      registerE = u8Portable(registerE + 1);\n      Cpu.registerE = registerE;\n      setZeroFlag(<i32>(registerE === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x1d: {\n      // DEC E\n      // 1  4\n      // Z 1 H -\n      let registerE = Cpu.registerE;\n      checkAndSetEightBitHalfCarryFlag(registerE, -1);\n      registerE = u8Portable(registerE - 1);\n      Cpu.registerE = registerE;\n      setZeroFlag(<i32>(registerE === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x1e: {\n      // LD E,d8\n      // 2 8\n\n      // 4 cycles\n      Cpu.registerE = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x1f: {\n      // RRA\n      // 1 4\n      // 0 0 0 C\n      // Check for the carry\n      // setting has low bit since we need to use carry\n      let hasLowBit = (Cpu.registerA & 0x01) === 0x01;\n      Cpu.registerA = rotateByteRightThroughCarry(Cpu.registerA);\n\n      setCarryFlag(<i32>hasLowBit);\n      // Set all other flags to zero\n      setZeroFlag(0);\n      setSubtractFlag(0);\n      setHalfCarryFlag(0);\n      return 4;\n    }\n  }\n\n  return -1;\n}\n\nfunction handleOpcode2x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x20: {\n      // JR NZ,r8\n      // 2  12/8\n      // NOTE: NZ stands for not [flag], so in this case, not zero flag\n      // Also, / means, if condition. so if met, 12 cycles, otherwise 8 cycles\n      if (getZeroFlag() === 0) {\n        // 4 cycles\n        relativeJump(getDataByteOne());\n        // Relative Jump Funciton handles program counter\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      }\n      return 8;\n    }\n    case 0x21: {\n      // LD HL,d16\n      // 3  12\n      // 8 cycles\n      let sixteenBitDataByte = getConcatenatedDataByte();\n      Cpu.registerH = <u8>splitHighByte(sixteenBitDataByte);\n      Cpu.registerL = <u8>splitLowByte(sixteenBitDataByte);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n      return 4;\n    }\n    case 0x22: {\n      // LD (HL+),A\n      // 1 8\n      let registerHL2 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      // 4 cycles\n      eightBitStoreSyncCycles(registerHL2, Cpu.registerA);\n      registerHL2 = u16Portable(registerHL2 + 1);\n      Cpu.registerH = <u8>splitHighByte(registerHL2);\n      Cpu.registerL = <u8>splitLowByte(registerHL2);\n      return 4;\n    }\n    case 0x23: {\n      // INC HL\n      // 1  8\n      let registerHL3 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      registerHL3 = u16Portable(registerHL3 + 1);\n      Cpu.registerH = <u8>splitHighByte(registerHL3);\n      Cpu.registerL = <u8>splitLowByte(registerHL3);\n      return 8;\n    }\n    case 0x24: {\n      // INC H\n      // 1  4\n      // Z 0 H -\n      let registerH = Cpu.registerH;\n      checkAndSetEightBitHalfCarryFlag(registerH, 1);\n      registerH = u8Portable(registerH + 1);\n      Cpu.registerH = registerH;\n      setZeroFlag(<i32>(registerH === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x25: {\n      // DEC H\n      // 1  4\n      // Z 1 H -\n      let registerH = Cpu.registerH;\n      checkAndSetEightBitHalfCarryFlag(registerH, -1);\n      registerH = u8Portable(registerH - 1);\n      Cpu.registerH = registerH;\n      setZeroFlag(<i32>(registerH === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x26: {\n      // LD H,d8\n      // 2 8\n\n      // 4 cycles\n      Cpu.registerH = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x27: {\n      // DAA\n      // 1 4\n      // Z - 0 C\n      let adjustedRegister: u8 = 0;\n      let adjustment: u8 = 0;\n\n      if (getHalfCarryFlag() > 0) {\n        adjustment = adjustment | 0x06;\n      }\n      if (getCarryFlag() > 0) {\n        adjustment = adjustment | 0x60;\n      }\n\n      let registerA = Cpu.registerA;\n      if (getSubtractFlag() > 0) {\n        adjustedRegister = u8Portable(registerA - <u8>adjustment);\n      } else {\n        if ((registerA & 0x0f) > 0x09) {\n          adjustment = adjustment | 0x06;\n        }\n        if (registerA > 0x99) {\n          adjustment = adjustment | 0x60;\n        }\n        adjustedRegister = u8Portable(registerA + <u8>adjustment);\n      }\n\n      // Now set our flags to the correct values\n      setZeroFlag(<i32>(adjustedRegister === 0));\n      setCarryFlag(<i32>((adjustment & 0x60) !== 0));\n      setHalfCarryFlag(0);\n\n      Cpu.registerA = <u8>adjustedRegister;\n      return 4;\n    }\n    case 0x28: {\n      // JR Z,r8\n      // 2  12/8\n      if (getZeroFlag() > 0) {\n        // 4 cycles\n        relativeJump(getDataByteOne());\n        // Relative Jump funciton handles pogram counter\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      }\n      return 8;\n    }\n    case 0x29: {\n      // ADD HL,HL\n      // 1  8\n      // - 0 H C\n      let registerHL9 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      checkAndSetSixteenBitFlagsAddOverflow(registerHL9, registerHL9, false);\n      registerHL9 = u16Portable(registerHL9 * 2);\n      Cpu.registerH = <u8>splitHighByte(registerHL9);\n      Cpu.registerL = <u8>splitLowByte(registerHL9);\n      setSubtractFlag(0);\n      return 8;\n    }\n    case 0x2a: {\n      // LD A,(HL+)\n      // 1  8\n      let registerHLA = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      // 4 cycles\n      Cpu.registerA = <u8>eightBitLoadSyncCycles(registerHLA);\n      registerHLA = u16Portable(registerHLA + 1);\n      Cpu.registerH = <u8>splitHighByte(registerHLA);\n      Cpu.registerL = <u8>splitLowByte(registerHLA);\n      return 4;\n    }\n    case 0x2b: {\n      // DEC HL\n      // 1 8\n      let registerHLB = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      registerHLB = u16Portable(registerHLB - 1);\n      Cpu.registerH = <u8>splitHighByte(registerHLB);\n      Cpu.registerL = <u8>splitLowByte(registerHLB);\n      return 8;\n    }\n    case 0x2c: {\n      // INC L\n      // 1  4\n      // Z 0 H -\n      let registerL = Cpu.registerL;\n      checkAndSetEightBitHalfCarryFlag(registerL, 1);\n      registerL = u8Portable(registerL + 1);\n      Cpu.registerL = registerL;\n      setZeroFlag(<i32>(registerL === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x2d: {\n      // DEC L\n      // 1  4\n      // Z 1 H -\n      let registerL = Cpu.registerL;\n      checkAndSetEightBitHalfCarryFlag(registerL, -1);\n      registerL = u8Portable(registerL - 1);\n      Cpu.registerL = registerL;\n      setZeroFlag(<i32>(registerL === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x2e: {\n      // LD L,d8\n      // 2  8\n      // 4 cycles\n      Cpu.registerL = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x2f: {\n      // CPL\n      // 1 4\n      // - 1 1 -\n      Cpu.registerA = ~Cpu.registerA;\n      setSubtractFlag(1);\n      setHalfCarryFlag(1);\n      return 4;\n    }\n  }\n  return -1;\n}\n\nfunction handleOpcode3x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x30: {\n      // JR NC,r8\n      // 2 12 / 8\n      if (getCarryFlag() === 0) {\n        // 4 cycles\n        relativeJump(getDataByteOne());\n        // Relative Jump function handles program counter\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      }\n      return 8;\n    }\n    case 0x31: {\n      // LD SP,d16\n      // 3 12\n      // 8 cycles\n      Cpu.stackPointer = getConcatenatedDataByte();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n      return 4;\n    }\n    case 0x32: {\n      // LD (HL-),A\n      // 1 8\n      let registerHL2 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      // 4 cycles\n      eightBitStoreSyncCycles(registerHL2, Cpu.registerA);\n      registerHL2 = u16Portable(registerHL2 - 1);\n      Cpu.registerH = <u8>splitHighByte(registerHL2);\n      Cpu.registerL = <u8>splitLowByte(registerHL2);\n      return 4;\n    }\n    case 0x33: {\n      // INC SP\n      // 1 8\n      Cpu.stackPointer = u16Portable(Cpu.stackPointer + 1);\n      return 8;\n    }\n    case 0x34: {\n      // INC (HL)\n      // 1  12\n      // Z 0 H -\n      let registerHL4 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      // 4 cycles\n      let valueAtHL4 = <u8>eightBitLoadSyncCycles(registerHL4);\n      // Creating a varible for this to fix assemblyscript overflow bug\n      // Requires explicit casting\n      // https://github.com/AssemblyScript/assemblyscript/issues/26\n      let incrementer: u8 = 1;\n      checkAndSetEightBitHalfCarryFlag(<u8>valueAtHL4, <i16>incrementer);\n      valueAtHL4 = u8Portable(<u8>valueAtHL4 + <u8>incrementer);\n\n      setZeroFlag(<i32>(valueAtHL4 === 0));\n      setSubtractFlag(0);\n      // 4 cycles\n      eightBitStoreSyncCycles(registerHL4, <u8>valueAtHL4);\n      return 4;\n    }\n    case 0x35: {\n      // DEC (HL)\n      // 1  12\n      // Z 1 H -\n      let registerHL5 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      // 4 cycles\n      let valueAtHL5 = <u8>eightBitLoadSyncCycles(registerHL5);\n      // NOTE: This opcode may not overflow correctly,\n      // Please see previous opcode\n      checkAndSetEightBitHalfCarryFlag(valueAtHL5, -1);\n      valueAtHL5 = u8Portable(valueAtHL5 - 1);\n      setZeroFlag(<i32>(valueAtHL5 === 0));\n      setSubtractFlag(1);\n      // 4 cycles\n      eightBitStoreSyncCycles(registerHL5, valueAtHL5);\n      return 4;\n    }\n    case 0x36: {\n      // LD (HL),d8\n      // 2  12\n      // 8 cycles, 4 from store, 4 from data byte\n      eightBitStoreSyncCycles(<u16>concatenateBytes(Cpu.registerH, Cpu.registerL), getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x37: {\n      // SCF\n      // 1  4\n      // - 0 0 1\n      // Simply set the carry flag\n      setSubtractFlag(0);\n      setHalfCarryFlag(0);\n      setCarryFlag(1);\n      return 4;\n    }\n    case 0x38: {\n      // JR C,r8\n      // 2 12/8\n      if (getCarryFlag() === 1) {\n        // 4 cycles\n        relativeJump(getDataByteOne());\n        // Relative Jump Funciton handles program counter\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      }\n      return 8;\n    }\n    case 0x39: {\n      // ADD HL,SP\n      // 1 8\n      // - 0 H C\n      let registerHL9 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      checkAndSetSixteenBitFlagsAddOverflow(<u16>registerHL9, Cpu.stackPointer, false);\n      let result = u16Portable(<u16>(registerHL9 + Cpu.stackPointer));\n      Cpu.registerH = <u8>splitHighByte(<u16>result);\n      Cpu.registerL = <u8>splitLowByte(<u16>result);\n      setSubtractFlag(0);\n      return 8;\n    }\n    case 0x3a: {\n      // LD A,(HL-)\n      // 1 8\n      let registerHLA = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      // 4 cycles\n      Cpu.registerA = <u8>eightBitLoadSyncCycles(registerHLA);\n      registerHLA = u16Portable(registerHLA - 1);\n      Cpu.registerH = <u8>splitHighByte(registerHLA);\n      Cpu.registerL = <u8>splitLowByte(registerHLA);\n      return 4;\n    }\n    case 0x3b: {\n      // DEC SP\n      // 1 8\n      Cpu.stackPointer = u16Portable(Cpu.stackPointer - 1);\n      return 8;\n    }\n    case 0x3c: {\n      // INC A\n      // 1  4\n      // Z 0 H -\n      let registerA = Cpu.registerA;\n      checkAndSetEightBitHalfCarryFlag(registerA, 1);\n      registerA = u8Portable(registerA + 1);\n      Cpu.registerA = registerA;\n      setZeroFlag(<i32>(registerA === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x3d: {\n      // DEC A\n      // 1  4\n      // Z 1 H -\n      let registerA = Cpu.registerA;\n      checkAndSetEightBitHalfCarryFlag(registerA, -1);\n      registerA = u8Portable(registerA - 1);\n      Cpu.registerA = registerA;\n      setZeroFlag(<i32>(registerA === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x3e: {\n      // LD A,d8\n      // 2 8\n      // 4 cycles\n      Cpu.registerA = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x3f: {\n      // CCF\n      // 1 4\n      // - 0 0 C\n      setSubtractFlag(0);\n      setHalfCarryFlag(0);\n      setCarryFlag(<i32>(getCarryFlag() <= 0));\n      return 4;\n    }\n  }\n  return -1;\n}\n\nfunction handleOpcode4x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x40:\n      // LD B,B\n      // 1 4\n      // Load B into B, Do nothing\n      return 4;\n    case 0x41:\n      // LD B,C\n      // 1 4\n      Cpu.registerB = Cpu.registerC;\n      return 4;\n    case 0x42:\n      // LD B,D\n      // 1 4\n      Cpu.registerB = Cpu.registerD;\n      return 4;\n    case 0x43:\n      // LD B,E\n      // 1 4\n      Cpu.registerB = Cpu.registerE;\n      return 4;\n    case 0x44:\n      // LD B,H\n      // 1 4\n      Cpu.registerB = Cpu.registerH;\n      return 4;\n    case 0x45:\n      // LD B,L\n      // 1 4\n      Cpu.registerB = Cpu.registerL;\n      return 4;\n    case 0x46:\n      // LD B,(HL)\n      // 1 8\n      // 4 cycles\n      Cpu.registerB = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x47:\n      // LD B,A\n      // 1 4\n      Cpu.registerB = Cpu.registerA;\n      return 4;\n    case 0x48:\n      // LD C,B\n      // 1 4\n      Cpu.registerC = Cpu.registerB;\n      return 4;\n    case 0x49:\n      // LD C,C\n      // 1 4\n      // Do nothing\n      return 4;\n    case 0x4a:\n      // LD C,D\n      // 1 4\n      Cpu.registerC = Cpu.registerD;\n      return 4;\n    case 0x4b:\n      // LD C,E\n      // 1 4\n      Cpu.registerC = Cpu.registerE;\n      return 4;\n    case 0x4c:\n      // LD C,H\n      // 1 4\n      Cpu.registerC = Cpu.registerH;\n      return 4;\n    case 0x4d:\n      // LD C,L\n      // 1 4\n      Cpu.registerC = Cpu.registerL;\n      return 4;\n    case 0x4e:\n      // LD C,(HL)\n      // 1 8\n      // 4 cycles\n      Cpu.registerC = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x4f:\n      // LD C,A\n      // 1 4\n      Cpu.registerC = Cpu.registerA;\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcode5x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x50:\n      // LD D,B\n      // 1 4\n      Cpu.registerD = Cpu.registerB;\n      return 4;\n    case 0x51:\n      // LD D,C\n      // 1 4\n      Cpu.registerD = Cpu.registerC;\n      return 4;\n    case 0x52:\n      // LD D,D\n      // 1 4\n      // Do Nothing\n      return 4;\n    case 0x53:\n      // LD D,E\n      // 1 4\n      Cpu.registerD = Cpu.registerE;\n      return 4;\n    case 0x54:\n      // LD D,H\n      // 1 4\n      Cpu.registerD = Cpu.registerH;\n      return 4;\n    case 0x55:\n      // LD D,L\n      // 1 4\n      Cpu.registerD = Cpu.registerL;\n      return 4;\n    case 0x56:\n      // LD D,(HL)\n      // 1 8\n      // 4 cycles\n      Cpu.registerD = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x57:\n      // LD D,A\n      // 1 4\n      Cpu.registerD = Cpu.registerA;\n      return 4;\n    case 0x58:\n      // LD E,B\n      // 1 4\n      Cpu.registerE = Cpu.registerB;\n      return 4;\n    case 0x59:\n      // LD E,C\n      // 1 4\n      Cpu.registerE = Cpu.registerC;\n      return 4;\n    case 0x5a:\n      // LD E,D\n      // 1 4\n      Cpu.registerE = Cpu.registerD;\n      return 4;\n    case 0x5b:\n      // LD E,E\n      // 1 4\n      // Do Nothing\n      return 4;\n    case 0x5c:\n      // LD E,H\n      // 1 4\n      Cpu.registerE = Cpu.registerH;\n      return 4;\n    case 0x5d:\n      // LD E,L\n      // 1 4\n      Cpu.registerE = Cpu.registerL;\n      return 4;\n    case 0x5e:\n      // LD E,(HL)\n      // 1 8\n      // 4 cycles\n      Cpu.registerE = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x5f:\n      // LD E,A\n      // 1 4\n      Cpu.registerE = Cpu.registerA;\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcode6x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x60:\n      // LD H,B\n      // 1 4\n      Cpu.registerH = Cpu.registerB;\n      return 4;\n    case 0x61:\n      // LD H,C\n      // 1 4\n      Cpu.registerH = Cpu.registerC;\n      return 4;\n    case 0x62:\n      // LD H,D\n      // 1 4\n      Cpu.registerH = Cpu.registerD;\n      return 4;\n    case 0x63:\n      // LD H,E\n      // 1 4\n      Cpu.registerH = Cpu.registerE;\n      return 4;\n    case 0x64:\n      // LD H,H\n      // 1 4\n      Cpu.registerH = Cpu.registerH;\n      return 4;\n    case 0x65:\n      // LD H,L\n      // 1 4\n      Cpu.registerH = Cpu.registerL;\n      return 4;\n    case 0x66:\n      // LD H,(HL)\n      // 1 8\n      // 4 cycles\n      Cpu.registerH = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x67:\n      // LD H,A\n      // 1 4\n      Cpu.registerH = Cpu.registerA;\n      return 4;\n    case 0x68:\n      // LD L,B\n      // 1 4\n      Cpu.registerL = Cpu.registerB;\n      return 4;\n    case 0x69:\n      // LD L,C\n      // 1 4\n      Cpu.registerL = Cpu.registerC;\n      return 4;\n    case 0x6a:\n      // LD L,D\n      // 1 4\n      Cpu.registerL = Cpu.registerD;\n      return 4;\n    case 0x6b:\n      // LD L,E\n      // 1 4\n      Cpu.registerL = Cpu.registerE;\n      return 4;\n    case 0x6c:\n      // LD L,H\n      // 1 4\n      Cpu.registerL = Cpu.registerH;\n      return 4;\n    case 0x6d:\n      // LD L,L\n      // 1 4\n      Cpu.registerL = Cpu.registerL;\n      return 4;\n    case 0x6e:\n      // LD L,(HL)\n      // 1 8\n      // 4 cycles\n      Cpu.registerL = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x6f:\n      // LD L,A\n      // 1 4\n      Cpu.registerL = Cpu.registerA;\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcode7x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x70:\n      // LD (HL),B\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerB);\n      return 4;\n    case 0x71:\n      // LD (HL),C\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerC);\n      return 4;\n    case 0x72:\n      // LD (HL),D\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerD);\n      return 4;\n    case 0x73:\n      // LD (HL),E\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerE);\n      return 4;\n    case 0x74:\n      // LD (HL),H\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerH);\n      return 4;\n    case 0x75:\n      // LD (HL),L\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerL);\n      return 4;\n    case 0x76:\n      // HALT\n      // 1 4\n      // Enter CPU very low power mode\n      // Meaning Don't Decode anymore opcodes until an interrupt occurs\n      // Still need to do timers and things\n\n      // Can't Halt during an HDMA\n      // https://gist.github.com/drhelius/3394856\n      if (!Memory.isHblankHdmaActive) {\n        Cpu.enableHalt();\n      }\n      return 4;\n    case 0x77:\n      // LD (HL),A\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerA);\n      return 4;\n    case 0x78:\n      // LD A,B\n      // 1 4\n      Cpu.registerA = Cpu.registerB;\n      return 4;\n    case 0x79:\n      // LD A,C\n      // 1 4\n      Cpu.registerA = Cpu.registerC;\n      return 4;\n    case 0x7a:\n      // LD A,D\n      // 1 4\n      Cpu.registerA = Cpu.registerD;\n      return 4;\n    case 0x7b:\n      // LD A,E\n      // 1 4\n      Cpu.registerA = Cpu.registerE;\n      return 4;\n    case 0x7c:\n      // LD A,H\n      // 1 4\n      Cpu.registerA = Cpu.registerH;\n      return 4;\n    case 0x7d:\n      // LD A,L\n      // 1 4\n      Cpu.registerA = Cpu.registerL;\n      return 4;\n    case 0x7e:\n      // LD A,(HL)\n      // 1 8\n      // NOTE: Thanks to @binji for catching that this should be 8 cycles, not 4\n      // 4 cycles\n      Cpu.registerA = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x7f:\n      // LD A,A\n      // 1 4\n      // Do Nothing\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcode8x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x80:\n      // ADD A,B\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerB);\n      return 4;\n    case 0x81:\n      // ADD A,C\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerC);\n      return 4;\n    case 0x82:\n      // ADD A,D\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerD);\n      return 4;\n    case 0x83:\n      // ADD A,E\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerE);\n      return 4;\n    case 0x84:\n      // ADD A,H\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerH);\n      return 4;\n    case 0x85:\n      // ADD A,L\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerL);\n      return 4;\n    case 0x86:\n      // ADD A,(HL)\n      // 1 8\n      // Z 0 H C\n      // 4 cycles\n      let valueAtHL6: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      addARegister(<u8>valueAtHL6);\n      return 4;\n    case 0x87:\n      // ADD A,A\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerA);\n      return 4;\n    case 0x88:\n      // ADC A,B\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerB);\n      return 4;\n    case 0x89:\n      // ADC A,C\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerC);\n      return 4;\n    case 0x8a:\n      // ADC A,D\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerD);\n      return 4;\n    case 0x8b:\n      // ADC A,E\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerE);\n      return 4;\n    case 0x8c:\n      // ADC A,H\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerH);\n      return 4;\n    case 0x8d:\n      // ADC A,L\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerL);\n      return 4;\n    case 0x8e:\n      // ADC A,(HL)\n      // 1 8\n      // Z 0 H C\n      // 4 cycles\n      let valueAtHLE: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      addAThroughCarryRegister(<u8>valueAtHLE);\n      return 4;\n    case 0x8f:\n      // ADC A,A\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerA);\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcode9x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x90:\n      // SUB B\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerB);\n      return 4;\n    case 0x91:\n      // SUB C\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerC);\n      return 4;\n    case 0x92:\n      // SUB D\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerD);\n      return 4;\n    case 0x93:\n      // SUB E\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerE);\n      return 4;\n    case 0x94:\n      // SUB H\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerH);\n      return 4;\n    case 0x95:\n      // SUB L\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerL);\n      return 4;\n    case 0x96:\n      // SUB (HL)\n      // 1  8\n      // Z 1 H C\n      // 4 cycles\n      let valueAtHL6: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      subARegister(<u8>valueAtHL6);\n      return 4;\n    case 0x97:\n      // SUB A\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerA);\n      return 4;\n    case 0x98:\n      // SBC A,B\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerB);\n      return 4;\n    case 0x99:\n      // SBC A,C\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerC);\n      return 4;\n    case 0x9a:\n      // SBC A,D\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerD);\n      return 4;\n    case 0x9b:\n      // SBC A,E\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerE);\n      return 4;\n    case 0x9c:\n      // SBC A,H\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerH);\n      return 4;\n    case 0x9d:\n      // SBC A,L\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerL);\n      return 4;\n    case 0x9e:\n      // SBC A,(HL)\n      // 1  8\n      // Z 1 H C\n      // 4 cycles\n      let valueAtHLE: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      subAThroughCarryRegister(<u8>valueAtHLE);\n      return 4;\n    case 0x9f:\n      // SBC A,A\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerA);\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcodeAx(opcode: i32): i32 {\n  switch (opcode) {\n    case 0xa0:\n      // AND B\n      // 1  4\n      // Z 0 1 0\n      andARegister(Cpu.registerB);\n      return 4;\n    case 0xa1:\n      // AND C\n      // 1  4\n      // Z 0 1 0\n      andARegister(Cpu.registerC);\n      return 4;\n    case 0xa2:\n      // AND D\n      // 1  4\n      // Z 0 1 0\n      andARegister(Cpu.registerD);\n      return 4;\n    case 0xa3:\n      // AND E\n      // 1  4\n      // Z 0 1 0\n      andARegister(Cpu.registerE);\n      return 4;\n    case 0xa4:\n      // AND H\n      // 1  4\n      // Z 0 1 0\n      andARegister(Cpu.registerH);\n      return 4;\n    case 0xa5:\n      // AND L\n      // 1  4\n      // Z 0 1 0\n      andARegister(Cpu.registerL);\n      return 4;\n    case 0xa6:\n      // AND (HL)\n      // 1  8\n      // Z 0 1 0\n      // 4 cycles\n      let valueAtHL6: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      andARegister(<u8>valueAtHL6);\n      return 4;\n    case 0xa7:\n      // AND A\n      // 1  4\n      // Z 0 1 0\n      // NOTE: & Yourself, does nothing\n      andARegister(Cpu.registerA);\n      return 4;\n    case 0xa8:\n      // XOR B\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerB);\n      return 4;\n    case 0xa9:\n      // XOR C\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerC);\n      return 4;\n    case 0xaa:\n      // XOR D\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerD);\n      return 4;\n    case 0xab:\n      // XOR E\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerE);\n      return 4;\n    case 0xac:\n      // XOR H\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerH);\n      return 4;\n    case 0xad:\n      // XOR L\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerL);\n      return 4;\n    case 0xae:\n      // XOR (HL)\n      // 1  8\n      // Z 0 0 0\n      // 4 cycles\n      let valueAtHLE: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      xorARegister(<u8>valueAtHLE);\n      return 4;\n    case 0xaf:\n      // XOR A\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerA);\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcodeBx(opcode: i32): i32 {\n  switch (opcode) {\n    case 0xb0:\n      // OR B\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerB);\n      return 4;\n    case 0xb1:\n      // OR C\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerC);\n      return 4;\n    case 0xb2:\n      // OR D\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerD);\n      return 4;\n    case 0xb3:\n      // OR E\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerE);\n      return 4;\n    case 0xb4:\n      // OR H\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerH);\n      return 4;\n    case 0xb5:\n      // OR L\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerL);\n      return 4;\n    case 0xb6:\n      // OR (HL)\n      // 1  8\n      // Z 0 0 0\n      // 4 cycles\n      let valueAtHL6: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      orARegister(<u8>valueAtHL6);\n      return 4;\n    case 0xb7:\n      // OR A\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerA);\n      return 4;\n    case 0xb8:\n      // CP B\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerB);\n      return 4;\n    case 0xb9:\n      // CP C\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerC);\n      return 4;\n    case 0xba:\n      // CP D\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerD);\n      return 4;\n    case 0xbb:\n      // CP E\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerE);\n      return 4;\n    case 0xbc:\n      // CP H\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerH);\n      return 4;\n    case 0xbd:\n      // CP L\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerL);\n      return 4;\n    case 0xbe:\n      // CP (HL)\n      // 1  8\n      // Z 1 H C\n      // 4 cycles\n      let valueAtHLE: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      cpARegister(<u8>valueAtHLE);\n      return 4;\n    case 0xbf:\n      // CP A\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerA);\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcodeCx(opcode: i32): i32 {\n  switch (opcode) {\n    case 0xc0: {\n      // RET NZ\n      // 1  20/8\n      if (getZeroFlag() === 0) {\n        // 8 cycles\n        let stackPointer = Cpu.stackPointer;\n        Cpu.programCounter = <u16>sixteenBitLoadSyncCycles(stackPointer);\n        Cpu.stackPointer = u16Portable(stackPointer + 2);\n        return 12;\n      } else {\n        return 8;\n      }\n    }\n    case 0xc1: {\n      // POP BC\n      // 1  12\n      // 8 cycles\n      let registerBC1: i32 = sixteenBitLoadSyncCycles(Cpu.stackPointer);\n      Cpu.stackPointer = u16Portable(Cpu.stackPointer + 2);\n      Cpu.registerB = <u8>splitHighByte(registerBC1);\n      Cpu.registerC = <u8>splitLowByte(registerBC1);\n      return 4;\n    }\n    case 0xc2: {\n      // JP NZ,a16\n      // 3  16/12\n      if (getZeroFlag() === 0) {\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    case 0xc3: {\n      // JP a16\n      // 3  16\n      // 8 cycles\n      Cpu.programCounter = getConcatenatedDataByte();\n      return 8;\n    }\n    case 0xc4: {\n      // CALL NZ,a16\n      // 3  24/12\n      if (getZeroFlag() === 0) {\n        let stackPointer = u16Portable(Cpu.stackPointer - 2);\n        Cpu.stackPointer = stackPointer;\n        // 8 cycles\n        sixteenBitStoreSyncCycles(stackPointer, u16Portable(Cpu.programCounter + 2));\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    case 0xc5: {\n      // PUSH BC\n      // 1  16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, concatenateBytes(Cpu.registerB, Cpu.registerC));\n      return 8;\n    }\n    case 0xc6: {\n      // ADD A,d8\n      // 2 8\n      // Z 0 H C\n      // 4 cycles\n      addARegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xc7: {\n      // RST 00H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x00;\n      return 8;\n    }\n    case 0xc8: {\n      // RET Z\n      // 1  20/8\n      if (getZeroFlag() === 1) {\n        // 8 cycles\n        let stackPointer = Cpu.stackPointer;\n        Cpu.programCounter = <u16>sixteenBitLoadSyncCycles(stackPointer);\n        Cpu.stackPointer = u16Portable(stackPointer + 2);\n        return 12;\n      } else {\n        return 8;\n      }\n    }\n    case 0xc9: {\n      // RET\n      // 1 16\n      // 8 cycles\n      let stackPointer = Cpu.stackPointer;\n      Cpu.programCounter = <u16>sixteenBitLoadSyncCycles(stackPointer);\n      Cpu.stackPointer = u16Portable(stackPointer + 2);\n      return 8;\n    }\n    case 0xca: {\n      // JP Z,a16\n      // 3 16/12\n      if (getZeroFlag() === 1) {\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    case 0xcb: {\n      // PREFIX CB\n      // 1  4\n      // 4 cycles\n      let cbCycles: i32 = handleCbOpcode(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return cbCycles;\n    }\n    case 0xcc: {\n      // CALL Z,a16\n      // 3  24/12\n      if (getZeroFlag() === 1) {\n        let stackPointer = u16Portable(Cpu.stackPointer - 2);\n        Cpu.stackPointer = stackPointer;\n        // 8 cycles\n        sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter + 2);\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    case 0xcd: {\n      // CALL a16\n      // 3  24\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, u16Portable(Cpu.programCounter + 2));\n      // 8 cycles\n      Cpu.programCounter = getConcatenatedDataByte();\n      return 8;\n    }\n    case 0xce: {\n      // ADC A,d8\n      // 2  8\n      // Z 0 H C\n      // 4 cycles\n      addAThroughCarryRegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xcf: {\n      // RST 08H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x08;\n      return 8;\n    }\n  }\n  return -1;\n}\n\nfunction handleOpcodeDx(opcode: i32): i32 {\n  switch (opcode) {\n    case 0xd0: {\n      // RET NC\n      // 1  20/8\n      if (getCarryFlag() === 0) {\n        // 8 cycles\n        let stackPointer = Cpu.stackPointer;\n        Cpu.programCounter = <u16>sixteenBitLoadSyncCycles(stackPointer);\n        Cpu.stackPointer = u16Portable(stackPointer + 2);\n        return 12;\n      } else {\n        return 8;\n      }\n    }\n    case 0xd1: {\n      // POP DE\n      // 1  12\n      // 8 cycles\n      let stackPointer = Cpu.stackPointer;\n      let registerDE1: i32 = sixteenBitLoadSyncCycles(stackPointer);\n      Cpu.stackPointer = u16Portable(stackPointer + 2);\n      Cpu.registerD = <u8>splitHighByte(registerDE1);\n      Cpu.registerE = <u8>splitLowByte(registerDE1);\n      return 4;\n    }\n    case 0xd2: {\n      // JP NC,a16\n      // 3  16/12\n      if (getCarryFlag() === 0) {\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    /* No Opcode for: 0xD3 */\n    case 0xd4: {\n      // CALL NC,a16\n      // 3  24/12\n      if (getCarryFlag() === 0) {\n        let stackPointer = u16Portable(Cpu.stackPointer - 2);\n        Cpu.stackPointer = stackPointer;\n        // 8 cycles\n        sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter + 2);\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    case 0xd5: {\n      // PUSH DE\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, concatenateBytes(Cpu.registerD, Cpu.registerE));\n      return 8;\n    }\n    case 0xd6: {\n      // SUB d8\n      // 2  8\n      // Z 1 H C\n      // 4 cycles\n      subARegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xd7: {\n      // RST 10H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x10;\n      return 8;\n    }\n    case 0xd8: {\n      // RET C\n      // 1  20/8\n      if (getCarryFlag() === 1) {\n        let stackPointer = Cpu.stackPointer;\n        // 8 cycles\n        Cpu.programCounter = <u16>sixteenBitLoadSyncCycles(stackPointer);\n        Cpu.stackPointer = u16Portable(stackPointer + 2);\n        return 12;\n      } else {\n        return 8;\n      }\n    }\n    case 0xd9: {\n      // RETI\n      // 1  16\n      let stackPointer = Cpu.stackPointer;\n      // 8 cycles\n      Cpu.programCounter = <u16>sixteenBitLoadSyncCycles(stackPointer);\n      // Enable interrupts\n      setInterrupts(true);\n      Cpu.stackPointer = u16Portable(stackPointer + 2);\n      return 8;\n    }\n    case 0xda: {\n      // JP C,a16\n      // 3 16/12\n      if (getCarryFlag() === 1) {\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    /* No Opcode for: 0xDB */\n    case 0xdc: {\n      // CALL C,a16\n      // 3  24/12\n      if (getCarryFlag() === 1) {\n        let stackPointer = u16Portable(Cpu.stackPointer - 2);\n        Cpu.stackPointer = stackPointer;\n        // 8 cycles\n        sixteenBitStoreSyncCycles(stackPointer, u16Portable(Cpu.programCounter + 2));\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    /* No Opcode for: 0xDD */\n    case 0xde: {\n      // SBC A,d8\n      // 2 8\n      // Z 1 H C\n      // 4 cycles\n      subAThroughCarryRegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xdf: {\n      // RST 18H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x18;\n      return 8;\n    }\n  }\n  return -1;\n}\n\nfunction handleOpcodeEx(opcode: i32): i32 {\n  switch (opcode) {\n    case 0xe0: {\n      // LDH (a8),A\n      // 2  12\n\n      // Store value in high RAM ($FF00 + a8)\n      // 4 cycles\n      let largeDataByteOne: i32 = getDataByteOne();\n      // 4 cycles\n      eightBitStoreSyncCycles(0xff00 + largeDataByteOne, Cpu.registerA);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xe1: {\n      // POP HL\n      // 1  12\n      // 8 cycles\n      let stackPointer = Cpu.stackPointer;\n      let registerHL1: i32 = sixteenBitLoadSyncCycles(stackPointer);\n      Cpu.stackPointer = u16Portable(stackPointer + 2);\n      Cpu.registerH = <u8>splitHighByte(registerHL1);\n      Cpu.registerL = <u8>splitLowByte(registerHL1);\n      return 4;\n    }\n    case 0xe2: {\n      // LD (C),A\n      // 1  8\n      // NOTE: Table says 2 Program counter,\n      // But stepping through the boot rom, should be one\n      // Also should change 0xF2\n\n      // Store value in high RAM ($FF00 + register c)\n      // 4 cycles\n      eightBitStoreSyncCycles(0xff00 + <i32>Cpu.registerC, Cpu.registerA);\n      return 4;\n    }\n    /* No Opcode for: 0xE3, 0xE4 */\n    case 0xe5: {\n      // PUSH HL\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 8;\n    }\n    case 0xe6: {\n      // AND d8\n      // 2  8\n      // Z 0 1 0\n      // 4 cycles\n      andARegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xe7: {\n      // RST 20H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x20;\n      return 8;\n    }\n    case 0xe8: {\n      // ADD SP, r8\n      // 2 16\n      // 0 0 H C\n      // NOTE: Discoved dataByte is signed\n      // 4 cycles\n      let signedDataByteOne = i8Portable(<i8>getDataByteOne());\n\n      checkAndSetSixteenBitFlagsAddOverflow(Cpu.stackPointer, signedDataByteOne, true);\n      Cpu.stackPointer = u16Portable(Cpu.stackPointer + signedDataByteOne);\n      setZeroFlag(0);\n      setSubtractFlag(0);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 12;\n    }\n    case 0xe9: {\n      // JP HL\n      // 1 4\n      Cpu.programCounter = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      return 4;\n    }\n    case 0xea: {\n      // LD (a16),A\n      // 3 16\n      // 12 cycles, 4 from store, 8 from concatenated data byte\n      eightBitStoreSyncCycles(getConcatenatedDataByte(), Cpu.registerA);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n      return 4;\n    }\n    /* No Opcode for: 0xEB, 0xEC, 0xED */\n    case 0xee: {\n      // XOR d8\n      // 2 8\n      // Z 0 0 0\n      // 4 cycles\n      xorARegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xef: {\n      // RST 28H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x28;\n      return 8;\n    }\n  }\n  return -1;\n}\n\nfunction handleOpcodeFx(opcode: i32): i32 {\n  switch (opcode) {\n    case 0xf0: {\n      // LDH A,(a8)\n      // 2 12\n      // 4 cycles\n      let largeDataByteOne: i32 = getDataByteOne();\n      // 4 cycles\n      Cpu.registerA = u8Portable(<u8>eightBitLoadSyncCycles(0xff00 + largeDataByteOne));\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xf1: {\n      // POP AF\n      // 1 12\n      // Z N H C (But No work require, flags are already set)\n      // 8 cycles\n      let stackPointer = Cpu.stackPointer;\n      let registerAF1: i32 = <u16>sixteenBitLoadSyncCycles(stackPointer);\n      Cpu.stackPointer = u16Portable(stackPointer + 2);\n      Cpu.registerA = <u8>splitHighByte(registerAF1);\n      Cpu.registerF = <u8>splitLowByte(registerAF1);\n      return 4;\n    }\n    case 0xf2: {\n      // LD A,(C)\n      // 1 8\n      // 4 cycles\n      Cpu.registerA = u8Portable(<u8>eightBitLoadSyncCycles(0xff00 + <i32>Cpu.registerC));\n      return 4;\n    }\n    case 0xf3: {\n      // DI\n      // 1 4\n      setInterrupts(false);\n      return 4;\n    }\n    /* No Opcode for: 0xF4 */\n    case 0xf5: {\n      // PUSH AF\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, concatenateBytes(Cpu.registerA, Cpu.registerF));\n      return 8;\n    }\n    case 0xf6: {\n      // OR d8\n      // 2 8\n      // Z 0 0 0\n      // 4 cycles\n      orARegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xf7: {\n      // RST 30H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x30;\n      return 8;\n    }\n    case 0xf8: {\n      // LD HL,SP+r8\n      // 2 12\n      // 0 0 H C\n      // NOTE: Discoved dataByte is signed\n      // 4 cycles\n      let signedDataByteOne = i8Portable(<i8>getDataByteOne());\n      let stackPointer = Cpu.stackPointer;\n\n      // First, let's handle flags\n      setZeroFlag(0);\n      setSubtractFlag(0);\n      checkAndSetSixteenBitFlagsAddOverflow(stackPointer, signedDataByteOne, true);\n      let registerHL = u16Portable(stackPointer + signedDataByteOne);\n      Cpu.registerH = <u8>splitHighByte(registerHL);\n      Cpu.registerL = <u8>splitLowByte(registerHL);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 8;\n    }\n    case 0xf9: {\n      // LD SP,HL\n      // 1 8\n      Cpu.stackPointer = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      return 8;\n    }\n    case 0xfa: {\n      // LD A,(a16)\n      // 3 16\n      // 12 cycles, 4 from load, 8 from concatenated data byte\n      Cpu.registerA = <u8>eightBitLoadSyncCycles(getConcatenatedDataByte());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n      return 4;\n    }\n    case 0xfb: {\n      // EI\n      // 1 4\n      setInterrupts(true);\n      return 4;\n    }\n    /* No Opcode for: 0xFC, 0xFD */\n    case 0xfe: {\n      // CP d8\n      // 2 8\n      // Z 1 H C\n      // 4 cycles\n      cpARegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xff: {\n      // RST 38H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x38;\n      return 8;\n    }\n  }\n  return -1;\n}\n","// Portable Code for JS Wasm Benchmarking\n// https://github.com/AssemblyScript/assemblyscript/wiki/Writing-portable-code\n// https://github.com/AssemblyScript/assemblyscript/blob/master/std/portable/index.js\n\nexport function u8Portable(param: u8): u8 {\n  return param & 0xff;\n}\n\nexport function i16Portable(param: i16): i16 {\n  return (param << 16) >> 16;\n}\n\nexport function u16Portable(param: u16): u16 {\n  return param & 0xffff;\n}\n\nexport function i8Portable(param: i8): i8 {\n  return (param << 24) >> 24;\n}\n\nexport function i32Portable(param: i32): i32 {\n  return param | 0;\n}\n","// Functions for rendering the background\nimport { FRAME_LOCATION } from '../constants';\nimport { Cpu } from '../cpu/index';\nimport { Config } from '../config';\nimport { Graphics, loadFromVramBank, setPixelOnFrame, getRgbPixelStart } from './graphics';\nimport { getColorizedGbHexColorFromPalette, getRgbColorFromPalette, getColorComponentFromRgb } from './palette';\nimport { getRedFromHexColor, getGreenFromHexColor, getBlueFromHexColor } from './colors';\nimport { addPriorityforPixel, getPriorityforPixel } from './priority';\nimport { TileCache, drawPixelsFromLineOfTile, getTileDataAddress } from './tiles';\n// Assembly script really not feeling the reexport\n// using Skip Traps, because LCD has unrestricted access\n// http://gbdev.gg8.se/wiki/articles/Video_Display#LCD_OAM_DMA_Transfers\nimport { eightBitLoadFromGBMemory } from '../memory/load';\nimport { checkBitOnByte, resetBitOnByte } from '../helpers/index';\nimport { i32Portable } from '../portable/portable';\n\n// NOTE: i32Portable wraps modulo here as somehow it gets converted to a double:\n// https://github.com/torch2424/wasmboy/issues/216\n\n// Inlined because closure compiler inlines\nexport function renderBackground(scanlineRegister: i32, tileDataMemoryLocation: i32, tileMapMemoryLocation: i32): void {\n  // NOTE: Camera is reffering to what you can see inside the 160x144 viewport of the entire rendered 256x256 map.\n\n  // Get our scrollX and scrollY (u16 to play nice with assemblyscript)\n  // let scrollX: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationScrollX);\n  // let scrollY: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationScrollY);\n  let scrollX: i32 = Graphics.scrollX;\n  let scrollY: i32 = Graphics.scrollY;\n\n  // Get our current pixel y positon on the 160x144 camera (Row that the scanline draws across)\n  // this is done by getting the current scroll Y position,\n  // and adding it do what Y Value the scanline is drawing on the camera.\n  let pixelYPositionInMap: i32 = scanlineRegister + scrollY;\n\n  // Gameboy camera will \"wrap\" around the background map,\n  // meaning that if the pixelValue is 350, then we need to subtract 256 (decimal) to get it's actual value\n  // pixel values (scrollX and scrollY) range from 0x00 - 0xFF\n  pixelYPositionInMap &= 0x100 - 1;\n\n  // Draw the Background scanline\n  drawBackgroundWindowScanline(scanlineRegister, tileDataMemoryLocation, tileMapMemoryLocation, pixelYPositionInMap, 0, scrollX);\n}\n\n// Inlined because closure compiler inlines\nexport function renderWindow(scanlineRegister: i32, tileDataMemoryLocation: i32, tileMapMemoryLocation: i32): void {\n  // Get our windowX and windowY\n  // let windowX: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationWindowX);\n  // let windowY: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationWindowY);\n  let windowX: i32 = Graphics.windowX;\n  let windowY: i32 = Graphics.windowY;\n\n  // NOTE: Camera is reffering to what you can see inside the 160x144 viewport of the entire rendered 256x256 map.\n\n  // First ensure that the scanline is greater than our window\n  if (scanlineRegister < windowY) {\n    // Window is not within the current camera view\n    return;\n  }\n\n  // WindowX is offset by 7\n  windowX -= 7;\n\n  // Get our current pixel y positon on the 160x144 camera (Row that the scanline draws across)\n  let pixelYPositionInMap = scanlineRegister - windowY;\n\n  // xOffset is simply a neagative window x\n  // NOTE: This can become negative zero?\n  // https://github.com/torch2424/wasmboy/issues/216\n  let xOffset = i32Portable(-windowX);\n\n  // Draw the Background scanline\n  drawBackgroundWindowScanline(scanlineRegister, tileDataMemoryLocation, tileMapMemoryLocation, pixelYPositionInMap, windowX, xOffset);\n}\n\n// Function frankenstein'd together to allow background and window to share the same draw scanline function\nfunction drawBackgroundWindowScanline(\n  scanlineRegister: i32,\n  tileDataMemoryLocation: i32,\n  tileMapMemoryLocation: i32,\n  pixelYPositionInMap: i32,\n  iStart: i32,\n  xOffset: i32\n): void {\n  // Get our tile Y position in the map\n  let tileYPositionInMap = pixelYPositionInMap >> 3;\n\n  // Loop through x to draw the line like a CRT\n  for (let i = iStart; i < 160; ++i) {\n    // Get our Current X position of our pixel on the on the 160x144 camera\n    // this is done by getting the current scroll X position,\n    // and adding it do what X Value the scanline is drawing on the camera.\n    let pixelXPositionInMap = i + xOffset;\n\n    // This is to compensate wrapping, same as pixelY\n    if (pixelXPositionInMap >= 0x100) {\n      pixelXPositionInMap -= 0x100;\n    }\n\n    // Divide our pixel position by 8 to get our tile.\n    // Since, there are 256x256 pixels, and 32x32 tiles.\n    // 256 / 8 = 32.\n    // Also, bitshifting by 3, do do a division by 8\n    // Need to use u16s, as they will be used to compute an address, which will cause weird errors and overflows\n    let tileXPositionInMap = pixelXPositionInMap >> 3;\n\n    // Get our tile address on the tileMap\n    // NOTE: (tileMap represents where each tile is displayed on the screen)\n    // NOTE: (tile map represents the entire map, now just what is within the \"camera\")\n    // For instance, if we have y pixel 144. 144 / 8 = 18. 18 * 32 = line address in map memory.\n    // And we have x pixel 160. 160 / 8 = 20.\n    // * 32, because remember, this is NOT only for the camera, the actual map is 32x32. Therefore, the next tile line of the map, is 32 byte offset.\n    // Think like indexing a 2d array, as a 1d array and it make sense :)\n    let tileMapAddress = tileMapMemoryLocation + (tileYPositionInMap << 5) + tileXPositionInMap;\n\n    // Get the tile Id on the Tile Map\n    let tileIdFromTileMap: i32 = loadFromVramBank(tileMapAddress, 0);\n\n    // Now that we have our Tile Id, let's check our Tile Cache\n    let usedTileCache = false;\n    if (Config.tileCaching) {\n      let pixelsDrawn: i32 = drawLineOfTileFromTileCache(\n        i,\n        scanlineRegister,\n        pixelXPositionInMap,\n        pixelYPositionInMap,\n        tileMapAddress,\n        tileDataMemoryLocation,\n        tileIdFromTileMap\n      );\n      // Increment i by 7, not 8 because i will be incremented at end of for loop\n      if (pixelsDrawn > 0) {\n        i += pixelsDrawn - 1;\n        usedTileCache = true;\n      }\n    }\n\n    if (Config.tileRendering && !usedTileCache) {\n      let pixelsDrawn: i32 = drawLineOfTileFromTileId(\n        i,\n        scanlineRegister,\n        pixelXPositionInMap,\n        pixelYPositionInMap,\n        tileMapAddress,\n        tileDataMemoryLocation,\n        tileIdFromTileMap\n      );\n      // A line of a tile is 8 pixels wide, therefore increase i by (pixelsDrawn - 1), and then the for loop will increment by 1\n      // For a net increment for 8\n      if (pixelsDrawn > 0) {\n        i += pixelsDrawn - 1;\n      }\n    } else if (!usedTileCache) {\n      if (Cpu.GBCEnabled) {\n        // Draw the individual pixel\n        drawColorPixelFromTileId(\n          i,\n          scanlineRegister,\n          pixelXPositionInMap,\n          pixelYPositionInMap,\n          tileMapAddress,\n          tileDataMemoryLocation,\n          tileIdFromTileMap\n        );\n      } else {\n        // Draw the individual pixel\n        drawMonochromePixelFromTileId(\n          i,\n          scanlineRegister,\n          pixelXPositionInMap,\n          pixelYPositionInMap,\n          tileDataMemoryLocation,\n          tileIdFromTileMap\n        );\n      }\n    }\n  }\n}\n\n// Function to draw a pixel for the standard GB\n// Inlined because closure compiler inlines\nfunction drawMonochromePixelFromTileId(\n  xPixel: i32,\n  yPixel: i32,\n  pixelXPositionInMap: i32,\n  pixelYPositionInMap: i32,\n  tileDataMemoryLocation: i32,\n  tileIdFromTileMap: i32\n): void {\n  // Now we can process the the individual bytes that represent the pixel on a tile\n\n  // Now get our tileDataAddress for the corresponding tileID we found in the map\n  // Read the comments in _getTileDataAddress() to see what's going on.\n  // tl;dr if we had the tile map of \"a b c d\", and wanted tileId 2.\n  // This funcitons returns the start of memory locaiton for the tile 'c'.\n  let tileDataAddress: i32 = getTileDataAddress(tileDataMemoryLocation, tileIdFromTileMap);\n\n  // Get the y pixel of the 8 by 8 tile.\n  // Simply modulo the scanline.\n  // For instance, let's say we are printing the first line of pixels on our camera,\n  // And the first line of pixels on our tile.\n  // yPixel = 1. 1 % 8 = 1.\n  // And for the last line\n  // yPixel = 144. 144 % 8 = 0.\n  // 0 Represents last line of pixels in a tile, 1 represents first. 1 2 3 4 5 6 7 0.\n  // Because remember, we are counting lines on the display NOT including zero\n  let pixelYInTile = i32Portable(pixelYPositionInMap & 7);\n\n  // Remember to represent a single line of 8 pixels on a tile, we need two bytes.\n  // Therefore, we need to times our modulo by 2, to get the correct line of pixels on the tile.\n  // Again, think like you had to map a 2d array as a 1d.\n  let byteOneForLineOfTilePixels: i32 = loadFromVramBank(tileDataAddress + pixelYInTile * 2, 0);\n  let byteTwoForLineOfTilePixels: i32 = loadFromVramBank(tileDataAddress + pixelYInTile * 2 + 1, 0);\n\n  // Same logic as pixelYInTile.\n  // However, We need to reverse our byte,\n  // As pixel 0 is on byte 7, and pixel 1 is on byte 6, etc...\n  // Therefore, is pixelX was 2, then really is need to be 5\n  // So 2 - 7 = -5, * 1 = 5\n  // Or to simplify, 7 - 2 = 5 haha!\n  let pixelXInTile = i32Portable(pixelXPositionInMap & 7);\n  pixelXInTile = 7 - pixelXInTile;\n\n  // Now we can get the color for that pixel\n  // Colors are represented by getting X position of ByteTwo, and X positon of Byte One\n  // To Get the color Id.\n  // For example, the result of the color id is 0000 00[xPixelByteTwo][xPixelByteOne]\n  // See: How to draw a tile/sprite from memory: http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html\n  let paletteColorId: u8 = 0;\n  if (checkBitOnByte(pixelXInTile, byteTwoForLineOfTilePixels)) {\n    // Byte one represents the second bit in our color id, so bit shift\n    paletteColorId += 1;\n    paletteColorId = paletteColorId << 1;\n  }\n  if (checkBitOnByte(pixelXInTile, byteOneForLineOfTilePixels)) {\n    paletteColorId += 1;\n  }\n  // Not checking u8 Portability overflow here, since it can't be greater than i32 over :p\n\n  // Now get the colorId from the pallete, to get our final color\n  // Developers could change colorIds to represents different colors\n  // in their palette, thus we need to grab the color from there\n  //let pixelColorInTileFromPalette: u8 = getColorFromPalette(paletteColorId, Graphics.memoryLocationBackgroundPalette);\n  // Moved below for perofrmance\n\n  // FINALLY, RENDER THAT PIXEL!\n  // Only rendering camera for now, so coordinates are for the camera.\n  // Get the rgb value for the color Id, will be repeated into R, G, B. if not colorized\n  let hexColor: i32 = getColorizedGbHexColorFromPalette(paletteColorId, Graphics.memoryLocationBackgroundPalette);\n  setPixelOnFrame(xPixel, yPixel, 0, getRedFromHexColor(hexColor));\n  setPixelOnFrame(xPixel, yPixel, 1, getGreenFromHexColor(hexColor));\n  setPixelOnFrame(xPixel, yPixel, 2, getBlueFromHexColor(hexColor));\n\n  // Lastly, add the pixel to our background priority map\n  // https://github.com/torch2424/wasmBoy/issues/51\n  // Bits 0 & 1 will represent the color Id drawn by the BG/Window\n  // Bit 2 will represent if the Bg/Window has GBC priority.\n  addPriorityforPixel(xPixel, yPixel, paletteColorId);\n}\n\n// Function to draw a pixel from a tile in C O L O R\n// See above for more context on some variables\n// Inlined because closure compiler inlines\nfunction drawColorPixelFromTileId(\n  xPixel: i32,\n  yPixel: i32,\n  pixelXPositionInMap: i32,\n  pixelYPositionInMap: i32,\n  tileMapAddress: i32,\n  tileDataMemoryLocation: i32,\n  tileIdFromTileMap: i32\n): void {\n  // Now get our tileDataAddress for the corresponding tileID we found in the map\n  // Read the comments in _getTileDataAddress() to see what's going on.\n  // tl;dr if we had the tile map of \"a b c d\", and wanted tileId 2.\n  // This funcitons returns the start of memory locaiton for the tile 'c'.\n  let tileDataAddress: i32 = getTileDataAddress(tileDataMemoryLocation, tileIdFromTileMap);\n\n  // Get the GB Map Attributes\n  // Bit 0-2  Background Palette number  (BGP0-7)\n  // Bit 3    Tile VRAM Bank number      (0=Bank 0, 1=Bank 1)\n  // Bit 4    Not used\n  // Bit 5    Horizontal Flip            (0=Normal, 1=Mirror horizontally)\n  // Bit 6    Vertical Flip              (0=Normal, 1=Mirror vertically)\n  // Bit 7    BG-to-OAM Priority         (0=Use OAM priority bit, 1=BG Priority)\n  let bgMapAttributes: i32 = loadFromVramBank(tileMapAddress, 1);\n\n  // See above for explanation\n  let pixelYInTile = i32Portable(pixelYPositionInMap & 7);\n  if (checkBitOnByte(6, bgMapAttributes)) {\n    // We are mirroring the tile, therefore, we need to opposite byte\n    // So if our pixel was 0 our of 8, it wild become 7 :)\n    pixelYInTile = 7 - pixelYInTile;\n  }\n\n  // Remember to represent a single line of 8 pixels on a tile, we need two bytes.\n  // Therefore, we need to times our modulo by 2, to get the correct line of pixels on the tile.\n  // But we need to load the time from a specific Vram bank\n  let vramBankId = i32Portable(<i32>checkBitOnByte(3, bgMapAttributes));\n  let byteOneForLineOfTilePixels: i32 = loadFromVramBank(tileDataAddress + pixelYInTile * 2, vramBankId);\n  let byteTwoForLineOfTilePixels: i32 = loadFromVramBank(tileDataAddress + pixelYInTile * 2 + 1, vramBankId);\n\n  // Get our X pixel. Need to NOT reverse it if it was flipped.\n  // See above, you have to reverse this normally\n  let pixelXInTile = i32Portable(pixelXPositionInMap & 7);\n  if (!checkBitOnByte(5, bgMapAttributes)) {\n    pixelXInTile = 7 - pixelXInTile;\n  }\n\n  // Now we can get the color for that pixel\n  // Colors are represented by getting X position of ByteTwo, and X positon of Byte One\n  // To Get the color Id.\n  // For example, the result of the color id is 0000 00[xPixelByteTwo][xPixelByteOne]\n  // See: How to draw a tile/sprite from memory: http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html\n  let paletteColorId = 0;\n  if (checkBitOnByte(pixelXInTile, byteTwoForLineOfTilePixels)) {\n    // Byte one represents the second bit in our color id, so bit shift\n    paletteColorId += 1;\n    paletteColorId = paletteColorId << 1;\n  }\n  if (checkBitOnByte(pixelXInTile, byteOneForLineOfTilePixels)) {\n    paletteColorId += 1;\n  }\n\n  // Finally lets add some, C O L O R\n  // Want the botom 3 bits\n  let bgPalette = bgMapAttributes & 0x07;\n\n  // Call the helper function to grab the correct color from the palette\n  let rgbColorPalette = getRgbColorFromPalette(bgPalette, paletteColorId, false);\n\n  // Split off into red green and blue\n  let red = getColorComponentFromRgb(0, rgbColorPalette);\n  let green = getColorComponentFromRgb(1, rgbColorPalette);\n  let blue = getColorComponentFromRgb(2, rgbColorPalette);\n\n  // Finally Place our colors on the things\n  setPixelOnFrame(xPixel, yPixel, 0, red);\n  setPixelOnFrame(xPixel, yPixel, 1, green);\n  setPixelOnFrame(xPixel, yPixel, 2, blue);\n\n  // Lastly, add the pixel to our background priority map\n  // https://github.com/torch2424/wasmBoy/issues/51\n  // Bits 0 & 1 will represent the color Id drawn by the BG/Window\n  // Bit 2 will represent if the Bg/Window has GBC priority.\n  addPriorityforPixel(xPixel, yPixel, paletteColorId, checkBitOnByte(7, bgMapAttributes));\n}\n\n// Function to attempt to draw the tile from the tile cache\n// Inlined because closure compiler inlines\nfunction drawLineOfTileFromTileCache(\n  xPixel: i32,\n  yPixel: i32,\n  pixelXPositionInMap: i32,\n  pixelYPositionInMap: i32,\n  tileMapAddress: i32,\n  tileDataMemoryLocation: i32,\n  tileIdFromTileMap: i32\n): i32 {\n  // First, initialize how many pixels we have drawn\n  let pixelsDrawn: i32 = 0;\n\n  // Check if the current tile matches our tileId\n  // TODO: Allow the first line to use the tile cache, for some odd reason it doesn't work when scanline is 0\n  let nextXIndexToPerformCacheCheck = TileCache.nextXIndexToPerformCacheCheck;\n  if (yPixel > 0 && xPixel > 8 && <i32>tileIdFromTileMap === TileCache.tileId && xPixel === nextXIndexToPerformCacheCheck) {\n    // Was last tile flipped\n    let wasLastTileHorizontallyFlipped = checkBitOnByte(5, eightBitLoadFromGBMemory(tileMapAddress - 1));\n    let isCurrentTileHorizontallyFlipped = checkBitOnByte(5, eightBitLoadFromGBMemory(tileMapAddress));\n\n    // Simply copy the last 8 pixels from memory to copy the line from the tile\n    for (let tileCacheIndex = 0; tileCacheIndex < 8; ++tileCacheIndex) {\n      // Check if we need to render backwards for flipping\n      if (wasLastTileHorizontallyFlipped !== isCurrentTileHorizontallyFlipped) {\n        tileCacheIndex = 7 - tileCacheIndex;\n      }\n\n      let xPos = xPixel + tileCacheIndex;\n      // First check for overflow\n      if (xPos <= 160) {\n        // Get the pixel location in memory of the tile\n        let previousXPixel = xPixel - (8 - tileCacheIndex);\n        let previousTilePixelLocation = FRAME_LOCATION + getRgbPixelStart(xPos, yPixel);\n\n        // Cycle through the RGB\n        // for (let tileCacheRgb = 0; tileCacheRgb < 3; ++tileCacheRgb) {\n        //  setPixelOnFrame(xPixel + tileCacheIndex, yPixel, tileCacheRgb, load<u8>(previousTilePixelLocation + tileCacheRgb));\n        // }\n        // unroll\n        setPixelOnFrame(xPos, yPixel, 0, load<u8>(previousTilePixelLocation, 0));\n        setPixelOnFrame(xPos, yPixel, 1, load<u8>(previousTilePixelLocation, 1));\n        setPixelOnFrame(xPos, yPixel, 2, load<u8>(previousTilePixelLocation, 2));\n\n        // Copy the priority for the pixel\n        let pixelPriority: i32 = getPriorityforPixel(previousXPixel, yPixel);\n        addPriorityforPixel(xPos, yPixel, resetBitOnByte(2, pixelPriority), checkBitOnByte(2, pixelPriority));\n\n        pixelsDrawn++;\n      }\n    }\n  } else {\n    // Save our current tile Id, and the next x value we should check the x index\n    TileCache.tileId = tileIdFromTileMap;\n  }\n\n  // Calculate when we should do the tileCache calculation again\n  if (xPixel >= nextXIndexToPerformCacheCheck) {\n    nextXIndexToPerformCacheCheck = xPixel + 8;\n    let xOffsetTileWidthRemainder = i32Portable(pixelXPositionInMap & 7);\n    if (xPixel < xOffsetTileWidthRemainder) {\n      nextXIndexToPerformCacheCheck += xOffsetTileWidthRemainder;\n    }\n  }\n  TileCache.nextXIndexToPerformCacheCheck = nextXIndexToPerformCacheCheck;\n\n  return pixelsDrawn;\n}\n\n// Function to draw a line of a tile in Color\n// This is for tile rendering shortcuts\n// Inlined because closure compiler inlines\nfunction drawLineOfTileFromTileId(\n  xPixel: i32,\n  yPixel: i32,\n  pixelXPositionInMap: i32,\n  pixelYPositionInMap: i32,\n  tileMapAddress: i32,\n  tileDataMemoryLocation: i32,\n  tileIdFromTileMap: i32\n): i32 {\n  // Get the which line of the tile we are rendering\n  let tileLineY: i32 = i32Portable(pixelYPositionInMap & 7);\n\n  // Now lets find our tileX start and end\n  // This is for the case where i = 0, but scroll X was 3.\n  // Or i is 157, and our camera is only 160 pixels wide\n  let tileXStart = 0;\n  if (xPixel == 0) {\n    tileXStart = pixelXPositionInMap - ((pixelXPositionInMap >> 3) << 3);\n  }\n  let tileXEnd = 7;\n  if (xPixel + 8 > 160) {\n    tileXEnd = 160 - xPixel;\n  }\n\n  // initialize some variables for GBC\n  let bgMapAttributes = -1;\n  let vramBankId = 0;\n  if (Cpu.GBCEnabled) {\n    // Get Our GBC properties\n    bgMapAttributes = loadFromVramBank(tileMapAddress, 1);\n    vramBankId = i32Portable(<i32>checkBitOnByte(3, <u8>bgMapAttributes));\n\n    if (checkBitOnByte(6, bgMapAttributes)) {\n      // We are mirroring the tile, therefore, we need to opposite byte\n      // So if our pixel was 0 our of 8, it wild become 7 :)\n      tileLineY = 7 - tileLineY;\n    }\n  }\n\n  // Return the number of pixels drawn\n  return drawPixelsFromLineOfTile(\n    tileIdFromTileMap,\n    tileDataMemoryLocation,\n    vramBankId,\n    tileXStart,\n    tileXEnd,\n    tileLineY,\n    xPixel,\n    yPixel,\n    160,\n    FRAME_LOCATION,\n    false,\n    0,\n    bgMapAttributes,\n    -1\n  );\n}\n","// https://github.com/torch2424/wasmBoy/issues/51\n// Bits 0 & 1 will represent the color Id drawn by the BG/Window\n// Bit 2 will represent if the Bg/Window has GBC priority.\n\nimport { BG_PRIORITY_MAP_LOCATION } from '../constants';\nimport { setBitOnByte } from '../helpers/index';\n\nexport function addPriorityforPixel(x: i32, y: i32, colorId: i32 = 0, hasGbcBgPriority: boolean = false): void {\n  let bgPriorityByte = colorId & 0x03;\n  if (hasGbcBgPriority) {\n    bgPriorityByte = setBitOnByte(2, bgPriorityByte);\n  }\n\n  store<u8>(BG_PRIORITY_MAP_LOCATION + getPixelStart(x, y), <u8>bgPriorityByte);\n}\n\n// Inlined because closure compiler inlines\nexport function getPriorityforPixel(x: i32, y: i32): u8 {\n  return load<u8>(BG_PRIORITY_MAP_LOCATION + getPixelStart(x, y));\n}\n\n// Inlined because closure compiler inlines\nexport function clearPriorityMap(): void {\n  for (let y = 0; y < 144; ++y) {\n    for (let x = 0; x < 160; ++x) {\n      store<u8>(BG_PRIORITY_MAP_LOCATION + getPixelStart(x, y), 0);\n    }\n  }\n}\n\n// Inlined because closure compiler inlines\nfunction getPixelStart(x: i32, y: i32): i32 {\n  // Get the pixel number\n  return y * 160 + x;\n}\n","// Functions for rendering the sprites\nimport { Graphics, loadFromVramBank, setPixelOnFrame } from './graphics';\nimport { Lcd } from './lcd';\nimport { Cpu } from '../cpu/index';\nimport { getTileDataAddress } from './tiles';\nimport { getColorizedGbHexColorFromPalette, getRgbColorFromPalette, getColorComponentFromRgb } from './palette';\nimport { getRedFromHexColor, getGreenFromHexColor, getBlueFromHexColor } from './colors';\nimport { getPriorityforPixel } from './priority';\n// Assembly script really not feeling the reexport\n// using Skip Traps, because LCD has unrestricted access\n// http://gbdev.gg8.se/wiki/articles/Video_Display#LCD_OAM_DMA_Transfers\nimport { eightBitLoadFromGBMemory } from '../memory/load';\nimport { checkBitOnByte } from '../helpers/index';\n\n// Inlined because closure compiler inlines\nexport function renderSprites(scanlineRegister: i32, useLargerSprites: boolean): void {\n  // Need to loop through all 40 sprites to check their status\n  // Going backwards since lower sprites draw over higher ones\n  // Will fix dragon warrior 3 intro\n  for (let i = 39; i >= 0; --i) {\n    // Sprites occupy 4 bytes in the sprite attribute table\n    let spriteTableIndex = i * 4;\n    // Y positon is offset by 16, X position is offset by 8\n\n    let index = Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex;\n\n    let spriteYPosition = eightBitLoadFromGBMemory(index + 0);\n    let spriteXPosition = eightBitLoadFromGBMemory(index + 1);\n    let spriteTileId = eightBitLoadFromGBMemory(index + 2);\n\n    // Pan docs of sprite attirbute table\n    // Bit7   OBJ-to-BG Priority (0=OBJ Above BG, 1=OBJ Behind BG color 1-3)\n    //      (Used for both BG and Window. BG color 0 is always behind OBJ)\n    // Bit6   Y flip          (0=Normal, 1=Vertically mirrored)\n    // Bit5   X flip          (0=Normal, 1=Horizontally mirrored)\n    // Bit4   Palette number  **Non CGB Mode Only** (0=OBP0, 1=OBP1)\n    // Bit3   Tile VRAM-Bank  **CGB Mode Only**     (0=Bank 0, 1=Bank 1)\n    // Bit2-0 Palette number  **CGB Mode Only**     (OBP0-7)\n\n    // Apply sprite X and Y offset\n    // TODO: Sprites are overflowing on x if less than 8\n    spriteYPosition -= 16;\n    spriteXPosition -= 8;\n\n    // Find our sprite height\n    let spriteHeight = 8;\n    if (useLargerSprites) {\n      spriteHeight = 16;\n      // @binji says in 8x16 mode, even tileId always drawn first\n      // This will fix shantae sprites which always uses odd numbered indexes\n\n      // TODO: Do the actual Pandocs thing:\n      // \"In 8x16 mode, the lower bit of the tile number is ignored. Ie. the upper 8x8 tile is \"NN AND FEh\", and the lower 8x8 tile is \"NN OR 01h\".\"\n      // So just knock off the last bit? :)\n      spriteTileId -= spriteTileId & 1;\n    }\n\n    // Find if our sprite is on the current scanline\n    if (scanlineRegister >= spriteYPosition && scanlineRegister < spriteYPosition + spriteHeight) {\n      // Then we need to draw the current sprite\n\n      // Get our sprite attributes since we know we shall be drawing the tile\n      let spriteAttributes = eightBitLoadFromGBMemory(Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex + 3);\n\n      // Check sprite Priority\n      let isSpritePriorityBehindWindowAndBackground = checkBitOnByte(7, spriteAttributes);\n\n      // Check if we should flip the sprite on the x or y axis\n      let flipSpriteY = checkBitOnByte(6, spriteAttributes);\n      let flipSpriteX = checkBitOnByte(5, spriteAttributes);\n\n      // TODO: Torch2424 continue here.\n\n      // Find which line on the sprite we are on\n      let currentSpriteLine = scanlineRegister - spriteYPosition;\n\n      // If we fliiped the Y axis on our sprite, need to read from memory backwards to acheive the same effect\n      if (flipSpriteY) {\n        currentSpriteLine = spriteHeight - currentSpriteLine;\n\n        // Bug fix for the flipped flies in link's awakening\n        currentSpriteLine -= 1;\n      }\n\n      // Each line of a tile takes two bytes of memory\n      currentSpriteLine <<= 1;\n\n      // Get our sprite tile address, need to also add the current sprite line to get the correct bytes\n      let spriteTileAddressStart = getTileDataAddress(Graphics.memoryLocationTileDataSelectOneStart, spriteTileId);\n      spriteTileAddressStart += currentSpriteLine;\n      let spriteTileAddress = spriteTileAddressStart;\n\n      // Find which VRAM Bank to load from\n      let vramBankId = <i32>(Cpu.GBCEnabled && checkBitOnByte(3, spriteAttributes));\n      let spriteDataByteOneForLineOfTilePixels = loadFromVramBank(spriteTileAddress + 0, vramBankId);\n      let spriteDataByteTwoForLineOfTilePixels = loadFromVramBank(spriteTileAddress + 1, vramBankId);\n\n      // Iterate over the width of our sprite to find our individual pixels\n      for (let tilePixel = 7; tilePixel >= 0; --tilePixel) {\n        // Get our spritePixel, and check for flipping\n        let spritePixelXInTile = tilePixel;\n        if (flipSpriteX) {\n          spritePixelXInTile -= 7;\n          spritePixelXInTile = -spritePixelXInTile;\n        }\n\n        // Get the color Id of our sprite, similar to renderBackground()\n        // With the first byte, and second byte lined up method thing\n        // Yes, the second byte comes before the first, see ./background.ts\n        let spriteColorId = 0;\n        if (checkBitOnByte(spritePixelXInTile, spriteDataByteTwoForLineOfTilePixels)) {\n          // Byte one represents the second bit in our color id, so bit shift\n          spriteColorId = (spriteColorId + 1) << 1;\n        }\n        if (checkBitOnByte(spritePixelXInTile, spriteDataByteOneForLineOfTilePixels)) {\n          spriteColorId += 1;\n        }\n\n        // ColorId zero (last two bits of pallette) are transparent\n        // http://gbdev.gg8.se/wiki/articles/Video_Display\n        if (spriteColorId !== 0) {\n          // Find our actual X pixel location on the gameboy \"camera\" view\n          // This cannot be less than zero, i32 will overflow\n          let spriteXPixelLocationInCameraView = spriteXPosition + (7 - tilePixel);\n          if (spriteXPixelLocationInCameraView >= 0 && spriteXPixelLocationInCameraView <= 160) {\n            // There are two cases where wouldnt draw the pixel on top of the Bg/window\n            // 1. if isSpritePriorityBehindWindowAndBackground, sprite can only draw over color 0\n            // 2. if bit 2 of our priority is set, then BG-to-OAM Priority from pandoc\n            //  is active, meaning BG tile will have priority above all OBJs\n            //  (regardless of the priority bits in OAM memory)\n            // But if GBC and Bit 0 of LCDC is set, we always draw the object\n            let shouldShowFromLcdcPriority = Cpu.GBCEnabled && !Lcd.bgDisplayEnabled; // LCDC Priority\n            let shouldHideFromOamPriority = false;\n            let shouldHideFromBgPriority = false;\n\n            if (!shouldShowFromLcdcPriority) {\n              // Now that we have our coordinates, check for sprite priority\n              // Lets get the priority byte we put in memory\n              let bgPriorityByte = getPriorityforPixel(spriteXPixelLocationInCameraView, scanlineRegister);\n\n              let bgColorFromPriorityByte = bgPriorityByte & 0x03;\n\n              // Doing an else if, since either will automatically stop drawing the pixel\n              if (isSpritePriorityBehindWindowAndBackground && bgColorFromPriorityByte > 0) {\n                // OAM Priority\n                shouldHideFromOamPriority = true;\n              } else if (Cpu.GBCEnabled && checkBitOnByte(2, bgPriorityByte) && bgColorFromPriorityByte > 0) {\n                // Bg priority\n                shouldHideFromBgPriority = true;\n              }\n            }\n\n            if (shouldShowFromLcdcPriority || (!shouldHideFromOamPriority && !shouldHideFromBgPriority)) {\n              if (!Cpu.GBCEnabled) {\n                // Get our monochrome color RGB from the current sprite pallete\n                // Get our sprite pallete\n                let spritePaletteLocation = Graphics.memoryLocationSpritePaletteOne;\n                if (checkBitOnByte(4, spriteAttributes)) {\n                  spritePaletteLocation = Graphics.memoryLocationSpritePaletteTwo;\n                }\n\n                let hexColor = getColorizedGbHexColorFromPalette(spriteColorId, spritePaletteLocation);\n\n                // Finally set the pixel!\n                setPixelOnFrame(spriteXPixelLocationInCameraView, scanlineRegister, 0, getRedFromHexColor(hexColor));\n                setPixelOnFrame(spriteXPixelLocationInCameraView, scanlineRegister, 1, getGreenFromHexColor(hexColor));\n                setPixelOnFrame(spriteXPixelLocationInCameraView, scanlineRegister, 2, getBlueFromHexColor(hexColor));\n              } else {\n                // Get our RGB Color\n\n                // Finally lets add some, C O L O R\n                // Want the botom 3 bits\n                let bgPalette = spriteAttributes & 0x07;\n\n                // Call the helper function to grab the correct color from the palette\n                let rgbColorPalette = getRgbColorFromPalette(bgPalette, spriteColorId, true);\n\n                // Split off into red green and blue\n                let red = getColorComponentFromRgb(0, rgbColorPalette);\n                let green = getColorComponentFromRgb(1, rgbColorPalette);\n                let blue = getColorComponentFromRgb(2, rgbColorPalette);\n\n                // Finally Place our colors on the things\n                setPixelOnFrame(spriteXPixelLocationInCameraView, scanlineRegister, 0, red);\n                setPixelOnFrame(spriteXPixelLocationInCameraView, scanlineRegister, 1, green);\n                setPixelOnFrame(spriteXPixelLocationInCameraView, scanlineRegister, 2, blue);\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n}\n","import { Memory } from './memory';\nimport { Cpu } from '../cpu/index';\nimport { Graphics } from '../graphics/graphics';\nimport { Lcd } from '../graphics/index';\nimport { batchProcessAudio, SoundRegisterReadTraps, Channel3 } from '../sound/index';\nimport { eightBitStoreIntoGBMemory } from './store';\nimport { eightBitLoadFromGBMemory } from './load';\nimport { Joypad, getJoypadState } from '../joypad/index';\nimport { Timers } from '../timers/index';\nimport { Interrupts } from '../interrupts/index';\nimport { checkBitOnByte, resetBitOnByte, splitHighByte } from '../helpers/index';\n\n// Returns -1 if no trap found, otherwise returns a value that should be fed for the address\nexport function checkReadTraps(offset: i32): i32 {\n  // Cache globals used multiple times for performance\n  let videoRamLocation = Memory.videoRamLocation;\n\n  // Try to break early for most common scenario\n  if (offset < videoRamLocation) {\n    return -1;\n  }\n\n  // Check the graphics mode to see if we can read VRAM\n  // http://gbdev.gg8.se/wiki/articles/Video_Display#Accessing_VRAM_and_OAM\n  if (offset >= videoRamLocation && offset < Memory.cartridgeRamLocation) {\n    // Can only read/write from VRAM During Modes 0 - 2\n    // See graphics/lcd.ts\n    // TODO: This can do more harm than good in a beta emulator,\n    // requres precise timing, disabling for now\n    // if (Graphics.currentLcdMode > 2) {\n    //   return 0xFF;\n    // }\n\n    return -1;\n  }\n\n  // ECHO Ram, E000\tFDFF\tMirror of C000~DDFF (ECHO RAM)\n  // http://gbdev.gg8.se/wiki/articles/Memory_Map\n  if (offset >= Memory.echoRamLocation && offset < Memory.spriteInformationTableLocation) {\n    // Simply return the mirror'd value\n    return eightBitLoadFromGBMemory(offset - 0x2000);\n  }\n\n  // Check for individal writes\n  // Can only read/write from OAM During Modes 0 - 1\n  // See graphics/lcd.ts\n  if (offset >= Memory.spriteInformationTableLocation && offset <= Memory.spriteInformationTableLocationEnd) {\n    // Can only read/write from OAM During Mode 2\n    // See graphics/lcd.ts\n    // if (Lcd.currentLcdMode < 2) {\n    // return 0xff;\n    // }\n\n    // Not batch processing here for performance\n    // batchProcessGraphics();\n\n    // return -1;\n    return Lcd.currentLcdMode < 2 ? 0xff : -1;\n  }\n\n  // CPU\n  if (offset === Cpu.memoryLocationSpeedSwitch) {\n    // TCAGBD, only Bit 7 and 0 are readable, all others are 1\n    let response = 0xff;\n\n    let currentSpeedSwitchRegister = eightBitLoadFromGBMemory(Cpu.memoryLocationSpeedSwitch);\n    if (!checkBitOnByte(0, currentSpeedSwitchRegister)) {\n      response = resetBitOnByte(0, response);\n    }\n\n    if (!Cpu.GBCDoubleSpeed) {\n      response = resetBitOnByte(7, response);\n    }\n\n    return response;\n  }\n\n  // Graphics\n  // Not batch processing here for performance\n  // batchProcessGraphics();\n  if (offset === Graphics.memoryLocationScanlineRegister) {\n    eightBitStoreIntoGBMemory(offset, Graphics.scanlineRegister);\n    return Graphics.scanlineRegister;\n  }\n\n  // Sound\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n  // TODO: Put these bounds on the Sound Class\n  if (offset >= 0xff10 && offset <= 0xff26) {\n    batchProcessAudio();\n    return SoundRegisterReadTraps(offset);\n  }\n\n  // FF27 - FF2F not used\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Register_Reading\n  // Always read as 0xFF\n  if (offset >= 0xff27 && offset <= 0xff2f) {\n    return 0xff;\n  }\n\n  // Final Wave Table for Channel 3\n  if (offset >= 0xff30 && offset <= 0xff3f) {\n    batchProcessAudio();\n\n    if (Channel3.isEnabled) {\n      return Channel3.handleWaveRamRead();\n    }\n    return -1;\n  }\n\n  // Timers\n  if (offset === Timers.memoryLocationDividerRegister) {\n    // Divider register in memory is just the upper 8 bits\n    // http://gbdev.gg8.se/wiki/articles/Timer_Obscure_Behaviour\n    let upperDividerRegisterBits = splitHighByte(Timers.dividerRegister);\n    eightBitStoreIntoGBMemory(offset, upperDividerRegisterBits);\n    return upperDividerRegisterBits;\n  }\n\n  if (offset === Timers.memoryLocationTimerCounter) {\n    eightBitStoreIntoGBMemory(offset, Timers.timerCounter);\n    return Timers.timerCounter;\n  }\n\n  // Interrupts\n  if (offset === Interrupts.memoryLocationInterruptRequest) {\n    // TCAGB and BGB say the top 5 bits are always 1.\n    return 0xe0 | Interrupts.interruptsRequestedValue;\n  }\n\n  // Joypad\n  if (offset === Joypad.memoryLocationJoypadRegister) {\n    return getJoypadState();\n  }\n\n  return -1;\n}\n","// Functions to help with Handling Duty on Square Channels\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Square_Wave\n\nimport { checkBitOnByte } from '../helpers/index';\n\n// Since there are no 2d arrays, we will use a byte to represent duty cycles (wave form from percentages)\nexport function isDutyCycleClockPositiveOrNegativeForWaveform(channelDuty: i32, waveFormPositionOnDuty: i32): boolean {\n  // Get our Wave Form According to the Duty\n  // Default to a duty of 1\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Square_Wave\n  switch (channelDuty) {\n    case 0x01:\n      // 1000 0001\n      return checkBitOnByte(waveFormPositionOnDuty, 0x81);\n    case 0x02:\n      // 1000 0111\n      return checkBitOnByte(waveFormPositionOnDuty, 0x87);\n    case 0x03:\n      // 0111 1110\n      return checkBitOnByte(waveFormPositionOnDuty, 0x7e);\n    default:\n      // 0000 0001\n      return checkBitOnByte(waveFormPositionOnDuty, 0x01);\n  }\n}\n","// Functions involved in R/W of sound registers\n// Information of bits on every register can be found at: https://gist.github.com/drhelius/3652407\n// Passing channel number to make things simpler than passing around memory addresses, to avoid bugs in choosing the wrong address\n\nimport { Sound } from './sound';\nimport { SoundAccumulator } from './accumulator';\nimport { Channel1 } from './channel1';\nimport { Channel2 } from './channel2';\nimport { Channel3 } from './channel3';\nimport { Channel4 } from './channel4';\nimport { eightBitLoadFromGBMemory, eightBitStoreIntoGBMemory, eightBitStoreIntoGBMemoryWithTraps } from '../memory/index';\nimport { checkBitOnByte, setBitOnByte, resetBitOnByte, log } from '../helpers/index';\n\n// Function to check and handle writes to sound registers\n// Inlined because closure compiler inlines\n// NOTE: For write traps, return false = don't write to memory,\n// return true = allow the write to memory\nexport function SoundRegisterWriteTraps(offset: i32, value: i32): boolean {\n  if (offset !== Sound.memoryLocationNR52 && !Sound.NR52IsSoundEnabled) {\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Power_Control\n    // When sound is turned off / enabled\n    // Block all writes to any sound register EXCEPT NR52!\n    // This is under the assumption that the check for\n    // offset >= 0xFF10 && offset <= 0xFF26\n    // is done in writeTraps.ts (which it is)\n    // NOTE: Except on DMG, length can still be written (whatever that means)\n    return false;\n  }\n\n  switch (offset) {\n    // Handle NRx0 on Channels\n    case Channel1.memoryLocationNRx0:\n      Channel1.updateNRx0(value);\n      return true;\n    case Channel3.memoryLocationNRx0:\n      Channel3.updateNRx0(value);\n      return true;\n    // Handle NRx1 (Length Counter) on Channels\n    case Channel1.memoryLocationNRx1:\n      Channel1.updateNRx1(value);\n      return true;\n    case Channel2.memoryLocationNRx1:\n      Channel2.updateNRx1(value);\n      return true;\n    case Channel3.memoryLocationNRx1:\n      Channel3.updateNRx1(value);\n      return true;\n    case Channel4.memoryLocationNRx1:\n      Channel4.updateNRx1(value);\n      return true;\n    // Handle NRx2 (Envelope / Volume) on Channels\n    case Channel1.memoryLocationNRx2:\n      Channel1.updateNRx2(value);\n      return true;\n    case Channel2.memoryLocationNRx2:\n      Channel2.updateNRx2(value);\n      return true;\n    case Channel3.memoryLocationNRx2:\n      // Check if channel 3's volume code was written too\n      // This is handcy to know for accumulation of samples\n      Channel3.volumeCodeChanged = true;\n      Channel3.updateNRx2(value);\n      return true;\n    case Channel4.memoryLocationNRx2:\n      Channel4.updateNRx2(value);\n      return true;\n    // Handle NRx3 (Frequency / Noise Properties) on Channels\n    case Channel1.memoryLocationNRx3:\n      Channel1.updateNRx3(value);\n      return true;\n    case Channel2.memoryLocationNRx3:\n      Channel2.updateNRx3(value);\n      return true;\n    case Channel3.memoryLocationNRx3:\n      Channel3.updateNRx3(value);\n      return true;\n    case Channel4.memoryLocationNRx3:\n      Channel4.updateNRx3(value);\n      return true;\n    // Check our NRx4 registers to trap our trigger bits\n    case Channel1.memoryLocationNRx4:\n      Channel1.updateNRx4(value);\n      return true;\n    case Channel2.memoryLocationNRx4:\n      Channel2.updateNRx4(value);\n      return true;\n    case Channel3.memoryLocationNRx4:\n      Channel3.updateNRx4(value);\n      return true;\n    case Channel4.memoryLocationNRx4:\n      Channel4.updateNRx4(value);\n      return true;\n    // Tell the sound accumulator if volumes changes\n    case Sound.memoryLocationNR50:\n      Sound.updateNR50(value);\n      SoundAccumulator.mixerVolumeChanged = true;\n      return true;\n    // Tell the sound accumulator if volumes changes\n    case Sound.memoryLocationNR51:\n      Sound.updateNR51(value);\n      SoundAccumulator.mixerEnabledChanged = true;\n      return true;\n    case Sound.memoryLocationNR52:\n      // Reset all registers except NR52\n\n      // See if we were enabled, then update the register.\n      let wasNR52Enabled = Sound.NR52IsSoundEnabled;\n\n      // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Power_Control\n      // When powered on, the frame sequencer is reset so that the next step will be 0,\n      // the square duty units are reset to the first step of the waveform,\n      // and the wave channel's sample buffer is reset to 0.\n      if (!wasNR52Enabled && checkBitOnByte(7, value)) {\n        Sound.frameSequencer = 0x07;\n        Channel1.waveFormPositionOnDuty = 0x00;\n        Channel2.waveFormPositionOnDuty = 0x00;\n\n        // TODO: Wave Channel Sample Buffer?\n        // I don't think we clear wave RAM here...\n      }\n\n      // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Power_Control\n      // When powered off, all registers (NR10-NR51) are instantly written with zero\n      // and any writes to those registers are ignored while power remains off\n      if (wasNR52Enabled && !checkBitOnByte(7, value)) {\n        for (let i = 0xff10; i < 0xff26; ++i) {\n          eightBitStoreIntoGBMemoryWithTraps(i, 0x00);\n        }\n      }\n\n      // Need to update our new value here, that way writes go through :p\n      Sound.updateNR52(value);\n      return true;\n  }\n\n  // We did not handle the write, Allow the write\n  return true;\n}\n\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n// Inlined because closure compiler inlines\nexport function SoundRegisterReadTraps(offset: i32): i32 {\n  // Registers must be OR'd with values when being read\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n\n  switch (offset) {\n    // Handle NRx0 on Channels\n    case Channel1.memoryLocationNRx0: {\n      let register = eightBitLoadFromGBMemory(Channel1.memoryLocationNRx0);\n      return register | 0x80;\n    }\n    case Channel2.memoryLocationNRx0: {\n      let register = eightBitLoadFromGBMemory(Channel2.memoryLocationNRx0);\n      return register | 0xff;\n    }\n    case Channel3.memoryLocationNRx0: {\n      let register = eightBitLoadFromGBMemory(Channel3.memoryLocationNRx0);\n      return register | 0x7f;\n    }\n    case Channel4.memoryLocationNRx0: {\n      let register = eightBitLoadFromGBMemory(Channel4.memoryLocationNRx0);\n      return register | 0xff;\n    }\n    case Sound.memoryLocationNR50: {\n      let register = eightBitLoadFromGBMemory(Sound.memoryLocationNR50);\n      return register | 0x00;\n    }\n\n    // Handle NRx1 on Channels\n    case Channel1.memoryLocationNRx1: {\n      let register = eightBitLoadFromGBMemory(Channel1.memoryLocationNRx1);\n      return register | 0x3f;\n    }\n    case Channel2.memoryLocationNRx1: {\n      let register = eightBitLoadFromGBMemory(Channel2.memoryLocationNRx1);\n      return register | 0x3f;\n    }\n    case Channel3.memoryLocationNRx1: {\n      let register = eightBitLoadFromGBMemory(Channel3.memoryLocationNRx1);\n      return register | 0xff;\n    }\n    case Channel4.memoryLocationNRx1: {\n      let register = eightBitLoadFromGBMemory(Channel4.memoryLocationNRx1);\n      return register | 0xff;\n    }\n    case Sound.memoryLocationNR51: {\n      let register = eightBitLoadFromGBMemory(Sound.memoryLocationNR51);\n      return register | 0x00;\n    }\n\n    // Handle NRx2 on Channels\n    case Channel1.memoryLocationNRx2: {\n      let register = eightBitLoadFromGBMemory(Channel1.memoryLocationNRx2);\n      return register | 0x00;\n    }\n    case Channel2.memoryLocationNRx2: {\n      let register = eightBitLoadFromGBMemory(Channel2.memoryLocationNRx2);\n      return register | 0x00;\n    }\n    case Channel3.memoryLocationNRx2: {\n      let register = eightBitLoadFromGBMemory(Channel3.memoryLocationNRx2);\n      return register | 0x9f;\n    }\n    case Channel4.memoryLocationNRx2: {\n      let register = eightBitLoadFromGBMemory(Channel4.memoryLocationNRx2);\n      return register | 0x00;\n    }\n    case Sound.memoryLocationNR52: {\n      // This will fix bugs in orcale of ages :)\n\n      // Start our registerNR52\n      let registerNR52 = 0x00;\n\n      // Set the first bit to the sound paower status\n      if (Sound.NR52IsSoundEnabled) {\n        registerNR52 = setBitOnByte(7, registerNR52);\n      } else {\n        registerNR52 = resetBitOnByte(7, registerNR52);\n      }\n\n      // Set our lower 4 bits to our channel length statuses\n      if (Channel1.isEnabled) {\n        registerNR52 = setBitOnByte(0, registerNR52);\n      } else {\n        registerNR52 = resetBitOnByte(0, registerNR52);\n      }\n\n      if (Channel2.isEnabled) {\n        registerNR52 = setBitOnByte(1, registerNR52);\n      } else {\n        registerNR52 = resetBitOnByte(1, registerNR52);\n      }\n\n      if (Channel3.isEnabled) {\n        registerNR52 = setBitOnByte(2, registerNR52);\n      } else {\n        registerNR52 = resetBitOnByte(2, registerNR52);\n      }\n\n      if (Channel4.isEnabled) {\n        registerNR52 = setBitOnByte(3, registerNR52);\n      } else {\n        registerNR52 = resetBitOnByte(3, registerNR52);\n      }\n\n      // Or from the table\n      registerNR52 |= 0x70;\n      return registerNR52;\n    }\n\n    // Handle NRx3 on Channels\n    case Channel1.memoryLocationNRx3: {\n      let register = eightBitLoadFromGBMemory(Channel1.memoryLocationNRx3);\n      return register | 0xff;\n    }\n    case Channel2.memoryLocationNRx3: {\n      let register = eightBitLoadFromGBMemory(Channel2.memoryLocationNRx3);\n      return register | 0xff;\n    }\n    case Channel3.memoryLocationNRx3: {\n      let register = eightBitLoadFromGBMemory(Channel3.memoryLocationNRx3);\n      return register | 0xff;\n    }\n    case Channel4.memoryLocationNRx3: {\n      let register = eightBitLoadFromGBMemory(Channel4.memoryLocationNRx3);\n      return register | 0x00;\n    }\n\n    // Handle NRx4 on Channels\n    case Channel1.memoryLocationNRx4: {\n      let register = eightBitLoadFromGBMemory(Channel1.memoryLocationNRx4);\n      return register | 0xbf;\n    }\n    case Channel2.memoryLocationNRx4: {\n      let register = eightBitLoadFromGBMemory(Channel2.memoryLocationNRx4);\n      return register | 0xbf;\n    }\n    case Channel3.memoryLocationNRx4: {\n      let register = eightBitLoadFromGBMemory(Channel3.memoryLocationNRx4);\n      return register | 0xbf;\n    }\n    case Channel4.memoryLocationNRx4: {\n      let register = eightBitLoadFromGBMemory(Channel4.memoryLocationNRx4);\n      return register | 0xbf;\n    }\n  }\n\n  return -1;\n}\n","import { Memory } from './memory';\nimport { Cpu } from '../cpu/index';\nimport { Graphics } from '../graphics/graphics';\nimport { Palette, writeColorPaletteToMemory, Lcd } from '../graphics/index';\nimport { batchProcessAudio, SoundRegisterWriteTraps, Channel3 } from '../sound/index';\nimport { Timers, batchProcessTimers } from '../timers/index';\nimport { Serial } from '../serial/serial';\nimport { Interrupts } from '../interrupts/index';\nimport { Joypad } from '../joypad/index';\nimport { handleBanking } from './banking';\nimport { eightBitStoreIntoGBMemory } from './store';\nimport { startDmaTransfer, startHdmaTransfer } from './dma';\n\n// Internal function to trap any modify data trying to be written to Gameboy memory\n// Follows the Gameboy memory map\n// Return true if you want to continue the write, return false to end it here\nexport function checkWriteTraps(offset: i32, value: i32): boolean {\n  // Cpu\n  if (offset === Cpu.memoryLocationSpeedSwitch) {\n    // TCAGBD, only Bit 0 is writable\n    eightBitStoreIntoGBMemory(Cpu.memoryLocationSpeedSwitch, value & 0x01);\n    // We did the write, dont need to\n    return false;\n  }\n\n  // Handle Boot ROM Switch\n  if (Cpu.BootROMEnabled && offset === Cpu.memoryLocationBootROMSwitch) {\n    // Disable the boot rom\n    Cpu.BootROMEnabled = false;\n\n    // Set the program counter to be incremented after this command\n    Cpu.programCounter = 0x00ff;\n\n    // Allow the write\n    return true;\n  }\n\n  // Graphics\n  // Cache globals used multiple times for performance\n  let videoRamLocation = Memory.videoRamLocation;\n  let spriteInformationTableLocation = Memory.spriteInformationTableLocation;\n\n  // Handle banking\n  if (offset < videoRamLocation) {\n    handleBanking(offset, value);\n    return false;\n  }\n\n  // Check the graphics mode to see if we can write to VRAM\n  // http://gbdev.gg8.se/wiki/articles/Video_Display#Accessing_VRAM_and_OAM\n  if (offset >= videoRamLocation && offset < Memory.cartridgeRamLocation) {\n    // Can only read/write from VRAM During Modes 0 - 2\n    // See graphics/lcd.ts\n    // TODO: This can do more harm than good in a beta emulator,\n    // requires precise timing disabling for now\n    // if (Graphics.currentLcdMode > 2) {\n    //   return false;\n    // }\n\n    // Not batch processing here for performance\n    // batchProcessGraphics();\n\n    // Allow the original write, and return since we dont need to look anymore\n    return true;\n  }\n\n  // Be sure to copy everything in EchoRam to Work Ram\n  // Codeslinger: The ECHO memory region (0xE000-0xFDFF) is quite different because any data written here is also written in the equivelent ram memory region 0xC000-0xDDFF.\n  // Hence why it is called echo\n  if (offset >= Memory.echoRamLocation && offset < spriteInformationTableLocation) {\n    let wramOffset = offset - 0x2000;\n    eightBitStoreIntoGBMemory(wramOffset, value);\n\n    // Allow the original write, and return since we dont need to look anymore\n    return true;\n  }\n\n  // Also check for individal writes\n  // Can only read/write from OAM During Modes 0 - 1\n  // See graphics/lcd.ts\n  if (offset >= spriteInformationTableLocation && offset <= Memory.spriteInformationTableLocationEnd) {\n    // Can only read/write from OAM During Mode 2\n    // See graphics/lcd.ts\n    // if (Lcd.currentLcdMode < 2) {\n    // return false;\n    // }\n    // Not batch processing here for performance\n    // batchProcessGraphics();\n\n    // Allow the original write, and return since we dont need to look anymore\n    // return true;\n    return Lcd.currentLcdMode >= 2;\n  }\n\n  if (offset >= Memory.unusableMemoryLocation && offset <= Memory.unusableMemoryEndLocation) {\n    return false;\n  }\n\n  // Serial\n  if (offset === Serial.memoryLocationSerialTransferControl) {\n    // SC\n    return Serial.updateTransferControl(value);\n  }\n\n  // Sound\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n  if (offset >= 0xff10 && offset <= 0xff26) {\n    batchProcessAudio();\n    return SoundRegisterWriteTraps(offset, value);\n  }\n\n  // FF27 - FF2F not used\n\n  // Final Wave Table for Channel 3\n  if (offset >= 0xff30 && offset <= 0xff3f) {\n    batchProcessAudio();\n\n    // Need to handle the write if channel 3 is enabled\n    if (Channel3.isEnabled) {\n      Channel3.handleWaveRamWrite(value);\n      return false;\n    }\n    return true;\n  }\n\n  // Other Memory effects fomr read/write to Lcd/Graphics\n  if (offset >= Lcd.memoryLocationLcdControl && offset <= Graphics.memoryLocationWindowX) {\n    // Not batch processing here for performance\n    // batchProcessGraphics();\n\n    if (offset === Lcd.memoryLocationLcdControl) {\n      // Shorcut for isLCD Enabled since it gets \"hot\"\n      Lcd.updateLcdControl(value);\n      return true;\n    }\n\n    if (offset === Lcd.memoryLocationLcdStatus) {\n      // We are handling the write here\n      Lcd.updateLcdStatus(value);\n      return false;\n    }\n\n    // reset the current scanline if the game tries to write to it\n    if (offset === Graphics.memoryLocationScanlineRegister) {\n      Graphics.scanlineRegister = 0;\n      eightBitStoreIntoGBMemory(offset, 0);\n      return false;\n    }\n\n    // Cache our coincidence compare\n    if (offset === Lcd.memoryLocationCoincidenceCompare) {\n      Lcd.coincidenceCompare = value;\n      return true;\n    }\n\n    // Do the direct memory access transfer for spriteInformationTable\n    // Check the graphics mode to see if we can write to VRAM\n    // http://gbdev.gg8.se/wiki/articles/Video_Display#Accessing_VRAM_and_OAM\n    if (offset === Graphics.memoryLocationDmaTransfer) {\n      // otherwise, perform a DMA transfer\n      // And allow the original write\n      startDmaTransfer(value);\n      return true;\n    }\n\n    // Scroll and Window XY\n    switch (offset) {\n      case Graphics.memoryLocationScrollX:\n        Graphics.scrollX = value;\n        return true;\n      case Graphics.memoryLocationScrollY:\n        Graphics.scrollY = value;\n        return true;\n      case Graphics.memoryLocationWindowX:\n        Graphics.windowX = value;\n        return true;\n      case Graphics.memoryLocationWindowY:\n        Graphics.windowY = value;\n        return true;\n    }\n\n    // Allow the original write, and return since we dont need to look anymore\n    return true;\n  }\n\n  // Do an HDMA\n  if (offset === Memory.memoryLocationHdmaTrigger) {\n    startHdmaTransfer(value);\n    return false;\n  }\n\n  // Don't allow banking if we are doing an Hblank HDM transfer\n  // https://gist.github.com/drhelius/3394856\n  if (offset === Memory.memoryLocationGBCWRAMBank || offset === Memory.memoryLocationGBCVRAMBank) {\n    if (Memory.isHblankHdmaActive) {\n      let hblankHdmaSource = Memory.hblankHdmaSource;\n      if ((hblankHdmaSource >= 0x4000 && hblankHdmaSource <= 0x7fff) || (hblankHdmaSource >= 0xd000 && hblankHdmaSource <= 0xdfff)) {\n        return false;\n      }\n    }\n  }\n\n  // Handle GBC Pallete Write\n  if (offset >= Palette.memoryLocationBackgroundPaletteIndex && offset <= Palette.memoryLocationSpritePaletteData) {\n    // Incremeenting the palette handled by the write\n    writeColorPaletteToMemory(offset, value);\n    return true;\n  }\n\n  // Handle timer writes\n  if (offset >= Timers.memoryLocationDividerRegister && offset <= Timers.memoryLocationTimerControl) {\n    // Batch Process\n    batchProcessTimers();\n\n    switch (offset) {\n      case Timers.memoryLocationDividerRegister:\n        Timers.updateDividerRegister();\n        return false;\n      case Timers.memoryLocationTimerCounter:\n        Timers.updateTimerCounter(value);\n        return true;\n      case Timers.memoryLocationTimerModulo:\n        Timers.updateTimerModulo(value);\n        return true;\n      case Timers.memoryLocationTimerControl:\n        Timers.updateTimerControl(value);\n        return true;\n    }\n\n    return true;\n  }\n\n  // Handle Joypad writes for HW reg caching\n  if (offset === Joypad.memoryLocationJoypadRegister) {\n    Joypad.updateJoypad(value);\n  }\n\n  // Handle Interrupt writes\n  if (offset === Interrupts.memoryLocationInterruptRequest) {\n    Interrupts.updateInterruptRequested(value);\n    return true;\n  }\n  if (offset === Interrupts.memoryLocationInterruptEnabled) {\n    Interrupts.updateInterruptEnabled(value);\n    return true;\n  }\n\n  // Allow the original write\n  return true;\n}\n","import { Cpu } from './index';\nimport { u8Portable, u16Portable } from '../portable/portable';\n\n// Set flag bit on on register F. For instance set zero flag to zero -> (7, 0)\nfunction setFlagBit(flagBit: u8, flagValue: i32): u8 {\n  let bitwiseOperand = u8Portable(1 << flagBit);\n  if (flagValue > 0) {\n    Cpu.registerF = Cpu.registerF | bitwiseOperand;\n  } else {\n    // XOR out the two ones\n    bitwiseOperand = 0xff ^ bitwiseOperand;\n    Cpu.registerF = Cpu.registerF & bitwiseOperand;\n  }\n\n  return Cpu.registerF;\n}\n\n// Overload the set flag bit for ease of use\nexport function setZeroFlag(value: i32): void {\n  setFlagBit(7, value);\n}\n\nexport function setSubtractFlag(value: i32): void {\n  setFlagBit(6, value);\n}\n\nexport function setHalfCarryFlag(value: i32): void {\n  setFlagBit(5, value);\n}\n\nexport function setCarryFlag(value: i32): void {\n  setFlagBit(4, value);\n}\n\n// Getters for flags\nexport function getZeroFlag(): u8 {\n  return (Cpu.registerF >> 7) & 0x01;\n}\n\nexport function getSubtractFlag(): u8 {\n  return (Cpu.registerF >> 6) & 0x01;\n}\n\nexport function getHalfCarryFlag(): u8 {\n  return (Cpu.registerF >> 5) & 0x01;\n}\n\nexport function getCarryFlag(): u8 {\n  return (Cpu.registerF >> 4) & 0x01;\n}\n\n// Must be run before the register actually performs the add\n// amountToAdd i16, since max number can be an u8\nexport function checkAndSetEightBitHalfCarryFlag(value: u8, amountToAdd: i32): void {\n  if (amountToAdd >= 0) {\n    // https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/\n    let result = u8Portable(((<u8>value) & 0x0f) + ((<u8>amountToAdd) & 0x0f)) & 0x10;\n    setHalfCarryFlag(<i32>(result !== 0x00));\n  } else {\n    // From: https://github.com/djhworld/gomeboycolor/blob/master/src/cpu/index.go\n    // CTRL+F \"subBytes(a, b byte)\"\n    setHalfCarryFlag(<i32>(<u8>(abs(amountToAdd) & 0x0f) > (value & 0x0f)));\n  }\n}\n\nexport function checkAndSetEightBitCarryFlag(value: u8, amountToAdd: i32): void {\n  if (amountToAdd >= 0) {\n    let result = u8Portable(value + <u8>amountToAdd);\n    setCarryFlag(<i32>(value > result));\n  } else {\n    setCarryFlag(<i32>(abs(amountToAdd) > <i32>value));\n  }\n}\n\n// Function to handle 16 bit addition overflow, and set the carry flags accordingly\n// i32 on valueTwo to support passing signed immedaite values\nexport function checkAndSetSixteenBitFlagsAddOverflow(valueOne: u16, valueTwo: i32, useStackPointerBits: boolean): void {\n  // need to differentiate between HL and SP\n  // HL carries are at 11 and 15, SP carries are at 3 and 7 :p\n  if (useStackPointerBits) {\n    // Logic from : https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js\n    // CTRL+F add_sp_n\n    // using the stack pointer bits means we can safely assume the value is signed\n    let signedValueOne = <i32>valueOne;\n    let result = signedValueOne + valueTwo;\n    let flagXor = signedValueOne ^ valueTwo ^ result;\n\n    setHalfCarryFlag(<i32>((flagXor & 0x10) !== 0));\n    setCarryFlag(<i32>((flagXor & 0x100) !== 0));\n  } else {\n    // Logic from: https://github.com/djhworld/gomeboycolor/blob/master/src/cpu/index.go\n    // CTRL+F addWords\n    // Value two is not signed\n    let result = u16Portable(valueOne + <u16>valueTwo);\n\n    // Check the carry flag by allowing the overflow\n    setCarryFlag(<i32>(result < valueOne));\n\n    // To check for half carry flag (bit 15), by XOR'ing valyes, and and'ing the bit in question\n    let halfCarryXor: u16 = valueOne ^ (<u16>valueTwo) ^ (<u16>result);\n    let halfCarryAnd = u16Portable(halfCarryXor & 0x1000);\n    setHalfCarryFlag(<i32>(halfCarryAnd !== 0x00));\n  }\n}\n","// Imports\nimport { Cpu } from './index';\nimport {\n  setZeroFlag,\n  setSubtractFlag,\n  setHalfCarryFlag,\n  setCarryFlag,\n  getCarryFlag,\n  checkAndSetEightBitCarryFlag,\n  checkAndSetEightBitHalfCarryFlag\n} from './flags';\nimport { rotateByteLeft, rotateByteLeftThroughCarry, rotateByteRight, rotateByteRightThroughCarry } from '../helpers/index';\nimport { u8Portable, u16Portable, i8Portable } from '../portable/portable';\n\n// General Logic Instructions\n// Such as the ones found on the CB table and 0x40 - 0xBF\n// NOTE: Only CB table uses these for now, was mostly me realizing that I messed up, trying to be all cute and verbose :p\n// NOTE: TODO: Refactor honestly shouldn't take that long, and may happen once assembly script is improved\nexport function addARegister(register: u8): void {\n  let registerA = Cpu.registerA;\n  checkAndSetEightBitHalfCarryFlag(registerA, register);\n  checkAndSetEightBitCarryFlag(registerA, register);\n  registerA = u8Portable(registerA + register);\n  Cpu.registerA = registerA;\n  setZeroFlag(<i32>(registerA === 0));\n  setSubtractFlag(0);\n}\n\nexport function addAThroughCarryRegister(register: u8): void {\n  // Handling flags manually as they require some special overflow\n  // From: https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js\n  // CTRL+F adc\n  let registerA = Cpu.registerA;\n  let result = u8Portable(registerA + register + getCarryFlag());\n  setHalfCarryFlag(<i32>((u8Portable(registerA ^ register ^ result) & 0x10) != 0));\n\n  let overflowedResult = u16Portable(<u16>registerA + <u16>register + <u16>getCarryFlag());\n  setCarryFlag(<i32>((overflowedResult & 0x100) > 0));\n\n  Cpu.registerA = result;\n  setZeroFlag(<i32>(result === 0));\n  setSubtractFlag(0);\n}\n\nexport function subARegister(register: u8): void {\n  // Need to convert the register on one line, and flip the sign on another\n  let negativeRegister: i32 = register;\n  negativeRegister = negativeRegister * -1;\n\n  let registerA = Cpu.registerA;\n  checkAndSetEightBitHalfCarryFlag(registerA, negativeRegister);\n  checkAndSetEightBitCarryFlag(registerA, negativeRegister);\n  registerA = u8Portable(registerA - register);\n  Cpu.registerA = registerA;\n  setZeroFlag(<i32>(registerA === 0));\n  setSubtractFlag(1);\n}\n\nexport function subAThroughCarryRegister(register: u8): void {\n  // Handling flags manually as they require some special overflow\n  // From: https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js\n  // CTRL+F adc\n  let registerA = Cpu.registerA;\n  let result = u8Portable(registerA - register - getCarryFlag());\n\n  let carryRegisterCheck = u8Portable((registerA ^ register ^ result) & 0x10);\n  setHalfCarryFlag(<i32>(carryRegisterCheck != 0));\n\n  let overflowedResult = u16Portable(<u16>registerA - <u16>register - <u16>getCarryFlag());\n  setCarryFlag(<i32>((overflowedResult & 0x100) > 0));\n\n  Cpu.registerA = result;\n  setZeroFlag(<i32>(result === 0));\n  setSubtractFlag(1);\n}\n\nexport function andARegister(register: u8): void {\n  let registerA = Cpu.registerA & register;\n  Cpu.registerA = registerA;\n  setZeroFlag(<i32>(registerA === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(1);\n  setCarryFlag(0);\n}\n\nexport function xorARegister(register: u8): void {\n  let registerA = u8Portable(Cpu.registerA ^ register);\n  Cpu.registerA = registerA;\n  setZeroFlag(<i32>(registerA === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n  setCarryFlag(0);\n}\n\nexport function orARegister(register: u8): void {\n  let registerA = Cpu.registerA | register;\n  Cpu.registerA = registerA;\n  setZeroFlag(<i32>(registerA === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n  setCarryFlag(0);\n}\n\nexport function cpARegister(register: u8): void {\n  // 0xB8 - 0xBF\n  // CP B\n  // 1  4\n  // Z 1 H C\n  let registerA = Cpu.registerA;\n  let negativeRegister: i32 = register;\n  negativeRegister = negativeRegister * -1;\n  checkAndSetEightBitHalfCarryFlag(registerA, negativeRegister);\n  checkAndSetEightBitCarryFlag(registerA, negativeRegister);\n  let tempResult = <i32>registerA + negativeRegister;\n  setZeroFlag(<i32>(tempResult === 0));\n  setSubtractFlag(1);\n}\n\n// Inlined because closure compiler inlines\nexport function rotateRegisterLeft(register: u8): u8 {\n  // RLC register 8-bit\n  // Z 0 0 C\n  setCarryFlag(<i32>((register & 0x80) === 0x80));\n\n  register = rotateByteLeft(register);\n  setZeroFlag(<i32>(register === 0));\n\n  // Set all other flags to zero\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n\n  // Return the register\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function rotateRegisterRight(register: u8): u8 {\n  // RLC register 8-bit\n  // Z 0 0 C\n  // Check for the last bit, to see if it will be carried\n  setCarryFlag(<i32>((register & 0x01) > 0));\n  register = rotateByteRight(register);\n\n  setZeroFlag(<i32>(register === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n\n  // Return the register\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function rotateRegisterLeftThroughCarry(register: u8): u8 {\n  // RL register 8-bit\n  // Z 0 0 C\n  // setting has first bit since we need to use carry\n  let hasHighbit = (register & 0x80) === 0x80;\n  register = rotateByteLeftThroughCarry(register);\n\n  setCarryFlag(<i32>hasHighbit);\n  setZeroFlag(<i32>(register === 0));\n\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function rotateRegisterRightThroughCarry(register: u8): u8 {\n  // RR register 8-bit\n  // Z 0 0 C\n  let hasLowBit = (register & 0x01) === 0x01;\n  register = rotateByteRightThroughCarry(register);\n\n  setCarryFlag(<i32>hasLowBit);\n  setZeroFlag(<i32>(register === 0));\n\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function shiftLeftRegister(register: u8): u8 {\n  // SLA register 8-bit\n  // Z 0 0 C\n  let hasHighbit = (register & 0x80) === 0x80;\n  register = u8Portable(register << 1);\n\n  setCarryFlag(<i32>hasHighbit);\n  setZeroFlag(<i32>(register === 0));\n\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function shiftRightArithmeticRegister(register: u8): u8 {\n  // SRA register 8-bit\n  // Z 0 0 C\n  // NOTE: This C flag may need to be set to 0;\n  // This preserves the MSB (Most significant bit)\n  let hasHighbit = (register & 0x80) === 0x80;\n  let hasLowbit = (register & 0x01) === 0x01;\n\n  register = u8Portable(register >> 1);\n\n  if (hasHighbit) {\n    register = register | 0x80;\n  }\n\n  setZeroFlag(<i32>(register === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n  setCarryFlag(<i32>hasLowbit);\n\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function swapNibblesOnRegister(register: u8): u8 {\n  // SWAP register 8-bit\n  // Z 0 0 0\n  let highNibble = register & 0xf0;\n  let lowNibble = register & 0x0f;\n  register = u8Portable((lowNibble << 4) | (highNibble >> 4));\n\n  setZeroFlag(<i32>(register === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n  setCarryFlag(0);\n\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function shiftRightLogicalRegister(register: u8): u8 {\n  // SRA register 8-bit\n  // Z 0 0 C\n  // NOTE: This C flag may need to be set to 0;\n  // This does NOT preserve MSB (most significant bit)\n\n  let hasLowbit = (register & 0x01) === 0x01;\n  register = u8Portable(register >> 1);\n\n  setZeroFlag(<i32>(register === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n  setCarryFlag(<i32>hasLowbit);\n\n  return register;\n}\n\nexport function testBitOnRegister(bitPosition: u8, register: u8): u8 {\n  // BIT bitPosition ,register 8-bit\n  // Z 0 1 -\n\n  let testByte: u8 = 0x01 << bitPosition;\n  let result = register & testByte;\n\n  setZeroFlag(<i32>(result === 0x00));\n  setSubtractFlag(0);\n  setHalfCarryFlag(1);\n\n  return register;\n}\n\nexport function setBitOnRegister(bitPosition: u8, bitValue: i32, register: u8): u8 {\n  // RES 0,B or SET 0,B depending on bit value\n\n  if (bitValue > 0) {\n    let setByte: u8 = 0x01 << bitPosition;\n    register = register | setByte;\n  } else {\n    // NOT (byte we want)\n    // 0000 0100 becomes 1111 1011\n    let setByte: u8 = ~(0x01 << bitPosition);\n    register = register & setByte;\n  }\n\n  return register;\n}\n\n// Private function for our relative jumps\nexport function relativeJump(value: u8): void {\n  // Need to convert the value to i8, since in this case, u8 can be negative\n  let relativeJumpOffset = i8Portable(<i8>value);\n  let programCounter = Cpu.programCounter;\n  programCounter = u16Portable(programCounter + relativeJumpOffset);\n  // Realtive jump, using bgb debugger\n  // and my debugger shows,\n  // on JR you need to jump to the relative jump offset,\n  // However, if the jump fails (such as conditional), only jump +2 in total\n\n  programCounter = u16Portable(programCounter + 1);\n  Cpu.programCounter = programCounter;\n}\n","// Imports\nimport { Cpu } from './index';\nimport {\n  rotateRegisterLeft,\n  rotateRegisterRight,\n  rotateRegisterLeftThroughCarry,\n  rotateRegisterRightThroughCarry,\n  shiftLeftRegister,\n  shiftRightArithmeticRegister,\n  swapNibblesOnRegister,\n  shiftRightLogicalRegister,\n  testBitOnRegister,\n  setBitOnRegister\n} from './instructions';\nimport { eightBitLoadSyncCycles, eightBitStoreSyncCycles } from './opcodes';\nimport { concatenateBytes } from '../helpers/index';\n\n// Handle CB Opcodes\n// NOTE: Program stpes and cycles are standardized depending on the register type\n// NOTE: Doing some funny stuff to get around not having arrays or objects\n// Inlined because closure compiler inlines.\nexport function handleCbOpcode(cbOpcode: i32): i32 {\n  let numberOfCycles = -1;\n  let handledOpcode = false;\n\n  // The result of our cb logic instruction\n  let instructionRegisterValue: u8 = 0;\n  let instructionRegisterResult: u8 = 0;\n\n  // Get our register number by modulo 0x08 (number of registers)\n  // cbOpcode % 0x08\n  let registerNumber = cbOpcode & 0x07;\n\n  // NOTE: registerNumber = register on CB table. Cpu.registerB = 0, Cpu.registerC = 1....Cpu.registerA = 7\n  switch (registerNumber) {\n    case 0:\n      instructionRegisterValue = Cpu.registerB;\n      break;\n    case 1:\n      instructionRegisterValue = Cpu.registerC;\n      break;\n    case 2:\n      instructionRegisterValue = Cpu.registerD;\n      break;\n    case 3:\n      instructionRegisterValue = Cpu.registerE;\n      break;\n    case 4:\n      instructionRegisterValue = Cpu.registerH;\n      break;\n    case 5:\n      instructionRegisterValue = Cpu.registerL;\n      break;\n    case 6:\n      // Value at register HL\n      // 4 cycles\n      instructionRegisterValue = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      break;\n    case 7:\n      instructionRegisterValue = Cpu.registerA;\n      break;\n  }\n\n  // Grab the high nibble to perform skips to speed up performance\n  let opcodeHighNibble = cbOpcode & 0xf0;\n  opcodeHighNibble = opcodeHighNibble >> 4;\n\n  // Send to the correct function\n  switch (opcodeHighNibble) {\n    case 0x00:\n      if (cbOpcode <= 0x07) {\n        // RLC register 8-bit\n        // Z 0 0 C\n        instructionRegisterResult = rotateRegisterLeft(instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x0f) {\n        // RRC register 8-bit\n        // Z 0 0 C\n        instructionRegisterResult = rotateRegisterRight(instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x01:\n      if (cbOpcode <= 0x17) {\n        // RL register 8-bit\n        // Z 0 0 C\n        instructionRegisterResult = rotateRegisterLeftThroughCarry(instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x1f) {\n        // RR register 8-bit\n        // Z 0 0 C\n        instructionRegisterResult = rotateRegisterRightThroughCarry(instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x02:\n      if (cbOpcode <= 0x27) {\n        // SLA register 8-bit\n        // Z 0 0 C\n        instructionRegisterResult = shiftLeftRegister(instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x2f) {\n        // SRA register 8-bit\n        // Z 0 0 0\n        instructionRegisterResult = shiftRightArithmeticRegister(instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x03:\n      if (cbOpcode <= 0x37) {\n        // SWAP register 8-bit\n        // Z 0 0 0\n        instructionRegisterResult = swapNibblesOnRegister(instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x3f) {\n        // SRL B\n        // Z 0 0 C\n        instructionRegisterResult = shiftRightLogicalRegister(instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x04:\n      if (cbOpcode <= 0x47) {\n        // BIT 0,register 8-bit\n        // Z 0 1 -\n        //TODO: Optimize this not to do logic of setting register back\n        instructionRegisterResult = testBitOnRegister(0, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x4f) {\n        // BIT 1,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(1, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x05:\n      if (cbOpcode <= 0x57) {\n        // BIT 2,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(2, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x5f) {\n        // BIT 3,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(3, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x06:\n      if (cbOpcode <= 0x67) {\n        // BIT 4,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(4, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x6f) {\n        // BIT 5,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(5, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x07:\n      if (cbOpcode <= 0x77) {\n        // BIT 6,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(6, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x7f) {\n        // BIT 7,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(7, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x08:\n      if (cbOpcode <= 0x87) {\n        // Res 0,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(0, 0, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x8f) {\n        // Res 1,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(1, 0, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x09:\n      if (cbOpcode <= 0x97) {\n        // Res 2,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(2, 0, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x9f) {\n        // Res 3,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(3, 0, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x0a:\n      if (cbOpcode <= 0xa7) {\n        // Res 4,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(4, 0, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0xaf) {\n        // Res 5,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(5, 0, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x0b:\n      if (cbOpcode <= 0xb7) {\n        // Res 6,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(6, 0, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0xbf) {\n        // Res 7,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(7, 0, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x0c:\n      if (cbOpcode <= 0xc7) {\n        // SET 0,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(0, 1, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0xcf) {\n        // SET 1,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(1, 1, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x0d:\n      if (cbOpcode <= 0xd7) {\n        // SET 2,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(2, 1, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0xdf) {\n        // SET 3,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(3, 1, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x0e:\n      if (cbOpcode <= 0xe7) {\n        // SET 4,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(4, 1, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0xef) {\n        // SET 5,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(5, 1, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x0f:\n      if (cbOpcode <= 0xf7) {\n        // SET 6,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(6, 1, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0xff) {\n        // SET 7,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(7, 1, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n  }\n\n  // Finally Pass back into the correct register\n  switch (registerNumber) {\n    case 0:\n      Cpu.registerB = instructionRegisterResult;\n      break;\n    case 1:\n      Cpu.registerC = instructionRegisterResult;\n      break;\n    case 2:\n      Cpu.registerD = instructionRegisterResult;\n      break;\n    case 3:\n      Cpu.registerE = instructionRegisterResult;\n      break;\n    case 4:\n      Cpu.registerH = instructionRegisterResult;\n      break;\n    case 5:\n      Cpu.registerL = instructionRegisterResult;\n      break;\n    case 6:\n      // Value at register HL\n\n      // Opcodes 0x40 -> 0x7F only do simple\n      // Bit test, and don't need to be stored back in memory\n      // Thus they take 4 less cycles to run\n      if (opcodeHighNibble < 0x04 || opcodeHighNibble > 0x07) {\n        // Store the result back\n        // 4 cycles\n        eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), instructionRegisterResult);\n      }\n      break;\n    case 7:\n      Cpu.registerA = instructionRegisterResult;\n      break;\n  }\n\n  // Finally our number of cycles\n  // Set if we handled the opcode\n  if (handledOpcode) {\n    numberOfCycles = 4;\n  }\n\n  // Return our number of cycles\n  return numberOfCycles;\n}\n","// Functions to get information about the emulator for debugging purposes\nimport { Cpu } from '../cpu/index';\nimport { eightBitLoadFromGBMemory } from '../memory/index';\n\nexport function getRegisterA(): u8 {\n  return Cpu.registerA;\n}\n\nexport function getRegisterB(): u8 {\n  return Cpu.registerB;\n}\n\nexport function getRegisterC(): u8 {\n  return Cpu.registerC;\n}\n\nexport function getRegisterD(): u8 {\n  return Cpu.registerD;\n}\n\nexport function getRegisterE(): u8 {\n  return Cpu.registerE;\n}\n\nexport function getRegisterH(): u8 {\n  return Cpu.registerH;\n}\n\nexport function getRegisterL(): u8 {\n  return Cpu.registerL;\n}\n\nexport function getRegisterF(): u8 {\n  return Cpu.registerF;\n}\n\nexport function getProgramCounter(): u16 {\n  return Cpu.programCounter;\n}\n\nexport function getStackPointer(): u16 {\n  return Cpu.stackPointer;\n}\n\nexport function getOpcodeAtProgramCounter(): u8 {\n  return <u8>eightBitLoadFromGBMemory(Cpu.programCounter);\n}\n","// Functions to debug graphical output\nimport { BACKGROUND_MAP_LOCATION, TILE_DATA_LOCATION, OAM_TILES_LOCATION } from '../constants';\nimport {\n  Graphics,\n  Lcd,\n  getTileDataAddress,\n  drawPixelsFromLineOfTile,\n  getMonochromeColorFromPalette,\n  getColorizedGbHexColorFromPalette,\n  getRedFromHexColor,\n  getGreenFromHexColor,\n  getBlueFromHexColor,\n  getRgbColorFromPalette,\n  getColorComponentFromRgb,\n  loadFromVramBank\n} from '../graphics/index';\nimport { Cpu } from '../cpu/index';\nimport { eightBitLoadFromGBMemory, Memory } from '../memory/index';\nimport { checkBitOnByte } from '../helpers/index';\n\n// Some Simple internal getters\nexport function getLY(): i32 {\n  return Graphics.scanlineRegister;\n}\n\n// TODO: Render by tile, rather than by pixel\nexport function drawBackgroundMapToWasmMemory(showColor: i32): void {\n  // http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html\n  // Bit 7 - LCD Display Enable (0=Off, 1=On)\n  // Bit 6 - Window Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)\n  // Bit 5 - Window Display Enable (0=Off, 1=On)\n  // Bit 4 - BG & Window Tile Data Select (0=8800-97FF, 1=8000-8FFF)\n  // Bit 3 - BG Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)\n  // Bit 2 - OBJ (Sprite) Size (0=8x8, 1=8x16)\n  // Bit 1 - OBJ (Sprite) Display Enable (0=Off, 1=On)\n  // Bit 0 - BG Display (for CGB see below) (0=Off, 1=On)\n\n  // Get our seleted tile data memory location\n  let tileDataMemoryLocation = Graphics.memoryLocationTileDataSelectZeroStart;\n  if (Lcd.bgWindowTileDataSelect) {\n    tileDataMemoryLocation = Graphics.memoryLocationTileDataSelectOneStart;\n  }\n\n  let tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectZeroStart;\n  if (Lcd.bgTileMapDisplaySelect) {\n    tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectOneStart;\n  }\n\n  for (let y: i32 = 0; y < 256; y++) {\n    for (let x: i32 = 0; x < 256; x++) {\n      // Get our current Y\n      let pixelYPositionInMap: i32 = y;\n\n      // Get our Current X position of our pixel on the on the 160x144 camera\n      // this is done by getting the current scroll X position,\n      // and adding it do what X Value the scanline is drawing on the camera.\n      let pixelXPositionInMap: i32 = x;\n\n      // Divide our pixel position by 8 to get our tile.\n      // Since, there are 256x256 pixels, and 32x32 tiles.\n      // 256 / 8 = 32.\n      // Also, bitshifting by 3, do do a division by 8\n      // Need to use u16s, as they will be used to compute an address, which will cause weird errors and overflows\n      let tileXPositionInMap: i32 = pixelXPositionInMap >> 3;\n      let tileYPositionInMap: i32 = pixelYPositionInMap >> 3;\n\n      // Get our tile address on the tileMap\n      // NOTE: (tileMap represents where each tile is displayed on the screen)\n      // NOTE: (tile map represents the entire map, now just what is within the \"camera\")\n      // For instance, if we have y pixel 144. 144 / 8 = 18. 18 * 32 = line address in map memory.\n      // And we have x pixel 160. 160 / 8 = 20.\n      // * 32, because remember, this is NOT only for the camera, the actual map is 32x32. Therefore, the next tile line of the map, is 32 byte offset.\n      // Think like indexing a 2d array, as a 1d array and it make sense :)\n      let tileMapAddress: i32 = tileMapMemoryLocation + tileYPositionInMap * 32 + tileXPositionInMap;\n\n      // Get the tile Id on the Tile Map\n      let tileIdFromTileMap: i32 = loadFromVramBank(tileMapAddress, 0);\n\n      // Now get our tileDataAddress for the corresponding tileID we found in the map\n      // Read the comments in _getTileDataAddress() to see what's going on.\n      // tl;dr if we had the tile map of \"a b c d\", and wanted tileId 2.\n      // This funcitons returns the start of memory locaiton for the tile 'c'.\n      let tileDataAddress: i32 = getTileDataAddress(tileDataMemoryLocation, tileIdFromTileMap);\n\n      // Now we can process the the individual bytes that represent the pixel on a tile\n\n      // Get the y pixel of the 8 by 8 tile.\n      // Simply modulo the scanline.\n      // For instance, let's say we are printing the first line of pixels on our camera,\n      // And the first line of pixels on our tile.\n      // yPixel = 1. 1 % 8 = 1.\n      // And for the last line\n      // yPixel = 144. 144 % 8 = 0.\n      // 0 Represents last line of pixels in a tile, 1 represents first. 1 2 3 4 5 6 7 0.\n      // Because remember, we are counting lines on the display NOT including zero\n      let pixelYInTile: i32 = pixelYPositionInMap % 8;\n\n      // Same logic as pixelYInTile.\n      // However, We need to reverse our byte,\n      // As pixel 0 is on byte 7, and pixel 1 is on byte 6, etc...\n      // Therefore, is pixelX was 2, then really is need to be 5\n      // So 2 - 7 = -5, * 1 = 5\n      // Or to simplify, 7 - 2 = 5 haha!\n      let pixelXInTile: i32 = pixelXPositionInMap % 8;\n      pixelXInTile = 7 - pixelXInTile;\n\n      // Get the GB Map Attributes\n      // Bit 0-2  Background Palette number  (BGP0-7)\n      // Bit 3    Tile VRAM Bank number      (0=Bank 0, 1=Bank 1)\n      // Bit 4    Not used\n      // Bit 5    Horizontal Flip            (0=Normal, 1=Mirror horizontally)\n      // Bit 6    Vertical Flip              (0=Normal, 1=Mirror vertically)\n      // Bit 7    BG-to-OAM Priority         (0=Use OAM priority bit, 1=BG Priority)\n      let bgMapAttributes: i32 = 0;\n      if (Cpu.GBCEnabled && showColor > 0) {\n        bgMapAttributes = loadFromVramBank(tileMapAddress, 1);\n      }\n\n      if (checkBitOnByte(6, bgMapAttributes)) {\n        // We are mirroring the tile, therefore, we need to opposite byte\n        // So if our pizel was 0 our of 8, it wild become 7 :)\n        // TODO: This may be wrong :p\n        pixelYInTile = 7 - pixelYInTile;\n      }\n\n      // Remember to represent a single line of 8 pixels on a tile, we need two bytes.\n      // Therefore, we need to times our modulo by 2, to get the correct line of pixels on the tile.\n      // But we need to load the time from a specific Vram bank\n      let vramBankId: i32 = 0;\n      if (checkBitOnByte(3, bgMapAttributes)) {\n        vramBankId = 1;\n      }\n\n      // Remember to represent a single line of 8 pixels on a tile, we need two bytes.\n      // Therefore, we need to times our modulo by 2, to get the correct line of pixels on the tile.\n      // Again, think like you had to map a 2d array as a 1d.\n      let byteOneForLineOfTilePixels: i32 = loadFromVramBank(tileDataAddress + pixelYInTile * 2, vramBankId);\n      let byteTwoForLineOfTilePixels: i32 = loadFromVramBank(tileDataAddress + pixelYInTile * 2 + 1, vramBankId);\n\n      // Now we can get the color for that pixel\n      // Colors are represented by getting X position of ByteTwo, and X positon of Byte One\n      // To Get the color Id.\n      // For example, the result of the color id is 0000 00[xPixelByteTwo][xPixelByteOne]\n      // See: How to draw a tile/sprite from memory: http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html\n      let paletteColorId: i32 = 0;\n      if (checkBitOnByte(pixelXInTile, byteTwoForLineOfTilePixels)) {\n        // Byte one represents the second bit in our color id, so bit shift\n        paletteColorId += 1;\n        paletteColorId = paletteColorId << 1;\n      }\n      if (checkBitOnByte(pixelXInTile, byteOneForLineOfTilePixels)) {\n        paletteColorId += 1;\n      }\n\n      // FINALLY, RENDER THAT PIXEL!\n      let pixelStart: i32 = (y * 256 + x) * 3;\n\n      if (Cpu.GBCEnabled && showColor > 0) {\n        // Finally lets add some, C O L O R\n        // Want the botom 3 bits\n        let bgPalette: i32 = bgMapAttributes & 0x07;\n\n        // Call the helper function to grab the correct color from the palette\n        let rgbColorPalette: i32 = getRgbColorFromPalette(bgPalette, paletteColorId, false);\n\n        // Split off into red green and blue\n        let red: i32 = getColorComponentFromRgb(0, rgbColorPalette);\n        let green: i32 = getColorComponentFromRgb(1, rgbColorPalette);\n        let blue: i32 = getColorComponentFromRgb(2, rgbColorPalette);\n\n        let offset: i32 = BACKGROUND_MAP_LOCATION + pixelStart;\n        store<u8>(offset, <u8>red);\n        store<u8>(offset + 1, <u8>green);\n        store<u8>(offset + 2, <u8>blue);\n      } else {\n        // Only rendering camera for now, so coordinates are for the camera.\n        // Get the rgb value for the color Id, will be repeated into R, G, B (if not colorized)\n        let hexColor: i32 = getColorizedGbHexColorFromPalette(paletteColorId, Graphics.memoryLocationBackgroundPalette);\n\n        let offset: i32 = BACKGROUND_MAP_LOCATION + pixelStart;\n\n        // Red\n        store<u8>(offset + 0, <u8>getRedFromHexColor(hexColor));\n        // Green\n        store<u8>(offset + 1, <u8>getGreenFromHexColor(hexColor));\n        // Blue\n        store<u8>(offset + 2, <u8>getBlueFromHexColor(hexColor));\n      }\n    }\n  }\n}\n\nexport function drawTileDataToWasmMemory(): void {\n  for (let tileDataMapGridY: i32 = 0; tileDataMapGridY < 0x17; tileDataMapGridY++) {\n    for (let tileDataMapGridX: i32 = 0; tileDataMapGridX < 0x1f; tileDataMapGridX++) {\n      // Get Our VramBankID\n      let vramBankId: i32 = 0;\n      if (tileDataMapGridX > 0x0f) {\n        vramBankId = 1;\n      }\n\n      // Get our tile ID\n      let tileId: i32 = tileDataMapGridY;\n      if (tileDataMapGridY > 0x0f) {\n        tileId -= 0x0f;\n      }\n      tileId = tileId << 4;\n      if (tileDataMapGridX > 0x0f) {\n        tileId = tileId + (tileDataMapGridX - 0x0f);\n      } else {\n        tileId = tileId + tileDataMapGridX;\n      }\n\n      // Finally get our tile Data location\n      let tileDataMemoryLocation: i32 = Graphics.memoryLocationTileDataSelectOneStart;\n      if (tileDataMapGridY > 0x0f) {\n        tileDataMemoryLocation = Graphics.memoryLocationTileDataSelectZeroStart;\n      }\n\n      // Let's see if we have C O L O R\n      // Set the map and sprite attributes to -1\n      // Meaning, we will draw monochrome\n      let paletteLocation: i32 = Graphics.memoryLocationBackgroundPalette;\n      let bgMapAttributes: i32 = -1;\n      let spriteAttributes: i32 = -1;\n\n      // Let's see if the tile is being used by a sprite\n      for (let spriteRow: i32 = 0; spriteRow < 8; spriteRow++) {\n        for (let spriteColumn: i32 = 0; spriteColumn < 5; spriteColumn++) {\n          let spriteIndex = spriteColumn * 8 + spriteRow;\n\n          // Sprites occupy 4 bytes in the sprite attribute table\n          let spriteTableIndex: i32 = spriteIndex * 4;\n          let spriteTileId: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex + 2);\n\n          if (tileId === spriteTileId) {\n            let currentSpriteAttributes: i32 = eightBitLoadFromGBMemory(\n              Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex + 3\n            );\n\n            let spriteVramBankId: i32 = 0;\n            if (Cpu.GBCEnabled && checkBitOnByte(3, currentSpriteAttributes)) {\n              spriteVramBankId = 1;\n            }\n\n            if (spriteVramBankId === vramBankId) {\n              spriteAttributes = currentSpriteAttributes;\n              spriteRow = 8;\n              spriteColumn = 5;\n\n              // Set our paletteLocation\n              paletteLocation = Graphics.memoryLocationSpritePaletteOne;\n              if (checkBitOnByte(4, spriteAttributes)) {\n                paletteLocation = Graphics.memoryLocationSpritePaletteTwo;\n              }\n            }\n          }\n        }\n      }\n\n      // If we didn't find a sprite,\n      // Let's see if the tile is on the bg tile map\n      // If so, use that bg map for attributes\n      if (Cpu.GBCEnabled && spriteAttributes < 0) {\n        let tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectZeroStart;\n        if (Lcd.bgTileMapDisplaySelect) {\n          tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectOneStart;\n        }\n        // Loop through the tileMap, and find if we have our current ID\n        let foundTileMapAddress: i32 = -1;\n        for (let x: i32 = 0; x < 32; x++) {\n          for (let y: i32 = 0; y < 32; y++) {\n            let tileMapAddress: i32 = tileMapMemoryLocation + y * 32 + x;\n            let tileIdFromTileMap: i32 = loadFromVramBank(tileMapAddress, 0);\n\n            // Check if we found our tileId\n            if (tileId === tileIdFromTileMap) {\n              foundTileMapAddress = tileMapAddress;\n              x = 32;\n              y = 32;\n            }\n          }\n        }\n\n        if (foundTileMapAddress >= 0) {\n          bgMapAttributes = loadFromVramBank(foundTileMapAddress, 1);\n        }\n      }\n\n      // Draw each Y line of the tile\n      for (let tileLineY: i32 = 0; tileLineY < 8; tileLineY++) {\n        drawPixelsFromLineOfTile(\n          tileId, // tileId\n          tileDataMemoryLocation, // Graphics.memoryLocationTileDataSelect\n          vramBankId, // Vram Bank\n          0, // Tile Line X Start\n          7, // Tile Line X End\n          tileLineY, // Tile Line Y\n          tileDataMapGridX * 8, // Output line X\n          tileDataMapGridY * 8 + tileLineY, // Output line Y\n          0x1f * 8, // Output Width\n          TILE_DATA_LOCATION, // Wasm Memory Start\n          false, // shouldRepresentMonochromeColorByColorId\n          paletteLocation, // paletteLocation\n          bgMapAttributes, // bgMapAttributes\n          spriteAttributes // spriteAttributes\n        );\n      }\n    }\n  }\n}\n\nexport function drawOamToWasmMemory(): void {\n  // Draw all 40 sprites\n  // Going to be like BGB and do 8 x 5 sprites\n  for (let spriteRow: i32 = 0; spriteRow < 8; spriteRow++) {\n    for (let spriteColumn: i32 = 0; spriteColumn < 5; spriteColumn++) {\n      let spriteIndex = spriteColumn * 8 + spriteRow;\n\n      // Sprites occupy 4 bytes in the sprite attribute table\n      let spriteTableIndex: i32 = spriteIndex * 4;\n\n      // Y positon is offset by 16, X position is offset by 8\n\n      let spriteYPosition: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex);\n      let spriteXPosition: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex + 1);\n      let spriteTileId: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex + 2);\n\n      let tilesToDraw: i32 = 1;\n      if (Lcd.tallSpriteSize) {\n        // @binji says in 8x16 mode, even tileId always drawn first\n        // This will fix shantae sprites which always uses odd numbered indexes\n\n        // TODO: Do the actual Pandocs thing:\n        // \"In 8x16 mode, the lower bit of the tile number is ignored. Ie. the upper 8x8 tile is \"NN AND FEh\", and the lower 8x8 tile is \"NN OR 01h\".\"\n        // So just knock off the last bit? :)\n        if (spriteTileId % 2 === 1) {\n          spriteTileId -= 1;\n        }\n\n        tilesToDraw += 1;\n      }\n\n      // Get our sprite attributes since we know we shall be drawing the tile\n      let spriteAttributes: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex + 3);\n\n      // Check if we should flip the sprite on the x or y axis\n      let flipSpriteY: boolean = checkBitOnByte(6, spriteAttributes);\n      let flipSpriteX: boolean = checkBitOnByte(5, spriteAttributes);\n\n      // Find which VRAM Bank to load from\n      let vramBankId: i32 = 0;\n      if (Cpu.GBCEnabled && checkBitOnByte(3, spriteAttributes)) {\n        vramBankId = 1;\n      }\n\n      // Find which monochrome palette we should use\n      let paletteLocation: i32 = Graphics.memoryLocationSpritePaletteOne;\n      if (checkBitOnByte(4, spriteAttributes)) {\n        paletteLocation = Graphics.memoryLocationSpritePaletteTwo;\n      }\n\n      // Start Drawing our tiles\n      for (let i: i32 = 0; i < tilesToDraw; i++) {\n        // Draw each Y line of the tile\n        for (let tileLineY: i32 = 0; tileLineY < 8; tileLineY++) {\n          drawPixelsFromLineOfTile(\n            spriteTileId + i, // tileId\n            Graphics.memoryLocationTileDataSelectOneStart, // Graphics.memoryLocationTileDataSelect\n            vramBankId, // VRAM Bank\n            0, // Tile Line X Start\n            7, // Tile Line X End\n            tileLineY, // Tile Line Y\n            spriteRow * 8, // Output line X\n            spriteColumn * 16 + tileLineY + i * 8, // Output line Y\n            8 * 8, // Output Width\n            OAM_TILES_LOCATION, // Wasm Memory Start\n            false, // shouldRepresentMonochromeColorByColorId\n            paletteLocation, // paletteLocation\n            -1, // bgMapAttributes\n            spriteAttributes // spriteAttributes\n          );\n        }\n      }\n    }\n  }\n}\n","import { Timers } from '../timers/timers';\nimport { setBitOnByte } from '../helpers/index';\n\nexport function getDIV(): i32 {\n  return Timers.dividerRegister;\n}\n\nexport function getTIMA(): i32 {\n  return Timers.timerCounter;\n}\n\nexport function getTMA(): i32 {\n  return Timers.timerModulo;\n}\n\nexport function getTAC(): i32 {\n  let response: i32 = Timers.timerInputClock;\n\n  if (Timers.timerEnabled) {\n    response = setBitOnByte(2, response);\n  }\n\n  return response;\n}\n","// Functions to debug internal gameboy memory\n// Great for disassembelr\nimport { DEBUG_GAMEBOY_MEMORY_LOCATION, DEBUG_GAMEBOY_MEMORY_SIZE } from '../constants';\nimport { eightBitLoadFromGBMemoryWithTraps } from '../memory/index';\nimport { Breakpoints } from './breakpoints';\n\nexport function updateDebugGBMemory(): void {\n  for (let i: i32 = 0; i < DEBUG_GAMEBOY_MEMORY_SIZE; i++) {\n    store<u8>(DEBUG_GAMEBOY_MEMORY_LOCATION + i, eightBitLoadFromGBMemoryWithTraps(i));\n  }\n\n  // Since we are debugging, we don't want to be responsible for tripping the breakpoints\n  Breakpoints.reachedBreakpoint = false;\n}\n"]}