-
location.reload()}>Reload
-
history.back()}>Go Back
+
+ This could not be opened.
+ {message}
+
-
+
+
+
diff --git a/src/lib/components/SiteFooter.svelte b/src/lib/components/SiteFooter.svelte
new file mode 100644
index 0000000..b2ff60c
--- /dev/null
+++ b/src/lib/components/SiteFooter.svelte
@@ -0,0 +1,43 @@
+
+
+
diff --git a/src/lib/components/SiteHeader.svelte b/src/lib/components/SiteHeader.svelte
new file mode 100644
index 0000000..bceba4c
--- /dev/null
+++ b/src/lib/components/SiteHeader.svelte
@@ -0,0 +1,120 @@
+
+
+
Skip to content
+
+
+
diff --git a/src/lib/components/ThemeSwitch.svelte b/src/lib/components/ThemeSwitch.svelte
deleted file mode 100644
index a3ede1f..0000000
--- a/src/lib/components/ThemeSwitch.svelte
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
- Color theme switch
-
-
-
-
-
-
-
diff --git a/src/lib/computer/Screen.svelte b/src/lib/computer/Screen.svelte
new file mode 100644
index 0000000..da48b5b
--- /dev/null
+++ b/src/lib/computer/Screen.svelte
@@ -0,0 +1,58 @@
+
+
+
+
+ 512 × 256 pixels · each memory word controls 16 pixels
+
+
+
diff --git a/src/lib/computer/TestPanel.svelte b/src/lib/computer/TestPanel.svelte
new file mode 100644
index 0000000..12a6d0e
--- /dev/null
+++ b/src/lib/computer/TestPanel.svelte
@@ -0,0 +1,125 @@
+
+
+
+ Test scripts
+
+ Run Nand2Tetris TST commands against this circuit. A new run resets stored state. Each batch
+ runs at most 1,000 commands; continue a paused test when ready.
+
+
+ TST script Expected output
+
+
+ execute(false)}
+ disabled={!circuit || session?.done}
+ >{session && !session.done ? 'Continue test' : 'Run tests'} execute(true)} disabled={!circuit || session?.done}
+ >Step test Restart test
+
+ {message}
+ {#if error}{error}
{/if}{#if session}Actual test output {#if session.messages.length}
+ {#each session.messages as text, index (index)}{text} {/each}
+ {/if}{#each session.rows.filter((row) => row.pass === false) as row, index (index)}
+ {row.differences.join('; ')}
+
{/each}{/if}
+
+ ROM and test files
+ Supply files referenced by the script, such as a .hack program loaded into ROM32K.
+ Test files {#if Object.keys(files).length}{Object.keys(files).join(', ')}
+ {
+ files = {};
+ edited();
+ }}>Clear test files {/if}
+
+
diff --git a/src/lib/computer/bitmap.test.ts b/src/lib/computer/bitmap.test.ts
new file mode 100644
index 0000000..1767b30
--- /dev/null
+++ b/src/lib/computer/bitmap.test.ts
@@ -0,0 +1,32 @@
+import { describe, it, expect } from 'vitest';
+import { bitmapWords, bitmapAssembly, bitmapJack } from './bitmap.js';
+import { assemble, createMachine } from './hack.js';
+describe('Bitmap exports', () => {
+ it('maps leftmost pixel to bit zero and crosses word boundaries at unaligned positions', () => {
+ const bitmap = { width: 3, height: 2, pixels: [true, true, false, false, false, true] };
+ expect(bitmapWords(bitmap, 15, 1)).toEqual([
+ { address: 16416, value: 32768 },
+ { address: 16417, value: 1 },
+ { address: 16448, value: 0 },
+ { address: 16449, value: 2 },
+ ]);
+ });
+ it('assembles exported high-bit words into identical screen memory', () => {
+ const bitmap = {
+ width: 16,
+ height: 2,
+ pixels: Array.from({ length: 32 }, (_, i) => i === 15 || i >= 16),
+ };
+ const expected = bitmapWords(bitmap);
+ const machine = createMachine(assemble(bitmapAssembly(bitmap)).words);
+ machine.run(100);
+ for (const word of expected) expect(machine.read(word.address)).toBe(word.value);
+ expect(bitmapJack(bitmap)).toContain('Memory.poke(16384, ~32767)');
+ expect(bitmapJack(bitmap)).toContain('Memory.poke(16416, -1)');
+ });
+ it('rejects dimensions, incorrect pixel length and positions outside the screen', () => {
+ expect(() => bitmapWords({ width: 16, height: 1, pixels: [] })).toThrow();
+ expect(() => bitmapWords({ width: 1, height: 1, pixels: [true] }, 512, 0)).toThrow();
+ expect(() => bitmapWords({ width: 1, height: 1, pixels: [true] }, 0, 256)).toThrow();
+ });
+});
diff --git a/src/lib/computer/bitmap.ts b/src/lib/computer/bitmap.ts
new file mode 100644
index 0000000..b16c688
--- /dev/null
+++ b/src/lib/computer/bitmap.ts
@@ -0,0 +1,50 @@
+export type Bitmap = { width: number; height: number; pixels: boolean[] };
+export function bitmapWords(bitmap: Bitmap, x = 0, y = 0): { address: number; value: number }[] {
+ const { width, height, pixels } = bitmap;
+ if (
+ ![width, height, x, y].every(Number.isInteger) ||
+ width < 1 ||
+ height < 1 ||
+ width > 64 ||
+ height > 64 ||
+ x < 0 ||
+ y < 0 ||
+ x + width > 512 ||
+ y + height > 256 ||
+ pixels.length !== width * height
+ )
+ throw new Error('Use a 1–64 pixel bitmap positioned within the 512 × 256 screen.');
+ const words = new Map
();
+ for (let row = 0; row < height; row++)
+ for (let col = 0; col < width; col++) {
+ const address = 16384 + (y + row) * 32 + ((x + col) >>> 4);
+ words.set(
+ address,
+ (words.get(address) ?? 0) | (pixels[row * width + col] ? 1 << ((x + col) & 15) : 0),
+ );
+ }
+ return [...words].map(([address, value]) => ({ address, value }));
+}
+export function bitmapJack(bitmap: Bitmap, x = 0, y = 0): string {
+ const expression = (word: number) =>
+ word === 32768 ? '~32767' : String(word > 32767 ? word - 65536 : word);
+ return (
+ 'class Sprite {\n function void draw() {\n' +
+ bitmapWords(bitmap, x, y)
+ .map(({ address, value }) => ` do Memory.poke(${address}, ${expression(value)});`)
+ .join('\n') +
+ '\n return;\n }\n}\n'
+ );
+}
+export function bitmapAssembly(bitmap: Bitmap, x = 0, y = 0): string {
+ return (
+ '// Draws whole screen words, including blank pixels.\n' +
+ bitmapWords(bitmap, x, y)
+ .map(
+ ({ address, value }) =>
+ `@${value > 32767 ? 65535 - value : value}\nD=${value > 32767 ? '!A' : 'A'}\n@${address}\nM=D`,
+ )
+ .join('\n') +
+ '\n'
+ );
+}
diff --git a/src/lib/computer/hack.test.ts b/src/lib/computer/hack.test.ts
new file mode 100644
index 0000000..dfecd2b
--- /dev/null
+++ b/src/lib/computer/hack.test.ts
@@ -0,0 +1,306 @@
+import { readFileSync } from 'node:fs';
+import { describe, expect, it } from 'vitest';
+import {
+ assemble,
+ AssemblyError,
+ binary16,
+ signed16,
+ parseHack,
+ disassemble,
+ HACK_COMP,
+ HACK_DEST,
+ HACK_JUMP,
+ predefinedSymbols,
+ alu,
+ cpuStep,
+ createMachine,
+} from './hack';
+
+const fixture = (name: string) =>
+ readFileSync(new URL(`./testing/fixtures/hack/${name}.asm`, import.meta.url), 'utf8');
+
+describe('Hack assembler', () => {
+ it('matches the official Add binary and retains one-based source locations', () => {
+ const result = assemble(fixture('Add'));
+ expect(result.words).toEqual([2, 0xec10, 3, 0xe090, 0, 0xe308]);
+ expect(parseHack(result.binary)).toEqual(result.words);
+ expect(result.instructions.map((item) => item.address)).toEqual([0, 1, 2, 3, 4, 5]);
+ expect(result.instructions[0]).toMatchObject({ source: '@2', type: 'A', word: 2 });
+ expect(result.sourceMap).toEqual([8, 9, 10, 11, 12, 13]);
+ });
+ it.each(['Max', 'Rect', 'Pong'])(
+ 'translates official %s identically with and without symbols',
+ (name) => {
+ expect(assemble(fixture(name)).words).toEqual(assemble(fixture(`${name}L`)).words);
+ },
+ );
+ it('resolves forward labels before allocating variables, with case-sensitive symbols', () => {
+ const result = assemble(
+ '// header\n @end // future ROM label\n@value\n@Value\n(value.label)\nD = A + 1 ; JGT\n(end)\n@value\n@SCREEN\n@KBD\n@R15',
+ );
+ expect(result.symbols.end).toBe(4);
+ expect(result.symbols['value.label']).toBe(3);
+ expect(result.symbols.value).toBe(16);
+ expect(result.symbols.Value).toBe(17);
+ expect(result.words).toEqual([4, 16, 17, 0xedd1, 16, 16384, 24576, 15]);
+ expect(result.sourceMap).toEqual([2, 3, 4, 6, 8, 9, 10, 11]);
+ expect(predefinedSymbols()).toMatchObject({
+ SP: 0,
+ LCL: 1,
+ ARG: 2,
+ THIS: 3,
+ THAT: 4,
+ R0: 0,
+ R15: 15,
+ });
+ expect(assemble('@__proto__\n@constructor').words).toEqual([16, 17]);
+ });
+ it('encodes every documented computation, destination and jump combination', () => {
+ for (const [comp, c] of Object.entries(HACK_COMP)) {
+ for (const [dest, d] of Object.entries(HACK_DEST)) {
+ for (const [jump, j] of Object.entries(HACK_JUMP)) {
+ const source = `${dest ? `${dest}=` : ''}${comp}${jump ? `;${jump}` : ''}`;
+ const [word] = assemble(source).words;
+ expect(word).toBe(0xe000 | (c << 6) | (d << 3) | j);
+ expect(disassemble(word)).toBe(source);
+ }
+ }
+ }
+ expect(disassemble(32767)).toBe('@32767');
+ expect(disassemble(0x8000)).toBe(binary16(0x8000));
+ expect(disassemble(0xffff)).toBe(binary16(0xffff));
+ });
+ it.each([
+ '@',
+ '@-1',
+ '@32768',
+ '@999999999999999999',
+ '@2.5',
+ '@0x10',
+ '@1a',
+ '(bad-label)',
+ '(foo',
+ '(a)(b)',
+ 'D=',
+ '=D',
+ 'D;;JGT',
+ 'DD=M',
+ 'D=A+D',
+ 'D;NOPE',
+ 'D=__proto__',
+ 'constructor=D',
+ ])('rejects malformed assembly %s with its original line', (source) => {
+ expect(() => assemble(`// first\n\n${source}`)).toThrow(AssemblyError);
+ expect(() => assemble(`// first\n\n${source}`)).toThrow('Line 3:');
+ });
+ it('rejects conflicting symbols and exhausted address spaces', () => {
+ expect(() => assemble('(SP)')).toThrow('already defined');
+ expect(() => assemble('(loop)\n(loop)')).toThrow('already defined');
+ expect(assemble('@0\n'.repeat(32768)).words).toHaveLength(32768);
+ expect(() => assemble('@0\n'.repeat(32769))).toThrow('at most 32768');
+ expect(() => assemble('@0\n'.repeat(32768) + '(END)')).toThrow('15-bit ROM');
+ expect(() =>
+ assemble(Array.from({ length: 16369 }, (_, i) => `@variable${i}`).join('\n')),
+ ).toThrow('overlap screen');
+ expect(assemble(' // nothing\n').binary).toBe('');
+ });
+ it('validates binary files strictly', () => {
+ expect(parseHack(' \r\n0000000000000001\r\n1111111111111111')).toEqual([1, 65535]);
+ for (const code of ['0', '0000000000000002', '00000000000000001', '// comment'])
+ expect(() => parseHack(code)).toThrow(AssemblyError);
+ expect(() => parseHack('0000000000000000\n'.repeat(32769))).toThrow('at most 32768');
+ expect(binary16(-1)).toBe('1111111111111111');
+ expect(signed16(65535)).toBe(-1);
+ });
+});
+
+describe('Hack ALU and CPU', () => {
+ it('implements all 64 control combinations with two’s-complement flags', () => {
+ for (const x of [0, 1, 32767, 32768, 65535, 0xaaaa]) {
+ for (const y of [0, 1, 32767, 32768, 65535, 0x5555]) {
+ for (let control = 0; control < 64; control++) {
+ const [zx, nx, zy, ny, f, no] = control
+ .toString(2)
+ .padStart(6, '0')
+ .split('')
+ .map(Number);
+ let left = zx ? 0 : signed16(x),
+ right = zy ? 0 : signed16(y);
+ if (nx) left = ~left;
+ if (ny) right = ~right;
+ let output = f ? left + right : left & right;
+ if (no) output = ~output;
+ output &= 65535;
+ expect(alu(x, y, control)).toEqual({
+ out: output,
+ zr: Number(output === 0),
+ ng: Number(output >= 32768),
+ });
+ }
+ }
+ }
+ });
+ it('evaluates every documented computation independently', () => {
+ const expected: Record number> = {
+ '0': () => 0,
+ '1': () => 1,
+ '-1': () => -1,
+ D: (d) => d,
+ A: (_, a) => a,
+ '!D': (d) => ~d,
+ '!A': (_, a) => ~a,
+ '-D': (d) => -d,
+ '-A': (_, a) => -a,
+ 'D+1': (d) => d + 1,
+ 'A+1': (_, a) => a + 1,
+ 'D-1': (d) => d - 1,
+ 'A-1': (_, a) => a - 1,
+ 'D+A': (d, a) => d + a,
+ 'D-A': (d, a) => d - a,
+ 'A-D': (d, a) => a - d,
+ 'D&A': (d, a) => d & a,
+ 'D|A': (d, a) => d | a,
+ };
+ for (const [comp, code] of Object.entries(HACK_COMP)) {
+ for (const d of [0, 1, 32767, 32768, 65535]) {
+ const state = { a: 17, d, pc: 9 },
+ memory = 301;
+ const result = cpuStep(state, 0xe010 | (code << 6), memory);
+ expect(result.d).toBe(
+ expected[comp.replaceAll('M', 'A')](d, comp.includes('M') ? memory : state.a) & 65535,
+ );
+ }
+ }
+ });
+ it('uses the old A register for simultaneous memory writes and jumps', () => {
+ const instruction = assemble('AMD=D+1;JMP').words[0];
+ expect(cpuStep({ a: 123, d: 7, pc: 2 }, instruction, 99)).toEqual({
+ a: 8,
+ d: 8,
+ pc: 123,
+ addressM: 123,
+ outM: 8,
+ writeM: true,
+ jumped: true,
+ });
+ expect(
+ cpuStep({ a: 0xffff, d: 0xffff, pc: 32767 }, assemble('MD=D+1').words[0], 0),
+ ).toMatchObject({ a: 65535, d: 0, pc: 0, addressM: 32767, outM: 0 });
+ expect(cpuStep({ a: 123, d: 7, pc: 2 }, instruction, 99, true)).toMatchObject({
+ a: 8,
+ d: 8,
+ pc: 0,
+ writeM: true,
+ jumped: false,
+ });
+ });
+ it('implements all jumps for negative, zero and positive ALU results', () => {
+ const predicates = [
+ () => false,
+ (n: number) => n > 0,
+ (n: number) => n === 0,
+ (n: number) => n >= 0,
+ (n: number) => n < 0,
+ (n: number) => n !== 0,
+ (n: number) => n <= 0,
+ () => true,
+ ];
+ for (let jump = 0; jump < 8; jump++)
+ for (const d of [0, 1, 32767, 32768, 65535]) {
+ const result = cpuStep({ a: 21, d, pc: 4 }, 0xe300 | jump, 0);
+ const shouldJump = predicates[jump](signed16(d));
+ expect(result.pc).toBe(shouldJump ? 21 : 5);
+ expect(result.jumped).toBe(shouldJump);
+ }
+ expect(cpuStep({ a: 123, d: 9, pc: 4 }, 32767, 0)).toMatchObject({
+ a: 32767,
+ d: 9,
+ pc: 5,
+ writeM: false,
+ jumped: false,
+ });
+ });
+});
+
+describe('Hack computer execution', () => {
+ it('runs official Add and stops at the loaded extent without inventing a HALT opcode', () => {
+ const machine = createMachine(assemble(fixture('Add')).words);
+ const trace = machine.run(20)!;
+ expect(machine.ram[0]).toBe(5);
+ expect(machine.cycles).toBe(6);
+ expect(machine.halted).toBe(true);
+ expect(trace).toMatchObject({
+ cycle: 6,
+ before: { a: 0 },
+ after: { pc: 6 },
+ addressM: 0,
+ outM: 5,
+ writeM: true,
+ });
+ expect(machine.step()).toBeNull();
+ expect(machine.step(true)).toBeNull();
+ expect(machine.pc).toBe(0);
+ });
+ it('runs official Max for both branches and equality', () => {
+ const machine = createMachine(assemble(fixture('Max')).words);
+ for (const [a, b] of [
+ [1, 2],
+ [7, 3],
+ [9, 9],
+ ]) {
+ machine.reset();
+ machine.ram[0] = a;
+ machine.ram[1] = b;
+ machine.run(100);
+ expect(machine.ram[2]).toBe(Math.max(a, b));
+ }
+ });
+ it('runs official Rect against the memory-mapped screen, including its zero-height branch', () => {
+ const machine = createMachine(assemble(fixture('Rect')).words);
+ machine.ram[0] = 3;
+ machine.run(200);
+ expect(Array.from(machine.screen).filter(Boolean)).toHaveLength(3);
+ expect(machine.screen[0]).toBe(65535);
+ expect(machine.screen[32]).toBe(65535);
+ expect(machine.screen[64]).toBe(65535);
+ expect(machine.screen[1]).toBe(0);
+ machine.reset();
+ machine.run(100);
+ expect(machine.screen.every((word) => word === 0)).toBe(true);
+ });
+ it('keeps memory writes on old A while loading A and observes keyboard as read-only', () => {
+ const machine = createMachine(assemble('@123\nD=A\n@7\nAM=D\n@KBD\nD=M\nM=0').words);
+ machine.setKeyboard(130);
+ machine.run(7);
+ expect(machine.ram[7]).toBe(123);
+ expect(machine.ram[123]).toBe(0);
+ expect(machine.d).toBe(130);
+ expect(machine.read(24576)).toBe(130);
+ machine.write(16384, -1);
+ expect(machine.read(16384)).toBe(65535);
+ machine.write(24575, 17);
+ expect(machine.read(24575)).toBe(17);
+ machine.write(24577, 10);
+ expect(machine.read(24577)).toBe(0);
+ machine.reset(false);
+ expect(machine.screen[0]).toBe(65535);
+ expect(machine.keyboard).toBe(130);
+ machine.reset();
+ expect(machine.screen[0]).toBe(0);
+ expect(machine.keyboard).toBe(0);
+ expect(machine.ram[7]).toBe(0);
+ machine.d = 17;
+ machine.step(true);
+ expect(machine.pc).toBe(0);
+ expect(machine.d).toBe(17);
+ });
+ it('rejects invalid ROM, keyboard and run inputs without unbounded execution', () => {
+ for (const words of [[-1], [65536], [0.5], [NaN], new Array(32769).fill(0)])
+ expect(() => createMachine(words)).toThrow('ROM accepts');
+ const machine = createMachine([0]);
+ for (const n of [-1, 32768, NaN, 1.2])
+ expect(() => machine.setKeyboard(n)).toThrow('Keyboard code');
+ for (const n of [-1, 1000001, NaN, 1.2]) expect(() => machine.run(n)).toThrow('Run between');
+ expect(machine.run(0)).toBeNull();
+ });
+});
diff --git a/src/lib/computer/hack.ts b/src/lib/computer/hack.ts
new file mode 100644
index 0000000..40066c8
--- /dev/null
+++ b/src/lib/computer/hack.ts
@@ -0,0 +1,359 @@
+/** Hack architecture, Chapters 4–6 of Nand2Tetris. Independent browser implementation.
+ * Words are unsigned internally; signed comparisons interpret two's-complement values.
+ */
+export const HACK_COMP: Readonly> = Object.freeze({
+ '0': 0b0101010,
+ '1': 0b0111111,
+ '-1': 0b0111010,
+ D: 0b0001100,
+ A: 0b0110000,
+ '!D': 0b0001101,
+ '!A': 0b0110001,
+ '-D': 0b0001111,
+ '-A': 0b0110011,
+ 'D+1': 0b0011111,
+ 'A+1': 0b0110111,
+ 'D-1': 0b0001110,
+ 'A-1': 0b0110010,
+ 'D+A': 0b0000010,
+ 'D-A': 0b0010011,
+ 'A-D': 0b0000111,
+ 'D&A': 0b0000000,
+ 'D|A': 0b0010101,
+ M: 0b1110000,
+ '!M': 0b1110001,
+ '-M': 0b1110011,
+ 'M+1': 0b1110111,
+ 'M-1': 0b1110010,
+ 'D+M': 0b1000010,
+ 'D-M': 0b1010011,
+ 'M-D': 0b1000111,
+ 'D&M': 0b1000000,
+ 'D|M': 0b1010101,
+});
+export const HACK_DEST: Readonly> = Object.freeze({
+ '': 0,
+ M: 1,
+ D: 2,
+ MD: 3,
+ A: 4,
+ AM: 5,
+ AD: 6,
+ AMD: 7,
+});
+export const HACK_JUMP: Readonly> = Object.freeze({
+ '': 0,
+ JGT: 1,
+ JEQ: 2,
+ JGE: 3,
+ JLT: 4,
+ JNE: 5,
+ JLE: 6,
+ JMP: 7,
+});
+
+export class AssemblyError extends Error {
+ constructor(
+ message: string,
+ public readonly line: number,
+ ) {
+ super(`Line ${line}: ${message}`);
+ this.name = 'AssemblyError';
+ }
+}
+export interface AssemblyInstruction {
+ address: number;
+ line: number;
+ source: string;
+ type: 'A' | 'C';
+ word: number;
+}
+export interface AssemblyResult {
+ words: number[];
+ binary: string;
+ symbols: Record;
+ /** One-based source line for each ROM address. */
+ sourceMap: number[];
+ instructions: AssemblyInstruction[];
+}
+const symbolPattern = /^[A-Za-z_.$:][A-Za-z0-9_.$:]*$/;
+const has = (record: Readonly>, key: string) =>
+ Object.prototype.hasOwnProperty.call(record, key);
+
+export function binary16(value: number): string {
+ return (value & 0xffff).toString(2).padStart(16, '0');
+}
+export function signed16(value: number): number {
+ return (value << 16) >> 16;
+}
+export function predefinedSymbols(): Record {
+ const symbols: Record = Object.assign(Object.create(null), {
+ SP: 0,
+ LCL: 1,
+ ARG: 2,
+ THIS: 3,
+ THAT: 4,
+ SCREEN: 16384,
+ KBD: 24576,
+ });
+ for (let i = 0; i < 16; i++) symbols[`R${i}`] = i;
+ return symbols;
+}
+
+/** Two passes: collect ROM labels, then allocate variables and encode instructions. */
+export function assemble(source: string): AssemblyResult {
+ const symbols = predefinedSymbols();
+ const commands: { source: string; line: number }[] = [];
+ source.split(/\r?\n/).forEach((raw, index) => {
+ const line = index + 1;
+ const text = raw.replace(/\/\/.*$/, '').replace(/\s/g, '');
+ if (!text) return;
+ if (text.startsWith('(')) {
+ const match = /^\(([^()]+)\)$/.exec(text);
+ if (!match || !symbolPattern.test(match[1]))
+ throw new AssemblyError('Use a valid label inside parentheses.', line);
+ const name = match[1];
+ if (has(symbols, name)) throw new AssemblyError(`Symbol ${name} is already defined.`, line);
+ if (commands.length >= 32768)
+ throw new AssemblyError('Label exceeds the 15-bit ROM address space.', line);
+ symbols[name] = commands.length;
+ } else {
+ if (commands.length >= 32768)
+ throw new AssemblyError('A program can contain at most 32768 instructions.', line);
+ commands.push({ source: text, line });
+ }
+ });
+ let nextVariable = 16;
+ const instructions: AssemblyInstruction[] = commands.map(({ source: text, line }, address) => {
+ if (text.startsWith('@')) {
+ const operand = text.slice(1);
+ let value: number;
+ if (/^\d+$/.test(operand)) {
+ value = Number(operand);
+ if (!Number.isSafeInteger(value) || value > 32767)
+ throw new AssemblyError('An A-instruction needs an address from 0 to 32767.', line);
+ } else {
+ if (!symbolPattern.test(operand))
+ throw new AssemblyError('Expected a decimal address or a valid symbol after @.', line);
+ if (!has(symbols, operand)) {
+ if (nextVariable >= 16384)
+ throw new AssemblyError('Variable allocation would overlap screen memory.', line);
+ symbols[operand] = nextVariable++;
+ }
+ value = symbols[operand];
+ }
+ return { address, line, source: text, type: 'A', word: value };
+ }
+ const match = /^(?:([^=;]+)=)?([^=;]+)(?:;([^=;]+))?$/.exec(text);
+ if (!match)
+ throw new AssemblyError('Expected dest=comp;jump, with destination and jump optional.', line);
+ const [, destination = '', computation, jump = ''] = match;
+ if (!/^[ADM]*$/.test(destination) || new Set(destination).size !== destination.length)
+ throw new AssemblyError(
+ `Unknown destination ${destination}. Use A, D, M, or a combination without repeats.`,
+ line,
+ );
+ if (!has(HACK_COMP, computation))
+ throw new AssemblyError(`Unknown computation ${computation}.`, line);
+ if (!has(HACK_JUMP, jump)) throw new AssemblyError(`Unknown jump ${jump}.`, line);
+ // The official symbol-free fixtures also use DM; destinations are a set of registers.
+ const destinationBits =
+ (destination.includes('A') ? 4 : 0) |
+ (destination.includes('D') ? 2 : 0) |
+ (destination.includes('M') ? 1 : 0);
+ const word = 0xe000 | (HACK_COMP[computation] << 6) | (destinationBits << 3) | HACK_JUMP[jump];
+ return { address, line, source: text, type: 'C', word };
+ });
+ const words = instructions.map((item) => item.word);
+ return {
+ words,
+ binary: words.map(binary16).join('\n'),
+ symbols,
+ sourceMap: instructions.map((item) => item.line),
+ instructions,
+ };
+}
+
+/** Parse a .hack file; blank lines are ignored, every other line must have 16 bits. */
+export function parseHack(source: string): number[] {
+ const words: number[] = [];
+ source.split(/\r?\n/).forEach((raw, index) => {
+ const value = raw.trim();
+ if (!value) return;
+ if (!/^[01]{16}$/.test(value))
+ throw new AssemblyError(
+ 'A machine-code line must contain exactly 16 binary digits.',
+ index + 1,
+ );
+ if (words.length >= 32768)
+ throw new AssemblyError('A program can contain at most 32768 instructions.', index + 1);
+ words.push(parseInt(value, 2));
+ });
+ return words;
+}
+
+export function disassemble(word: number): string {
+ if (!(word & 0x8000)) return `@${word & 0x7fff}`;
+ const computation = Object.keys(HACK_COMP).find((key) => HACK_COMP[key] === ((word >> 6) & 127));
+ if (!computation || (word & 0xe000) !== 0xe000) return binary16(word);
+ const destination = Object.keys(HACK_DEST).find((key) => HACK_DEST[key] === ((word >> 3) & 7))!;
+ const jump = Object.keys(HACK_JUMP).find((key) => HACK_JUMP[key] === (word & 7))!;
+ return `${destination ? `${destination}=` : ''}${computation}${jump ? `;${jump}` : ''}`;
+}
+
+export interface ALUResult {
+ out: number;
+ zr: number;
+ ng: number;
+}
+/** control bits, from high to low: zx nx zy ny f no. */
+export function alu(x: number, y: number, control: number): ALUResult {
+ x &= 0xffff;
+ y &= 0xffff;
+ if (control & 32) x = 0;
+ if (control & 16) x = ~x & 0xffff;
+ if (control & 8) y = 0;
+ if (control & 4) y = ~y & 0xffff;
+ let out = (control & 2 ? x + y : x & y) & 0xffff;
+ if (control & 1) out = ~out & 0xffff;
+ return { out, zr: Number(out === 0), ng: (out >>> 15) & 1 };
+}
+export interface CPUState {
+ a: number;
+ d: number;
+ pc: number;
+}
+export interface CPUResult extends CPUState {
+ outM: number;
+ writeM: boolean;
+ addressM: number;
+ jumped: boolean;
+}
+
+/** One clock cycle, including simultaneous destinations and PC update. */
+export function cpuStep(
+ state: CPUState,
+ instruction: number,
+ inM: number,
+ reset = false,
+): CPUResult {
+ const oldA = state.a & 0xffff;
+ const addressM = oldA & 0x7fff;
+ const isCompute = !!(instruction & 0x8000);
+ // The combinational ALU output remains defined on A-instructions, but writeM is false.
+ const result = alu(state.d, instruction & 0x1000 ? inM : oldA, (instruction >> 6) & 63);
+ const signed = signed16(result.out);
+ const jump = instruction & 7;
+ const jumped =
+ isCompute &&
+ !!((jump & 4 && signed < 0) || (jump & 2 && signed === 0) || (jump & 1 && signed > 0));
+ return {
+ a: isCompute ? (instruction & 32 ? result.out : oldA) : instruction & 0x7fff,
+ d: isCompute && instruction & 16 ? result.out : state.d & 0xffff,
+ pc: reset ? 0 : jumped ? addressM : (state.pc + 1) & 0x7fff,
+ outM: result.out,
+ writeM: isCompute && !!(instruction & 8),
+ addressM,
+ jumped: !reset && jumped,
+ };
+}
+export interface StepTrace {
+ cycle: number;
+ before: CPUState;
+ after: CPUState;
+ instruction: number;
+ addressM: number;
+ inM: number;
+ outM: number;
+ writeM: boolean;
+ jumped: boolean;
+}
+
+export class HackMachine {
+ a = 0;
+ d = 0;
+ pc = 0;
+ cycles = 0;
+ keyboard = 0;
+ readonly ram = new Uint16Array(16384);
+ readonly screen = new Uint16Array(8192);
+ readonly rom: Uint16Array;
+ readonly programLength: number;
+ constructor(words: readonly number[]) {
+ if (
+ words.length > 32768 ||
+ words.some((word) => !Number.isInteger(word) || word < 0 || word > 65535)
+ )
+ throw new Error('ROM accepts at most 32768 unsigned 16-bit words.');
+ this.rom = new Uint16Array(32768);
+ this.rom.set(words);
+ this.programLength = words.length;
+ }
+ /** Simulator convenience: stop at the end of the loaded program; Hack has no HALT instruction. */
+ get halted(): boolean {
+ return this.pc >= this.programLength;
+ }
+ read(address: number): number {
+ address &= 0x7fff;
+ if (address < 16384) return this.ram[address];
+ if (address < 24576) return this.screen[address - 16384];
+ if (address === 24576) return this.keyboard & 0xffff;
+ return 0; // Addresses above KBD are outside the specified address space.
+ }
+ write(address: number, value: number): void {
+ address &= 0x7fff;
+ if (address < 16384) this.ram[address] = value & 0xffff;
+ else if (address < 24576) this.screen[address - 16384] = value & 0xffff;
+ // Keyboard is read-only; writes outside RAM/screen do nothing.
+ }
+ setKeyboard(value: number): void {
+ if (!Number.isInteger(value) || value < 0 || value > 32767)
+ throw new Error('Keyboard code must be an integer from 0 to 32767.');
+ this.keyboard = value;
+ }
+ step(reset = false): StepTrace | null {
+ if (this.halted) {
+ if (reset) this.pc = 0;
+ return null;
+ }
+ const before = { a: this.a, d: this.d, pc: this.pc };
+ const instruction = this.rom[this.pc];
+ const inM = this.read(this.a);
+ const result = cpuStep(before, instruction, inM, reset);
+ if (result.writeM) this.write(result.addressM, result.outM);
+ this.a = result.a;
+ this.d = result.d;
+ this.pc = result.pc;
+ this.cycles++;
+ return {
+ cycle: this.cycles,
+ before,
+ after: { a: this.a, d: this.d, pc: this.pc },
+ instruction,
+ inM,
+ addressM: result.addressM,
+ outM: result.outM,
+ writeM: result.writeM,
+ jumped: result.jumped,
+ };
+ }
+ run(limit: number): StepTrace | null {
+ if (!Number.isInteger(limit) || limit < 0 || limit > 1_000_000)
+ throw new Error('Run between 0 and 1000000 cycles at a time.');
+ let last: StepTrace | null = null;
+ for (let i = 0; i < limit && !this.halted; i++) last = this.step();
+ return last;
+ }
+ reset(clearMemory = true): void {
+ this.a = 0;
+ this.d = 0;
+ this.pc = 0;
+ this.cycles = 0;
+ if (clearMemory) {
+ this.ram.fill(0);
+ this.screen.fill(0);
+ this.keyboard = 0;
+ }
+ }
+}
+export const createMachine = (words: readonly number[]) => new HackMachine(words);
diff --git a/src/lib/computer/hdl.test.ts b/src/lib/computer/hdl.test.ts
new file mode 100644
index 0000000..cebe7ad
--- /dev/null
+++ b/src/lib/computer/hdl.test.ts
@@ -0,0 +1,251 @@
+import { describe, expect, it } from 'vitest';
+import { readFileSync, readdirSync } from 'node:fs';
+import { compileHDL, builtinContracts, HDLError } from './hdl.js';
+const fixtureRoot = new URL('./testing/official/', import.meta.url);
+function wrapper(name: string) {
+ const spec = builtinContracts[name];
+ const pins = (values: Record) =>
+ Object.entries(values)
+ .map(([pin, width]) => `${pin}${width > 1 ? `[${width}]` : ''}`)
+ .join(', ');
+ return `CHIP Probe { ${Object.keys(spec.inputs).length ? `IN ${pins(spec.inputs)};` : ''} ${Object.keys(spec.outputs).length ? `OUT ${pins(spec.outputs)};` : ''} PARTS: ${name}(${[...Object.keys(spec.inputs), ...Object.keys(spec.outputs)].map((pin) => `${pin}=${pin}`).join(',')}); }`;
+}
+const read = (name: string) => readFileSync(new URL(name, fixtureRoot), 'utf8');
+/** Only the explicitly supported official TDL commands are accepted. */
+function runOfficial(name: string) {
+ const chip = name === 'CPU-external' ? 'CPU' : name === 'ALU-nostat' ? 'ALU' : name;
+ const circuit = compileHDL(wrapper(chip));
+ const script = read(name + '.tst').replace(/\/\/[^\n]*/g, '');
+ const expected = read(name + '.cmp')
+ .trim()
+ .split(/\r?\n/)
+ .map((row) =>
+ row
+ .split('|')
+ .slice(1, -1)
+ .map((cell) => cell.trim()),
+ );
+ const header = expected.shift()!;
+ let row = 0;
+ const formats: Record = {};
+ for (const raw of script.split(/[,;]/)) {
+ const command = raw.trim();
+ if (!command) continue;
+ if (/^(load|output-file|compare-to)\s/.test(command)) continue;
+ if (command.startsWith('output-list ')) {
+ for (const [, pin, type] of command.matchAll(/([\w]+)%([BDS])/g)) formats[pin] = type;
+ continue;
+ }
+ const setting = command.match(/^set\s+(\w+)\s+(-?\d+|%B[01]+)$/);
+ if (setting) {
+ circuit.evaluate({
+ [setting[1]]: setting[2].startsWith('%B')
+ ? parseInt(setting[2].slice(2), 2)
+ : Number(setting[2]),
+ });
+ continue;
+ }
+ if (command === 'eval') {
+ circuit.evaluate();
+ continue;
+ }
+ if (command === 'tick') {
+ circuit.tick();
+ continue;
+ }
+ if (command === 'tock') {
+ circuit.tock();
+ continue;
+ }
+ if (command === 'output') {
+ const values = { ...circuit.inputs, ...circuit.outputs };
+ const cells = expected[row++];
+ expect(cells, `${name} output row ${row}`).toBeDefined();
+ Object.keys(formats).forEach((pin, i) => {
+ if (pin === 'time' || cells[i].includes('*')) return;
+ const expectedNumber = formats[pin] === 'B' ? parseInt(cells[i], 2) : Number(cells[i]);
+ expect(values[pin], `${name} row ${row} pin ${pin}`).toBe(
+ expectedNumber & (2 ** (circuit.inputWidths[pin] ?? circuit.outputWidths[pin]) - 1),
+ );
+ });
+ continue;
+ }
+ throw new Error(`Unsupported official TDL command: ${command}`);
+ }
+ expect(Object.keys(formats)).toHaveLength(header.length);
+ expect(row).toBe(expected.length);
+}
+describe('Official Nand2Tetris hardware contracts', () => {
+ for (const name of readdirSync(fixtureRoot)
+ .filter(
+ (name) =>
+ name.endsWith('.tst') &&
+ !name.startsWith('Computer') &&
+ name !== 'Memory.tst' &&
+ name !== 'CPU.tst',
+ )
+ .map((name) => name.slice(0, -4)))
+ it(name, () => runOfficial(name));
+});
+describe('Structural HDL wiring and state', () => {
+ it('supports bus splitting, concatenation, fanout and constants', () => {
+ const chip = compileHDL(
+ 'CHIP Probe { IN x[16]; OUT a[8], b[8], copy[16]; PARTS: And16(a=x,b=true,out[0..7]=a,out[8..15]=b,out=copy); }',
+ );
+ expect(chip.evaluate({ x: 0xabcd })).toEqual({ a: 0xcd, b: 0xab, copy: 0xabcd });
+ expect(chip.evaluate({ x: -1 })).toEqual({ a: 255, b: 255, copy: 65535 });
+ const slices = compileHDL(
+ 'CHIP Probe { IN x[8], y[8]; OUT out[16]; PARTS: Or16(a[0..7]=x,a[8..15]=y,b=false,out=out); }',
+ );
+ expect(slices.evaluate({ x: 52, y: 18 }).out).toBe(0x1234);
+ });
+ it('resolves parts independently of declaration order and supports custom dependencies', () => {
+ const chip = compileHDL(
+ 'CHIP Probe { IN in; OUT out; PARTS: DelayFree(in=w,out=out); Not(in=in,out=w); }',
+ { DelayFree: 'CHIP DelayFree { IN in; OUT out; PARTS: Not(in=in,out=out); }' },
+ );
+ expect(chip.evaluate({ in: 1 }).out).toBe(1);
+ expect(chip.evaluate({ in: 0 }).out).toBe(0);
+ });
+ it('infers internal buses from slices and rejects no legal fanout', () => {
+ const chip = compileHDL(
+ 'CHIP Probe { IN a[8],b[8]; OUT out[16]; PARTS: Or16(a=false,b[0..7]=a,b[8..15]=b,out[0..7]=wire[0..7],out[8..15]=wire[8..15]); And16(a=wire,b=wire,out=out); }',
+ );
+ expect(chip.evaluate({ a: 255, b: 64 }).out).toBe(16639);
+ });
+ it('captures all flip flops simultaneously, permits feedback, and separates tick from tock', () => {
+ const chip = compileHDL(
+ 'CHIP Probe { IN in; OUT first,second; PARTS: DFF(in=in,out=first); DFF(in=first,out=second); }',
+ );
+ expect(chip.tick({ in: 1 })).toEqual({ first: 0, second: 0 });
+ chip.evaluate({ in: 0 });
+ expect(chip.tock()).toEqual({ first: 1, second: 0 });
+ expect(chip.cycle()).toEqual({ first: 0, second: 1 });
+ expect(chip.reset()).toEqual({ first: 0, second: 0 });
+ const feedback = compileHDL(
+ 'CHIP Probe { OUT out; PARTS: Not(in=out,out=next); DFF(in=next,out=out); }',
+ );
+ expect(feedback.cycle().out).toBe(1);
+ expect(feedback.cycle().out).toBe(0);
+ });
+ it('handles GUI register aliases and built-in keyboard/ROM', () => {
+ for (const name of ['ARegister', 'DRegister']) {
+ const c = compileHDL(wrapper(name));
+ expect(c.cycle({ in: 123, load: 1 }).out).toBe(123);
+ expect(c.cycle({ in: 456, load: 0 }).out).toBe(123);
+ }
+ const keyboard = compileHDL(wrapper('Keyboard'));
+ keyboard.setKeyboard(65);
+ expect(keyboard.outputs.out).toBe(65);
+ const rom = compileHDL(wrapper('ROM32K'));
+ rom.loadROM([123, 456]);
+ expect(rom.evaluate({ address: 1 }).out).toBe(456);
+ rom.loadROM([7]);
+ expect(rom.outputs.out).toBe(0);
+ });
+ it('maps RAM, screen and keyboard with read-before-write and ROM-backed computer execution', () => {
+ const memory = compileHDL(wrapper('Memory'));
+ memory.setKeyboard(65);
+ for (const address of [0, 16383, 16384, 24575]) {
+ expect(memory.tick({ address, in: 0xcafe, load: 1 }).out).toBe(0);
+ expect(memory.tock().out).toBe(0xcafe);
+ expect(memory.readMemory(address)).toBe(0xcafe);
+ }
+ expect(memory.cycle({ address: 24576, in: 0, load: 1 }).out).toBe(65);
+ expect(memory.readMemory(24576)).toBe(65);
+ expect(memory.readMemory(32767)).toBe(0);
+ expect(memory.evaluate({ address: 32767 }).out).toBe(0);
+ memory.reset();
+ expect(memory.readMemory(0)).toBe(0);
+ const screen = compileHDL(wrapper('Screen'));
+ screen.cycle({ in: 1, load: 1, address: 8191 });
+ expect(screen.readMemory(24575)).toBe(1);
+ const computer = compileHDL(wrapper('Computer'));
+ computer.loadROM([7, 0xec10, 0, 0xe308]);
+ for (let i = 0; i < 4; i++) computer.cycle();
+ expect(computer.readMemory(0)).toBe(7);
+ computer.reset();
+ expect(computer.readMemory(0)).toBe(0);
+ });
+ it('inspects a structurally composed Memory through the real dependency', () => {
+ const c = compileHDL(
+ 'CHIP Probe { IN reset; PARTS: Memory(in=1,load=reset,address=false,out=unused); }'.replace(
+ 'in=1',
+ 'in=true',
+ ),
+ {
+ Memory:
+ 'CHIP Memory { IN in[16],load,address[15]; OUT out[16]; PARTS: RAM16K(in=in,load=load,address=address[0..13],out=out); }',
+ },
+ );
+ c.cycle({ reset: 1 });
+ expect(c.readMemory(0)).toBe(65535);
+ });
+ it('evaluates custom CPU-memory feedback without false combinational loops', () => {
+ const c = compileHDL(
+ 'CHIP Probe { IN reset; PARTS: ROM32K(address=pc,out=instruction); CPU(inM=data,instruction=instruction,reset=reset,outM=out,writeM=write,addressM=address,pc=pc); Memory(in=out,load=write,address=address,out=data); }',
+ );
+ c.loadROM([10, 0xec10, 1, 0xe308]);
+ for (let i = 0; i < 4; i++) c.cycle();
+ expect(c.readMemory(1)).toBe(10);
+ });
+});
+describe('HDL diagnostics', () => {
+ const errors: [string, string][] = [
+ ['', 'Expected CHIP'],
+ ['CHIP 7 {}', 'Expected a name'],
+ ['CHIP P { IN a[x]; PARTS: }', 'bus width'],
+ ['CHIP P { IN a,a; PARTS: }', 'Duplicate'],
+ ['CHIP P { IN true; PARTS: }', 'reserved'],
+ ['CHIP P { IN a[0]; PARTS: }', 'widths'],
+ ['CHIP P { IN a[17]; PARTS: }', 'widths'],
+ ['CHIP P { PARTS: }', 'at least one'],
+ ['CHIP P { PARTS: Keyboard(); } extra', 'Unexpected'],
+ ['CHIP P { IN a; OUT out; PARTS: Missing(in=a,out=out); }', 'Unknown chip'],
+ ['CHIP P { IN a; OUT out; PARTS: Not(wrong=a,out=out); }', 'has no pin'],
+ ['CHIP P { IN a; OUT out; PARTS: Not(in[1]=a,out=out); }', 'exceeds'],
+ ['CHIP P { IN a; OUT out; PARTS: Not(in=true[0],out=out); }', 'Constants'],
+ ['CHIP P { IN a; OUT out; PARTS: Not(in=a,out=false); }', 'constant'],
+ ['CHIP P { IN a[16]; OUT out; PARTS: Not(in=a,out=out); }', 'Width mismatch'],
+ ['CHIP P { IN a[16]; OUT out; PARTS: Not(in=a[0..1],out=out); }', 'Slice width'],
+ ['CHIP P { IN a; OUT out; PARTS: Not(in=a[1],out=out); }', 'Slice exceeds'],
+ ['CHIP P { IN a; OUT out; PARTS: Not(in=a[1..0],out=out); }', 'ascending'],
+ ['CHIP P { IN a; OUT out; PARTS: Not(in=a[16],out=out); }', 'ascending'],
+ ['CHIP P { IN a; OUT out; PARTS: Not(in=a,in=a,out=out); }', 'connected twice'],
+ ['CHIP P { IN a; OUT out; PARTS: Not(in=a,out=out); Not(in=a,out=out); }', 'multiple drivers'],
+ ['CHIP P { IN a; OUT out; PARTS: Not(out=out); }', 'Connect input'],
+ ['CHIP P { OUT out; PARTS: Not(in=missing,out=out); }', 'no driver'],
+ ['CHIP P { OUT out; PARTS: Not(in=out,out=out); }', 'loop'],
+ ['CHIP P { OUT out; PARTS: Keyboard(out=unused); }', 'no driver'],
+ ];
+ it.each(errors)('rejects invalid source %s', (source, message) =>
+ expect(() => compileHDL(source)).toThrow(message),
+ );
+ it('rejects invalid dependencies and recursive definitions', () => {
+ expect(() =>
+ compileHDL(wrapper('Not'), { Thing: 'CHIP Other { OUT out; PARTS: Keyboard(out=out); }' }),
+ ).toThrow('declares CHIP');
+ expect(() =>
+ compileHDL('CHIP Probe { IN in; OUT out; PARTS: Echo(in=in,out=out); }', {
+ Echo: 'CHIP Echo { IN in; OUT out; PARTS: Echo(in=in,out=out); }',
+ }),
+ ).toThrow('Recursive');
+ });
+ it('validates input values, external devices and clock sequencing', () => {
+ const c = compileHDL(wrapper('DFF'));
+ expect(c.phase).toBe('tock');
+ expect(() => c.tock()).toThrow('Tick');
+ c.tick();
+ expect(c.phase).toBe('tick');
+ expect(() => c.tick()).toThrow('already high');
+ c.tock();
+ expect(() => c.evaluate({ bad: 0 })).toThrow('Unknown input');
+ for (const value of [2, NaN, 0.5, -2])
+ expect(() => c.evaluate({ in: value })).toThrow(HDLError);
+ expect(() => c.loadROM([65536])).toThrow('ROM');
+ expect(() => c.loadROM(Array(32769).fill(0))).toThrow('ROM');
+ expect(() => c.setKeyboard(-1)).toThrow('Keyboard');
+ expect(() => c.readMemory(-1)).toThrow('address');
+ expect(() => c.readMemory(0)).toThrow('no mapped');
+ });
+});
diff --git a/src/lib/computer/hdl.ts b/src/lib/computer/hdl.ts
new file mode 100644
index 0000000..10f0ed1
--- /dev/null
+++ b/src/lib/computer/hdl.ts
@@ -0,0 +1,609 @@
+/** Educational HDL interpreter. Nets carry unsigned words; state changes only at tock. */
+import { alu, cpuStep } from './hack.js';
+export class HDLError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = 'HDLError';
+ }
+}
+export type PinWidths = Record;
+export type PinValues = Record;
+export interface ChipContract {
+ inputs: PinWidths;
+ outputs: PinWidths;
+}
+const contract = (inputs: PinWidths, outputs: PinWidths): ChipContract => ({ inputs, outputs });
+export const builtinContracts: Record = {
+ Nand: contract({ a: 1, b: 1 }, { out: 1 }),
+ Not: contract({ in: 1 }, { out: 1 }),
+ And: contract({ a: 1, b: 1 }, { out: 1 }),
+ Or: contract({ a: 1, b: 1 }, { out: 1 }),
+ Xor: contract({ a: 1, b: 1 }, { out: 1 }),
+ Mux: contract({ a: 1, b: 1, sel: 1 }, { out: 1 }),
+ DMux: contract({ in: 1, sel: 1 }, { a: 1, b: 1 }),
+ Not16: contract({ in: 16 }, { out: 16 }),
+ And16: contract({ a: 16, b: 16 }, { out: 16 }),
+ Or16: contract({ a: 16, b: 16 }, { out: 16 }),
+ Mux16: contract({ a: 16, b: 16, sel: 1 }, { out: 16 }),
+ Or8Way: contract({ in: 8 }, { out: 1 }),
+ Mux4Way16: contract({ a: 16, b: 16, c: 16, d: 16, sel: 2 }, { out: 16 }),
+ Mux8Way16: contract(
+ { a: 16, b: 16, c: 16, d: 16, e: 16, f: 16, g: 16, h: 16, sel: 3 },
+ { out: 16 },
+ ),
+ DMux4Way: contract({ in: 1, sel: 2 }, { a: 1, b: 1, c: 1, d: 1 }),
+ DMux8Way: contract({ in: 1, sel: 3 }, { a: 1, b: 1, c: 1, d: 1, e: 1, f: 1, g: 1, h: 1 }),
+ HalfAdder: contract({ a: 1, b: 1 }, { sum: 1, carry: 1 }),
+ FullAdder: contract({ a: 1, b: 1, c: 1 }, { sum: 1, carry: 1 }),
+ Add16: contract({ a: 16, b: 16 }, { out: 16 }),
+ Inc16: contract({ in: 16 }, { out: 16 }),
+ ALU: contract(
+ { x: 16, y: 16, zx: 1, nx: 1, zy: 1, ny: 1, f: 1, no: 1 },
+ { out: 16, zr: 1, ng: 1 },
+ ),
+ DFF: contract({ in: 1 }, { out: 1 }),
+ Bit: contract({ in: 1, load: 1 }, { out: 1 }),
+ Register: contract({ in: 16, load: 1 }, { out: 16 }),
+ ARegister: contract({ in: 16, load: 1 }, { out: 16 }),
+ DRegister: contract({ in: 16, load: 1 }, { out: 16 }),
+ PC: contract({ in: 16, load: 1, inc: 1, reset: 1 }, { out: 16 }),
+ RAM8: contract({ in: 16, load: 1, address: 3 }, { out: 16 }),
+ RAM64: contract({ in: 16, load: 1, address: 6 }, { out: 16 }),
+ RAM512: contract({ in: 16, load: 1, address: 9 }, { out: 16 }),
+ RAM4K: contract({ in: 16, load: 1, address: 12 }, { out: 16 }),
+ RAM16K: contract({ in: 16, load: 1, address: 14 }, { out: 16 }),
+ Screen: contract({ in: 16, load: 1, address: 13 }, { out: 16 }),
+ Keyboard: contract({}, { out: 16 }),
+ ROM32K: contract({ address: 15 }, { out: 16 }),
+ Memory: contract({ in: 16, load: 1, address: 15 }, { out: 16 }),
+ CPU: contract(
+ { inM: 16, instruction: 16, reset: 1 },
+ { outM: 16, writeM: 1, addressM: 15, pc: 15 },
+ ),
+ Computer: contract({ reset: 1 }, {}),
+};
+type Ref = { name: string; low?: number; high?: number };
+type Connection = { pin: Ref; net: Ref };
+type Part = { name: string; connections: Connection[] };
+type Definition = ChipContract & { name: string; parts: Part[] };
+const mask = (width: number) => 2 ** width - 1;
+function parse(source: string): Definition {
+ const clean = source.replace(/\/\*[\s\S]*?\*\//g, ' ').replace(/\/\/[^\n]*/g, ' ');
+ const tokens = clean.match(/[A-Za-z_][\w]*|\d+|\.\.|[^\s]/g) ?? [];
+ let position = 0;
+ const take = () => tokens[position++];
+ const expect = (value: string) => {
+ if (take() !== value) throw new HDLError(`Expected ${value} near token ${position}.`);
+ };
+ const identifier = () => {
+ const token = take();
+ if (!token || !/^[A-Za-z_]\w*$/.test(token))
+ throw new HDLError(`Expected a name near token ${position}.`);
+ return token;
+ };
+ const number = () => {
+ const token = take();
+ if (!token || !/^\d+$/.test(token)) throw new HDLError('Expected a bus width or bit index.');
+ return Number(token);
+ };
+ const ref = (): Ref => {
+ const name = identifier();
+ if (tokens[position] !== '[') return { name };
+ take();
+ const low = number();
+ let high = low;
+ if (tokens[position] === '..') {
+ take();
+ high = number();
+ }
+ expect(']');
+ if (high < low || high > 15)
+ throw new HDLError('Bus slices must have ascending indices from 0 to 15.');
+ return { name, low, high };
+ };
+ expect('CHIP');
+ const name = identifier();
+ expect('{');
+ const inputs: PinWidths = {},
+ outputs: PinWidths = {};
+ while (tokens[position] === 'IN' || tokens[position] === 'OUT') {
+ const target = take() === 'IN' ? inputs : outputs;
+ for (;;) {
+ const pin = identifier();
+ if (pin in inputs || pin in outputs || pin === 'true' || pin === 'false')
+ throw new HDLError(`Duplicate or reserved pin ${pin}.`);
+ let width = 1;
+ if (tokens[position] === '[') {
+ take();
+ width = number();
+ expect(']');
+ }
+ if (width < 1 || width > 16) throw new HDLError('Pin widths must be between 1 and 16.');
+ target[pin] = width;
+ if (tokens[position] !== ',') break;
+ take();
+ }
+ expect(';');
+ }
+ expect('PARTS');
+ expect(':');
+ const parts: Part[] = [];
+ while (tokens[position] !== '}' && position < tokens.length) {
+ const part: Part = { name: identifier(), connections: [] };
+ expect('(');
+ if (tokens[position] !== ')')
+ for (;;) {
+ const pin = ref();
+ expect('=');
+ const net = ref();
+ part.connections.push({ pin, net });
+ if (tokens[position] !== ',') break;
+ take();
+ }
+ expect(')');
+ expect(';');
+ parts.push(part);
+ }
+ expect('}');
+ if (position !== tokens.length) throw new HDLError('Unexpected text after the chip definition.');
+ if (parts.length === 0) throw new HDLError('Add at least one part to complete the circuit.');
+ return { name, inputs, outputs, parts };
+}
+type Read = (context: Evaluation) => number;
+class Evaluation {
+ cache = new Map();
+ visiting = new Set();
+ read(key: object, compute: () => number): number {
+ const cached = this.cache.get(key);
+ if (cached !== undefined) return cached;
+ if (this.visiting.has(key))
+ throw new HDLError(
+ 'The circuit contains a combinational loop. Add a clocked state boundary.',
+ );
+ this.visiting.add(key);
+ const result = compute();
+ this.visiting.delete(key);
+ this.cache.set(key, result);
+ return result;
+ }
+}
+type Instance = { inputs: Record; outputs: Record };
+type Stateful = { capture: (context: Evaluation) => void; commit: () => void; reset: () => void };
+export interface HDLCircuit {
+ readonly name: string;
+ getState(name: string, index?: number): number;
+ setState(name: string, value: number, index?: number): void;
+ readonly inputWidths: PinWidths;
+ readonly outputWidths: PinWidths;
+ readonly inputs: PinValues;
+ readonly outputs: PinValues;
+ readonly phase: 'tick' | 'tock';
+ evaluate(values?: PinValues): PinValues;
+ tick(values?: PinValues): PinValues;
+ tock(): PinValues;
+ cycle(values?: PinValues): PinValues;
+ reset(): PinValues;
+ loadROM(words: number[]): void;
+ setKeyboard(value: number): void;
+ readMemory(address: number): number;
+}
+/** Compile without evaluating user JavaScript; supports structural HDL only. */
+export function compileHDL(source: string, dependencies: Record = {}): HDLCircuit {
+ const root = parse(source),
+ definitions = new Map();
+ for (const [name, code] of Object.entries(dependencies)) {
+ const definition = parse(code);
+ if (definition.name !== name)
+ throw new HDLError(`Dependency ${name} declares CHIP ${definition.name}.`);
+ definitions.set(name, definition);
+ }
+ const stateful: Stateful[] = [],
+ validators: Read[] = [],
+ inputs: PinValues = {},
+ outputs: PinValues = {};
+ const memoryPorts: Array<{
+ name: string;
+ instance: Instance;
+ read?: (address: number) => number;
+ }> = [];
+ const statePorts: Array<{
+ name: string;
+ size: number;
+ read: (index: number) => number;
+ write: (index: number, value: number) => void;
+ }> = [];
+ let count = 0,
+ keyboard = 0,
+ phase: 'tick' | 'tock' = 'tock';
+ const rom = new Uint16Array(32768);
+ for (const key of Object.keys(root.inputs)) inputs[key] = 0;
+ const getContract = (name: string): ChipContract => {
+ const value =
+ definitions.get(name) ??
+ (Object.hasOwn(builtinContracts, name) ? builtinContracts[name] : undefined);
+ if (!value) throw new HDLError(`Unknown chip ${name}. Add its HDL dependency.`);
+ return value;
+ };
+ function builtin(name: string): Instance {
+ const spec = builtinContracts[name],
+ port: Instance = { inputs: {}, outputs: {} };
+ const g = (pin: string, ctx: Evaluation) => port.inputs[pin](ctx);
+ let value = 0,
+ next = 0,
+ writeAddress = 0,
+ writeValue = 0,
+ write = false;
+ const ramSize =
+ name === 'Memory' || name === 'Computer'
+ ? 24576
+ : name === 'Screen'
+ ? 8192
+ : name.startsWith('RAM')
+ ? 2 ** spec.inputs.address
+ : 0;
+ const memory = new Uint16Array(ramSize);
+ let cpu = { a: 0, d: 0, pc: 0 },
+ nextCpu = { ...cpu };
+ const readMemory = (address: number) =>
+ address < 24576 ? memory[address] : address === 24576 ? keyboard : 0;
+ if (name === 'Computer') memoryPorts.push({ name, instance: port, read: readMemory });
+ else if (name === 'Memory' || name === 'RAM16K' || name === 'Screen')
+ memoryPorts.push({ name, instance: port });
+ function cpuResult(ctx: Evaluation) {
+ return cpuStep(cpu, g('instruction', ctx), g('inM', ctx), Boolean(g('reset', ctx)));
+ }
+ if (ramSize)
+ statePorts.push({
+ name: name === 'Computer' ? 'RAM16K' : name,
+ size: name === 'Computer' ? 16384 : ramSize,
+ read: (index) =>
+ phase === 'tick' && write && writeAddress === index ? writeValue : memory[index],
+ write: (index, data) => {
+ memory[index] = data;
+ },
+ });
+ if (name === 'Computer')
+ statePorts.push({
+ name: 'Screen',
+ size: 8192,
+ read: (index) =>
+ phase === 'tick' && write && writeAddress === index + 16384
+ ? writeValue
+ : memory[index + 16384],
+ write: (index, data) => {
+ memory[index + 16384] = data;
+ },
+ });
+ if (['DFF', 'Bit', 'Register', 'ARegister', 'DRegister', 'PC'].includes(name))
+ statePorts.push({
+ name,
+ size: 1,
+ read: () => (phase === 'tick' ? next : value),
+ write: (_index, data) => {
+ value = data & mask(spec.outputs.out);
+ next = value;
+ },
+ });
+ if (name === 'CPU' || name === 'Computer')
+ for (const [label, key] of [
+ ['ARegister', 'a'],
+ ['DRegister', 'd'],
+ ['PC', 'pc'],
+ ] as const)
+ statePorts.push({
+ name: label,
+ size: 1,
+ read: () => (phase === 'tick' ? nextCpu[key] : cpu[key]),
+ write: (_index, data) => {
+ cpu[key] = data;
+ nextCpu[key] = data;
+ },
+ });
+ const compute = (pin: string, ctx: Evaluation): number => {
+ if (name === 'Nand') return 1 - (g('a', ctx) & g('b', ctx));
+ if (name === 'Not' || name === 'Not16') return ~g('in', ctx) & mask(spec.outputs.out);
+ if (name === 'And' || name === 'And16') return g('a', ctx) & g('b', ctx);
+ if (name === 'Or' || name === 'Or16') return g('a', ctx) | g('b', ctx);
+ if (name === 'Xor') return g('a', ctx) ^ g('b', ctx);
+ if (name.startsWith('Mux')) return g(String.fromCharCode(97 + g('sel', ctx)), ctx);
+ if (name.startsWith('DMux'))
+ return pin.charCodeAt(0) - 97 === g('sel', ctx) ? g('in', ctx) : 0;
+ if (name === 'Or8Way') return g('in', ctx) ? 1 : 0;
+ if (name === 'HalfAdder' || name === 'FullAdder') {
+ const sum = g('a', ctx) + g('b', ctx) + (name === 'FullAdder' ? g('c', ctx) : 0);
+ return pin === 'sum' ? sum & 1 : sum >> 1;
+ }
+ if (name === 'Add16') return (g('a', ctx) + g('b', ctx)) & 65535;
+ if (name === 'Inc16') return (g('in', ctx) + 1) & 65535;
+ if (name === 'ALU') {
+ const control = ['zx', 'nx', 'zy', 'ny', 'f', 'no'].reduce(
+ (acc, k) => (acc << 1) | g(k, ctx),
+ 0,
+ );
+ return alu(g('x', ctx), g('y', ctx), control)[pin as 'out' | 'zr' | 'ng'];
+ }
+ if (name === 'Keyboard') return keyboard;
+ if (name === 'ROM32K') return rom[g('address', ctx)];
+ if (name === 'Memory') return readMemory(g('address', ctx));
+ if (ramSize) return memory[g('address', ctx)];
+ if (name === 'CPU') {
+ if (pin === 'addressM') return cpu.a & 32767;
+ if (pin === 'pc') return cpu.pc & 32767;
+ const result = cpuResult(ctx);
+ return pin === 'writeM' ? Number(result.writeM) : result.outM;
+ }
+ return value;
+ };
+ for (const pin of Object.keys(spec.outputs)) {
+ const key = {};
+ port.outputs[pin] = (ctx) => ctx.read(key, () => compute(pin, ctx));
+ validators.push(port.outputs[pin]);
+ }
+ if (
+ ['DFF', 'Bit', 'Register', 'ARegister', 'DRegister', 'PC', 'CPU', 'Computer'].includes(
+ name,
+ ) ||
+ ramSize
+ ) {
+ stateful.push({
+ capture(ctx) {
+ write = false;
+ if (name === 'Computer') {
+ const instruction = rom[cpu.pc & 32767];
+ const result = cpuStep(
+ cpu,
+ instruction,
+ readMemory(cpu.a & 32767),
+ Boolean(g('reset', ctx)),
+ );
+ nextCpu = { a: result.a, d: result.d, pc: result.pc };
+ write = result.writeM && result.addressM < 24576;
+ writeAddress = result.addressM;
+ writeValue = result.outM;
+ } else if (name === 'CPU') {
+ const result = cpuResult(ctx);
+ nextCpu = { a: result.a, d: result.d, pc: result.pc };
+ } else if (ramSize) {
+ writeAddress = g('address', ctx);
+ write = Boolean(g('load', ctx)) && writeAddress < ramSize;
+ writeValue = g('in', ctx);
+ } else if (name === 'PC') {
+ next = g('reset', ctx)
+ ? 0
+ : g('load', ctx)
+ ? g('in', ctx)
+ : g('inc', ctx)
+ ? (value + 1) & 65535
+ : value;
+ } else next = name === 'DFF' || g('load', ctx) ? g('in', ctx) : value;
+ },
+ commit() {
+ value = next;
+ cpu = { ...nextCpu };
+ if (write) memory[writeAddress] = writeValue;
+ },
+ reset() {
+ value = next = 0;
+ write = false;
+ memory.fill(0);
+ cpu = { a: 0, d: 0, pc: 0 };
+ nextCpu = { ...cpu };
+ },
+ });
+ }
+ return port;
+ }
+ function instantiate(def: Definition, ancestry: string[]): Instance {
+ if (++count > 20000)
+ throw new HDLError(
+ 'This design exceeds the 20,000-part simulation limit. Use built-in RAM blocks for larger memories.',
+ );
+ const port: Instance = { inputs: {}, outputs: {} },
+ widths: PinWidths = { ...def.inputs, ...def.outputs };
+ if (def.name === 'Memory' || def.name === 'RAM16K' || def.name === 'Screen')
+ memoryPorts.push({ name: def.name, instance: port });
+ const minimum: PinWidths = {};
+ const children = def.parts.map((part) => {
+ const spec = getContract(part.name);
+ let instance: Instance;
+ if (definitions.has(part.name)) {
+ if (ancestry.includes(part.name))
+ throw new HDLError(`Recursive chip dependency: ${[...ancestry, part.name].join(' → ')}.`);
+ if (ancestry.length > 32) throw new HDLError('Chip dependency nesting is too deep.');
+ instance = instantiate(definitions.get(part.name)!, [...ancestry, part.name]);
+ } else {
+ if (++count > 20000)
+ throw new HDLError('Circuit exceeds the 20,000-part simulation limit.');
+ instance = builtin(part.name);
+ }
+ for (const { pin, net } of part.connections) {
+ const full = spec.inputs[pin.name] ?? spec.outputs[pin.name];
+ if (!full) throw new HDLError(`${part.name} has no pin ${pin.name}.`);
+ if (pin.high !== undefined && pin.high >= full)
+ throw new HDLError(`Pin slice ${part.name}.${pin.name} exceeds its ${full}-bit width.`);
+ const width = pin.low === undefined ? full : pin.high! - pin.low + 1;
+ if (net.name === 'true' || net.name === 'false') {
+ if (net.low !== undefined) throw new HDLError('Constants cannot be sliced.');
+ if (pin.name in spec.outputs)
+ throw new HDLError('A chip output cannot drive a constant.');
+ continue;
+ }
+ if (net.low === undefined) {
+ if (widths[net.name] !== undefined && widths[net.name] !== width)
+ throw new HDLError(
+ `Width mismatch on ${net.name}: expected ${widths[net.name]}, received ${width}.`,
+ );
+ widths[net.name] = width;
+ } else {
+ if (net.high! - net.low + 1 !== width)
+ throw new HDLError(`Slice width mismatch on ${net.name}.`);
+ minimum[net.name] = Math.max(minimum[net.name] ?? 0, net.high! + 1);
+ }
+ }
+ return { part, spec, instance };
+ });
+ for (const [name, min] of Object.entries(minimum)) {
+ if (widths[name] !== undefined && widths[name] < min)
+ throw new HDLError(`Slice exceeds the width of ${name}.`);
+ widths[name] ??= min;
+ }
+ const nets: Record> = {};
+ for (const [name, width] of Object.entries(widths)) nets[name] = Array(width);
+ for (const [name, width] of Object.entries(def.inputs))
+ for (let bit = 0; bit < width; bit++)
+ nets[name][bit] = (ctx) => (port.inputs[name](ctx) >> bit) & 1;
+ const readNet = (ref: Ref, width: number, ctx: Evaluation) => {
+ if (ref.name === 'true') return mask(width);
+ if (ref.name === 'false') return 0;
+ let result = 0;
+ for (let bit = 0; bit < width; bit++) {
+ const driver = nets[ref.name]?.[(ref.low ?? 0) + bit];
+ if (!driver)
+ throw new HDLError(`Signal ${ref.name}[${(ref.low ?? 0) + bit}] has no driver.`);
+ result |= driver(ctx) << bit;
+ }
+ return result;
+ };
+ for (const { part, spec, instance } of children) {
+ const bindings: Record> = {};
+ for (const [name, width] of Object.entries(spec.inputs)) bindings[name] = Array(width);
+ for (const { pin, net } of part.connections) {
+ const full = spec.inputs[pin.name] ?? spec.outputs[pin.name],
+ width = pin.low === undefined ? full : pin.high! - pin.low + 1;
+ if (pin.name in spec.inputs) {
+ for (let bit = 0; bit < width; bit++) {
+ const index = (pin.low ?? 0) + bit;
+ if (bindings[pin.name][index])
+ throw new HDLError(`Input ${part.name}.${pin.name}[${index}] is connected twice.`);
+ bindings[pin.name][index] = (ctx) => (readNet(net, width, ctx) >> bit) & 1;
+ }
+ } else
+ for (let bit = 0; bit < width; bit++) {
+ const index = (net.low ?? 0) + bit;
+ if (nets[net.name][index])
+ throw new HDLError(`Signal ${net.name}[${index}] has multiple drivers.`);
+ nets[net.name][index] = (ctx) =>
+ (instance.outputs[pin.name](ctx) >> ((pin.low ?? 0) + bit)) & 1;
+ }
+ }
+ for (const [name, bits] of Object.entries(bindings)) {
+ for (let bit = 0; bit < bits.length; bit++)
+ if (!bits[bit]) throw new HDLError(`Connect input ${part.name}.${name}[${bit}].`);
+ instance.inputs[name] = (ctx) =>
+ bits.reduce((result, read, bit) => result | (read!(ctx) << bit), 0);
+ }
+ }
+ for (const [name, width] of Object.entries(def.outputs))
+ port.outputs[name] = (ctx) => readNet({ name }, width, ctx);
+ // Reject undriven internal bits even when the affected output is currently unused.
+ for (const [name, bits] of Object.entries(nets))
+ for (let bit = 0; bit < bits.length; bit++)
+ if (!bits[bit]) throw new HDLError(`Signal ${name}[${bit}] has no driver.`);
+ return port;
+ }
+ const top = instantiate(root, [root.name]);
+ for (const name of Object.keys(root.inputs)) top.inputs[name] = () => inputs[name];
+ function evaluate(values: PinValues = {}): PinValues {
+ for (const [name, value] of Object.entries(values)) {
+ const width = root.inputs[name];
+ if (!width) throw new HDLError(`Unknown input ${name}.`);
+ if (!Number.isInteger(value) || value < -(2 ** (width - 1)) || value > mask(width))
+ throw new HDLError(`Input ${name} needs a ${width}-bit integer.`);
+ inputs[name] = value & mask(width);
+ }
+ const context = new Evaluation();
+ for (const read of validators) read(context);
+ for (const [name, read] of Object.entries(top.outputs)) outputs[name] = read(context);
+ return { ...outputs };
+ }
+ const circuit: HDLCircuit = {
+ name: root.name,
+ getState(name, index = 0) {
+ const port = statePorts.find((port) => port.name === name);
+ if (!port) throw new HDLError(`No inspectable ${name} component in this circuit.`);
+ if (!Number.isInteger(index) || index < 0 || index >= port.size)
+ throw new HDLError(`Index outside ${name}.`);
+ return port.read(index);
+ },
+ setState(name, value, index = 0) {
+ const port = statePorts.find((port) => port.name === name);
+ if (!port) throw new HDLError(`No inspectable ${name} component in this circuit.`);
+ if (!Number.isInteger(index) || index < 0 || index >= port.size)
+ throw new HDLError(`Index outside ${name}.`);
+ if (!Number.isInteger(value) || value < -32768 || value > 65535)
+ throw new HDLError('State value must fit a 16-bit word.');
+ if (phase === 'tick') throw new HDLError('Change state only between complete clock cycles.');
+ port.write(index, value & 65535);
+ evaluate();
+ },
+ inputWidths: { ...root.inputs },
+ outputWidths: { ...root.outputs },
+ inputs,
+ outputs,
+ get phase() {
+ return phase;
+ },
+ evaluate,
+ tick(values = {}) {
+ if (phase === 'tick')
+ throw new HDLError('The clock is already high. Tock before ticking again.');
+ evaluate(values);
+ const context = new Evaluation();
+ stateful.forEach((state) => state.capture(context));
+ phase = 'tick';
+ return { ...outputs };
+ },
+ tock() {
+ if (phase !== 'tick') throw new HDLError('Tick before tock.');
+ stateful.forEach((state) => state.commit());
+ phase = 'tock';
+ return evaluate();
+ },
+ cycle(values = {}) {
+ this.tick(values);
+ return this.tock();
+ },
+ reset() {
+ stateful.forEach((state) => state.reset());
+ phase = 'tock';
+ return evaluate();
+ },
+ loadROM(words) {
+ if (
+ words.length > 32768 ||
+ words.some((word) => !Number.isInteger(word) || word < 0 || word > 65535)
+ )
+ throw new HDLError('ROM needs at most 32768 unsigned 16-bit instructions.');
+ rom.fill(0);
+ rom.set(words);
+ evaluate();
+ },
+ readMemory(address) {
+ if (!Number.isInteger(address) || address < 0 || address > 32767)
+ throw new HDLError('Memory address must be between 0 and 32767.');
+ const entry =
+ memoryPorts.find((item) => item.name === 'Memory' || item.name === 'Computer') ??
+ memoryPorts.find((item) => item.name === (address < 16384 ? 'RAM16K' : 'Screen'));
+ if (address === 24576) return keyboard;
+ if (address > 24576) return 0;
+ if (!entry)
+ throw new HDLError('This circuit has no mapped Memory, RAM16K, or Screen component.');
+ if (entry.read) return entry.read(address);
+ const previous = entry.instance.inputs.address;
+ entry.instance.inputs.address = () => (entry.name === 'Screen' ? address - 16384 : address);
+ try {
+ return entry.instance.outputs.out(new Evaluation());
+ } finally {
+ entry.instance.inputs.address = previous;
+ }
+ },
+ setKeyboard(value) {
+ if (!Number.isInteger(value) || value < 0 || value > 65535)
+ throw new HDLError('Keyboard value must be an unsigned 16-bit integer.');
+ keyboard = value;
+ evaluate();
+ },
+ };
+ evaluate();
+ return circuit;
+}
diff --git a/src/lib/computer/testing.test.ts b/src/lib/computer/testing.test.ts
new file mode 100644
index 0000000..a9eb3e9
--- /dev/null
+++ b/src/lib/computer/testing.test.ts
@@ -0,0 +1,221 @@
+import { describe, expect, it } from 'vitest';
+import { readFileSync, readdirSync } from 'node:fs';
+import { builtinContracts, compileHDL } from './hdl.js';
+import { createHDLTest } from './testing.js';
+const directory = new URL('./testing/official/', import.meta.url);
+const files = Object.fromEntries(
+ readdirSync(directory).map((name) => [name, readFileSync(new URL(name, directory), 'utf8')]),
+);
+function source(name: string) {
+ const spec = builtinContracts[name];
+ const pins = (widths: Record) =>
+ Object.entries(widths)
+ .map(([pin, width]) => `${pin}${width > 1 ? `[${width}]` : ''}`)
+ .join(',');
+ return `CHIP ${name} { ${Object.keys(spec.inputs).length ? `IN ${pins(spec.inputs)};` : ''} ${Object.keys(spec.outputs).length ? `OUT ${pins(spec.outputs)};` : ''} PARTS: ${name}(${[...Object.keys(spec.inputs), ...Object.keys(spec.outputs)].map((pin) => `${pin}=${pin}`).join(',')}); }`;
+}
+const probe = () => compileHDL(source('Not16'));
+describe('Production hardware test runner', () => {
+ for (const file of Object.keys(files).filter(
+ (file) => file.endsWith('.tst') && !file.startsWith('Memory'),
+ )) {
+ const name = file.slice(0, -4);
+ const chip = name.startsWith('Computer')
+ ? 'Computer'
+ : name.startsWith('CPU')
+ ? 'CPU'
+ : name === 'ALU-nostat'
+ ? 'ALU'
+ : name;
+ it(`runs official ${name}`, () => {
+ const test = createHDLTest(compileHDL(source(chip)), files[file], { files });
+ test.run(10000);
+ expect(test.error).toBeNull();
+ expect(
+ test.failed,
+ JSON.stringify(test.rows.filter((row) => row.pass === false).slice(0, 3)),
+ ).toBe(0);
+ expect(test.status).toBe('complete');
+ expect(test.rows.length).toBeGreaterThan(0);
+ expect(test.passed).toBe(test.rows.length);
+ });
+ }
+ it('pauses an interactive keyboard condition, resumes after input, and handles echo punctuation', () => {
+ const c = compileHDL(source('Memory'));
+ const t = createHDLTest(
+ c,
+ 'set address 24576; echo "Press K, then continue!"; while out <> 75 { eval; } clear-echo; output-list out%D1.6.1; output;',
+ );
+ t.run(10);
+ expect(t.status).toBe('paused');
+ expect(t.messages).toEqual(['Press K, then continue!']);
+ c.setKeyboard(75);
+ t.run();
+ expect(t.status).toBe('complete');
+ expect(t.messages).toEqual([]);
+ expect(t.rows[0].values.out).toBe('75');
+ expect(t.rows[0].pass).toBeNull();
+ });
+ it('runs the official interactive Memory script with controlled keyboard responses', () => {
+ const c = compileHDL(source('Memory'));
+ const t = createHDLTest(c, files['Memory.tst'], { files });
+ t.run(1000);
+ expect(t.status).toBe('paused');
+ c.setKeyboard(75);
+ t.run(1000);
+ expect(t.status).toBe('paused');
+ c.setKeyboard(89);
+ t.run(1000);
+ expect(t.error).toBeNull();
+ expect(t.status).toBe('complete');
+ expect(t.failed).toBe(0);
+ expect(c.readMemory(16384 + 256 * 16)).toBeDefined();
+ });
+ it('supports stepping, nested and zero repeats, numeric formats, and complete-state controls', () => {
+ const c = probe();
+ const t = createHDLTest(
+ c,
+ '/* setup */ load Not16.hdl; set in %X00FF; output-list in%X1.4.1 out%B1.16.1; repeat 0 { eval; } repeat 2 { repeat 2 { eval; output; } }',
+ );
+ t.step();
+ expect(t.status).toBe('paused');
+ t.run();
+ expect(t.status).toBe('complete');
+ expect(t.rows).toHaveLength(4);
+ expect(t.rows[0].values.in).toBe('00FF');
+ expect(t.output).toContain('1111111100000000');
+ t.run();
+ expect(t.rows).toHaveLength(4);
+ const clock = compileHDL(source('Register'));
+ const state = createHDLTest(
+ clock,
+ 'set Register[] %D-1; output-list out; output; set in 42; set load 1; ticktock; output;',
+ );
+ state.run();
+ expect(state.rows.map((row) => row.values.out)).toEqual(['-1', '42']);
+ });
+ it('evaluates all numeric condition operators and bounded indefinite repeats', () => {
+ for (const [condition, finish] of [
+ ['in = 0', 1],
+ ['in <= 0', 1],
+ ['in >= 1', 0],
+ ['in < 1', 1],
+ ['in > 0', 0],
+ ] as const) {
+ const test = createHDLTest(
+ probe(),
+ `set in ${condition.startsWith('in >') ? 1 : 0}; while ${condition} { set in ${finish}; }`,
+ { maxSteps: 10 },
+ );
+ test.run();
+ expect(test.error).toBeNull();
+ }
+ const test = createHDLTest(probe(), 'repeat { eval; }', { maxSteps: 12 });
+ test.run(4);
+ expect(test.status).toBe('paused');
+ test.run();
+ expect(test.status).toBe('failed');
+ expect(test.error).toContain('exceeded');
+ });
+ it('reports cell and row mismatches, supports wildcard values and files supplied directly', () => {
+ const c = probe();
+ const script = 'output-list in%B1.16.1 out%D1.6.1; output;';
+ const t = createHDLTest(c, script, { compare: '|in|out|\n|0000000000000000|99|' });
+ t.run();
+ expect(t.failed).toBe(1);
+ expect(t.rows[0].differences).toEqual(['out: expected 99, got -1.']);
+ const wild = createHDLTest(c, script, { compare: '|in|out|\n|00000000********|******|' });
+ wild.run();
+ expect(wild.passed).toBe(1);
+ const short = createHDLTest(c, script, { compare: '|in|out|\n|0|\n|0|' });
+ short.run();
+ expect(short.error).toContain('Expected 2 output rows');
+ expect(short.rows[0].differences[0]).toContain('column count');
+ const extra = createHDLTest(c, script + script, {
+ compare: '|in|out|\n|****************|******|',
+ });
+ extra.run();
+ expect(extra.rows[1].differences).toContain('Unexpected additional output row.');
+ });
+ it('loads array ROM files and handles keyboard assignment', () => {
+ const c = compileHDL(source('Computer'));
+ const t = createHDLTest(
+ c,
+ 'ROM32K load Test.hack; set Keyboard 65; output-list Keyboard%D1.6.1; output;',
+ { files: { 'Test.hack': [0, 0] } },
+ );
+ t.run();
+ expect(t.error).toBeNull();
+ expect(t.rows[0].values.Keyboard).toBe('65');
+ });
+});
+describe('Test runner diagnostics', () => {
+ it.each(['/*', 'echo "oops;', 'eval', '}', 'repeat 2 eval;', 'repeat 2 { }', 'repeat 2 { eval;'])(
+ 'rejects malformed script %s',
+ (script) => expect(() => createHDLTest(probe(), script)).toThrow(),
+ );
+ it.each([
+ ['vmstep;', 'Unsupported'],
+ ['load Other.hdl;', 'compile CHIP'],
+ ['compare-to missing.cmp;', 'expected output file'],
+ ['ROM32K load absent.hack;', 'Provide ROM'],
+ ['ROM32K load bad.hack;', '16-bit binary'],
+ ['output;', 'output-list'],
+ ['output-list out%Q1.6.1;', 'Invalid output'],
+ ['output-list out%D1.999.1;', 'column dimensions'],
+ ['output-list unknown;', 'No inspectable'],
+ ['set in invalid;', 'numeric'],
+ ['set x.y 1;', 'signal'],
+ ['while nonsense { eval; }', 'condition'],
+ ['output-list time%D1.4.1; output;', 'string formatting'],
+ ])('reports %s', (script, error) => {
+ const t = createHDLTest(probe(), script, { files: { 'bad.hack': 'no' } });
+ t.run();
+ expect(t.status).toBe('failed');
+ expect(t.error).toContain(error);
+ });
+ it('resets inputs when loading a test and rejects prototype chip names', () => {
+ const c = probe();
+ c.evaluate({ in: 123 });
+ const t = createHDLTest(c, 'load Not16.hdl; output-list in; output;');
+ t.run();
+ expect(t.rows[0].values.in).toBe('0');
+ expect(() => compileHDL('CHIP P { PARTS: constructor(); }')).toThrow('Unknown chip');
+ });
+ it('edits and inspects individual bus bits without changing neighboring bits', () => {
+ const c = probe();
+ const t = createHDLTest(
+ c,
+ 'set in[] 2; set in[15] 1; output-list in[15]%B1.1.1 out[15]%B1.1.1 in%D1.6.1; output; while in[15]=1 { set in[15] 0; } output;',
+ );
+ t.run();
+ expect(t.error).toBeNull();
+ expect(t.rows[0].values).toEqual({ 'in[15]': '1', 'out[15]': '0', in: '-32766' });
+ expect(c.inputs.in).toBe(2);
+ for (const script of ['set in[16] 1;', 'set in[0] 2;', 'output-list out[16];']) {
+ const failed = createHDLTest(probe(), script);
+ failed.run();
+ expect(failed.status).toBe('failed');
+ }
+ });
+ it('checks comparison format and execution budgets', () => {
+ expect(() => createHDLTest(probe(), 'eval;', { compare: 'not a table' })).toThrow(
+ 'pipe-delimited',
+ );
+ expect(() => createHDLTest(probe(), 'eval;', { maxSteps: 0 })).toThrow('step limit');
+ expect(() => createHDLTest(probe(), 'eval;').run(0)).toThrow('Run budget');
+ });
+ it('rejects invalid state access and changes halfway through a cycle', () => {
+ const c = compileHDL(source('Register'));
+ expect(() => c.getState('Other')).toThrow('No inspectable');
+ expect(() => c.getState('Register', 1)).toThrow('Index');
+ expect(() => c.setState('Other', 0)).toThrow('No inspectable');
+ expect(() => c.setState('Register', 0, 1)).toThrow('Index');
+ expect(() => c.setState('Register', 65536)).toThrow('16-bit');
+ c.tick();
+ expect(() => c.setState('Register', 0)).toThrow('complete clock');
+ const cpu = compileHDL(source('CPU'));
+ cpu.setState('DRegister', 7);
+ expect(cpu.getState('DRegister')).toBe(7);
+ });
+});
diff --git a/src/lib/computer/testing.ts b/src/lib/computer/testing.ts
new file mode 100644
index 0000000..5cec44f
--- /dev/null
+++ b/src/lib/computer/testing.ts
@@ -0,0 +1,422 @@
+/** Bounded structural HDL test-script runner, compatible with the Part I TDL commands. */
+import type { HDLCircuit } from './hdl.js';
+export class HDLTestError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = 'HDLTestError';
+ }
+}
+export type HDLTestOptions = {
+ compare?: string;
+ files?: Record;
+ maxSteps?: number;
+};
+export type HDLTestRow = {
+ values: Record;
+ pass: boolean | null;
+ differences: string[];
+};
+export interface HDLTestSession {
+ rows: HDLTestRow[];
+ output: string;
+ messages: string[];
+ error: string | null;
+ passed: number;
+ failed: number;
+ done: boolean;
+ status: 'ready' | 'running' | 'paused' | 'complete' | 'failed';
+ step(): void;
+ run(budget?: number): void;
+}
+type Node =
+ | { kind: 'command'; text: string }
+ | { kind: 'repeat'; count: number | null; body: Node[] }
+ | { kind: 'while'; condition: string; body: Node[] };
+type Frame = { nodes: Node[]; index: number; remaining: number | null; condition?: string };
+type Format = { name: string; style: string; left: number; width: number; right: number };
+function parseScript(source: string): Node[] {
+ const pieces: string[] = [];
+ let chunk = '',
+ quoted = false;
+ for (let i = 0; i < source.length; i++) {
+ const char = source[i];
+ if (char === '"' && source[i - 1] !== '\\') {
+ quoted = !quoted;
+ chunk += char;
+ continue;
+ }
+ if (!quoted && char === '/' && source[i + 1] === '/') {
+ while (i < source.length && source[i] !== '\n') i++;
+ chunk += ' ';
+ continue;
+ }
+ if (!quoted && char === '/' && source[i + 1] === '*') {
+ const end = source.indexOf('*/', i + 2);
+ if (end < 0) throw new HDLTestError('Unterminated comment.');
+ i = end + 1;
+ chunk += ' ';
+ continue;
+ }
+ if (!quoted && '{};,!'.includes(char)) {
+ if (chunk.trim()) pieces.push(chunk.trim());
+ pieces.push(char);
+ chunk = '';
+ } else chunk += char;
+ }
+ if (quoted) throw new HDLTestError('Unterminated quoted message.');
+ if (chunk.trim()) pieces.push(chunk.trim());
+ let pos = 0;
+ function block(nested = false, depth = 0): Node[] {
+ if (depth > 32) throw new HDLTestError('Test loops are nested too deeply.');
+ const nodes: Node[] = [];
+ while (pos < pieces.length) {
+ const text = pieces[pos++];
+ if (text === '}') {
+ if (!nested) throw new HDLTestError('Unexpected closing brace.');
+ return nodes;
+ }
+ if (/[;,!]/.test(text) && text.length === 1) continue;
+ const repeat = text.match(/^repeat(?:\s+(\d+))?$/),
+ condition = text.match(/^while\s+(.+)$/);
+ if (repeat || condition) {
+ if (pieces[pos++] !== '{') throw new HDLTestError('Expected a loop body in braces.');
+ const body = block(true, depth + 1);
+ if (!body.length) throw new HDLTestError('Loop bodies must contain a command.');
+ nodes.push(
+ repeat
+ ? { kind: 'repeat', count: repeat[1] === undefined ? null : Number(repeat[1]), body }
+ : { kind: 'while', condition: condition![1], body },
+ );
+ } else {
+ if (/^repeat\b|^while\b/.test(text)) throw new HDLTestError('Invalid loop declaration.');
+ if (![';', ',', '!'].includes(pieces[pos] ?? ''))
+ throw new HDLTestError(`Missing separator after ${text}.`);
+ pos++;
+ nodes.push({ kind: 'command', text });
+ }
+ }
+ if (nested) throw new HDLTestError('Unclosed loop body.');
+ return nodes;
+ }
+ return block();
+}
+function numeric(value: string): number {
+ if (/^%B[01]+$/i.test(value)) return parseInt(value.slice(2), 2);
+ if (/^%X[\da-f]+$/i.test(value)) return parseInt(value.slice(2), 16);
+ if (/^%D-?\d+$/i.test(value)) return Number(value.slice(2));
+ if (/^-?\d+$/.test(value)) return Number(value);
+ throw new HDLTestError(`Invalid numeric value ${value}.`);
+}
+export function createHDLTest(
+ circuit: HDLCircuit,
+ script: string,
+ options: HDLTestOptions = {},
+): HDLTestSession {
+ const nodes = parseScript(script),
+ frames: Frame[] = [{ nodes, index: 0, remaining: 1 }];
+ const maximum = options.maxSteps ?? 200000;
+ if (!Number.isInteger(maximum) || maximum < 1 || maximum > 1000000)
+ throw new HDLTestError('Test step limit must be between 1 and 1,000,000.');
+ let steps = 0,
+ halfClock = 0,
+ formats: Format[] = [],
+ compareRows: string[][] | null = null,
+ headerWritten = false;
+ function loadCompare(source: string) {
+ const rows = source
+ .trim()
+ .split(/\r?\n/)
+ .filter((line) => line.trim())
+ .map((line) =>
+ line
+ .split('|')
+ .slice(1, -1)
+ .map((value) => value.trim()),
+ );
+ if (!rows.length || rows.some((row) => row.length === 0))
+ throw new HDLTestError('Expected output must be a pipe-delimited comparison table.');
+ rows.shift();
+ compareRows = rows;
+ }
+ if (options.compare?.trim()) loadCompare(options.compare);
+ const session: HDLTestSession = {
+ rows: [],
+ output: '',
+ messages: [],
+ error: null,
+ passed: 0,
+ failed: 0,
+ done: false,
+ status: 'ready',
+ step() {
+ advance(1);
+ },
+ run(budget = 10000) {
+ if (!Number.isInteger(budget) || budget < 1 || budget > 1000000)
+ throw new HDLTestError('Run budget must be between 1 and 1,000,000.');
+ advance(budget);
+ },
+ };
+ const reference = (name: string) => {
+ const match = name.match(/^([A-Za-z_]\w*)(?:\[(\d*)\])?$/);
+ if (!match) throw new HDLTestError(`Invalid signal ${name}.`);
+ return {
+ name: match[1],
+ index: match[2] === undefined || match[2] === '' ? undefined : Number(match[2]),
+ indexed: match[2] !== undefined,
+ };
+ };
+ function value(name: string): number | string {
+ if (name === 'time') return `${Math.floor(halfClock / 2)}${halfClock % 2 ? '+' : ''}`;
+ const ref = reference(name);
+ const pin = circuit.inputs[ref.name] ?? circuit.outputs[ref.name];
+ if (pin !== undefined) {
+ if (ref.index === undefined) return pin;
+ const width = circuit.inputWidths[ref.name] ?? circuit.outputWidths[ref.name];
+ if (ref.index >= width) throw new HDLTestError(`Bit index exceeds ${ref.name}.`);
+ return (pin >>> ref.index) & 1;
+ }
+ if (ref.name === 'Keyboard') return circuit.readMemory(24576);
+ return circuit.getState(ref.name, ref.index);
+ }
+ function condition(expression: string): boolean {
+ const match = expression.match(/^([\w%[\]-]+)\s*(<>|<=|>=|=|<|>)\s*([\w%[\]-]+)$/);
+ if (!match) throw new HDLTestError(`Invalid while condition ${expression}.`);
+ const operand = (text: string) =>
+ /^-?\d|^%[BDX]/i.test(text) ? numeric(text) : Number(value(text));
+ const left = operand(match[1]),
+ right = operand(match[3]);
+ if (!Number.isFinite(left) || !Number.isFinite(right))
+ throw new HDLTestError('While conditions require numeric values.');
+ return match[2] === '='
+ ? left === right
+ : match[2] === '<>'
+ ? left !== right
+ : match[2] === '<'
+ ? left < right
+ : match[2] === '>'
+ ? left > right
+ : match[2] === '<='
+ ? left <= right
+ : left >= right;
+ }
+ function next(): string | null {
+ while (frames.length) {
+ if (++steps > maximum)
+ throw new HDLTestError(
+ `Test exceeded ${maximum} steps. Check its loops or keyboard condition.`,
+ );
+ const frame = frames[frames.length - 1];
+ if (frame.index >= frame.nodes.length) {
+ if (
+ frame.condition !== undefined
+ ? condition(frame.condition)
+ : frame.remaining === null || --frame.remaining > 0
+ ) {
+ frame.index = 0;
+ continue;
+ }
+ frames.pop();
+ continue;
+ }
+ const node = frame.nodes[frame.index++];
+ if (node.kind === 'command') return node.text;
+ if (node.kind === 'repeat') {
+ if (node.count !== 0) frames.push({ nodes: node.body, index: 0, remaining: node.count });
+ } else if (condition(node.condition))
+ frames.push({ nodes: node.body, index: 0, remaining: 1, condition: node.condition });
+ }
+ return null;
+ }
+ function output() {
+ if (!formats.length) throw new HDLTestError('Declare output-list before output.');
+ if (session.rows.length >= 10000)
+ throw new HDLTestError('Test output is limited to 10,000 rows.');
+ const cells = formats.map((format) => {
+ const raw = value(format.name);
+ if (format.style === 'S') return String(raw);
+ if (typeof raw !== 'number')
+ throw new HDLTestError(`Use string formatting for ${format.name}.`);
+ if (format.style === 'B') return raw.toString(2).padStart(format.width, '0');
+ if (format.style === 'X') return raw.toString(16).toUpperCase().padStart(format.width, '0');
+ const width = circuit.inputWidths[format.name] ?? circuit.outputWidths[format.name] ?? 16;
+ return String(width === 16 && raw >= 32768 ? raw - 65536 : raw);
+ });
+ const differences: string[] = [];
+ if (compareRows) {
+ const expected = compareRows[session.rows.length];
+ if (!expected) differences.push('Unexpected additional output row.');
+ else {
+ if (expected.length !== cells.length) differences.push('Comparison column count differs.');
+ cells.forEach((cell, i) => {
+ const target = expected[i];
+ if (target === undefined || /^\*+$/.test(target)) return;
+ const pattern =
+ '^' + target.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.') + '$';
+ if (!new RegExp(pattern).test(cell))
+ differences.push(`${formats[i].name}: expected ${target}, got ${cell}.`);
+ });
+ }
+ }
+ const pass = compareRows ? differences.length === 0 : null;
+ session.rows.push({
+ values: Object.fromEntries(formats.map((format, i) => [format.name, cells[i]])),
+ pass,
+ differences,
+ });
+ if (pass === true) session.passed++;
+ if (pass === false) session.failed++;
+ const render = (items: string[]) =>
+ '|' +
+ items
+ .map(
+ (cell, i) =>
+ ' '.repeat(formats[i].left) +
+ cell.padStart(formats[i].width, ' ') +
+ ' '.repeat(formats[i].right),
+ )
+ .join('|') +
+ '|\n';
+ if (!headerWritten) {
+ session.output += render(formats.map((format) => format.name.slice(0, format.width)));
+ headerWritten = true;
+ }
+ session.output += render(cells);
+ }
+ function command(text: string) {
+ if (text === 'eval') {
+ circuit.evaluate();
+ return;
+ }
+ if (text === 'tick') {
+ circuit.tick();
+ halfClock++;
+ return;
+ }
+ if (text === 'tock') {
+ circuit.tock();
+ halfClock++;
+ return;
+ }
+ if (text === 'ticktock') {
+ circuit.cycle();
+ halfClock += 2;
+ return;
+ }
+ if (text === 'output') {
+ output();
+ return;
+ }
+ if (text === 'clear-echo') {
+ session.messages = [];
+ return;
+ }
+ const echo = text.match(/^echo\s+("(?:\\.|[^"\\])*")$/);
+ if (echo) {
+ session.messages.push(JSON.parse(echo[1]));
+ return;
+ }
+ const set = text.match(/^set\s+(\S+)\s+(\S+)$/);
+ if (set) {
+ const ref = reference(set[1]),
+ number = numeric(set[2]);
+ if (Object.hasOwn(circuit.inputWidths, ref.name)) {
+ if (ref.index === undefined) circuit.evaluate({ [ref.name]: number });
+ else {
+ if (ref.index >= circuit.inputWidths[ref.name] || (number !== 0 && number !== 1))
+ throw new HDLTestError('A bus-bit assignment needs an in-range index and 0 or 1.');
+ circuit.evaluate({
+ [ref.name]: (circuit.inputs[ref.name] & ~(1 << ref.index)) | (number << ref.index),
+ });
+ }
+ } else if (ref.name === 'Keyboard') circuit.setKeyboard(number);
+ else circuit.setState(ref.name, number, ref.index);
+ return;
+ }
+ if (text.startsWith('output-list ')) {
+ const entries = text.slice(12).trim().split(/\s+/);
+ formats = entries.map((entry) => {
+ const match = entry.match(/^([A-Za-z_]\w*(?:\[\d*\])?)(?:%([BDSX])(\d+)\.(\d+)\.(\d+))?$/);
+ if (!match) throw new HDLTestError(`Invalid output format ${entry}.`);
+ const result = {
+ name: match[1],
+ style: match[2] ?? 'D',
+ left: Number(match[3] ?? 1),
+ width: Number(match[4] ?? 6),
+ right: Number(match[5] ?? 1),
+ };
+ if (result.width < 1 || result.width > 64 || result.left > 32 || result.right > 32)
+ throw new HDLTestError('Output column dimensions are outside the supported range.');
+ value(result.name);
+ return result;
+ });
+ headerWritten = false;
+ return;
+ }
+ const file = text.match(/^(load|output-file|compare-to|ROM32K\s+load)\s+([\w.$-]+)$/);
+ if (file) {
+ const [, operation, name] = file;
+ if (operation === 'output-file') return;
+ if (operation === 'load') {
+ if (name !== `${circuit.name}.hdl`)
+ throw new HDLTestError(
+ `This script loads ${name}; compile CHIP ${name.replace(/\.hdl$/, '')} first.`,
+ );
+ circuit.reset();
+ circuit.evaluate(
+ Object.fromEntries(Object.keys(circuit.inputWidths).map((pin) => [pin, 0])),
+ );
+ halfClock = 0;
+ return;
+ }
+ if (operation === 'compare-to') {
+ if (options.compare?.trim()) return;
+ const compare = options.files?.[name];
+ if (typeof compare === 'string') loadCompare(compare);
+ else throw new HDLTestError(`Provide the expected output file ${name}.`);
+ return;
+ }
+ const source = options.files?.[name];
+ if (source === undefined) throw new HDLTestError(`Provide ROM program ${name}.`);
+ let words: number[];
+ if (Array.isArray(source)) words = source;
+ else {
+ const lines = source
+ .replace(/\/\/[^\n]*/g, '')
+ .split(/\s+/)
+ .filter(Boolean);
+ if (lines.some((line) => !/^[01]{16}$/.test(line)))
+ throw new HDLTestError(`${name} must contain 16-bit binary instructions.`);
+ words = lines.map((line) => parseInt(line, 2));
+ }
+ circuit.loadROM(words);
+ return;
+ }
+ throw new HDLTestError(`Unsupported test command: ${text}.`);
+ }
+ function advance(budget: number) {
+ if (session.done) return;
+ session.status = 'running';
+ try {
+ for (let i = 0; i < budget; i++) {
+ const text = next();
+ if (text === null) {
+ session.done = true;
+ if (compareRows && session.rows.length !== compareRows.length) {
+ session.failed += Math.abs(compareRows.length - session.rows.length);
+ session.error = `Expected ${compareRows.length} output rows; produced ${session.rows.length}.`;
+ }
+ session.status = session.failed ? 'failed' : 'complete';
+ return;
+ }
+ command(text);
+ }
+ session.status = 'paused';
+ } catch (error) {
+ session.error = error instanceof Error ? error.message : String(error);
+ session.status = 'failed';
+ session.done = true;
+ }
+ }
+ return session;
+}
diff --git a/src/lib/computer/testing/fixtures/hack/Add.asm b/src/lib/computer/testing/fixtures/hack/Add.asm
new file mode 100644
index 0000000..3d4ec46
--- /dev/null
+++ b/src/lib/computer/testing/fixtures/hack/Add.asm
@@ -0,0 +1,13 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/06/add/Add.asm
+
+// Computes R0 = 2 + 3 (R0 refers to RAM[0])
+
+@2
+D=A
+@3
+D=D+A
+@0
+M=D
diff --git a/src/lib/computer/testing/fixtures/hack/LICENSE b/src/lib/computer/testing/fixtures/hack/LICENSE
new file mode 100644
index 0000000..da6f868
--- /dev/null
+++ b/src/lib/computer/testing/fixtures/hack/LICENSE
@@ -0,0 +1,12 @@
+MIT License
+
+© 2017 Shimon Schocken and Noam Nisan
+
+This software is based on Stefano Volpe's 'Nand2Tetris Tools'. Please check [here](https://github.com/foxyseta/nand-ide/blob/master/LICENSE) for further information.
+This software is based on Aviv Yaish's 'NAND IDE'. Please check [here](https://github.com/AvivYaish/nand-ide/blob/master/LICENSE) for further information.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/lib/computer/testing/fixtures/hack/Max.asm b/src/lib/computer/testing/fixtures/hack/Max.asm
new file mode 100644
index 0000000..b62c138
--- /dev/null
+++ b/src/lib/computer/testing/fixtures/hack/Max.asm
@@ -0,0 +1,26 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/06/max/Max.asm
+
+// Computes R2 = max(R0, R1) (R0,R1,R2 refer to RAM[0],RAM[1],RAM[2])
+
+ @R0
+ D=M // D = first number
+ @R1
+ D=D-M // D = first number - second number
+ @OUTPUT_FIRST
+ D;JGT // if D>0 (first is greater) goto output_first
+ @R1
+ D=M // D = second number
+ @OUTPUT_D
+ 0;JMP // goto output_d
+(OUTPUT_FIRST)
+ @R0
+ D=M // D = first number
+(OUTPUT_D)
+ @R2
+ M=D // M[2] = D (greatest number)
+(INFINITE_LOOP)
+ @INFINITE_LOOP
+ 0;JMP // infinite loop
diff --git a/src/lib/computer/testing/fixtures/hack/MaxL.asm b/src/lib/computer/testing/fixtures/hack/MaxL.asm
new file mode 100644
index 0000000..fc3ccbf
--- /dev/null
+++ b/src/lib/computer/testing/fixtures/hack/MaxL.asm
@@ -0,0 +1,23 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/06/max/MaxL.asm
+
+// Symbol-less version of the Max.asm program.
+
+@0
+D=M
+@1
+D=D-M
+@10
+D;JGT
+@1
+D=M
+@12
+0;JMP
+@0
+D=M
+@2
+M=D
+@14
+0;JMP
diff --git a/src/lib/computer/testing/fixtures/hack/Pong.asm b/src/lib/computer/testing/fixtures/hack/Pong.asm
new file mode 100644
index 0000000..641474d
--- /dev/null
+++ b/src/lib/computer/testing/fixtures/hack/Pong.asm
@@ -0,0 +1,28375 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/06/pong/Pong.asm
+
+// The Pong game program was originally written in the high-level Jack language.
+// The Jack code was then translated by the Jack compiler into VM code.
+// The VM code was then translated by the VM translator into the Hack
+// assembly code shown here.
+
+@256
+D=A
+@SP
+M=D
+@133
+0;JMP
+@R15
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+D=M-D
+M=0
+@END_EQ
+D;JNE
+@SP
+A=M-1
+M=-1
+(END_EQ)
+@R15
+A=M
+0;JMP
+@R15
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+D=M-D
+M=0
+@END_GT
+D;JLE
+@SP
+A=M-1
+M=-1
+(END_GT)
+@R15
+A=M
+0;JMP
+@R15
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+D=M-D
+M=0
+@END_LT
+D;JGE
+@SP
+A=M-1
+M=-1
+(END_LT)
+@R15
+A=M
+0;JMP
+@5
+D=A
+@LCL
+A=M-D
+D=M
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@ARG
+A=M
+M=D
+D=A
+@SP
+M=D+1
+@LCL
+D=M
+@R14
+AM=D-1
+D=M
+@THAT
+M=D
+@R14
+AM=M-1
+D=M
+@THIS
+M=D
+@R14
+AM=M-1
+D=M
+@ARG
+M=D
+@R14
+AM=M-1
+D=M
+@LCL
+M=D
+@R13
+A=M
+0;JMP
+@SP
+A=M
+M=D
+@LCL
+D=M
+@SP
+AM=M+1
+M=D
+@ARG
+D=M
+@SP
+AM=M+1
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+M=D
+@THAT
+D=M
+@SP
+AM=M+1
+M=D
+@4
+D=A
+@R13
+D=D+M
+@SP
+D=M-D
+@ARG
+M=D
+@SP
+DM=M+1
+@LCL
+M=D
+@R14
+A=M
+0;JMP
+@0
+D=A
+@R13
+M=D
+@sys.init
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL0
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL0)
+(ball.new)
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@memory.alloc
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL1
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL1)
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@10
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@THIS
+D=M
+@11
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@ARG
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@12
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@ARG
+D=M
+@5
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@THIS
+D=M
+@13
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@THIS
+D=M
+@14
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ball.show
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL2
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL2)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(ball.dispose)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@memory.dealloc
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL3
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL3)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(ball.show)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@1
+D=A
+@R13
+M=D
+@screen.setcolor
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL4
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL4)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ball.draw
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL5
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL5)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(ball.hide)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@1
+D=A
+@R13
+M=D
+@screen.setcolor
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL6
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL6)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ball.draw
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL7
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL7)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(ball.draw)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@5
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@5
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@R13
+M=D
+@screen.drawrectangle
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL8
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL8)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(ball.getleft)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(ball.getright)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@5
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@54
+0;JMP
+(ball.setdestination)
+@3
+D=A
+(LOOP_ball.setdestination)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_ball.setdestination
+D;JGT
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@math.abs
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL9
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL9)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@THIS
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@math.abs
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL10
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL10)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT0
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT0)
+@THIS
+D=M
+@7
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@THIS
+D=M
+@7
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ball.setdestination$if_true0
+D;JNE
+@ball.setdestination$if_false0
+0;JMP
+(ball.setdestination$if_true0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT1
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT1)
+@THIS
+D=M
+@8
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT2
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT2)
+@THIS
+D=M
+@9
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@ball.setdestination$if_end0
+0;JMP
+(ball.setdestination$if_false0)
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT3
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT3)
+@THIS
+D=M
+@8
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT4
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT4)
+@THIS
+D=M
+@9
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+(ball.setdestination$if_end0)
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL11
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL11)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL12
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL12)
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL13
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL13)
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(ball.move)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ball.hide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL14
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL14)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT5
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT5)
+@SP
+AM=M-1
+D=M
+@ball.move$if_true0
+D;JNE
+@ball.move$if_false0
+0;JMP
+(ball.move$if_true0)
+@THIS
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@5
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@ball.move$if_end0
+0;JMP
+(ball.move$if_false0)
+@THIS
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@THIS
+D=M
+@9
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ball.move$if_true1
+D;JNE
+@ball.move$if_false1
+0;JMP
+(ball.move$if_true1)
+@THIS
+D=M
+@7
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ball.move$if_true2
+D;JNE
+@ball.move$if_false2
+0;JMP
+(ball.move$if_true2)
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+@ball.move$if_end2
+0;JMP
+(ball.move$if_false2)
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+M=D
+(ball.move$if_end2)
+@ball.move$if_end1
+0;JMP
+(ball.move$if_false1)
+@THIS
+D=M
+@7
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ball.move$if_true3
+D;JNE
+@ball.move$if_false3
+0;JMP
+(ball.move$if_true3)
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+@ball.move$if_end3
+0;JMP
+(ball.move$if_false3)
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+M=D
+(ball.move$if_end3)
+(ball.move$if_end1)
+(ball.move$if_end0)
+@THIS
+D=M
+@8
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ball.move$if_true4
+D;JNE
+@ball.move$if_false4
+0;JMP
+(ball.move$if_true4)
+@THIS
+D=M
+@7
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ball.move$if_true5
+D;JNE
+@ball.move$if_false5
+0;JMP
+(ball.move$if_true5)
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+M=D
+@ball.move$if_end5
+0;JMP
+(ball.move$if_false5)
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+(ball.move$if_end5)
+@ball.move$if_end4
+0;JMP
+(ball.move$if_false4)
+@THIS
+D=M
+@7
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ball.move$if_true6
+D;JNE
+@ball.move$if_false6
+0;JMP
+(ball.move$if_true6)
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+M=D
+@ball.move$if_end6
+0;JMP
+(ball.move$if_false6)
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+(ball.move$if_end6)
+(ball.move$if_end4)
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@10
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT0
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT0)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@ball.move$if_true7
+D;JNE
+@ball.move$if_false7
+0;JMP
+(ball.move$if_true7)
+@SP
+M=M+1
+A=M-1
+M=1
+@THIS
+D=M
+@14
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@THIS
+D=M
+@10
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+(ball.move$if_false7)
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@11
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT6
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT6)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@ball.move$if_true8
+D;JNE
+@ball.move$if_false8
+0;JMP
+(ball.move$if_true8)
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@14
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@THIS
+D=M
+@11
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+(ball.move$if_false8)
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@12
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT1
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT1)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@ball.move$if_true9
+D;JNE
+@ball.move$if_false9
+0;JMP
+(ball.move$if_true9)
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@14
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@THIS
+D=M
+@12
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+M=D
+(ball.move$if_false9)
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@13
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT7
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT7)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@ball.move$if_true10
+D;JNE
+@ball.move$if_false10
+0;JMP
+(ball.move$if_true10)
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@14
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@THIS
+D=M
+@13
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+M=D
+(ball.move$if_false10)
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ball.show
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL15
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL15)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@14
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(ball.bounce)
+@5
+D=A
+(LOOP_ball.bounce)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_ball.bounce
+D;JGT
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL16
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL16)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@THIS
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL17
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL17)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ0
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ0)
+@SP
+AM=M-1
+D=M
+@ball.bounce$if_true0
+D;JNE
+@ball.bounce$if_false0
+0;JMP
+(ball.bounce$if_true0)
+@10
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@ball.bounce$if_end0
+0;JMP
+(ball.bounce$if_false0)
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT8
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT8)
+@SP
+A=M-1
+M=!M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@RET_ADDRESS_EQ1
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ1)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT9
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT9)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+A=M-1
+D=!M
+M=D+1
+@RET_ADDRESS_EQ2
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ2)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+AM=M-1
+D=M
+@ball.bounce$if_true1
+D;JNE
+@ball.bounce$if_false1
+0;JMP
+(ball.bounce$if_true1)
+@20
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@ball.bounce$if_end1
+0;JMP
+(ball.bounce$if_false1)
+@5
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+(ball.bounce$if_end1)
+(ball.bounce$if_end0)
+@THIS
+D=M
+@14
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@RET_ADDRESS_EQ3
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ3)
+@SP
+AM=M-1
+D=M
+@ball.bounce$if_true2
+D;JNE
+@ball.bounce$if_false2
+0;JMP
+(ball.bounce$if_true2)
+@506
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@50
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+D=!M
+M=D+1
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL18
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL18)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL19
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL19)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL20
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL20)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@ball.bounce$if_end2
+0;JMP
+(ball.bounce$if_false2)
+@THIS
+D=M
+@14
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ4
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ4)
+@SP
+AM=M-1
+D=M
+@ball.bounce$if_true3
+D;JNE
+@ball.bounce$if_false3
+0;JMP
+(ball.bounce$if_true3)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@50
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL21
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL21)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL22
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL22)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL23
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL23)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@ball.bounce$if_end3
+0;JMP
+(ball.bounce$if_false3)
+@THIS
+D=M
+@14
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ5
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ5)
+@SP
+AM=M-1
+D=M
+@ball.bounce$if_true4
+D;JNE
+@ball.bounce$if_false4
+0;JMP
+(ball.bounce$if_true4)
+@250
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@25
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+D=!M
+M=D+1
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL24
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL24)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL25
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL25)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL26
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL26)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@ball.bounce$if_end4
+0;JMP
+(ball.bounce$if_false4)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@25
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL27
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL27)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL28
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL28)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL29
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL29)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(ball.bounce$if_end4)
+(ball.bounce$if_end3)
+(ball.bounce$if_end2)
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@R13
+M=D
+@ball.setdestination
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL30
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL30)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(bat.new)
+@5
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@memory.alloc
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL31
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL31)
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@bat.show
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL32
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL32)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(bat.dispose)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@memory.dealloc
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL33
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL33)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(bat.show)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@1
+D=A
+@R13
+M=D
+@screen.setcolor
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL34
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL34)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@bat.draw
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL35
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL35)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(bat.hide)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@1
+D=A
+@R13
+M=D
+@screen.setcolor
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL36
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL36)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@bat.draw
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL37
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL37)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(bat.draw)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@R13
+M=D
+@screen.drawrectangle
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL38
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL38)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(bat.setdirection)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(bat.getleft)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(bat.getright)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@54
+0;JMP
+(bat.setwidth)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@bat.hide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL39
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL39)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@bat.show
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL40
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL40)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(bat.move)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@RET_ADDRESS_EQ6
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ6)
+@SP
+AM=M-1
+D=M
+@bat.move$if_true0
+D;JNE
+@bat.move$if_false0
+0;JMP
+(bat.move$if_true0)
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT10
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT10)
+@SP
+AM=M-1
+D=M
+@bat.move$if_true1
+D;JNE
+@bat.move$if_false1
+0;JMP
+(bat.move$if_true1)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+(bat.move$if_false1)
+@SP
+M=M+1
+A=M-1
+M=0
+@1
+D=A
+@R13
+M=D
+@screen.setcolor
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL41
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL41)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@R13
+M=D
+@screen.drawrectangle
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL42
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL42)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@1
+D=A
+@R13
+M=D
+@screen.setcolor
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL43
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL43)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@R13
+M=D
+@screen.drawrectangle
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL44
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL44)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@bat.move$if_end0
+0;JMP
+(bat.move$if_false0)
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@511
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT2
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT2)
+@SP
+AM=M-1
+D=M
+@bat.move$if_true2
+D;JNE
+@bat.move$if_false2
+0;JMP
+(bat.move$if_true2)
+@511
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+(bat.move$if_false2)
+@SP
+M=M+1
+A=M-1
+M=0
+@1
+D=A
+@R13
+M=D
+@screen.setcolor
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL45
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL45)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@R13
+M=D
+@screen.drawrectangle
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL46
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL46)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@1
+D=A
+@R13
+M=D
+@screen.setcolor
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL47
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL47)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@R13
+M=D
+@screen.drawrectangle
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL48
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL48)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(bat.move$if_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(main.main)
+@SP
+AM=M+1
+A=A-1
+M=0
+@0
+D=A
+@R13
+M=D
+@ponggame.newinstance
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL49
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL49)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@0
+D=A
+@R13
+M=D
+@ponggame.getinstance
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL50
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL50)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ponggame.run
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL51
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL51)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ponggame.dispose
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL52
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL52)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(ponggame.new)
+@7
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@memory.alloc
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL53
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL53)
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@0
+D=A
+@R13
+M=D
+@screen.clearscreen
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL54
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL54)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@50
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@230
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@229
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@7
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@R13
+M=D
+@bat.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL55
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL55)
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+@253
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@222
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@511
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@229
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@R13
+M=D
+@ball.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL56
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL56)
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@400
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@3
+D=A
+@R13
+M=D
+@ball.setdestination
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL57
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL57)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@238
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@511
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@240
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@R13
+M=D
+@screen.drawrectangle
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL58
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL58)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@22
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@2
+D=A
+@R13
+M=D
+@output.movecursor
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL59
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL59)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@8
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@string.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL60
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL60)
+@83
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL61
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL61)
+@99
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL62
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL62)
+@111
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL63
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL63)
+@114
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL64
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL64)
+@101
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL65
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL65)
+@58
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL66
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL66)
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL67
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL67)
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL68
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL68)
+@1
+D=A
+@R13
+M=D
+@output.printstring
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL69
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL69)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(ponggame.dispose)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@bat.dispose
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL70
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL70)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ball.dispose
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL71
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL71)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@memory.dealloc
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL72
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL72)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(ponggame.newinstance)
+@0
+D=A
+@R13
+M=D
+@ponggame.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL73
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL73)
+@SP
+AM=M-1
+D=M
+@ponggame.0
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(ponggame.getinstance)
+@ponggame.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(ponggame.run)
+@SP
+AM=M+1
+A=A-1
+M=0
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+(ponggame.run$while_exp0)
+@THIS
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@ponggame.run$while_end0
+D;JNE
+(ponggame.run$while_exp1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ7
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ7)
+@THIS
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@ponggame.run$while_end1
+D;JNE
+@0
+D=A
+@R13
+M=D
+@keyboard.keypressed
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL74
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL74)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@bat.move
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL75
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL75)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ponggame.moveball
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL76
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL76)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@ponggame.run$while_exp1
+0;JMP
+(ponggame.run$while_end1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@130
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ8
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ8)
+@SP
+AM=M-1
+D=M
+@ponggame.run$if_true0
+D;JNE
+@ponggame.run$if_false0
+0;JMP
+(ponggame.run$if_true0)
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@2
+D=A
+@R13
+M=D
+@bat.setdirection
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL77
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL77)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@ponggame.run$if_end0
+0;JMP
+(ponggame.run$if_false0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@132
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ9
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ9)
+@SP
+AM=M-1
+D=M
+@ponggame.run$if_true1
+D;JNE
+@ponggame.run$if_false1
+0;JMP
+(ponggame.run$if_true1)
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@bat.setdirection
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL78
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL78)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@ponggame.run$if_end1
+0;JMP
+(ponggame.run$if_false1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@140
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ10
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ10)
+@SP
+AM=M-1
+D=M
+@ponggame.run$if_true2
+D;JNE
+@ponggame.run$if_false2
+0;JMP
+(ponggame.run$if_true2)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+M=D
+(ponggame.run$if_false2)
+(ponggame.run$if_end1)
+(ponggame.run$if_end0)
+(ponggame.run$while_exp2)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ11
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ11)
+@SP
+A=M-1
+M=!M
+@THIS
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@ponggame.run$while_end2
+D;JNE
+@0
+D=A
+@R13
+M=D
+@keyboard.keypressed
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL79
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL79)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@bat.move
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL80
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL80)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ponggame.moveball
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL81
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL81)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@ponggame.run$while_exp2
+0;JMP
+(ponggame.run$while_end2)
+@ponggame.run$while_exp0
+0;JMP
+(ponggame.run$while_end0)
+@THIS
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ponggame.run$if_true3
+D;JNE
+@ponggame.run$if_false3
+0;JMP
+(ponggame.run$if_true3)
+@10
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@output.movecursor
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL82
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL82)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@9
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@string.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL83
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL83)
+@71
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL84
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL84)
+@97
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL85
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL85)
+@109
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL86
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL86)
+@101
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL87
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL87)
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL88
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL88)
+@79
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL89
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL89)
+@118
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL90
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL90)
+@101
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL91
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL91)
+@114
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL92
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL92)
+@1
+D=A
+@R13
+M=D
+@output.printstring
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL93
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL93)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(ponggame.run$if_false3)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(ponggame.moveball)
+@5
+D=A
+(LOOP_ponggame.moveball)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_ponggame.moveball
+D;JGT
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ball.move
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL94
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL94)
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT3
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT3)
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@5
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ12
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ12)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+AM=M-1
+D=M
+@ponggame.moveball$if_true0
+D;JNE
+@ponggame.moveball$if_false0
+0;JMP
+(ponggame.moveball$if_true0)
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@bat.getleft
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL95
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL95)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@bat.getright
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL96
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL96)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ball.getleft
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL97
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL97)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@ball.getright
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL98
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL98)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ13
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ13)
+@SP
+AM=M-1
+D=M
+@ponggame.moveball$if_true1
+D;JNE
+@ponggame.moveball$if_false1
+0;JMP
+(ponggame.moveball$if_true1)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT4
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT4)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT11
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT11)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+M=D
+@THIS
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@ponggame.moveball$if_true2
+D;JNE
+@ponggame.moveball$if_false2
+0;JMP
+(ponggame.moveball$if_true2)
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@RET_ADDRESS_LT12
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT12)
+@SP
+AM=M-1
+D=M
+@ponggame.moveball$if_true3
+D;JNE
+@ponggame.moveball$if_false3
+0;JMP
+(ponggame.moveball$if_true3)
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+A=M-1
+D=!M
+M=D+1
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@ponggame.moveball$if_end3
+0;JMP
+(ponggame.moveball$if_false3)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@RET_ADDRESS_GT5
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT5)
+@SP
+AM=M-1
+D=M
+@ponggame.moveball$if_true4
+D;JNE
+@ponggame.moveball$if_false4
+0;JMP
+(ponggame.moveball$if_true4)
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(ponggame.moveball$if_false4)
+(ponggame.moveball$if_end3)
+@THIS
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@bat.setwidth
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL99
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL99)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@22
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@7
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@output.movecursor
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL100
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL100)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@THIS
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@output.printint
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL101
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL101)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(ponggame.moveball$if_false2)
+(ponggame.moveball$if_false1)
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@ball.bounce
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL102
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL102)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(ponggame.moveball$if_false0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(array.new)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT6
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT6)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@array.new$if_true0
+D;JNE
+@array.new$if_false0
+0;JMP
+(array.new$if_true0)
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL103
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL103)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(array.new$if_false0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@memory.alloc
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL104
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL104)
+@54
+0;JMP
+(array.dispose)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@memory.dealloc
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL105
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL105)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(keyboard.init)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(keyboard.keypressed)
+@24576
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@memory.peek
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL106
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL106)
+@54
+0;JMP
+(keyboard.readchar)
+@SP
+A=M
+M=0
+AD=A+1
+M=0
+@SP
+M=D+1
+@SP
+M=M+1
+A=M-1
+M=0
+@1
+D=A
+@R13
+M=D
+@output.printchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL107
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL107)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(keyboard.readchar$while_exp0)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ14
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ14)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT7
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT7)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@keyboard.readchar$while_end0
+D;JNE
+@0
+D=A
+@R13
+M=D
+@keyboard.keypressed
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL108
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL108)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT8
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT8)
+@SP
+AM=M-1
+D=M
+@keyboard.readchar$if_true0
+D;JNE
+@keyboard.readchar$if_false0
+0;JMP
+(keyboard.readchar$if_true0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+(keyboard.readchar$if_false0)
+@keyboard.readchar$while_exp0
+0;JMP
+(keyboard.readchar$while_end0)
+@0
+D=A
+@R13
+M=D
+@string.backspace
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL109
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL109)
+@1
+D=A
+@R13
+M=D
+@output.printchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL110
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL110)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@output.printchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL111
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL111)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(keyboard.readline)
+@5
+D=A
+(LOOP_keyboard.readline)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_keyboard.readline
+D;JGT
+@80
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@string.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL112
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL112)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@output.printstring
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL113
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL113)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@0
+D=A
+@R13
+M=D
+@string.newline
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL114
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL114)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@0
+D=A
+@R13
+M=D
+@string.backspace
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL115
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL115)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+(keyboard.readline$while_exp0)
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@keyboard.readline$while_end0
+D;JNE
+@0
+D=A
+@R13
+M=D
+@keyboard.readchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL116
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL116)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ15
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ15)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@keyboard.readline$if_true0
+D;JNE
+@keyboard.readline$if_false0
+0;JMP
+(keyboard.readline$if_true0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ16
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ16)
+@SP
+AM=M-1
+D=M
+@keyboard.readline$if_true1
+D;JNE
+@keyboard.readline$if_false1
+0;JMP
+(keyboard.readline$if_true1)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@string.eraselastchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL117
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL117)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@keyboard.readline$if_end1
+0;JMP
+(keyboard.readline$if_false1)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL118
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL118)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+(keyboard.readline$if_end1)
+(keyboard.readline$if_false0)
+@keyboard.readline$while_exp0
+0;JMP
+(keyboard.readline$while_end0)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(keyboard.readint)
+@SP
+A=M
+M=0
+AD=A+1
+M=0
+@SP
+M=D+1
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@keyboard.readline
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL119
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL119)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@string.intvalue
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL120
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL120)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@string.dispose
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL121
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL121)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(math.init)
+@SP
+AM=M+1
+A=A-1
+M=0
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@array.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL122
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL122)
+@SP
+AM=M-1
+D=M
+@math.1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@array.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL123
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL123)
+@SP
+AM=M-1
+D=M
+@math.0
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@math.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+(math.init$while_exp0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT13
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT13)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@math.init$while_end0
+D;JNE
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@math.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@math.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@math.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@math.init$while_exp0
+0;JMP
+(math.init$while_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(math.abs)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT14
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT14)
+@SP
+AM=M-1
+D=M
+@math.abs$if_true0
+D;JNE
+@math.abs$if_false0
+0;JMP
+(math.abs$if_true0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+D=!M
+M=D+1
+@SP
+AM=M-1
+D=M
+@ARG
+A=M
+M=D
+(math.abs$if_false0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(math.multiply)
+@5
+D=A
+(LOOP_math.multiply)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_math.multiply
+D;JGT
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT15
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT15)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT9
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT9)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT10
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT10)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT16
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT16)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@math.abs
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL124
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL124)
+@SP
+AM=M-1
+D=M
+@ARG
+A=M
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@math.abs
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL125
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL125)
+@SP
+AM=M-1
+D=M
+@ARG
+A=M+1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT17
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT17)
+@SP
+AM=M-1
+D=M
+@math.multiply$if_true0
+D;JNE
+@math.multiply$if_false0
+0;JMP
+(math.multiply$if_true0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ARG
+A=M
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ARG
+A=M+1
+M=D
+(math.multiply$if_false0)
+(math.multiply$while_exp0)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT18
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT18)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@math.multiply$while_end0
+D;JNE
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@math.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT11
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT11)
+@SP
+AM=M-1
+D=M
+@math.multiply$if_true1
+D;JNE
+@math.multiply$if_false1
+0;JMP
+(math.multiply$if_true1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@math.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+(math.multiply$if_false1)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@ARG
+A=M
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@math.multiply$while_exp0
+0;JMP
+(math.multiply$while_end0)
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@math.multiply$if_true2
+D;JNE
+@math.multiply$if_false2
+0;JMP
+(math.multiply$if_true2)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+D=!M
+M=D+1
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(math.multiply$if_false2)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(math.divide)
+@4
+D=A
+(LOOP_math.divide)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_math.divide
+D;JGT
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ17
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ17)
+@SP
+AM=M-1
+D=M
+@math.divide$if_true0
+D;JNE
+@math.divide$if_false0
+0;JMP
+(math.divide$if_true0)
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL126
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL126)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(math.divide$if_false0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT19
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT19)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT12
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT12)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT13
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT13)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT20
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT20)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@math.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@math.abs
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL127
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL127)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@math.abs
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL128
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL128)
+@SP
+AM=M-1
+D=M
+@ARG
+A=M
+M=D
+(math.divide$while_exp0)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@math.divide$while_end0
+D;JNE
+@32767
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@math.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@math.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT21
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT21)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@math.divide$if_true1
+D;JNE
+@math.divide$if_false1
+0;JMP
+(math.divide$if_true1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@math.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@math.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@math.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@math.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT14
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT14)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@math.divide$if_true2
+D;JNE
+@math.divide$if_false2
+0;JMP
+(math.divide$if_true2)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(math.divide$if_false2)
+(math.divide$if_false1)
+@math.divide$while_exp0
+0;JMP
+(math.divide$while_end0)
+(math.divide$while_exp1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+A=M-1
+D=!M
+M=D+1
+@RET_ADDRESS_GT15
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT15)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@math.divide$while_end1
+D;JNE
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@math.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT16
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT16)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@math.divide$if_true3
+D;JNE
+@math.divide$if_false3
+0;JMP
+(math.divide$if_true3)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@math.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@math.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@ARG
+A=M
+M=D
+(math.divide$if_false3)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@math.divide$while_exp1
+0;JMP
+(math.divide$while_end1)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@math.divide$if_true4
+D;JNE
+@math.divide$if_false4
+0;JMP
+(math.divide$if_true4)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+D=!M
+M=D+1
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+(math.divide$if_false4)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(math.sqrt)
+@4
+D=A
+(LOOP_math.sqrt)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_math.sqrt
+D;JGT
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT22
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT22)
+@SP
+AM=M-1
+D=M
+@math.sqrt$if_true0
+D;JNE
+@math.sqrt$if_false0
+0;JMP
+(math.sqrt$if_true0)
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL129
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL129)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(math.sqrt$if_false0)
+@7
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(math.sqrt$while_exp0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+A=M-1
+D=!M
+M=D+1
+@RET_ADDRESS_GT17
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT17)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@math.sqrt$while_end0
+D;JNE
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@math.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL130
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL130)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT18
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT18)
+@SP
+A=M-1
+M=!M
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT23
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT23)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+AM=M-1
+D=M
+@math.sqrt$if_true1
+D;JNE
+@math.sqrt$if_false1
+0;JMP
+(math.sqrt$if_true1)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+(math.sqrt$if_false1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@math.sqrt$while_exp0
+0;JMP
+(math.sqrt$while_end0)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(math.max)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT19
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT19)
+@SP
+AM=M-1
+D=M
+@math.max$if_true0
+D;JNE
+@math.max$if_false0
+0;JMP
+(math.max$if_true0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ARG
+A=M+1
+M=D
+(math.max$if_false0)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(math.min)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT24
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT24)
+@SP
+AM=M-1
+D=M
+@math.min$if_true0
+D;JNE
+@math.min$if_false0
+0;JMP
+(math.min$if_true0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ARG
+A=M+1
+M=D
+(math.min$if_false0)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(memory.init)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@memory.0
+M=D
+@2048
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@memory.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@14334
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@2049
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@memory.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2050
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(memory.peek)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@memory.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(memory.poke)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@memory.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(memory.alloc)
+@SP
+AM=M+1
+A=A-1
+M=0
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@RET_ADDRESS_LT25
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT25)
+@SP
+AM=M-1
+D=M
+@memory.alloc$if_true0
+D;JNE
+@memory.alloc$if_false0
+0;JMP
+(memory.alloc$if_true0)
+@5
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL131
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL131)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(memory.alloc$if_false0)
+@2048
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(memory.alloc$while_exp0)
+@SP
+M=M+1
+A=M-1
+M=0
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT26
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT26)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@memory.alloc$while_end0
+D;JNE
+@SP
+M=M+1
+A=M-1
+M=1
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@memory.alloc$while_exp0
+0;JMP
+(memory.alloc$while_end0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@16379
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT20
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT20)
+@SP
+AM=M-1
+D=M
+@memory.alloc$if_true1
+D;JNE
+@memory.alloc$if_false1
+0;JMP
+(memory.alloc$if_true1)
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL132
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL132)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(memory.alloc$if_false1)
+@SP
+M=M+1
+A=M-1
+M=0
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@RET_ADDRESS_GT21
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT21)
+@SP
+AM=M-1
+D=M
+@memory.alloc$if_true2
+D;JNE
+@memory.alloc$if_false2
+0;JMP
+(memory.alloc$if_true2)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+M=M+1
+A=M-1
+M=0
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@RET_ADDRESS_EQ18
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ18)
+@SP
+AM=M-1
+D=M
+@memory.alloc$if_true3
+D;JNE
+@memory.alloc$if_false3
+0;JMP
+(memory.alloc$if_true3)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@memory.alloc$if_end3
+0;JMP
+(memory.alloc$if_false3)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+M=M+1
+A=M-1
+M=1
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+(memory.alloc$if_end3)
+@SP
+M=M+1
+A=M-1
+M=1
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+(memory.alloc$if_false2)
+@SP
+M=M+1
+A=M-1
+M=0
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@54
+0;JMP
+(memory.dealloc)
+@SP
+A=M
+M=0
+AD=A+1
+M=0
+@SP
+M=D+1
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ19
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ19)
+@SP
+AM=M-1
+D=M
+@memory.dealloc$if_true0
+D;JNE
+@memory.dealloc$if_false0
+0;JMP
+(memory.dealloc$if_true0)
+@SP
+M=M+1
+A=M-1
+M=0
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+M=M+1
+A=M-1
+M=1
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@memory.dealloc$if_end0
+0;JMP
+(memory.dealloc$if_false0)
+@SP
+M=M+1
+A=M-1
+M=0
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+M=M+1
+A=M-1
+M=1
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+M=M+1
+A=M-1
+M=0
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@RET_ADDRESS_EQ20
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ20)
+@SP
+AM=M-1
+D=M
+@memory.dealloc$if_true1
+D;JNE
+@memory.dealloc$if_false1
+0;JMP
+(memory.dealloc$if_true1)
+@SP
+M=M+1
+A=M-1
+M=1
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@memory.dealloc$if_end1
+0;JMP
+(memory.dealloc$if_false1)
+@SP
+M=M+1
+A=M-1
+M=1
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+M=M+1
+A=M-1
+M=1
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+(memory.dealloc$if_end1)
+(memory.dealloc$if_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(output.init)
+@16384
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@output.4
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@output.2
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@output.1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@output.0
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@string.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL133
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL133)
+@SP
+AM=M-1
+D=M
+@output.3
+M=D
+@0
+D=A
+@R13
+M=D
+@output.initmap
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL134
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL134)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@0
+D=A
+@R13
+M=D
+@output.createshiftedmap
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL135
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL135)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(output.initmap)
+@127
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@array.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL136
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL136)
+@SP
+AM=M-1
+D=M
+@output.5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL137
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL137)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL138
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL138)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@33
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL139
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL139)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@34
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@20
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL140
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL140)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@35
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@18
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL141
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL141)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@36
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL142
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL142)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@37
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@35
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@49
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL143
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL143)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@38
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL144
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL144)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@39
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL145
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL145)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@40
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL146
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL146)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@41
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL147
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL147)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@42
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL148
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL148)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@43
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL149
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL149)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@44
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL150
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL150)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@45
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL151
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL151)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@46
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL152
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL152)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@47
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL153
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL153)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL154
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL154)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@49
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@14
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL155
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL155)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@50
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL156
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL156)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL157
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL157)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@52
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@26
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@25
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@60
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL158
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL158)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@53
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL159
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL159)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL160
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL160)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@55
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@49
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL161
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL161)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@56
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL162
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL162)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@57
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@62
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@14
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL163
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL163)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@58
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL164
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL164)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@59
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL165
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL165)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@60
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL166
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL166)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@61
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL167
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL167)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@62
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL168
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL168)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@64
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL169
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL169)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL170
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL170)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@65
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL171
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL171)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@66
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL172
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL172)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@67
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL173
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL173)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@68
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL174
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL174)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@69
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@11
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@11
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL175
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL175)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@70
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@11
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@11
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL176
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL176)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@71
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@44
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL177
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL177)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@72
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL178
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL178)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@73
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL179
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL179)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@74
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@60
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@14
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL180
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL180)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@75
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL181
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL181)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@76
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL182
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL182)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@77
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@33
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL183
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL183)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@78
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@55
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@55
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL184
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL184)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@79
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL185
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL185)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@80
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL186
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL186)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@81
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL187
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL187)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@82
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL188
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL188)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@83
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL189
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL189)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@84
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@45
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL190
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL190)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@85
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL191
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL191)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@86
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL192
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL192)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@87
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL193
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL193)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@88
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL194
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL194)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@89
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL195
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL195)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@90
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@49
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL196
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL196)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@91
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL197
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL197)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@92
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=1
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL198
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL198)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@93
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL199
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL199)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@94
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@8
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL200
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL200)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@95
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL201
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL201)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@96
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL202
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL202)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@97
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@14
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL203
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL203)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@98
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL204
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL204)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@99
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL205
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL205)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@100
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@60
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL206
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL206)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@101
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL207
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL207)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@102
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@38
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL208
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL208)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@103
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@62
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL209
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL209)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@104
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@55
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL210
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL210)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@105
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@14
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL211
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL211)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@106
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@56
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL212
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL212)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@107
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL213
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL213)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@108
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@14
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL214
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL214)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@109
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@29
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@43
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@43
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@43
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@43
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL215
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL215)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@110
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@29
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL216
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL216)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@111
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL217
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL217)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@112
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL218
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL218)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@113
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@62
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL219
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL219)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@114
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@29
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@55
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@7
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL220
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL220)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@115
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL221
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL221)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@116
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL222
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL222)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@117
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL223
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL223)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@118
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL224
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL224)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@119
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL225
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL225)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@120
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL226
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL226)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@121
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@62
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL227
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL227)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@122
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL228
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL228)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@123
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@56
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@7
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@56
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL229
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL229)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@124
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL230
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL230)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@125
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@7
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@56
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@7
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL231
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL231)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@126
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@38
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@45
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@25
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@R13
+M=D
+@output.create
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL232
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL232)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(output.create)
+@SP
+AM=M+1
+A=A-1
+M=0
+@11
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@array.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL233
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL233)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@output.5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@4
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+D=M
+@5
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@5
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+D=M
+@7
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@7
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+D=M
+@8
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@8
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+D=M
+@9
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@9
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+D=M
+@10
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@10
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+D=M
+@11
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(output.createshiftedmap)
+@4
+D=A
+(LOOP_output.createshiftedmap)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_output.createshiftedmap
+D;JGT
+@127
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@array.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL234
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL234)
+@SP
+AM=M-1
+D=M
+@output.6
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+(output.createshiftedmap$while_exp0)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@127
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT27
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT27)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@output.createshiftedmap$while_end0
+D;JNE
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@output.5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@11
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@array.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL235
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL235)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@output.6
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+(output.createshiftedmap$while_exp1)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@11
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT28
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT28)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@output.createshiftedmap$while_end1
+D;JNE
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@256
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL236
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL236)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@output.createshiftedmap$while_exp1
+0;JMP
+(output.createshiftedmap$while_end1)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ21
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ21)
+@SP
+AM=M-1
+D=M
+@output.createshiftedmap$if_true0
+D;JNE
+@output.createshiftedmap$if_false0
+0;JMP
+(output.createshiftedmap$if_true0)
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@output.createshiftedmap$if_end0
+0;JMP
+(output.createshiftedmap$if_false0)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+(output.createshiftedmap$if_end0)
+@output.createshiftedmap$while_exp0
+0;JMP
+(output.createshiftedmap$while_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(output.getmap)
+@SP
+AM=M+1
+A=A-1
+M=0
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT29
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT29)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@126
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT22
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT22)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@output.getmap$if_true0
+D;JNE
+@output.getmap$if_false0
+0;JMP
+(output.getmap$if_true0)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@ARG
+A=M
+M=D
+(output.getmap$if_false0)
+@output.2
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@output.getmap$if_true1
+D;JNE
+@output.getmap$if_false1
+0;JMP
+(output.getmap$if_true1)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@output.5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@output.getmap$if_end1
+0;JMP
+(output.getmap$if_false1)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@output.6
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(output.getmap$if_end1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(output.drawchar)
+@4
+D=A
+(LOOP_output.drawchar)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_output.drawchar
+D;JGT
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@output.getmap
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL237
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL237)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@output.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(output.drawchar$while_exp0)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@11
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT30
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT30)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@output.drawchar$while_end0
+D;JNE
+@output.2
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@output.drawchar$if_true0
+D;JNE
+@output.drawchar$if_false0
+0;JMP
+(output.drawchar$if_true0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@output.4
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@256
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+D=!M
+M=D+1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@output.drawchar$if_end0
+0;JMP
+(output.drawchar$if_false0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@output.4
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@255
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+(output.drawchar$if_end0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@output.4
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@output.drawchar$while_exp0
+0;JMP
+(output.drawchar$while_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(output.movecursor)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT31
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT31)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@22
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT23
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT23)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT32
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT32)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT24
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT24)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@output.movecursor$if_true0
+D;JNE
+@output.movecursor$if_false0
+0;JMP
+(output.movecursor$if_true0)
+@20
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL238
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL238)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(output.movecursor$if_false0)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL239
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL239)
+@SP
+AM=M-1
+D=M
+@output.0
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@352
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL240
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL240)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@output.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@output.1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@output.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL241
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL241)
+@RET_ADDRESS_EQ22
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ22)
+@SP
+AM=M-1
+D=M
+@output.2
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@output.drawchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL242
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL242)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(output.printchar)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@0
+D=A
+@R13
+M=D
+@string.newline
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL243
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL243)
+@RET_ADDRESS_EQ23
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ23)
+@SP
+AM=M-1
+D=M
+@output.printchar$if_true0
+D;JNE
+@output.printchar$if_false0
+0;JMP
+(output.printchar$if_true0)
+@0
+D=A
+@R13
+M=D
+@output.println
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL244
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL244)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@output.printchar$if_end0
+0;JMP
+(output.printchar$if_false0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@0
+D=A
+@R13
+M=D
+@string.backspace
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL245
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL245)
+@RET_ADDRESS_EQ24
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ24)
+@SP
+AM=M-1
+D=M
+@output.printchar$if_true1
+D;JNE
+@output.printchar$if_false1
+0;JMP
+(output.printchar$if_true1)
+@0
+D=A
+@R13
+M=D
+@output.backspace
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL246
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL246)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@output.printchar$if_end1
+0;JMP
+(output.printchar$if_false1)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@output.drawchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL247
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL247)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@output.2
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@output.printchar$if_true2
+D;JNE
+@output.printchar$if_false2
+0;JMP
+(output.printchar$if_true2)
+@output.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@output.0
+M=D
+@output.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@output.1
+M=D
+(output.printchar$if_false2)
+@output.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ25
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ25)
+@SP
+AM=M-1
+D=M
+@output.printchar$if_true3
+D;JNE
+@output.printchar$if_false3
+0;JMP
+(output.printchar$if_true3)
+@0
+D=A
+@R13
+M=D
+@output.println
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL248
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL248)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@output.printchar$if_end3
+0;JMP
+(output.printchar$if_false3)
+@output.2
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@output.2
+M=D
+(output.printchar$if_end3)
+(output.printchar$if_end1)
+(output.printchar$if_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(output.printstring)
+@SP
+A=M
+M=0
+AD=A+1
+M=0
+@SP
+M=D+1
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@string.length
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL249
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL249)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+(output.printstring$while_exp0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT33
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT33)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@output.printstring$while_end0
+D;JNE
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.charat
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL250
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL250)
+@1
+D=A
+@R13
+M=D
+@output.printchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL251
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL251)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@output.printstring$while_exp0
+0;JMP
+(output.printstring$while_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(output.printint)
+@output.3
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.setint
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL252
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL252)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@output.3
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@output.printstring
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL253
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL253)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(output.println)
+@output.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@352
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@output.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@output.1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@output.0
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@output.2
+M=D
+@output.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@8128
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ26
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ26)
+@SP
+AM=M-1
+D=M
+@output.println$if_true0
+D;JNE
+@output.println$if_false0
+0;JMP
+(output.println$if_true0)
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@output.1
+M=D
+(output.println$if_false0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(output.backspace)
+@output.2
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@output.backspace$if_true0
+D;JNE
+@output.backspace$if_false0
+0;JMP
+(output.backspace$if_true0)
+@output.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT25
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT25)
+@SP
+AM=M-1
+D=M
+@output.backspace$if_true1
+D;JNE
+@output.backspace$if_false1
+0;JMP
+(output.backspace$if_true1)
+@output.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@output.0
+M=D
+@output.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@output.1
+M=D
+@output.backspace$if_end1
+0;JMP
+(output.backspace$if_false1)
+@31
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@output.0
+M=D
+@output.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ27
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ27)
+@SP
+AM=M-1
+D=M
+@output.backspace$if_true2
+D;JNE
+@output.backspace$if_false2
+0;JMP
+(output.backspace$if_true2)
+@8128
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@output.1
+M=D
+(output.backspace$if_false2)
+@output.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@321
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@output.1
+M=D
+(output.backspace$if_end1)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@output.2
+M=D
+@output.backspace$if_end0
+0;JMP
+(output.backspace$if_false0)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@output.2
+M=D
+(output.backspace$if_end0)
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@output.drawchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL254
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL254)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(screen.init)
+@SP
+AM=M+1
+A=A-1
+M=0
+@16384
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@screen.1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@screen.2
+M=D
+@17
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@array.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL255
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL255)
+@SP
+AM=M-1
+D=M
+@screen.0
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@screen.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+(screen.init$while_exp0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT34
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT34)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@screen.init$while_end0
+D;JNE
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@screen.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@screen.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@screen.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@screen.init$while_exp0
+0;JMP
+(screen.init$while_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(screen.clearscreen)
+@SP
+AM=M+1
+A=A-1
+M=0
+(screen.clearscreen$while_exp0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@8192
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT35
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT35)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@screen.clearscreen$while_end0
+D;JNE
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@screen.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@screen.clearscreen$while_exp0
+0;JMP
+(screen.clearscreen$while_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(screen.updatelocation)
+@screen.2
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@screen.updatelocation$if_true0
+D;JNE
+@screen.updatelocation$if_false0
+0;JMP
+(screen.updatelocation$if_true0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@screen.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@screen.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@screen.updatelocation$if_end0
+0;JMP
+(screen.updatelocation$if_false0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@screen.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@screen.1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+(screen.updatelocation$if_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(screen.setcolor)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@screen.2
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(screen.drawpixel)
+@3
+D=A
+(LOOP_screen.drawpixel)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_screen.drawpixel
+D;JGT
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT36
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT36)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@511
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT26
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT26)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT37
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT37)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@255
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT27
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT27)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@screen.drawpixel$if_true0
+D;JNE
+@screen.drawpixel$if_false0
+0;JMP
+(screen.drawpixel$if_true0)
+@7
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL256
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL256)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(screen.drawpixel$if_false0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL257
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL257)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL258
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL258)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL259
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL259)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@screen.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@screen.updatelocation
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL260
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL260)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(screen.drawconditional)
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@screen.drawconditional$if_true0
+D;JNE
+@screen.drawconditional$if_false0
+0;JMP
+(screen.drawconditional$if_true0)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@screen.drawpixel
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL261
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL261)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@screen.drawconditional$if_end0
+0;JMP
+(screen.drawconditional$if_false0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@screen.drawpixel
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL262
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL262)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(screen.drawconditional$if_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(screen.drawline)
+@11
+D=A
+(LOOP_screen.drawline)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_screen.drawline
+D;JGT
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT38
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT38)
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@511
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT28
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT28)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT39
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT39)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@255
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT29
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT29)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@screen.drawline$if_true0
+D;JNE
+@screen.drawline$if_false0
+0;JMP
+(screen.drawline$if_true0)
+@8
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL263
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL263)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(screen.drawline$if_false0)
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@1
+D=A
+@R13
+M=D
+@math.abs
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL264
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL264)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@1
+D=A
+@R13
+M=D
+@math.abs
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL265
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL265)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT40
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT40)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@LCL
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT41
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT41)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@LCL
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+M=!M
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT42
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT42)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@screen.drawline$if_true1
+D;JNE
+@screen.drawline$if_false1
+0;JMP
+(screen.drawline$if_true1)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ARG
+A=M
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ARG
+A=M+1
+A=A+1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ARG
+A=M+1
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ARG
+A=M+1
+A=A+1
+A=A+1
+M=D
+(screen.drawline$if_false1)
+@LCL
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@screen.drawline$if_true2
+D;JNE
+@screen.drawline$if_false2
+0;JMP
+(screen.drawline$if_true2)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@8
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT30
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT30)
+@LCL
+D=M
+@7
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@screen.drawline$if_end2
+0;JMP
+(screen.drawline$if_false2)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@8
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT31
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT31)
+@LCL
+D=M
+@7
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+(screen.drawline$if_end2)
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL266
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL266)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL267
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL267)
+@LCL
+D=M
+@9
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL268
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL268)
+@LCL
+D=M
+@10
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@R13
+M=D
+@screen.drawconditional
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL269
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL269)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(screen.drawline$while_exp0)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@8
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT43
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT43)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@screen.drawline$while_end0
+D;JNE
+@LCL
+D=M
+@5
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT44
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT44)
+@SP
+AM=M-1
+D=M
+@screen.drawline$if_true3
+D;JNE
+@screen.drawline$if_false3
+0;JMP
+(screen.drawline$if_true3)
+@LCL
+D=M
+@5
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@9
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@screen.drawline$if_end3
+0;JMP
+(screen.drawline$if_false3)
+@LCL
+D=M
+@5
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@10
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@LCL
+D=M
+@7
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@screen.drawline$if_true4
+D;JNE
+@screen.drawline$if_false4
+0;JMP
+(screen.drawline$if_true4)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@screen.drawline$if_end4
+0;JMP
+(screen.drawline$if_false4)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(screen.drawline$if_end4)
+(screen.drawline$if_end3)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@R13
+M=D
+@screen.drawconditional
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL270
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL270)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@screen.drawline$while_exp0
+0;JMP
+(screen.drawline$while_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(screen.drawrectangle)
+@9
+D=A
+(LOOP_screen.drawrectangle)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_screen.drawrectangle
+D;JGT
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT32
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT32)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT33
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT33)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT45
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT45)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@511
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT34
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT34)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT46
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT46)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@255
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT35
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT35)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@screen.drawrectangle$if_true0
+D;JNE
+@screen.drawrectangle$if_false0
+0;JMP
+(screen.drawrectangle$if_true0)
+@9
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL271
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL271)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(screen.drawrectangle$if_false0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL272
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL272)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL273
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL273)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@LCL
+D=M
+@7
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL274
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL274)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL275
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL275)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@LCL
+D=M
+@8
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@LCL
+D=M
+@7
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@screen.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@LCL
+D=M
+@8
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@screen.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL276
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL276)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+(screen.drawrectangle$while_exp0)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT36
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT36)
+@SP
+A=M-1
+M=!M
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@screen.drawrectangle$while_end0
+D;JNE
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ28
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ28)
+@SP
+AM=M-1
+D=M
+@screen.drawrectangle$if_true1
+D;JNE
+@screen.drawrectangle$if_false1
+0;JMP
+(screen.drawrectangle$if_true1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@5
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@2
+D=A
+@R13
+M=D
+@screen.updatelocation
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL277
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL277)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@screen.drawrectangle$if_end1
+0;JMP
+(screen.drawrectangle$if_false1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@screen.updatelocation
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL278
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL278)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(screen.drawrectangle$while_exp1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT47
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT47)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@screen.drawrectangle$while_end1
+D;JNE
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+A=M-1
+D=!M
+M=D+1
+@2
+D=A
+@R13
+M=D
+@screen.updatelocation
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL279
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL279)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@screen.drawrectangle$while_exp1
+0;JMP
+(screen.drawrectangle$while_end1)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@5
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@screen.updatelocation
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL280
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL280)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(screen.drawrectangle$if_end1)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@ARG
+A=M+1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@screen.drawrectangle$while_exp0
+0;JMP
+(screen.drawrectangle$while_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(screen.drawhorizontal)
+@11
+D=A
+(LOOP_screen.drawhorizontal)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_screen.drawhorizontal
+D;JGT
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.min
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL281
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL281)
+@LCL
+D=M
+@7
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.max
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL282
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL282)
+@LCL
+D=M
+@8
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+A=M-1
+D=!M
+M=D+1
+@RET_ADDRESS_GT37
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT37)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@256
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT48
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT48)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@LCL
+D=M
+@7
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@512
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT49
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT49)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@LCL
+D=M
+@8
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+A=M-1
+D=!M
+M=D+1
+@RET_ADDRESS_GT38
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT38)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+AM=M-1
+D=M
+@screen.drawhorizontal$if_true0
+D;JNE
+@screen.drawhorizontal$if_false0
+0;JMP
+(screen.drawhorizontal$if_true0)
+@LCL
+D=M
+@7
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@2
+D=A
+@R13
+M=D
+@math.max
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL283
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL283)
+@LCL
+D=M
+@7
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@LCL
+D=M
+@8
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@511
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.min
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL284
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL284)
+@LCL
+D=M
+@8
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@LCL
+D=M
+@7
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL285
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL285)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@LCL
+D=M
+@7
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL286
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL286)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@LCL
+D=M
+@9
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@LCL
+D=M
+@8
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL287
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL287)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@LCL
+D=M
+@8
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL288
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL288)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@LCL
+D=M
+@10
+D=D+A
+@R13
+M=D
+@SP
+AM=M-1
+D=M
+@R13
+A=M
+M=D
+@LCL
+D=M
+@9
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@screen.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@LCL
+D=M
+@10
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@screen.0
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL289
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL289)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@LCL
+D=M
+@6
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ29
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ29)
+@SP
+AM=M-1
+D=M
+@screen.drawhorizontal$if_true1
+D;JNE
+@screen.drawhorizontal$if_false1
+0;JMP
+(screen.drawhorizontal$if_true1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@5
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@2
+D=A
+@R13
+M=D
+@screen.updatelocation
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL290
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL290)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@screen.drawhorizontal$if_end1
+0;JMP
+(screen.drawhorizontal$if_false1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@5
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@screen.updatelocation
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL291
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL291)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(screen.drawhorizontal$while_exp0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT50
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT50)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@screen.drawhorizontal$while_end0
+D;JNE
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+A=M-1
+D=!M
+M=D+1
+@2
+D=A
+@R13
+M=D
+@screen.updatelocation
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL292
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL292)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@screen.drawhorizontal$while_exp0
+0;JMP
+(screen.drawhorizontal$while_end0)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@screen.updatelocation
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL293
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL293)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(screen.drawhorizontal$if_end1)
+(screen.drawhorizontal$if_false0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(screen.drawsymetric)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@3
+D=A
+@R13
+M=D
+@screen.drawhorizontal
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL294
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL294)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@3
+D=A
+@R13
+M=D
+@screen.drawhorizontal
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL295
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL295)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+D=A
+@R13
+M=D
+@screen.drawhorizontal
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL296
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL296)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+D=A
+@R13
+M=D
+@screen.drawhorizontal
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL297
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL297)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(screen.drawcircle)
+@3
+D=A
+(LOOP_screen.drawcircle)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_screen.drawcircle
+D;JGT
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT51
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT51)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@511
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT39
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT39)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT52
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT52)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@255
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT40
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT40)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@screen.drawcircle$if_true0
+D;JNE
+@screen.drawcircle$if_false0
+0;JMP
+(screen.drawcircle$if_true0)
+@12
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL298
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL298)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(screen.drawcircle$if_false0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT53
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT53)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@511
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT41
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT41)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT54
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT54)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@255
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT42
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT42)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@screen.drawcircle$if_true1
+D;JNE
+@screen.drawcircle$if_false1
+0;JMP
+(screen.drawcircle$if_true1)
+@13
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL299
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL299)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(screen.drawcircle$if_false1)
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@R13
+M=D
+@screen.drawsymetric
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL300
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL300)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(screen.drawcircle$while_exp0)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT43
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT43)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@screen.drawcircle$while_end0
+D;JNE
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT55
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT55)
+@SP
+AM=M-1
+D=M
+@screen.drawcircle$if_true2
+D;JNE
+@screen.drawcircle$if_false2
+0;JMP
+(screen.drawcircle$if_true2)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL301
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL301)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@screen.drawcircle$if_end2
+0;JMP
+(screen.drawcircle$if_false2)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL302
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL302)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@5
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+(screen.drawcircle$if_end2)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@R13
+M=D
+@screen.drawsymetric
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL303
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL303)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@screen.drawcircle$while_exp0
+0;JMP
+(screen.drawcircle$while_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(string.new)
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@memory.alloc
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL304
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL304)
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT56
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT56)
+@SP
+AM=M-1
+D=M
+@string.new$if_true0
+D;JNE
+@string.new$if_false0
+0;JMP
+(string.new$if_true0)
+@14
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL305
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL305)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(string.new$if_false0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT44
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT44)
+@SP
+AM=M-1
+D=M
+@string.new$if_true1
+D;JNE
+@string.new$if_false1
+0;JMP
+(string.new$if_true1)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@array.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL306
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL306)
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+M=D
+(string.new$if_false1)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(string.dispose)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT45
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT45)
+@SP
+AM=M-1
+D=M
+@string.dispose$if_true0
+D;JNE
+@string.dispose$if_false0
+0;JMP
+(string.dispose$if_true0)
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@array.dispose
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL307
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL307)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(string.dispose$if_false0)
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@memory.dealloc
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL308
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL308)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(string.length)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(string.charat)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT57
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT57)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT46
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT46)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ30
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ30)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@string.charat$if_true0
+D;JNE
+@string.charat$if_false0
+0;JMP
+(string.charat$if_true0)
+@15
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL309
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL309)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(string.charat$if_false0)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(string.setcharat)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT58
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT58)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT47
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT47)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ31
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ31)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+AM=M-1
+D=M
+@string.setcharat$if_true0
+D;JNE
+@string.setcharat$if_false0
+0;JMP
+(string.setcharat$if_true0)
+@16
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL310
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL310)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(string.setcharat$if_false0)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(string.appendchar)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ32
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ32)
+@SP
+AM=M-1
+D=M
+@string.appendchar$if_true0
+D;JNE
+@string.appendchar$if_false0
+0;JMP
+(string.appendchar$if_true0)
+@17
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL311
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL311)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(string.appendchar$if_false0)
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+M=D
+@THIS
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(string.eraselastchar)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ33
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ33)
+@SP
+AM=M-1
+D=M
+@string.eraselastchar$if_true0
+D;JNE
+@string.eraselastchar$if_false0
+0;JMP
+(string.eraselastchar$if_true0)
+@18
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL312
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL312)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(string.eraselastchar$if_false0)
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(string.intvalue)
+@5
+D=A
+(LOOP_string.intvalue)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_string.intvalue
+D;JGT
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ34
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ34)
+@SP
+AM=M-1
+D=M
+@string.intvalue$if_true0
+D;JNE
+@string.intvalue$if_false0
+0;JMP
+(string.intvalue$if_true0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(string.intvalue$if_false0)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@45
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_EQ35
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ35)
+@SP
+AM=M-1
+D=M
+@string.intvalue$if_true1
+D;JNE
+@string.intvalue$if_false1
+0;JMP
+(string.intvalue$if_true1)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(string.intvalue$if_false1)
+(string.intvalue$while_exp0)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT59
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT59)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@string.intvalue$while_end0
+D;JNE
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT60
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT60)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@9
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_GT48
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT48)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@string.intvalue$if_true2
+D;JNE
+@string.intvalue$if_false2
+0;JMP
+(string.intvalue$if_true2)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL313
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL313)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(string.intvalue$if_false2)
+@string.intvalue$while_exp0
+0;JMP
+(string.intvalue$while_end0)
+@LCL
+D=M
+@4
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@string.intvalue$if_true3
+D;JNE
+@string.intvalue$if_false3
+0;JMP
+(string.intvalue$if_true3)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+D=!M
+M=D+1
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+(string.intvalue$if_false3)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(string.setint)
+@4
+D=A
+(LOOP_string.setint)
+D=D-1
+@SP
+AM=M+1
+A=A-1
+M=0
+@LOOP_string.setint
+D;JGT
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THIS
+M=D
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ36
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ36)
+@SP
+AM=M-1
+D=M
+@string.setint$if_true0
+D;JNE
+@string.setint$if_false0
+0;JMP
+(string.setint$if_true0)
+@19
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL314
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL314)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(string.setint$if_false0)
+@6
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@array.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL315
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL315)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT61
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT61)
+@SP
+AM=M-1
+D=M
+@string.setint$if_true1
+D;JNE
+@string.setint$if_false1
+0;JMP
+(string.setint$if_true1)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+A=A+1
+A=A+1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+A=M-1
+D=!M
+M=D+1
+@SP
+AM=M-1
+D=M
+@ARG
+A=M+1
+M=D
+(string.setint$if_false1)
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+(string.setint$while_exp0)
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT49
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT49)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@string.setint$while_end0
+D;JNE
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.divide
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL316
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL316)
+@SP
+AM=M-1
+D=M
+@LCL
+A=M+1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@ARG
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@math.multiply
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL317
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL317)
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@LCL
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@ARG
+A=M+1
+M=D
+@string.setint$while_exp0
+0;JMP
+(string.setint$while_end0)
+@LCL
+D=M
+@3
+A=D+A
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@string.setint$if_true2
+D;JNE
+@string.setint$if_false2
+0;JMP
+(string.setint$if_true2)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@45
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(string.setint$if_false2)
+@THIS
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT62
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT62)
+@SP
+AM=M-1
+D=M
+@string.setint$if_true3
+D;JNE
+@string.setint$if_false3
+0;JMP
+(string.setint$if_true3)
+@19
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL318
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL318)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(string.setint$if_false3)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_EQ37
+D=A
+@6
+0;JMP
+(RET_ADDRESS_EQ37)
+@SP
+AM=M-1
+D=M
+@string.setint$if_true4
+D;JNE
+@string.setint$if_false4
+0;JMP
+(string.setint$if_true4)
+@SP
+M=M+1
+A=M-1
+M=0
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@48
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+M=D
+@string.setint$if_end4
+0;JMP
+(string.setint$if_false4)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+M=D
+(string.setint$while_exp1)
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@RET_ADDRESS_LT63
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT63)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@string.setint$while_end1
+D;JNE
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@THAT
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+M=D
+@R5
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@THAT
+A=M
+M=D
+@THIS
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@SP
+AM=M-1
+D=M
+@THIS
+A=M+1
+A=A+1
+M=D
+@string.setint$while_exp1
+0;JMP
+(string.setint$while_end1)
+(string.setint$if_end4)
+@LCL
+A=M+1
+A=A+1
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@array.dispose
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL319
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL319)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(string.newline)
+@128
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(string.backspace)
+@129
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(string.doublequote)
+@34
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+(sys.init)
+@0
+D=A
+@R13
+M=D
+@memory.init
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL320
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL320)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@0
+D=A
+@R13
+M=D
+@math.init
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL321
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL321)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@0
+D=A
+@R13
+M=D
+@screen.init
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL322
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL322)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@0
+D=A
+@R13
+M=D
+@output.init
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL323
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL323)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@0
+D=A
+@R13
+M=D
+@keyboard.init
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL324
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL324)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@0
+D=A
+@R13
+M=D
+@main.main
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL325
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL325)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@0
+D=A
+@R13
+M=D
+@sys.halt
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL326
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL326)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(sys.halt)
+(sys.halt$while_exp0)
+@SP
+M=M+1
+A=M-1
+M=0
+@SP
+A=M-1
+M=!M
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@sys.halt$while_end0
+D;JNE
+@sys.halt$while_exp0
+0;JMP
+(sys.halt$while_end0)
+(sys.wait)
+@SP
+AM=M+1
+A=A-1
+M=0
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_LT64
+D=A
+@38
+0;JMP
+(RET_ADDRESS_LT64)
+@SP
+AM=M-1
+D=M
+@sys.wait$if_true0
+D;JNE
+@sys.wait$if_false0
+0;JMP
+(sys.wait$if_true0)
+@SP
+M=M+1
+A=M-1
+M=1
+@1
+D=A
+@R13
+M=D
+@sys.error
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL327
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL327)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+(sys.wait$if_false0)
+(sys.wait$while_exp0)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT50
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT50)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@sys.wait$while_end0
+D;JNE
+@50
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+(sys.wait$while_exp1)
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=0
+@RET_ADDRESS_GT51
+D=A
+@22
+0;JMP
+(RET_ADDRESS_GT51)
+@SP
+A=M-1
+M=!M
+@SP
+AM=M-1
+D=M
+@sys.wait$while_end1
+D;JNE
+@LCL
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@LCL
+A=M
+M=D
+@sys.wait$while_exp1
+0;JMP
+(sys.wait$while_end1)
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@SP
+M=M+1
+A=M-1
+M=1
+@SP
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@SP
+AM=M-1
+D=M
+@ARG
+A=M
+M=D
+@sys.wait$while_exp0
+0;JMP
+(sys.wait$while_end0)
+@SP
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+(sys.error)
+@3
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@string.new
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL328
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL328)
+@69
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL329
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL329)
+@82
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL330
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL330)
+@82
+D=A
+@SP
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@R13
+M=D
+@string.appendchar
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL331
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL331)
+@1
+D=A
+@R13
+M=D
+@output.printstring
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL332
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL332)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@ARG
+A=M
+D=M
+@SP
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@R13
+M=D
+@output.printint
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL333
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL333)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
+@0
+D=A
+@R13
+M=D
+@sys.halt
+D=A
+@R14
+M=D
+@RET_ADDRESS_CALL334
+D=A
+@95
+0;JMP
+(RET_ADDRESS_CALL334)
+@SP
+AM=M-1
+D=M
+@R5
+M=D
diff --git a/src/lib/computer/testing/fixtures/hack/PongL.asm b/src/lib/computer/testing/fixtures/hack/PongL.asm
new file mode 100644
index 0000000..e7e4e58
--- /dev/null
+++ b/src/lib/computer/testing/fixtures/hack/PongL.asm
@@ -0,0 +1,27490 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/06/pong/PongL.asm
+
+// Symbol-less version of the Pong.asm program.
+
+@256
+D=A
+@0
+M=D
+@133
+0;JMP
+@15
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+D=M-D
+M=0
+@19
+D;JNE
+@0
+A=M-1
+M=-1
+@15
+A=M
+0;JMP
+@15
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+D=M-D
+M=0
+@35
+D;JLE
+@0
+A=M-1
+M=-1
+@15
+A=M
+0;JMP
+@15
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+D=M-D
+M=0
+@51
+D;JGE
+@0
+A=M-1
+M=-1
+@15
+A=M
+0;JMP
+@5
+D=A
+@1
+A=M-D
+D=M
+@13
+M=D
+@0
+AM=M-1
+D=M
+@2
+A=M
+M=D
+D=A
+@0
+M=D+1
+@1
+D=M
+@14
+AM=D-1
+D=M
+@4
+M=D
+@14
+AM=M-1
+D=M
+@3
+M=D
+@14
+AM=M-1
+D=M
+@2
+M=D
+@14
+AM=M-1
+D=M
+@1
+M=D
+@13
+A=M
+0;JMP
+@0
+A=M
+M=D
+@1
+D=M
+@0
+AM=M+1
+M=D
+@2
+D=M
+@0
+AM=M+1
+M=D
+@3
+D=M
+@0
+AM=M+1
+M=D
+@4
+D=M
+@0
+AM=M+1
+M=D
+@4
+D=A
+@13
+D=D+M
+@0
+D=M-D
+@2
+M=D
+@0
+DM=M+1
+@1
+M=D
+@14
+A=M
+0;JMP
+@0
+D=A
+@13
+M=D
+@27058
+D=A
+@14
+M=D
+@145
+D=A
+@95
+0;JMP
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@8643
+D=A
+@14
+M=D
+@163
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@3
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@10
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@3
+D=M
+@11
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@2
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@12
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@2
+D=M
+@5
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@3
+D=M
+@13
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@3
+D=M
+@14
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@387
+D=A
+@14
+M=D
+@333
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@9357
+D=A
+@14
+M=D
+@376
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@1
+D=A
+@13
+M=D
+@20889
+D=A
+@14
+M=D
+@418
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@514
+D=A
+@14
+M=D
+@441
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@1
+D=A
+@13
+M=D
+@20889
+D=A
+@14
+M=D
+@480
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@514
+D=A
+@14
+M=D
+@503
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@5
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@5
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@13
+M=D
+@22354
+D=A
+@14
+M=D
+@588
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@5
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@54
+0;JMP
+@3
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@654
+D;JGT
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@6774
+D=A
+@14
+M=D
+@747
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@3
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@6774
+D=A
+@14
+M=D
+@774
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@798
+D=A
+@38
+0;JMP
+@3
+D=M
+@7
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@3
+D=M
+@7
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@826
+D;JNE
+@930
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@886
+D=A
+@38
+0;JMP
+@3
+D=M
+@8
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@916
+D=A
+@38
+0;JMP
+@3
+D=M
+@9
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@991
+0;JMP
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@948
+D=A
+@38
+0;JMP
+@3
+D=M
+@8
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@979
+D=A
+@38
+0;JMP
+@3
+D=M
+@9
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@1016
+D=A
+@95
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@1062
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@1109
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@452
+D=A
+@14
+M=D
+@1156
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@1178
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@1185
+D;JNE
+@1219
+0;JMP
+@3
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@5
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@1401
+0;JMP
+@3
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@3
+D=M
+@9
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1267
+D;JNE
+@1335
+0;JMP
+@3
+D=M
+@7
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1283
+D;JNE
+@1309
+0;JMP
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@1333
+0;JMP
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+M=D
+@1401
+0;JMP
+@3
+D=M
+@7
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1351
+D;JNE
+@1377
+0;JMP
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@1401
+0;JMP
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+M=D
+@3
+D=M
+@8
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1417
+D;JNE
+@1485
+0;JMP
+@3
+D=M
+@7
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1433
+D;JNE
+@1459
+0;JMP
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+M=D
+@1483
+0;JMP
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@1551
+0;JMP
+@3
+D=M
+@7
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1501
+D;JNE
+@1527
+0;JMP
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+M=D
+@1551
+0;JMP
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@10
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1571
+D=A
+@22
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@1581
+D;JNE
+@1612
+0;JMP
+@0
+M=M+1
+A=M-1
+M=1
+@3
+D=M
+@14
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@3
+D=M
+@10
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@11
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1632
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@1642
+D;JNE
+@1675
+0;JMP
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@14
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@3
+D=M
+@11
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@12
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1695
+D=A
+@22
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@1705
+D;JNE
+@1738
+0;JMP
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@14
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@3
+D=M
+@12
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@13
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1758
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@1768
+D;JNE
+@1801
+0;JMP
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@14
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@3
+D=M
+@13
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@387
+D=A
+@14
+M=D
+@1819
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@14
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@5
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@1837
+D;JGT
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@1882
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@3
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@1916
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@1939
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@1946
+D;JNE
+@1963
+0;JMP
+@10
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2086
+0;JMP
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@1979
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@1997
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@2018
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+A=M-1
+D=!M
+M=D+1
+@2042
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+AM=M-1
+D=M
+@2054
+D;JNE
+@2071
+0;JMP
+@20
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2086
+0;JMP
+@5
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@3
+D=M
+@14
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@2103
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@2110
+D;JNE
+@2227
+0;JMP
+@506
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@50
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+D=!M
+M=D+1
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@2153
+D=A
+@95
+0;JMP
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@2173
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@2214
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@2616
+0;JMP
+@3
+D=M
+@14
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2246
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@2253
+D;JNE
+@2364
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@50
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@2290
+D=A
+@95
+0;JMP
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@2310
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@2351
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@2616
+0;JMP
+@3
+D=M
+@14
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2383
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@2390
+D;JNE
+@2507
+0;JMP
+@250
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@25
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+D=!M
+M=D+1
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@2432
+D=A
+@95
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@2453
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@2494
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@2616
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@25
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@2543
+D=A
+@95
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@2564
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@2605
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@13
+M=D
+@652
+D=A
+@14
+M=D
+@2648
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@5
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@8643
+D=A
+@14
+M=D
+@2677
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@3
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@2827
+D=A
+@14
+M=D
+@2773
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@9357
+D=A
+@14
+M=D
+@2816
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@1
+D=A
+@13
+M=D
+@20889
+D=A
+@14
+M=D
+@2858
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@2954
+D=A
+@14
+M=D
+@2881
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@1
+D=A
+@13
+M=D
+@20889
+D=A
+@14
+M=D
+@2920
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@2954
+D=A
+@14
+M=D
+@2943
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@13
+M=D
+@22354
+D=A
+@14
+M=D
+@3033
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@2892
+D=A
+@14
+M=D
+@3163
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@2827
+D=A
+@14
+M=D
+@3200
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@3240
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@3247
+D;JNE
+@3525
+0;JMP
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@3286
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@3293
+D;JNE
+@3303
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@1
+D=A
+@13
+M=D
+@20889
+D=A
+@14
+M=D
+@3319
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@13
+M=D
+@22354
+D=A
+@14
+M=D
+@3424
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@1
+D=A
+@13
+M=D
+@20889
+D=A
+@14
+M=D
+@3448
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@13
+M=D
+@22354
+D=A
+@14
+M=D
+@3518
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3831
+0;JMP
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@511
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3579
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+@3586
+D;JNE
+@3611
+0;JMP
+@511
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@1
+D=A
+@13
+M=D
+@20889
+D=A
+@14
+M=D
+@3627
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@13
+M=D
+@22354
+D=A
+@14
+M=D
+@3706
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@1
+D=A
+@13
+M=D
+@20889
+D=A
+@14
+M=D
+@3730
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@13
+M=D
+@22354
+D=A
+@14
+M=D
+@3826
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@0
+AM=M+1
+A=A-1
+M=0
+@0
+D=A
+@13
+M=D
+@4508
+D=A
+@14
+M=D
+@3853
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+D=A
+@13
+M=D
+@4531
+D=A
+@14
+M=D
+@3870
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@4539
+D=A
+@14
+M=D
+@3895
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@4419
+D=A
+@14
+M=D
+@3919
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@7
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@8643
+D=A
+@14
+M=D
+@3948
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@3
+M=D
+@0
+D=A
+@13
+M=D
+@20598
+D=A
+@14
+M=D
+@3965
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@50
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@230
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@229
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@7
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@13
+M=D
+@2659
+D=A
+@14
+M=D
+@4026
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@253
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@222
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@511
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@229
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@13
+M=D
+@145
+D=A
+@14
+M=D
+@4076
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@400
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@3
+D=A
+@13
+M=D
+@652
+D=A
+@14
+M=D
+@4111
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@238
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@511
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@240
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@13
+M=D
+@22354
+D=A
+@14
+M=D
+@4150
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@22
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@2
+D=A
+@13
+M=D
+@19350
+D=A
+@14
+M=D
+@4177
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@8
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@25105
+D=A
+@14
+M=D
+@4200
+D=A
+@95
+0;JMP
+@83
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@4218
+D=A
+@95
+0;JMP
+@99
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@4236
+D=A
+@95
+0;JMP
+@111
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@4254
+D=A
+@95
+0;JMP
+@114
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@4272
+D=A
+@95
+0;JMP
+@101
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@4290
+D=A
+@95
+0;JMP
+@58
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@4308
+D=A
+@95
+0;JMP
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@4326
+D=A
+@95
+0;JMP
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@4344
+D=A
+@95
+0;JMP
+@1
+D=A
+@13
+M=D
+@19850
+D=A
+@14
+M=D
+@4356
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@2786
+D=A
+@14
+M=D
+@4450
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@346
+D=A
+@14
+M=D
+@4474
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@9357
+D=A
+@14
+M=D
+@4497
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@0
+D=A
+@13
+M=D
+@3930
+D=A
+@14
+M=D
+@4520
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@16
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@16
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@0
+AM=M+1
+A=A-1
+M=0
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@4943
+D;JNE
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@4590
+D=A
+@6
+0;JMP
+@3
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@4682
+D;JNE
+@0
+D=A
+@13
+M=D
+@5924
+D=A
+@14
+M=D
+@4627
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@3211
+D=A
+@14
+M=D
+@4652
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5191
+D=A
+@14
+M=D
+@4675
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@4575
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@130
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@4699
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@4706
+D;JNE
+@4736
+0;JMP
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@2
+D=A
+@13
+M=D
+@3044
+D=A
+@14
+M=D
+@4729
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@4831
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@132
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@4753
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@4760
+D;JNE
+@4792
+0;JMP
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@3044
+D=A
+@14
+M=D
+@4785
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@4831
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@140
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@4809
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@4816
+D;JNE
+@4831
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@4846
+D=A
+@6
+0;JMP
+@0
+A=M-1
+M=!M
+@3
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@4941
+D;JNE
+@0
+D=A
+@13
+M=D
+@5924
+D=A
+@14
+M=D
+@4886
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@3211
+D=A
+@14
+M=D
+@4911
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5191
+D=A
+@14
+M=D
+@4934
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@4831
+0;JMP
+@4555
+0;JMP
+@3
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4959
+D;JNE
+@5185
+0;JMP
+@10
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@19350
+D=A
+@14
+M=D
+@4983
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@9
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@25105
+D=A
+@14
+M=D
+@5006
+D=A
+@95
+0;JMP
+@71
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@5024
+D=A
+@95
+0;JMP
+@97
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@5042
+D=A
+@95
+0;JMP
+@109
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@5060
+D=A
+@95
+0;JMP
+@101
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@5078
+D=A
+@95
+0;JMP
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@5096
+D=A
+@95
+0;JMP
+@79
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@5114
+D=A
+@95
+0;JMP
+@118
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@5132
+D=A
+@95
+0;JMP
+@101
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@5150
+D=A
+@95
+0;JMP
+@114
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@5168
+D=A
+@95
+0;JMP
+@1
+D=A
+@13
+M=D
+@19850
+D=A
+@14
+M=D
+@5180
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@5
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@5193
+D;JGT
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@1126
+D=A
+@14
+M=D
+@5231
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@5254
+D=A
+@22
+0;JMP
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@5
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@5275
+D=A
+@6
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+AM=M-1
+D=M
+@5290
+D;JNE
+@5802
+0;JMP
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@3078
+D=A
+@14
+M=D
+@5337
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@3099
+D=A
+@14
+M=D
+@5362
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@599
+D=A
+@14
+M=D
+@5388
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@620
+D=A
+@14
+M=D
+@5415
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@5442
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@5449
+D;JNE
+@5771
+0;JMP
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@5469
+D=A
+@22
+0;JMP
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@5490
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+M=D
+@3
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@5522
+D;JNE
+@5771
+0;JMP
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@5553
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@5560
+D;JNE
+@5576
+0;JMP
+@0
+M=M+1
+A=M-1
+M=1
+@0
+A=M-1
+D=!M
+M=D+1
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@5625
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@5608
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+@5615
+D;JNE
+@5625
+0;JMP
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@3
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@3133
+D=A
+@14
+M=D
+@5684
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@22
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@7
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@19350
+D=A
+@14
+M=D
+@5740
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@19981
+D=A
+@14
+M=D
+@5766
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@1835
+D=A
+@14
+M=D
+@5797
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@5823
+D=A
+@22
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@5833
+D;JNE
+@5856
+0;JMP
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@5851
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@8643
+D=A
+@14
+M=D
+@5875
+D=A
+@95
+0;JMP
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@9357
+D=A
+@14
+M=D
+@5907
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@24576
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@8558
+D=A
+@14
+M=D
+@5942
+D=A
+@95
+0;JMP
+@54
+0;JMP
+@0
+A=M
+M=0
+AD=A+1
+M=0
+@0
+M=D+1
+@0
+M=M+1
+A=M-1
+M=0
+@1
+D=A
+@13
+M=D
+@19610
+D=A
+@14
+M=D
+@5967
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@5987
+D=A
+@6
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@6002
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@6070
+D;JNE
+@0
+D=A
+@13
+M=D
+@5924
+D=A
+@14
+M=D
+@6027
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@6048
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+@6055
+D;JNE
+@6068
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@5972
+0;JMP
+@0
+D=A
+@13
+M=D
+@27042
+D=A
+@14
+M=D
+@6082
+D=A
+@95
+0;JMP
+@1
+D=A
+@13
+M=D
+@19610
+D=A
+@14
+M=D
+@6094
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@19610
+D=A
+@14
+M=D
+@6118
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@5
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@6134
+D;JGT
+@80
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@25105
+D=A
+@14
+M=D
+@6159
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@19850
+D=A
+@14
+M=D
+@6186
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+D=A
+@13
+M=D
+@27034
+D=A
+@14
+M=D
+@6203
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@0
+D=A
+@13
+M=D
+@27042
+D=A
+@14
+M=D
+@6221
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@6404
+D;JNE
+@0
+D=A
+@13
+M=D
+@5944
+D=A
+@14
+M=D
+@6260
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@6284
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@6312
+D;JNE
+@6402
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@6331
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@6338
+D;JNE
+@6366
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@25801
+D=A
+@14
+M=D
+@6359
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@6402
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@6394
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@6228
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@0
+A=M
+M=0
+AD=A+1
+M=0
+@0
+M=D+1
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@6132
+D=A
+@14
+M=D
+@6441
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@25889
+D=A
+@14
+M=D
+@6466
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@25252
+D=A
+@14
+M=D
+@6491
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@0
+AM=M+1
+A=A-1
+M=0
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5808
+D=A
+@14
+M=D
+@6527
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@17
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5808
+D=A
+@14
+M=D
+@6550
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@18
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@18
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6613
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@6768
+D;JNE
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@18
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@18
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@18
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@6596
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@6789
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@6796
+D;JNE
+@6813
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+D=!M
+M=D+1
+@0
+AM=M-1
+D=M
+@2
+A=M
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@5
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@6824
+D;JGT
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@6846
+D=A
+@38
+0;JMP
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@6861
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@6881
+D=A
+@22
+0;JMP
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@6896
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@6774
+D=A
+@14
+M=D
+@6934
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@2
+A=M
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@6774
+D=A
+@14
+M=D
+@6959
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@2
+A=M+1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@6983
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@6990
+D;JNE
+@7029
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@2
+A=M
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@2
+A=M+1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@7048
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@7245
+D;JNE
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@18
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+M=M+1
+A=M-1
+M=0
+@7108
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+@7115
+D;JNE
+@7192
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@18
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@2
+A=M
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@7029
+0;JMP
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@7261
+D;JNE
+@7278
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+D=!M
+M=D+1
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@4
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@7289
+D;JGT
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@7311
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@7318
+D;JNE
+@7341
+0;JMP
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@7336
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@7356
+D=A
+@38
+0;JMP
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@7371
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@7391
+D=A
+@22
+0;JMP
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@7406
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@17
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@6774
+D=A
+@14
+M=D
+@7457
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@6774
+D=A
+@14
+M=D
+@7498
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@2
+A=M
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@7841
+D;JNE
+@32767
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@17
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@17
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@7599
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@7626
+D;JNE
+@7839
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@17
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@17
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@17
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@17
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@7790
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@7817
+D;JNE
+@7839
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@7504
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+A=M-1
+D=!M
+M=D+1
+@7860
+D=A
+@22
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@8039
+D;JNE
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@17
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@7909
+D=A
+@22
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@7919
+D;JNE
+@8015
+0;JMP
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@18
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@17
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@2
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@7841
+0;JMP
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@8054
+D;JNE
+@8071
+0;JMP
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+D=!M
+M=D+1
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@4
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@8082
+D;JGT
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@8104
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@8111
+D;JNE
+@8134
+0;JMP
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@8129
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@7
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+A=M-1
+D=!M
+M=D+1
+@8165
+D=A
+@22
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@8348
+D;JNE
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@18
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@8249
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@8275
+D=A
+@22
+0;JMP
+@0
+A=M-1
+M=!M
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@8294
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+AM=M-1
+D=M
+@8309
+D;JNE
+@8324
+0;JMP
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@8146
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@8377
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+@8384
+D;JNE
+@8397
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@2
+A=M+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@8424
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@8431
+D;JNE
+@8444
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@2
+A=M+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@19
+M=D
+@2048
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@19
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@14334
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@2049
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@19
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2050
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@19
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@19
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@0
+AM=M+1
+A=A-1
+M=0
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@8662
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@8669
+D;JNE
+@8692
+0;JMP
+@5
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@8687
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2048
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@8743
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@8787
+D;JNE
+@0
+M=M+1
+A=M-1
+M=1
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@8704
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@16379
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@8816
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+@8823
+D;JNE
+@8846
+0;JMP
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@8841
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@8896
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+@8903
+D;JNE
+@9295
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+M=M+1
+A=M-1
+M=0
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@9056
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@9063
+D;JNE
+@9147
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@9227
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+M=M+1
+A=M-1
+M=1
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@54
+0;JMP
+@0
+A=M
+M=0
+AD=A+1
+M=0
+@0
+M=D+1
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@9458
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@9465
+D;JNE
+@9556
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+M=M+1
+A=M-1
+M=1
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@9848
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+M=M+1
+A=M-1
+M=1
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+M=M+1
+A=M-1
+M=0
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@9717
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@9724
+D;JNE
+@9782
+0;JMP
+@0
+M=M+1
+A=M-1
+M=1
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@9848
+0;JMP
+@0
+M=M+1
+A=M-1
+M=1
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+M=M+1
+A=M-1
+M=1
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@16384
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@20
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@21
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@22
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@23
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@25105
+D=A
+@14
+M=D
+@9915
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@24
+M=D
+@0
+D=A
+@13
+M=D
+@9960
+D=A
+@14
+M=D
+@9932
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+D=A
+@13
+M=D
+@18456
+D=A
+@14
+M=D
+@9949
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@127
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5808
+D=A
+@14
+M=D
+@9978
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@25
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@10061
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@10128
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@33
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@10211
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@34
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@20
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@10284
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@35
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@18
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@10367
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@36
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@10454
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@37
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@35
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@49
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@10535
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@38
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@10620
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@39
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@10693
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@40
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@10778
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@41
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@10863
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@42
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@10940
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@43
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11017
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@44
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11090
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@45
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11159
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@46
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11230
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@47
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11309
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11394
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@49
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@14
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11479
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@50
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11564
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11649
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@52
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@26
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@25
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@60
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11734
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@53
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11819
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11904
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@55
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@49
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@11989
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@56
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@12074
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@57
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@62
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@14
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@12159
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@58
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@12234
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@59
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@12311
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@60
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@12392
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@61
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@12463
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@62
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@12544
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@64
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@12629
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@12712
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@65
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@12797
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@66
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@12882
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@67
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@12967
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@68
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@13052
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@69
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@11
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@11
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@13137
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@70
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@11
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@11
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@13222
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@71
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@44
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@13307
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@72
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@13392
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@73
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@13477
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@74
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@60
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@14
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@13562
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@75
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@13647
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@76
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@13732
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@77
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@33
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@13817
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@78
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@55
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@55
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@13902
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@79
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@13987
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@80
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@14072
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@81
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@59
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@14159
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@82
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@14244
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@83
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@14329
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@84
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@45
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@14414
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@85
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@14499
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@86
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@14584
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@87
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@14669
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@88
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@14754
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@89
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@14839
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@90
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@49
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@35
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@14924
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@91
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15009
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@92
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=1
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15088
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@93
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15173
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@94
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@8
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15246
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@95
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15315
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@96
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15388
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@97
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@14
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15467
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@98
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15552
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@99
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15631
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@100
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@60
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15716
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@101
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15795
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@102
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@38
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15880
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@103
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@62
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@15963
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@104
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@55
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@16048
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@105
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@14
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@16131
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@106
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@56
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@16216
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@107
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@16301
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@108
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@14
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@16386
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@109
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@29
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@43
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@43
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@43
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@43
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@16465
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@110
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@29
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@16544
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@111
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@16623
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@112
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@31
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@16704
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@113
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@62
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@16785
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@114
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@29
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@55
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@7
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@16864
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@115
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@16943
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@116
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@28
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@17028
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@117
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@17107
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@118
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@17186
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@119
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@18
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@17265
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@120
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@30
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@17344
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@121
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@62
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@17425
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@122
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@51
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@17504
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@123
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@56
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@7
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@56
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@17589
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@124
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@17674
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@125
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@7
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@56
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@7
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@17759
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@126
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@38
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@45
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@25
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@0
+M=M+1
+A=M-1
+M=0
+@12
+D=A
+@13
+M=D
+@17843
+D=A
+@14
+M=D
+@17832
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@0
+AM=M+1
+A=A-1
+M=0
+@11
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5808
+D=A
+@14
+M=D
+@17865
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@25
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@4
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+D=M
+@5
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@5
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+D=M
+@7
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@7
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+D=M
+@8
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@8
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+D=M
+@9
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@9
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+D=M
+@10
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@10
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+D=M
+@11
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@4
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@18458
+D;JGT
+@127
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5808
+D=A
+@14
+M=D
+@18483
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@26
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@127
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@18517
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@18859
+D;JNE
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@25
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@11
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5808
+D=A
+@14
+M=D
+@18580
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@26
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@11
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@18665
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@18795
+D;JNE
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@256
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@18745
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@18646
+0;JMP
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@18811
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@18818
+D;JNE
+@18833
+0;JMP
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@18857
+0;JMP
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@18499
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@0
+AM=M+1
+A=A-1
+M=0
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@18886
+D=A
+@38
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@126
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@18903
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@18915
+D;JNE
+@18925
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@2
+A=M
+M=D
+@21
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@18938
+D;JNE
+@18976
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@25
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@19012
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@26
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@4
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@19023
+D;JGT
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@18865
+D=A
+@14
+M=D
+@19049
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@22
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@11
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@19085
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@19344
+D;JNE
+@21
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@19106
+D;JNE
+@19161
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@20
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@256
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+D=!M
+M=D+1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@19210
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@20
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@255
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@20
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@19068
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@19365
+D=A
+@38
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@22
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@19382
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@19402
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@63
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@19424
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@19436
+D;JNE
+@19459
+0;JMP
+@20
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@19454
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@19484
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@23
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@352
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@19520
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@23
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@22
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@23
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@19572
+D=A
+@95
+0;JMP
+@19576
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@21
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@19021
+D=A
+@14
+M=D
+@19599
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+D=A
+@13
+M=D
+@27034
+D=A
+@14
+M=D
+@19629
+D=A
+@95
+0;JMP
+@19633
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@19640
+D;JNE
+@19659
+0;JMP
+@0
+D=A
+@13
+M=D
+@20040
+D=A
+@14
+M=D
+@19652
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@19844
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+D=A
+@13
+M=D
+@27042
+D=A
+@14
+M=D
+@19678
+D=A
+@95
+0;JMP
+@19682
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@19689
+D;JNE
+@19708
+0;JMP
+@0
+D=A
+@13
+M=D
+@20134
+D=A
+@14
+M=D
+@19701
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@19844
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@19021
+D=A
+@14
+M=D
+@19727
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@21
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@19748
+D;JNE
+@19788
+0;JMP
+@23
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@23
+M=D
+@22
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@22
+M=D
+@23
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@19804
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@19811
+D;JNE
+@19830
+0;JMP
+@0
+D=A
+@13
+M=D
+@20040
+D=A
+@14
+M=D
+@19823
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@19844
+0;JMP
+@21
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@21
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@0
+A=M
+M=0
+AD=A+1
+M=0
+@0
+M=D+1
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@25339
+D=A
+@14
+M=D
+@19876
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@19900
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@19975
+D;JNE
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25361
+D=A
+@14
+M=D
+@19934
+D=A
+@95
+0;JMP
+@1
+D=A
+@13
+M=D
+@19610
+D=A
+@14
+M=D
+@19946
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@19882
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@24
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@26291
+D=A
+@14
+M=D
+@20006
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@24
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@19850
+D=A
+@14
+M=D
+@20029
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@22
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@352
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@23
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@22
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@23
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@21
+M=D
+@22
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@8128
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@20110
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@20117
+D;JNE
+@20128
+0;JMP
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@22
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@21
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@20147
+D;JNE
+@20288
+0;JMP
+@23
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@20161
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+@20168
+D;JNE
+@20210
+0;JMP
+@23
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@23
+M=D
+@22
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@22
+M=D
+@20277
+0;JMP
+@31
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@23
+M=D
+@22
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@20237
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@20244
+D;JNE
+@20255
+0;JMP
+@8128
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@22
+M=D
+@22
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@321
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@22
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@21
+M=D
+@20300
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@21
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@19021
+D=A
+@14
+M=D
+@20318
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@0
+AM=M+1
+A=A-1
+M=0
+@16384
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@27
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@28
+M=D
+@17
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5808
+D=A
+@14
+M=D
+@20374
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@29
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@29
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@20437
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@20592
+D;JNE
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@29
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@29
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@29
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@20420
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@0
+AM=M+1
+A=A-1
+M=0
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@8192
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@20619
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@20695
+D;JNE
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@20602
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@28
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@20714
+D;JNE
+@20798
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@20883
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@27
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@28
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@3
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@20909
+D;JGT
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@20931
+D=A
+@38
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@511
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@20948
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@20968
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@255
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@20990
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@21002
+D;JNE
+@21025
+0;JMP
+@7
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@21020
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@21050
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@21088
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@21124
+D=A
+@95
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@29
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@20701
+D=A
+@14
+M=D
+@21193
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@21219
+D;JNE
+@21252
+0;JMP
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@20907
+D=A
+@14
+M=D
+@21245
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@21283
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@20907
+D=A
+@14
+M=D
+@21278
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@11
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@21291
+D;JGT
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@21313
+D=A
+@38
+0;JMP
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@511
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@21331
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@21351
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@255
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@21375
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@21387
+D;JNE
+@21410
+0;JMP
+@8
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@21405
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@1
+D=A
+@13
+M=D
+@6774
+D=A
+@14
+M=D
+@21442
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@1
+D=A
+@13
+M=D
+@6774
+D=A
+@14
+M=D
+@21483
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@21511
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@1
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@21551
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@1
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+M=!M
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@21587
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@21604
+D;JNE
+@21698
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@2
+A=M
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@2
+A=M+1
+A=A+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@2
+A=M+1
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@2
+A=M+1
+A=A+1
+A=A+1
+M=D
+@1
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@21714
+D;JNE
+@21844
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@8
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@21830
+D=A
+@22
+0;JMP
+@1
+D=M
+@7
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@21922
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@8
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@21910
+D=A
+@22
+0;JMP
+@1
+D=M
+@7
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@21948
+D=A
+@95
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@21998
+D=A
+@95
+0;JMP
+@1
+D=M
+@9
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@22050
+D=A
+@95
+0;JMP
+@1
+D=M
+@10
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@13
+M=D
+@21204
+D=A
+@14
+M=D
+@22097
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@8
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@22122
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@22348
+D;JNE
+@1
+D=M
+@5
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@22147
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@22154
+D;JNE
+@22189
+0;JMP
+@1
+D=M
+@5
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@9
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@22284
+0;JMP
+@1
+D=M
+@5
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@10
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@1
+D=M
+@7
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@22238
+D;JNE
+@22262
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@22284
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+D=A
+@13
+M=D
+@21204
+D=A
+@14
+M=D
+@22341
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@22102
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@9
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@22356
+D;JGT
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@22382
+D=A
+@22
+0;JMP
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@22402
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@22422
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@511
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@22445
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@22465
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@255
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@22489
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@22501
+D;JNE
+@22524
+0;JMP
+@9
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@22519
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@22549
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@22591
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@1
+D=M
+@7
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@22634
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@22678
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@1
+D=M
+@8
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@1
+D=M
+@7
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@29
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@1
+D=M
+@8
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@29
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@22835
+D=A
+@95
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@22905
+D=A
+@22
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@23245
+D;JNE
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@22958
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@22965
+D;JNE
+@23014
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@5
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@2
+D=A
+@13
+M=D
+@20701
+D=A
+@14
+M=D
+@23007
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@23184
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@20701
+D=A
+@14
+M=D
+@23042
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@23087
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@23151
+D;JNE
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+A=M-1
+D=!M
+M=D+1
+@2
+D=A
+@13
+M=D
+@20701
+D=A
+@14
+M=D
+@23122
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@23069
+0;JMP
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@5
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@20701
+D=A
+@14
+M=D
+@23179
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@2
+A=M+1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@22885
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@11
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@23253
+D;JGT
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@8406
+D=A
+@14
+M=D
+@23287
+D=A
+@95
+0;JMP
+@1
+D=M
+@7
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@8359
+D=A
+@14
+M=D
+@23326
+D=A
+@95
+0;JMP
+@1
+D=M
+@8
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+A=M-1
+D=!M
+M=D+1
+@23357
+D=A
+@22
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@256
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@23374
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@1
+D=M
+@7
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@512
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@23398
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@1
+D=M
+@8
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+A=M-1
+D=!M
+M=D+1
+@23424
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+AM=M-1
+D=M
+@23436
+D;JNE
+@24145
+0;JMP
+@1
+D=M
+@7
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@2
+D=A
+@13
+M=D
+@8359
+D=A
+@14
+M=D
+@23461
+D=A
+@95
+0;JMP
+@1
+D=M
+@7
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@1
+D=M
+@8
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@511
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@8406
+D=A
+@14
+M=D
+@23500
+D=A
+@95
+0;JMP
+@1
+D=M
+@8
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@1
+D=M
+@7
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@23539
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+D=M
+@7
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@23579
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@1
+D=M
+@9
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@1
+D=M
+@8
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@23623
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@1
+D=M
+@8
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@23665
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@1
+D=M
+@10
+D=D+A
+@13
+M=D
+@0
+AM=M-1
+D=M
+@13
+A=M
+M=D
+@1
+D=M
+@9
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@29
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@1
+D=M
+@10
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@29
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@32
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@23820
+D=A
+@95
+0;JMP
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@1
+D=M
+@6
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@23915
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@23922
+D;JNE
+@23971
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@5
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@2
+D=A
+@13
+M=D
+@20701
+D=A
+@14
+M=D
+@23964
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@24145
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@5
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@20701
+D=A
+@14
+M=D
+@23999
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@24046
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@24110
+D;JNE
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+A=M-1
+D=!M
+M=D+1
+@2
+D=A
+@13
+M=D
+@20701
+D=A
+@14
+M=D
+@24081
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@24026
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@20701
+D=A
+@14
+M=D
+@24140
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@3
+D=A
+@13
+M=D
+@23251
+D=A
+@14
+M=D
+@24224
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@3
+D=A
+@13
+M=D
+@23251
+D=A
+@14
+M=D
+@24302
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+D=A
+@13
+M=D
+@23251
+D=A
+@14
+M=D
+@24381
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+D=A
+@13
+M=D
+@23251
+D=A
+@14
+M=D
+@24460
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@3
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@24473
+D;JGT
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@24495
+D=A
+@38
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@511
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24512
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@24532
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@255
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24554
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@24566
+D;JNE
+@24589
+0;JMP
+@12
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@24584
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+M=M+1
+A=M-1
+M=0
+@24617
+D=A
+@38
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@511
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24647
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+M=M+1
+A=M-1
+M=0
+@24680
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@255
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@24715
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@24727
+D;JNE
+@24750
+0;JMP
+@13
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@24745
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@13
+M=D
+@24151
+D=A
+@14
+M=D
+@24828
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@24851
+D=A
+@22
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@25099
+D;JNE
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@24875
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@24882
+D;JNE
+@24940
+0;JMP
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@24915
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@25030
+0;JMP
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@24985
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@5
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@4
+D=A
+@13
+M=D
+@24151
+D=A
+@14
+M=D
+@25092
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@24833
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@8643
+D=A
+@14
+M=D
+@25123
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@3
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@25143
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@25150
+D;JNE
+@25173
+0;JMP
+@14
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@25168
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@25188
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+@25195
+D;JNE
+@25220
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5808
+D=A
+@14
+M=D
+@25214
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@25279
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+@25286
+D;JNE
+@25310
+0;JMP
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5877
+D=A
+@14
+M=D
+@25305
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@9357
+D=A
+@14
+M=D
+@25328
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@25388
+D=A
+@38
+0;JMP
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@25407
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@25431
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@25443
+D;JNE
+@25466
+0;JMP
+@15
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@25461
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@25526
+D=A
+@38
+0;JMP
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@25545
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@25569
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+AM=M-1
+D=M
+@25581
+D;JNE
+@25604
+0;JMP
+@16
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@25599
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@25690
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@25697
+D;JNE
+@25720
+0;JMP
+@17
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@25715
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+M=D
+@3
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@25829
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@25836
+D;JNE
+@25859
+0;JMP
+@18
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@25854
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@5
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@25891
+D;JGT
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@25926
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@25933
+D;JNE
+@25939
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@45
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@25992
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@25999
+D;JNE
+@26025
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+A=A+1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@26044
+D=A
+@38
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D&M
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@26249
+D;JNE
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@26131
+D=A
+@38
+0;JMP
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@9
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@26149
+D=A
+@22
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=D|M
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@26181
+D;JNE
+@26247
+0;JMP
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@26206
+D=A
+@95
+0;JMP
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@26025
+0;JMP
+@1
+D=M
+@4
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@26265
+D;JNE
+@26282
+0;JMP
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+D=!M
+M=D+1
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@4
+D=A
+D=D-1
+@0
+AM=M+1
+A=A-1
+M=0
+@26293
+D;JGT
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@3
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@26327
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@26334
+D;JNE
+@26357
+0;JMP
+@19
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@26352
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@6
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5808
+D=A
+@14
+M=D
+@26375
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@26397
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@26404
+D;JNE
+@26436
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+A=A+1
+A=A+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+A=M-1
+D=!M
+M=D+1
+@0
+AM=M-1
+D=M
+@2
+A=M+1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@26464
+D=A
+@22
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@26630
+D;JNE
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@7287
+D=A
+@14
+M=D
+@26497
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@1
+A=M+1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@10
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@6822
+D=A
+@14
+M=D
+@26561
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@2
+A=M+1
+M=D
+@26449
+0;JMP
+@1
+D=M
+@3
+A=D+A
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@26646
+D;JNE
+@26716
+0;JMP
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@45
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@3
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@26734
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@26741
+D;JNE
+@26764
+0;JMP
+@19
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@26759
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@26779
+D=A
+@6
+0;JMP
+@0
+AM=M-1
+D=M
+@26786
+D;JNE
+@26843
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@48
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+M=D
+@27003
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@26873
+D=A
+@38
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@27003
+D;JNE
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@4
+M=D
+@4
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+AM=M-1
+D=M
+@4
+M=D
+@5
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@4
+A=M
+M=D
+@3
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=D+M
+@0
+AM=M-1
+D=M
+@3
+A=M+1
+A=A+1
+M=D
+@26854
+0;JMP
+@1
+A=M+1
+A=A+1
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@5877
+D=A
+@14
+M=D
+@27023
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@128
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@129
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@34
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@54
+0;JMP
+@0
+D=A
+@13
+M=D
+@8453
+D=A
+@14
+M=D
+@27070
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+D=A
+@13
+M=D
+@6505
+D=A
+@14
+M=D
+@27087
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+D=A
+@13
+M=D
+@20329
+D=A
+@14
+M=D
+@27104
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+D=A
+@13
+M=D
+@9854
+D=A
+@14
+M=D
+@27121
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+D=A
+@13
+M=D
+@5918
+D=A
+@14
+M=D
+@27138
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+D=A
+@13
+M=D
+@3837
+D=A
+@14
+M=D
+@27155
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+D=A
+@13
+M=D
+@27177
+D=A
+@14
+M=D
+@27172
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@0
+A=M-1
+M=!M
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@27194
+D;JNE
+@27177
+0;JMP
+@0
+AM=M+1
+A=A-1
+M=0
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@27213
+D=A
+@38
+0;JMP
+@0
+AM=M-1
+D=M
+@27220
+D;JNE
+@27241
+0;JMP
+@0
+M=M+1
+A=M-1
+M=1
+@1
+D=A
+@13
+M=D
+@27353
+D=A
+@14
+M=D
+@27236
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@27256
+D=A
+@22
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@27347
+D;JNE
+@50
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=0
+@27291
+D=A
+@22
+0;JMP
+@0
+A=M-1
+M=!M
+@0
+AM=M-1
+D=M
+@27323
+D;JNE
+@1
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@1
+A=M
+M=D
+@27276
+0;JMP
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@0
+M=M+1
+A=M-1
+M=1
+@0
+AM=M-1
+D=M
+A=A-1
+M=M-D
+@0
+AM=M-1
+D=M
+@2
+A=M
+M=D
+@27241
+0;JMP
+@0
+M=M+1
+A=M-1
+M=0
+@54
+0;JMP
+@3
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@25105
+D=A
+@14
+M=D
+@27371
+D=A
+@95
+0;JMP
+@69
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@27389
+D=A
+@95
+0;JMP
+@82
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@27407
+D=A
+@95
+0;JMP
+@82
+D=A
+@0
+AM=M+1
+A=A-1
+M=D
+@2
+D=A
+@13
+M=D
+@25659
+D=A
+@14
+M=D
+@27425
+D=A
+@95
+0;JMP
+@1
+D=A
+@13
+M=D
+@19850
+D=A
+@14
+M=D
+@27437
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@2
+A=M
+D=M
+@0
+AM=M+1
+A=A-1
+M=D
+@1
+D=A
+@13
+M=D
+@19981
+D=A
+@14
+M=D
+@27461
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
+@0
+D=A
+@13
+M=D
+@27177
+D=A
+@14
+M=D
+@27478
+D=A
+@95
+0;JMP
+@0
+AM=M-1
+D=M
+@5
+M=D
diff --git a/src/lib/computer/testing/fixtures/hack/README.md b/src/lib/computer/testing/fixtures/hack/README.md
new file mode 100644
index 0000000..cffd7dd
--- /dev/null
+++ b/src/lib/computer/testing/fixtures/hack/README.md
@@ -0,0 +1,5 @@
+Official Nand2Tetris Project 6 assembler test inputs.
+
+Source: https://github.com/nand2tetris/projects/tree/5bd2184edfd4945ff8a28eb0b237c12cdbe9e498/projects/06
+
+These are supplied test programs, not student project solutions. Original attribution is retained in every file; the source repository MIT license is included.
diff --git a/src/lib/computer/testing/fixtures/hack/Rect.asm b/src/lib/computer/testing/fixtures/hack/Rect.asm
new file mode 100644
index 0000000..6cbbaeb
--- /dev/null
+++ b/src/lib/computer/testing/fixtures/hack/Rect.asm
@@ -0,0 +1,35 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/06/rect/Rect.asm
+
+// Draws a rectangle at the top-left corner of the screen.
+// The rectangle is 16 pixels wide and R0 pixels high.
+
+ @0
+ D=M
+ @INFINITE_LOOP
+ D;JLE
+ @counter
+ M=D
+ @SCREEN
+ D=A
+ @address
+ M=D
+(LOOP)
+ @address
+ A=M
+ M=-1
+ @address
+ D=M
+ @32
+ D=D+A
+ @address
+ M=D
+ @counter
+ MD=M-1
+ @LOOP
+ D;JGT
+(INFINITE_LOOP)
+ @INFINITE_LOOP
+ 0;JMP
diff --git a/src/lib/computer/testing/fixtures/hack/RectL.asm b/src/lib/computer/testing/fixtures/hack/RectL.asm
new file mode 100644
index 0000000..f2f9646
--- /dev/null
+++ b/src/lib/computer/testing/fixtures/hack/RectL.asm
@@ -0,0 +1,32 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/06/rect/RectL.asm
+
+// Symbol-less version of the Rect.asm program.
+
+@0
+D=M
+@23
+D;JLE
+@16
+M=D
+@16384
+D=A
+@17
+M=D
+@17
+A=M
+M=-1
+@17
+D=M
+@32
+D=D+A
+@17
+M=D
+@16
+DM=M-1
+@10
+D;JGT
+@23
+0;JMP
diff --git a/src/lib/computer/testing/official/ALU-nostat.cmp b/src/lib/computer/testing/official/ALU-nostat.cmp
new file mode 100644
index 0000000..976ab78
--- /dev/null
+++ b/src/lib/computer/testing/official/ALU-nostat.cmp
@@ -0,0 +1,37 @@
+| x | y |zx |nx |zy |ny | f |no | out |
+| 0000000000000000 | 1111111111111111 | 1 | 0 | 1 | 0 | 1 | 0 | 0000000000000000 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 1 | 1 | 1 | 1 | 0000000000000001 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 1 | 0 | 1 | 0 | 1111111111111111 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 0 | 0 | 0000000000000000 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 0 | 0 | 1111111111111111 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 0 | 1 | 1111111111111111 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 0 | 1 | 0000000000000000 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 1 | 1 | 0000000000000000 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 1 | 1 | 0000000000000001 |
+| 0000000000000000 | 1111111111111111 | 0 | 1 | 1 | 1 | 1 | 1 | 0000000000000001 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 1 | 1 | 1 | 0000000000000000 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 1 | 0 | 1111111111111111 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 1 | 0 | 1111111111111110 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 0 | 0 | 1 | 0 | 1111111111111111 |
+| 0000000000000000 | 1111111111111111 | 0 | 1 | 0 | 0 | 1 | 1 | 0000000000000001 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 0 | 1 | 1 | 1 | 1111111111111111 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 0 | 0 | 0 | 0 | 0000000000000000 |
+| 0000000000000000 | 1111111111111111 | 0 | 1 | 0 | 1 | 0 | 1 | 1111111111111111 |
+| 0101101110100000 | 0001111011010010 | 1 | 0 | 1 | 0 | 1 | 0 | 0000000000000000 |
+| 0101101110100000 | 0001111011010010 | 1 | 1 | 1 | 1 | 1 | 1 | 0000000000000001 |
+| 0101101110100000 | 0001111011010010 | 1 | 1 | 1 | 0 | 1 | 0 | 1111111111111111 |
+| 0101101110100000 | 0001111011010010 | 0 | 0 | 1 | 1 | 0 | 0 | 0101101110100000 |
+| 0101101110100000 | 0001111011010010 | 1 | 1 | 0 | 0 | 0 | 0 | 0001111011010010 |
+| 0101101110100000 | 0001111011010010 | 0 | 0 | 1 | 1 | 0 | 1 | 1010010001011111 |
+| 0101101110100000 | 0001111011010010 | 1 | 1 | 0 | 0 | 0 | 1 | 1110000100101101 |
+| 0101101110100000 | 0001111011010010 | 0 | 0 | 1 | 1 | 1 | 1 | 1010010001100000 |
+| 0101101110100000 | 0001111011010010 | 1 | 1 | 0 | 0 | 1 | 1 | 1110000100101110 |
+| 0101101110100000 | 0001111011010010 | 0 | 1 | 1 | 1 | 1 | 1 | 0101101110100001 |
+| 0101101110100000 | 0001111011010010 | 1 | 1 | 0 | 1 | 1 | 1 | 0001111011010011 |
+| 0101101110100000 | 0001111011010010 | 0 | 0 | 1 | 1 | 1 | 0 | 0101101110011111 |
+| 0101101110100000 | 0001111011010010 | 1 | 1 | 0 | 0 | 1 | 0 | 0001111011010001 |
+| 0101101110100000 | 0001111011010010 | 0 | 0 | 0 | 0 | 1 | 0 | 0111101001110010 |
+| 0101101110100000 | 0001111011010010 | 0 | 1 | 0 | 0 | 1 | 1 | 0011110011001110 |
+| 0101101110100000 | 0001111011010010 | 0 | 0 | 0 | 1 | 1 | 1 | 1100001100110010 |
+| 0101101110100000 | 0001111011010010 | 0 | 0 | 0 | 0 | 0 | 0 | 0001101010000000 |
+| 0101101110100000 | 0001111011010010 | 0 | 1 | 0 | 1 | 0 | 1 | 0101111111110010 |
diff --git a/src/lib/computer/testing/official/ALU-nostat.tst b/src/lib/computer/testing/official/ALU-nostat.tst
new file mode 100644
index 0000000..fa3e448
--- /dev/null
+++ b/src/lib/computer/testing/official/ALU-nostat.tst
@@ -0,0 +1,353 @@
+// This file is part of the materials accompanying the book
+// "The Elements of Computing Systems" by Nisan and Schocken,
+// MIT Press. Book site: www.idc.ac.il/tecs
+// File name: projects/02/ALU-nostat.tst
+
+// ALU-nostat.tst provides a partial test of the ALU chip.
+// It IS NOT a replacement for ALU.tst.
+
+// ALU-nostat.tst tests only the computation part of the ALU.
+// The 'zr' and 'ng' status outputs are ignored.
+
+// This test lets you concentrate on getting the ALU computation right without the
+// additional task of handling the status outputs.
+
+// Once your ALU passes ALU-nostat.tst you need to test it with ALU.tst.
+// This way, any comparison failures during ALU.tst will be caused by errors in
+// the handling of the 'zr' and 'ng' status outputs.
+
+load ALU.hdl,
+output-file ALU-nostat.out,
+compare-to ALU-nostat.cmp,
+output-list x%B1.16.1 y%B1.16.1 zx%B1.1.1 nx%B1.1.1 zy%B1.1.1
+ ny%B1.1.1 f%B1.1.1 no%B1.1.1 out%B1.16.1;
+
+set x %B0000000000000000,
+set y %B1111111111111111,
+
+set zx 1,
+set nx 0,
+set zy 1,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 1,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 1,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 0,
+set no 0,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 0,
+set no 0,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 0,
+set no 1,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 0,
+set no 1,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 0,
+set nx 1,
+set zy 1,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 1,
+set no 0,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 0,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+set zx 0,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 0,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 0,
+set ny 0,
+set f 0,
+set no 0,
+eval,
+output;
+
+set zx 0,
+set nx 1,
+set zy 0,
+set ny 1,
+set f 0,
+set no 1,
+eval,
+output;
+
+set x %B101101110100000,
+set y %B001111011010010,
+
+set zx 1,
+set nx 0,
+set zy 1,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 1,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 1,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 0,
+set no 0,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 0,
+set no 0,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 0,
+set no 1,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 0,
+set no 1,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 0,
+set nx 1,
+set zy 1,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 1,
+set no 0,
+eval,
+output;
+
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 0,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+set zx 0,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 0,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+set zx 0,
+set nx 0,
+set zy 0,
+set ny 0,
+set f 0,
+set no 0,
+eval,
+output;
+
+set zx 0,
+set nx 1,
+set zy 0,
+set ny 1,
+set f 0,
+set no 1,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/ALU.cmp b/src/lib/computer/testing/official/ALU.cmp
new file mode 100644
index 0000000..2ec3a55
--- /dev/null
+++ b/src/lib/computer/testing/official/ALU.cmp
@@ -0,0 +1,37 @@
+| x | y |zx |nx |zy |ny | f |no | out |zr |ng |
+| 0000000000000000 | 1111111111111111 | 1 | 0 | 1 | 0 | 1 | 0 | 0000000000000000 | 1 | 0 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 1 | 1 | 1 | 1 | 0000000000000001 | 0 | 0 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 1 | 0 | 1 | 0 | 1111111111111111 | 0 | 1 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 0 | 0 | 0000000000000000 | 1 | 0 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 0 | 0 | 1111111111111111 | 0 | 1 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 0 | 1 | 1111111111111111 | 0 | 1 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 0 | 1 | 0000000000000000 | 1 | 0 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 1 | 1 | 0000000000000000 | 1 | 0 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 1 | 1 | 0000000000000001 | 0 | 0 |
+| 0000000000000000 | 1111111111111111 | 0 | 1 | 1 | 1 | 1 | 1 | 0000000000000001 | 0 | 0 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 1 | 1 | 1 | 0000000000000000 | 1 | 0 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 1 | 0 | 1111111111111111 | 0 | 1 |
+| 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 1 | 0 | 1111111111111110 | 0 | 1 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 0 | 0 | 1 | 0 | 1111111111111111 | 0 | 1 |
+| 0000000000000000 | 1111111111111111 | 0 | 1 | 0 | 0 | 1 | 1 | 0000000000000001 | 0 | 0 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 0 | 1 | 1 | 1 | 1111111111111111 | 0 | 1 |
+| 0000000000000000 | 1111111111111111 | 0 | 0 | 0 | 0 | 0 | 0 | 0000000000000000 | 1 | 0 |
+| 0000000000000000 | 1111111111111111 | 0 | 1 | 0 | 1 | 0 | 1 | 1111111111111111 | 0 | 1 |
+| 0000000000010001 | 0000000000000011 | 1 | 0 | 1 | 0 | 1 | 0 | 0000000000000000 | 1 | 0 |
+| 0000000000010001 | 0000000000000011 | 1 | 1 | 1 | 1 | 1 | 1 | 0000000000000001 | 0 | 0 |
+| 0000000000010001 | 0000000000000011 | 1 | 1 | 1 | 0 | 1 | 0 | 1111111111111111 | 0 | 1 |
+| 0000000000010001 | 0000000000000011 | 0 | 0 | 1 | 1 | 0 | 0 | 0000000000010001 | 0 | 0 |
+| 0000000000010001 | 0000000000000011 | 1 | 1 | 0 | 0 | 0 | 0 | 0000000000000011 | 0 | 0 |
+| 0000000000010001 | 0000000000000011 | 0 | 0 | 1 | 1 | 0 | 1 | 1111111111101110 | 0 | 1 |
+| 0000000000010001 | 0000000000000011 | 1 | 1 | 0 | 0 | 0 | 1 | 1111111111111100 | 0 | 1 |
+| 0000000000010001 | 0000000000000011 | 0 | 0 | 1 | 1 | 1 | 1 | 1111111111101111 | 0 | 1 |
+| 0000000000010001 | 0000000000000011 | 1 | 1 | 0 | 0 | 1 | 1 | 1111111111111101 | 0 | 1 |
+| 0000000000010001 | 0000000000000011 | 0 | 1 | 1 | 1 | 1 | 1 | 0000000000010010 | 0 | 0 |
+| 0000000000010001 | 0000000000000011 | 1 | 1 | 0 | 1 | 1 | 1 | 0000000000000100 | 0 | 0 |
+| 0000000000010001 | 0000000000000011 | 0 | 0 | 1 | 1 | 1 | 0 | 0000000000010000 | 0 | 0 |
+| 0000000000010001 | 0000000000000011 | 1 | 1 | 0 | 0 | 1 | 0 | 0000000000000010 | 0 | 0 |
+| 0000000000010001 | 0000000000000011 | 0 | 0 | 0 | 0 | 1 | 0 | 0000000000010100 | 0 | 0 |
+| 0000000000010001 | 0000000000000011 | 0 | 1 | 0 | 0 | 1 | 1 | 0000000000001110 | 0 | 0 |
+| 0000000000010001 | 0000000000000011 | 0 | 0 | 0 | 1 | 1 | 1 | 1111111111110010 | 0 | 1 |
+| 0000000000010001 | 0000000000000011 | 0 | 0 | 0 | 0 | 0 | 0 | 0000000000000001 | 0 | 0 |
+| 0000000000010001 | 0000000000000011 | 0 | 1 | 0 | 1 | 0 | 1 | 0000000000010011 | 0 | 0 |
diff --git a/src/lib/computer/testing/official/ALU.tst b/src/lib/computer/testing/official/ALU.tst
new file mode 100644
index 0000000..9e665b0
--- /dev/null
+++ b/src/lib/computer/testing/official/ALU.tst
@@ -0,0 +1,377 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/02/ALU.tst
+
+load ALU.hdl,
+output-file ALU.out,
+compare-to ALU.cmp,
+output-list x%B1.16.1 y%B1.16.1 zx%B1.1.1 nx%B1.1.1 zy%B1.1.1
+ ny%B1.1.1 f%B1.1.1 no%B1.1.1 out%B1.16.1 zr%B1.1.1
+ ng%B1.1.1;
+
+set x %B0000000000000000, // x = 0
+set y %B1111111111111111; // y = -1
+
+// Compute 0
+set zx 1,
+set nx 0,
+set zy 1,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+// Compute 1
+set zx 1,
+set nx 1,
+set zy 1,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute -1
+set zx 1,
+set nx 1,
+set zy 1,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+// Compute x
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 0,
+set no 0,
+eval,
+output;
+
+// Compute y
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 0,
+set no 0,
+eval,
+output;
+
+// Compute !x
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 0,
+set no 1,
+eval,
+output;
+
+// Compute !y
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 0,
+set no 1,
+eval,
+output;
+
+// Compute -x
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute -y
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute x + 1
+set zx 0,
+set nx 1,
+set zy 1,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute y + 1
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute x - 1
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 1,
+set no 0,
+eval,
+output;
+
+// Compute y - 1
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+// Compute x + y
+set zx 0,
+set nx 0,
+set zy 0,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+// Compute x - y
+set zx 0,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute y - x
+set zx 0,
+set nx 0,
+set zy 0,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute x & y
+set zx 0,
+set nx 0,
+set zy 0,
+set ny 0,
+set f 0,
+set no 0,
+eval,
+output;
+
+// Compute x | y
+set zx 0,
+set nx 1,
+set zy 0,
+set ny 1,
+set f 0,
+set no 1,
+eval,
+output;
+
+set x %B000000000010001, // x = 17
+set y %B000000000000011; // y = 3
+
+// Compute 0
+set zx 1,
+set nx 0,
+set zy 1,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+// Compute 1
+set zx 1,
+set nx 1,
+set zy 1,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute -1
+set zx 1,
+set nx 1,
+set zy 1,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+// Compute x
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 0,
+set no 0,
+eval,
+output;
+
+// Compute y
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 0,
+set no 0,
+eval,
+output;
+
+// Compute !x
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 0,
+set no 1,
+eval,
+output;
+
+// Compute !y
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 0,
+set no 1,
+eval,
+output;
+
+// Compute -x
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute -y
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute x + 1
+set zx 0,
+set nx 1,
+set zy 1,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute y + 1
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute x - 1
+set zx 0,
+set nx 0,
+set zy 1,
+set ny 1,
+set f 1,
+set no 0,
+eval,
+output;
+
+// Compute y - 1
+set zx 1,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+// Compute x + y
+set zx 0,
+set nx 0,
+set zy 0,
+set ny 0,
+set f 1,
+set no 0,
+eval,
+output;
+
+// Compute x - y
+set zx 0,
+set nx 1,
+set zy 0,
+set ny 0,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute y - x
+set zx 0,
+set nx 0,
+set zy 0,
+set ny 1,
+set f 1,
+set no 1,
+eval,
+output;
+
+// Compute x & y
+set zx 0,
+set nx 0,
+set zy 0,
+set ny 0,
+set f 0,
+set no 0,
+eval,
+output;
+
+// Compute x | y
+set zx 0,
+set nx 1,
+set zy 0,
+set ny 1,
+set f 0,
+set no 1,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/Add.hack b/src/lib/computer/testing/official/Add.hack
new file mode 100644
index 0000000..fe5969d
--- /dev/null
+++ b/src/lib/computer/testing/official/Add.hack
@@ -0,0 +1,6 @@
+0000000000000010
+1110110000010000
+0000000000000011
+1110000010010000
+0000000000000000
+1110001100001000
diff --git a/src/lib/computer/testing/official/Add16.cmp b/src/lib/computer/testing/official/Add16.cmp
new file mode 100644
index 0000000..76d069c
--- /dev/null
+++ b/src/lib/computer/testing/official/Add16.cmp
@@ -0,0 +1,7 @@
+| a | b | out |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 |
+| 0000000000000000 | 1111111111111111 | 1111111111111111 |
+| 1111111111111111 | 1111111111111111 | 1111111111111110 |
+| 1010101010101010 | 0101010101010101 | 1111111111111111 |
+| 0011110011000011 | 0000111111110000 | 0100110010110011 |
+| 0001001000110100 | 1001100001110110 | 1010101010101010 |
diff --git a/src/lib/computer/testing/official/Add16.tst b/src/lib/computer/testing/official/Add16.tst
new file mode 100644
index 0000000..85e1be1
--- /dev/null
+++ b/src/lib/computer/testing/official/Add16.tst
@@ -0,0 +1,39 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/02/Add16.tst
+
+load Add16.hdl,
+output-file Add16.out,
+compare-to Add16.cmp,
+output-list a%B1.16.1 b%B1.16.1 out%B1.16.1;
+
+set a %B0000000000000000,
+set b %B0000000000000000,
+eval,
+output;
+
+set a %B0000000000000000,
+set b %B1111111111111111,
+eval,
+output;
+
+set a %B1111111111111111,
+set b %B1111111111111111,
+eval,
+output;
+
+set a %B1010101010101010,
+set b %B0101010101010101,
+eval,
+output;
+
+set a %B0011110011000011,
+set b %B0000111111110000,
+eval,
+output;
+
+set a %B0001001000110100,
+set b %B1001100001110110,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/And.cmp b/src/lib/computer/testing/official/And.cmp
new file mode 100644
index 0000000..75e709a
--- /dev/null
+++ b/src/lib/computer/testing/official/And.cmp
@@ -0,0 +1,5 @@
+| a | b | out |
+| 0 | 0 | 0 |
+| 0 | 1 | 0 |
+| 1 | 0 | 0 |
+| 1 | 1 | 1 |
diff --git a/src/lib/computer/testing/official/And.tst b/src/lib/computer/testing/official/And.tst
new file mode 100644
index 0000000..7ace19d
--- /dev/null
+++ b/src/lib/computer/testing/official/And.tst
@@ -0,0 +1,29 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/And.tst
+
+load And.hdl,
+output-file And.out,
+compare-to And.cmp,
+output-list a%B3.1.3 b%B3.1.3 out%B3.1.3;
+
+set a 0,
+set b 0,
+eval,
+output;
+
+set a 0,
+set b 1,
+eval,
+output;
+
+set a 1,
+set b 0,
+eval,
+output;
+
+set a 1,
+set b 1,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/And16.cmp b/src/lib/computer/testing/official/And16.cmp
new file mode 100644
index 0000000..32c8648
--- /dev/null
+++ b/src/lib/computer/testing/official/And16.cmp
@@ -0,0 +1,7 @@
+| a | b | out |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 |
+| 0000000000000000 | 1111111111111111 | 0000000000000000 |
+| 1111111111111111 | 1111111111111111 | 1111111111111111 |
+| 1010101010101010 | 0101010101010101 | 0000000000000000 |
+| 0011110011000011 | 0000111111110000 | 0000110011000000 |
+| 0001001000110100 | 1001100001110110 | 0001000000110100 |
diff --git a/src/lib/computer/testing/official/And16.tst b/src/lib/computer/testing/official/And16.tst
new file mode 100644
index 0000000..c8921e7
--- /dev/null
+++ b/src/lib/computer/testing/official/And16.tst
@@ -0,0 +1,39 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/And16.tst
+
+load And16.hdl,
+output-file And16.out,
+compare-to And16.cmp,
+output-list a%B1.16.1 b%B1.16.1 out%B1.16.1;
+
+set a %B0000000000000000,
+set b %B0000000000000000,
+eval,
+output;
+
+set a %B0000000000000000,
+set b %B1111111111111111,
+eval,
+output;
+
+set a %B1111111111111111,
+set b %B1111111111111111,
+eval,
+output;
+
+set a %B1010101010101010,
+set b %B0101010101010101,
+eval,
+output;
+
+set a %B0011110011000011,
+set b %B0000111111110000,
+eval,
+output;
+
+set a %B0001001000110100,
+set b %B1001100001110110,
+eval,
+output;
\ No newline at end of file
diff --git a/src/lib/computer/testing/official/Bit.cmp b/src/lib/computer/testing/official/Bit.cmp
new file mode 100644
index 0000000..e900ec7
--- /dev/null
+++ b/src/lib/computer/testing/official/Bit.cmp
@@ -0,0 +1,215 @@
+| time | in |load | out |
+| 0+ | 0 | 0 | 0 |
+| 1 | 0 | 0 | 0 |
+| 1+ | 0 | 1 | 0 |
+| 2 | 0 | 1 | 0 |
+| 2+ | 1 | 0 | 0 |
+| 3 | 1 | 0 | 0 |
+| 3+ | 1 | 1 | 0 |
+| 4 | 1 | 1 | 1 |
+| 4+ | 0 | 0 | 1 |
+| 5 | 0 | 0 | 1 |
+| 5+ | 1 | 0 | 1 |
+| 6 | 1 | 0 | 1 |
+| 6+ | 0 | 1 | 1 |
+| 7 | 0 | 1 | 0 |
+| 7+ | 1 | 1 | 0 |
+| 8 | 1 | 1 | 1 |
+| 8+ | 0 | 0 | 1 |
+| 9 | 0 | 0 | 1 |
+| 9+ | 0 | 0 | 1 |
+| 10 | 0 | 0 | 1 |
+| 10+ | 0 | 0 | 1 |
+| 11 | 0 | 0 | 1 |
+| 11+ | 0 | 0 | 1 |
+| 12 | 0 | 0 | 1 |
+| 12+ | 0 | 0 | 1 |
+| 13 | 0 | 0 | 1 |
+| 13+ | 0 | 0 | 1 |
+| 14 | 0 | 0 | 1 |
+| 14+ | 0 | 0 | 1 |
+| 15 | 0 | 0 | 1 |
+| 15+ | 0 | 0 | 1 |
+| 16 | 0 | 0 | 1 |
+| 16+ | 0 | 0 | 1 |
+| 17 | 0 | 0 | 1 |
+| 17+ | 0 | 0 | 1 |
+| 18 | 0 | 0 | 1 |
+| 18+ | 0 | 0 | 1 |
+| 19 | 0 | 0 | 1 |
+| 19+ | 0 | 0 | 1 |
+| 20 | 0 | 0 | 1 |
+| 20+ | 0 | 0 | 1 |
+| 21 | 0 | 0 | 1 |
+| 21+ | 0 | 0 | 1 |
+| 22 | 0 | 0 | 1 |
+| 22+ | 0 | 0 | 1 |
+| 23 | 0 | 0 | 1 |
+| 23+ | 0 | 0 | 1 |
+| 24 | 0 | 0 | 1 |
+| 24+ | 0 | 0 | 1 |
+| 25 | 0 | 0 | 1 |
+| 25+ | 0 | 0 | 1 |
+| 26 | 0 | 0 | 1 |
+| 26+ | 0 | 0 | 1 |
+| 27 | 0 | 0 | 1 |
+| 27+ | 0 | 0 | 1 |
+| 28 | 0 | 0 | 1 |
+| 28+ | 0 | 0 | 1 |
+| 29 | 0 | 0 | 1 |
+| 29+ | 0 | 0 | 1 |
+| 30 | 0 | 0 | 1 |
+| 30+ | 0 | 0 | 1 |
+| 31 | 0 | 0 | 1 |
+| 31+ | 0 | 0 | 1 |
+| 32 | 0 | 0 | 1 |
+| 32+ | 0 | 0 | 1 |
+| 33 | 0 | 0 | 1 |
+| 33+ | 0 | 0 | 1 |
+| 34 | 0 | 0 | 1 |
+| 34+ | 0 | 0 | 1 |
+| 35 | 0 | 0 | 1 |
+| 35+ | 0 | 0 | 1 |
+| 36 | 0 | 0 | 1 |
+| 36+ | 0 | 0 | 1 |
+| 37 | 0 | 0 | 1 |
+| 37+ | 0 | 0 | 1 |
+| 38 | 0 | 0 | 1 |
+| 38+ | 0 | 0 | 1 |
+| 39 | 0 | 0 | 1 |
+| 39+ | 0 | 0 | 1 |
+| 40 | 0 | 0 | 1 |
+| 40+ | 0 | 0 | 1 |
+| 41 | 0 | 0 | 1 |
+| 41+ | 0 | 0 | 1 |
+| 42 | 0 | 0 | 1 |
+| 42+ | 0 | 0 | 1 |
+| 43 | 0 | 0 | 1 |
+| 43+ | 0 | 0 | 1 |
+| 44 | 0 | 0 | 1 |
+| 44+ | 0 | 0 | 1 |
+| 45 | 0 | 0 | 1 |
+| 45+ | 0 | 0 | 1 |
+| 46 | 0 | 0 | 1 |
+| 46+ | 0 | 0 | 1 |
+| 47 | 0 | 0 | 1 |
+| 47+ | 0 | 0 | 1 |
+| 48 | 0 | 0 | 1 |
+| 48+ | 0 | 0 | 1 |
+| 49 | 0 | 0 | 1 |
+| 49+ | 0 | 0 | 1 |
+| 50 | 0 | 0 | 1 |
+| 50+ | 0 | 0 | 1 |
+| 51 | 0 | 0 | 1 |
+| 51+ | 0 | 0 | 1 |
+| 52 | 0 | 0 | 1 |
+| 52+ | 0 | 0 | 1 |
+| 53 | 0 | 0 | 1 |
+| 53+ | 0 | 0 | 1 |
+| 54 | 0 | 0 | 1 |
+| 54+ | 0 | 0 | 1 |
+| 55 | 0 | 0 | 1 |
+| 55+ | 0 | 0 | 1 |
+| 56 | 0 | 0 | 1 |
+| 56+ | 0 | 0 | 1 |
+| 57 | 0 | 0 | 1 |
+| 57+ | 0 | 1 | 1 |
+| 58 | 0 | 1 | 0 |
+| 58+ | 1 | 0 | 0 |
+| 59 | 1 | 0 | 0 |
+| 59+ | 1 | 0 | 0 |
+| 60 | 1 | 0 | 0 |
+| 60+ | 1 | 0 | 0 |
+| 61 | 1 | 0 | 0 |
+| 61+ | 1 | 0 | 0 |
+| 62 | 1 | 0 | 0 |
+| 62+ | 1 | 0 | 0 |
+| 63 | 1 | 0 | 0 |
+| 63+ | 1 | 0 | 0 |
+| 64 | 1 | 0 | 0 |
+| 64+ | 1 | 0 | 0 |
+| 65 | 1 | 0 | 0 |
+| 65+ | 1 | 0 | 0 |
+| 66 | 1 | 0 | 0 |
+| 66+ | 1 | 0 | 0 |
+| 67 | 1 | 0 | 0 |
+| 67+ | 1 | 0 | 0 |
+| 68 | 1 | 0 | 0 |
+| 68+ | 1 | 0 | 0 |
+| 69 | 1 | 0 | 0 |
+| 69+ | 1 | 0 | 0 |
+| 70 | 1 | 0 | 0 |
+| 70+ | 1 | 0 | 0 |
+| 71 | 1 | 0 | 0 |
+| 71+ | 1 | 0 | 0 |
+| 72 | 1 | 0 | 0 |
+| 72+ | 1 | 0 | 0 |
+| 73 | 1 | 0 | 0 |
+| 73+ | 1 | 0 | 0 |
+| 74 | 1 | 0 | 0 |
+| 74+ | 1 | 0 | 0 |
+| 75 | 1 | 0 | 0 |
+| 75+ | 1 | 0 | 0 |
+| 76 | 1 | 0 | 0 |
+| 76+ | 1 | 0 | 0 |
+| 77 | 1 | 0 | 0 |
+| 77+ | 1 | 0 | 0 |
+| 78 | 1 | 0 | 0 |
+| 78+ | 1 | 0 | 0 |
+| 79 | 1 | 0 | 0 |
+| 79+ | 1 | 0 | 0 |
+| 80 | 1 | 0 | 0 |
+| 80+ | 1 | 0 | 0 |
+| 81 | 1 | 0 | 0 |
+| 81+ | 1 | 0 | 0 |
+| 82 | 1 | 0 | 0 |
+| 82+ | 1 | 0 | 0 |
+| 83 | 1 | 0 | 0 |
+| 83+ | 1 | 0 | 0 |
+| 84 | 1 | 0 | 0 |
+| 84+ | 1 | 0 | 0 |
+| 85 | 1 | 0 | 0 |
+| 85+ | 1 | 0 | 0 |
+| 86 | 1 | 0 | 0 |
+| 86+ | 1 | 0 | 0 |
+| 87 | 1 | 0 | 0 |
+| 87+ | 1 | 0 | 0 |
+| 88 | 1 | 0 | 0 |
+| 88+ | 1 | 0 | 0 |
+| 89 | 1 | 0 | 0 |
+| 89+ | 1 | 0 | 0 |
+| 90 | 1 | 0 | 0 |
+| 90+ | 1 | 0 | 0 |
+| 91 | 1 | 0 | 0 |
+| 91+ | 1 | 0 | 0 |
+| 92 | 1 | 0 | 0 |
+| 92+ | 1 | 0 | 0 |
+| 93 | 1 | 0 | 0 |
+| 93+ | 1 | 0 | 0 |
+| 94 | 1 | 0 | 0 |
+| 94+ | 1 | 0 | 0 |
+| 95 | 1 | 0 | 0 |
+| 95+ | 1 | 0 | 0 |
+| 96 | 1 | 0 | 0 |
+| 96+ | 1 | 0 | 0 |
+| 97 | 1 | 0 | 0 |
+| 97+ | 1 | 0 | 0 |
+| 98 | 1 | 0 | 0 |
+| 98+ | 1 | 0 | 0 |
+| 99 | 1 | 0 | 0 |
+| 99+ | 1 | 0 | 0 |
+| 100 | 1 | 0 | 0 |
+| 100+ | 1 | 0 | 0 |
+| 101 | 1 | 0 | 0 |
+| 101+ | 1 | 0 | 0 |
+| 102 | 1 | 0 | 0 |
+| 102+ | 1 | 0 | 0 |
+| 103 | 1 | 0 | 0 |
+| 103+ | 1 | 0 | 0 |
+| 104 | 1 | 0 | 0 |
+| 104+ | 1 | 0 | 0 |
+| 105 | 1 | 0 | 0 |
+| 105+ | 1 | 0 | 0 |
+| 106 | 1 | 0 | 0 |
+| 106+ | 1 | 0 | 0 |
+| 107 | 1 | 0 | 0 |
diff --git a/src/lib/computer/testing/official/Bit.tst b/src/lib/computer/testing/official/Bit.tst
new file mode 100644
index 0000000..c6bf523
--- /dev/null
+++ b/src/lib/computer/testing/official/Bit.tst
@@ -0,0 +1,865 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/03/a/Bit.tst
+
+load Bit.hdl,
+output-file Bit.out,
+compare-to Bit.cmp,
+output-list time%S1.4.1 in%B2.1.2 load%B2.1.2 out%B2.1.2;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 1,
+set load 0,
+tick,
+output;
+
+tock,
+output;
diff --git a/src/lib/computer/testing/official/CPU-external.cmp b/src/lib/computer/testing/official/CPU-external.cmp
new file mode 100644
index 0000000..58f43bd
--- /dev/null
+++ b/src/lib/computer/testing/official/CPU-external.cmp
@@ -0,0 +1,93 @@
+|time| inM | instruction |reset| outM |writeM |addre| pc |
+|0+ | 0|0011000000111001| 0 |*******| 0 | 0| 0|
+|1 | 0|0011000000111001| 0 |*******| 0 |12345| 1|
+|1+ | 0|1110110000010000| 0 |*******| 0 |12345| 1|
+|2 | 0|1110110000010000| 0 |*******| 0 |12345| 2|
+|2+ | 0|0101101110100000| 0 |*******| 0 |12345| 2|
+|3 | 0|0101101110100000| 0 |*******| 0 |23456| 3|
+|3+ | 0|1110000111010000| 0 |*******| 0 |23456| 3|
+|4 | 0|1110000111010000| 0 |*******| 0 |23456| 4|
+|4+ | 0|0000001111101000| 0 |*******| 0 |23456| 4|
+|5 | 0|0000001111101000| 0 |*******| 0 | 1000| 5|
+|5+ | 0|1110001100001000| 0 | 11111| 1 | 1000| 5|
+|6 | 0|1110001100001000| 0 | 11111| 1 | 1000| 6|
+|6+ | 0|0000001111101001| 0 |*******| 0 | 1000| 6|
+|7 | 0|0000001111101001| 0 |*******| 0 | 1001| 7|
+|7+ | 0|1110001110011000| 0 | 11110| 1 | 1001| 7|
+|8 | 0|1110001110011000| 0 | 11109| 1 | 1001| 8|
+|8+ | 0|0000001111101000| 0 |*******| 0 | 1001| 8|
+|9 | 0|0000001111101000| 0 |*******| 0 | 1000| 9|
+|9+ | 11111|1111010011010000| 0 |*******| 0 | 1000| 9|
+|10 | 11111|1111010011010000| 0 |*******| 0 | 1000| 10|
+|10+ | 11111|0000000000001110| 0 |*******| 0 | 1000| 10|
+|11 | 11111|0000000000001110| 0 |*******| 0 | 14| 11|
+|11+ | 11111|1110001100000100| 0 |*******| 0 | 14| 11|
+|12 | 11111|1110001100000100| 0 |*******| 0 | 14| 14|
+|12+ | 11111|0000001111100111| 0 |*******| 0 | 14| 14|
+|13 | 11111|0000001111100111| 0 |*******| 0 | 999| 15|
+|13+ | 11111|1110110111100000| 0 |*******| 0 | 999| 15|
+|14 | 11111|1110110111100000| 0 |*******| 0 | 1000| 16|
+|14+ | 11111|1110001100001000| 0 | -1| 1 | 1000| 16|
+|15 | 11111|1110001100001000| 0 | -1| 1 | 1000| 17|
+|15+ | 11111|0000000000010101| 0 |*******| 0 | 1000| 17|
+|16 | 11111|0000000000010101| 0 |*******| 0 | 21| 18|
+|16+ | 11111|1110011111000010| 0 |*******| 0 | 21| 18|
+|17 | 11111|1110011111000010| 0 |*******| 0 | 21| 21|
+|17+ | 11111|0000000000000010| 0 |*******| 0 | 21| 21|
+|18 | 11111|0000000000000010| 0 |*******| 0 | 2| 22|
+|18+ | 11111|1110000010010000| 0 |*******| 0 | 2| 22|
+|19 | 11111|1110000010010000| 0 |*******| 0 | 2| 23|
+|19+ | 11111|0000001111101000| 0 |*******| 0 | 2| 23|
+|20 | 11111|0000001111101000| 0 |*******| 0 | 1000| 24|
+|20+ | 11111|1110111010010000| 0 |*******| 0 | 1000| 24|
+|21 | 11111|1110111010010000| 0 |*******| 0 | 1000| 25|
+|21+ | 11111|1110001100000001| 0 |*******| 0 | 1000| 25|
+|22 | 11111|1110001100000001| 0 |*******| 0 | 1000| 26|
+|22+ | 11111|1110001100000010| 0 |*******| 0 | 1000| 26|
+|23 | 11111|1110001100000010| 0 |*******| 0 | 1000| 27|
+|23+ | 11111|1110001100000011| 0 |*******| 0 | 1000| 27|
+|24 | 11111|1110001100000011| 0 |*******| 0 | 1000| 28|
+|24+ | 11111|1110001100000100| 0 |*******| 0 | 1000| 28|
+|25 | 11111|1110001100000100| 0 |*******| 0 | 1000| 1000|
+|25+ | 11111|1110001100000101| 0 |*******| 0 | 1000| 1000|
+|26 | 11111|1110001100000101| 0 |*******| 0 | 1000| 1000|
+|26+ | 11111|1110001100000110| 0 |*******| 0 | 1000| 1000|
+|27 | 11111|1110001100000110| 0 |*******| 0 | 1000| 1000|
+|27+ | 11111|1110001100000111| 0 |*******| 0 | 1000| 1000|
+|28 | 11111|1110001100000111| 0 |*******| 0 | 1000| 1000|
+|28+ | 11111|1110101010010000| 0 |*******| 0 | 1000| 1000|
+|29 | 11111|1110101010010000| 0 |*******| 0 | 1000| 1001|
+|29+ | 11111|1110001100000001| 0 |*******| 0 | 1000| 1001|
+|30 | 11111|1110001100000001| 0 |*******| 0 | 1000| 1002|
+|30+ | 11111|1110001100000010| 0 |*******| 0 | 1000| 1002|
+|31 | 11111|1110001100000010| 0 |*******| 0 | 1000| 1000|
+|31+ | 11111|1110001100000011| 0 |*******| 0 | 1000| 1000|
+|32 | 11111|1110001100000011| 0 |*******| 0 | 1000| 1000|
+|32+ | 11111|1110001100000100| 0 |*******| 0 | 1000| 1000|
+|33 | 11111|1110001100000100| 0 |*******| 0 | 1000| 1001|
+|33+ | 11111|1110001100000101| 0 |*******| 0 | 1000| 1001|
+|34 | 11111|1110001100000101| 0 |*******| 0 | 1000| 1002|
+|34+ | 11111|1110001100000110| 0 |*******| 0 | 1000| 1002|
+|35 | 11111|1110001100000110| 0 |*******| 0 | 1000| 1000|
+|35+ | 11111|1110001100000111| 0 |*******| 0 | 1000| 1000|
+|36 | 11111|1110001100000111| 0 |*******| 0 | 1000| 1000|
+|36+ | 11111|1110111111010000| 0 |*******| 0 | 1000| 1000|
+|37 | 11111|1110111111010000| 0 |*******| 0 | 1000| 1001|
+|37+ | 11111|1110001100000001| 0 |*******| 0 | 1000| 1001|
+|38 | 11111|1110001100000001| 0 |*******| 0 | 1000| 1000|
+|38+ | 11111|1110001100000010| 0 |*******| 0 | 1000| 1000|
+|39 | 11111|1110001100000010| 0 |*******| 0 | 1000| 1001|
+|39+ | 11111|1110001100000011| 0 |*******| 0 | 1000| 1001|
+|40 | 11111|1110001100000011| 0 |*******| 0 | 1000| 1000|
+|40+ | 11111|1110001100000100| 0 |*******| 0 | 1000| 1000|
+|41 | 11111|1110001100000100| 0 |*******| 0 | 1000| 1001|
+|41+ | 11111|1110001100000101| 0 |*******| 0 | 1000| 1001|
+|42 | 11111|1110001100000101| 0 |*******| 0 | 1000| 1000|
+|42+ | 11111|1110001100000110| 0 |*******| 0 | 1000| 1000|
+|43 | 11111|1110001100000110| 0 |*******| 0 | 1000| 1001|
+|43+ | 11111|1110001100000111| 0 |*******| 0 | 1000| 1001|
+|44 | 11111|1110001100000111| 0 |*******| 0 | 1000| 1000|
+|44+ | 11111|1110001100000111| 1 |*******| 0 | 1000| 1000|
+|45 | 11111|1110001100000111| 1 |*******| 0 | 1000| 0|
+|45+ | 11111|0111111111111111| 0 |*******| 0 | 1000| 0|
+|46 | 11111|0111111111111111| 0 |*******| 0 |32767| 1|
diff --git a/src/lib/computer/testing/official/CPU-external.tst b/src/lib/computer/testing/official/CPU-external.tst
new file mode 100644
index 0000000..5aa0295
--- /dev/null
+++ b/src/lib/computer/testing/official/CPU-external.tst
@@ -0,0 +1,150 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/05/CPU-external.tst
+
+load CPU.hdl,
+output-file CPU-external.out,
+compare-to CPU-external.cmp,
+output-list time%S0.4.0 inM%D0.6.0 instruction%B0.16.0 reset%B2.1.2 outM%D1.6.0 writeM%B3.1.3 addressM%D0.5.0 pc%D0.5.0;
+
+
+set instruction %B0011000000111001, // @12345
+tick, output, tock, output;
+
+set instruction %B1110110000010000, // D=A
+tick, output, tock, output;
+
+set instruction %B0101101110100000, // @23456
+tick, output, tock, output;
+
+set instruction %B1110000111010000, // D=A-D
+tick, output, tock, output;
+
+set instruction %B0000001111101000, // @1000
+tick, output, tock, output;
+
+set instruction %B1110001100001000, // M=D
+tick, output, tock, output;
+
+set instruction %B0000001111101001, // @1001
+tick, output, tock, output;
+
+set instruction %B1110001110011000, // MD=D-1
+tick, output, tock, output;
+
+set instruction %B0000001111101000, // @1000
+tick, output, tock, output;
+
+set instruction %B1111010011010000, // D=D-M
+set inM 11111,
+tick, output, tock, output;
+
+set instruction %B0000000000001110, // @14
+tick, output, tock, output;
+
+set instruction %B1110001100000100, // D;jlt
+tick, output, tock, output;
+
+set instruction %B0000001111100111, // @999
+tick, output, tock, output;
+
+set instruction %B1110110111100000, // A=A+1
+tick, output, tock, output;
+
+set instruction %B1110001100001000, // M=D
+tick, output, tock, output;
+
+set instruction %B0000000000010101, // @21
+tick, output, tock, output;
+
+set instruction %B1110011111000010, // D+1;jeq
+tick, output, tock, output;
+
+set instruction %B0000000000000010, // @2
+tick, output, tock, output;
+
+set instruction %B1110000010010000, // D=D+A
+tick, output, tock, output;
+
+set instruction %B0000001111101000, // @1000
+tick, output, tock, output;
+
+set instruction %B1110111010010000, // D=-1
+tick, output, tock, output;
+
+set instruction %B1110001100000001, // D;JGT
+tick, output, tock, output;
+
+set instruction %B1110001100000010, // D;JEQ
+tick, output, tock, output;
+
+set instruction %B1110001100000011, // D;JGE
+tick, output, tock, output;
+
+set instruction %B1110001100000100, // D;JLT
+tick, output, tock, output;
+
+set instruction %B1110001100000101, // D;JNE
+tick, output, tock, output;
+
+set instruction %B1110001100000110, // D;JLE
+tick, output, tock, output;
+
+set instruction %B1110001100000111, // D;JMP
+tick, output, tock, output;
+
+set instruction %B1110101010010000, // D=0
+tick, output, tock, output;
+
+set instruction %B1110001100000001, // D;JGT
+tick, output, tock, output;
+
+set instruction %B1110001100000010, // D;JEQ
+tick, output, tock, output;
+
+set instruction %B1110001100000011, // D;JGE
+tick, output, tock, output;
+
+set instruction %B1110001100000100, // D;JLT
+tick, output, tock, output;
+
+set instruction %B1110001100000101, // D;JNE
+tick, output, tock, output;
+
+set instruction %B1110001100000110, // D;JLE
+tick, output, tock, output;
+
+set instruction %B1110001100000111, // D;JMP
+tick, output, tock, output;
+
+set instruction %B1110111111010000, // D=1
+tick, output, tock, output;
+
+set instruction %B1110001100000001, // D;JGT
+tick, output, tock, output;
+
+set instruction %B1110001100000010, // D;JEQ
+tick, output, tock, output;
+
+set instruction %B1110001100000011, // D;JGE
+tick, output, tock, output;
+
+set instruction %B1110001100000100, // D;JLT
+tick, output, tock, output;
+
+set instruction %B1110001100000101, // D;JNE
+tick, output, tock, output;
+
+set instruction %B1110001100000110, // D;JLE
+tick, output, tock, output;
+
+set instruction %B1110001100000111, // D;JMP
+tick, output, tock, output;
+
+set reset 1;
+tick, output, tock, output;
+
+set instruction %B0111111111111111, // @32767
+set reset 0;
+tick, output, tock, output;
diff --git a/src/lib/computer/testing/official/CPU.cmp b/src/lib/computer/testing/official/CPU.cmp
new file mode 100644
index 0000000..8025e61
--- /dev/null
+++ b/src/lib/computer/testing/official/CPU.cmp
@@ -0,0 +1,97 @@
+|time| inM | instruction |reset| outM |writeM |addre| pc |DRegiste|
+|0+ | 0|0011000000111001| 0 |*******| 0 | 0| 0| 0 |
+|1 | 0|0011000000111001| 0 |*******| 0 |12345| 1| 0 |
+|1+ | 0|1110110000010000| 0 |*******| 0 |12345| 1| 12345 |
+|2 | 0|1110110000010000| 0 |*******| 0 |12345| 2| 12345 |
+|2+ | 0|0101101110100000| 0 |*******| 0 |12345| 2| 12345 |
+|3 | 0|0101101110100000| 0 |*******| 0 |23456| 3| 12345 |
+|3+ | 0|1110000111110000| 0 |*******| 0 |23456| 3| 11111 |
+|4 | 0|1110000111110000| 0 |*******| 0 |11111| 4| 11111 |
+|4+ | 0|0000001111101011| 0 |*******| 0 |11111| 4| 11111 |
+|5 | 0|0000001111101011| 0 |*******| 0 | 1003| 5| 11111 |
+|5+ | 0|1110001100001000| 0 | 11111| 1 | 1003| 5| 11111 |
+|6 | 0|1110001100001000| 0 | 11111| 1 | 1003| 6| 11111 |
+|6+ | 0|0000001111101100| 0 |*******| 0 | 1003| 6| 11111 |
+|7 | 0|0000001111101100| 0 |*******| 0 | 1004| 7| 11111 |
+|7+ | 0|1110001110011000| 0 | 11110| 1 | 1004| 7| 11110 |
+|8 | 0|1110001110011000| 0 | 11109| 1 | 1004| 8| 11110 |
+|8+ | 0|0000001111101000| 0 |*******| 0 | 1004| 8| 11110 |
+|9 | 0|0000001111101000| 0 |*******| 0 | 1000| 9| 11110 |
+|9+ | 11111|1111010011110000| 0 |*******| 0 | 1000| 9| -1 |
+|10 | 11111|1111010011110000| 0 |*******| 0 |32767| 10| -1 |
+|10+ | 11111|0000000000001110| 0 |*******| 0 |32767| 10| -1 |
+|11 | 11111|0000000000001110| 0 |*******| 0 | 14| 11| -1 |
+|11+ | 11111|1110001100000100| 0 |*******| 0 | 14| 11| -1 |
+|12 | 11111|1110001100000100| 0 |*******| 0 | 14| 14| -1 |
+|12+ | 11111|0000001111100111| 0 |*******| 0 | 14| 14| -1 |
+|13 | 11111|0000001111100111| 0 |*******| 0 | 999| 15| -1 |
+|13+ | 11111|1111110111100000| 0 |*******| 0 | 999| 15| -1 |
+|14 | 11111|1111110111100000| 0 |*******| 0 |11112| 16| -1 |
+|14+ | 11111|1110001100101000| 0 | -1| 1 |11112| 16| -1 |
+|15 | 11111|1110001100101000| 0 | -1| 1 |32767| 17| -1 |
+|15+ | 11111|0000000000010101| 0 |*******| 0 |32767| 17| -1 |
+|16 | 11111|0000000000010101| 0 |*******| 0 | 21| 18| -1 |
+|16+ | 11111|1110011111000010| 0 |*******| 0 | 21| 18| -1 |
+|17 | 11111|1110011111000010| 0 |*******| 0 | 21| 21| -1 |
+|17+ | 11111|0000000000000010| 0 |*******| 0 | 21| 21| -1 |
+|18 | 11111|0000000000000010| 0 |*******| 0 | 2| 22| -1 |
+|18+ | 11111|1110000010111000| 0 | 1| 1 | 2| 22| 1 |
+|19 | 11111|1110000010111000| 0 | 2| 1 | 1| 23| 1 |
+|19+ | 11111|1111110111001000| 0 | 11112| 1 | 1| 23| 1 |
+|20 | 11111|1111110111001000| 0 | 11112| 1 | 1| 24| 1 |
+|20+ | 11111|1111110010101000| 0 | 11110| 1 | 1| 24| 1 |
+|21 | 11111|1111110010101000| 0 | 11110| 1 |11110| 25| 1 |
+|21+ | 11111|0000001111101000| 0 |*******| 0 |11110| 25| 1 |
+|22 | 11111|0000001111101000| 0 |*******| 0 | 1000| 26| 1 |
+|22+ | 11111|1110111010010000| 0 |*******| 0 | 1000| 26| -1 |
+|23 | 11111|1110111010010000| 0 |*******| 0 | 1000| 27| -1 |
+|23+ | 11111|1110001100000001| 0 |*******| 0 | 1000| 27| -1 |
+|24 | 11111|1110001100000001| 0 |*******| 0 | 1000| 28| -1 |
+|24+ | 11111|1110001100000010| 0 |*******| 0 | 1000| 28| -1 |
+|25 | 11111|1110001100000010| 0 |*******| 0 | 1000| 29| -1 |
+|25+ | 11111|1110001100000011| 0 |*******| 0 | 1000| 29| -1 |
+|26 | 11111|1110001100000011| 0 |*******| 0 | 1000| 30| -1 |
+|26+ | 11111|1110001100000100| 0 |*******| 0 | 1000| 30| -1 |
+|27 | 11111|1110001100000100| 0 |*******| 0 | 1000| 1000| -1 |
+|27+ | 11111|1110001100000101| 0 |*******| 0 | 1000| 1000| -1 |
+|28 | 11111|1110001100000101| 0 |*******| 0 | 1000| 1000| -1 |
+|28+ | 11111|1110001100000110| 0 |*******| 0 | 1000| 1000| -1 |
+|29 | 11111|1110001100000110| 0 |*******| 0 | 1000| 1000| -1 |
+|29+ | 11111|1110001100000111| 0 |*******| 0 | 1000| 1000| -1 |
+|30 | 11111|1110001100000111| 0 |*******| 0 | 1000| 1000| -1 |
+|30+ | 11111|1110101010010000| 0 |*******| 0 | 1000| 1000| 0 |
+|31 | 11111|1110101010010000| 0 |*******| 0 | 1000| 1001| 0 |
+|31+ | 11111|1110001100000001| 0 |*******| 0 | 1000| 1001| 0 |
+|32 | 11111|1110001100000001| 0 |*******| 0 | 1000| 1002| 0 |
+|32+ | 11111|1110001100000010| 0 |*******| 0 | 1000| 1002| 0 |
+|33 | 11111|1110001100000010| 0 |*******| 0 | 1000| 1000| 0 |
+|33+ | 11111|1110001100000011| 0 |*******| 0 | 1000| 1000| 0 |
+|34 | 11111|1110001100000011| 0 |*******| 0 | 1000| 1000| 0 |
+|34+ | 11111|1110001100000100| 0 |*******| 0 | 1000| 1000| 0 |
+|35 | 11111|1110001100000100| 0 |*******| 0 | 1000| 1001| 0 |
+|35+ | 11111|1110001100000101| 0 |*******| 0 | 1000| 1001| 0 |
+|36 | 11111|1110001100000101| 0 |*******| 0 | 1000| 1002| 0 |
+|36+ | 11111|1110001100000110| 0 |*******| 0 | 1000| 1002| 0 |
+|37 | 11111|1110001100000110| 0 |*******| 0 | 1000| 1000| 0 |
+|37+ | 11111|1110001100000111| 0 |*******| 0 | 1000| 1000| 0 |
+|38 | 11111|1110001100000111| 0 |*******| 0 | 1000| 1000| 0 |
+|38+ | 11111|1110111111010000| 0 |*******| 0 | 1000| 1000| 1 |
+|39 | 11111|1110111111010000| 0 |*******| 0 | 1000| 1001| 1 |
+|39+ | 11111|1110001100000001| 0 |*******| 0 | 1000| 1001| 1 |
+|40 | 11111|1110001100000001| 0 |*******| 0 | 1000| 1000| 1 |
+|40+ | 11111|1110001100000010| 0 |*******| 0 | 1000| 1000| 1 |
+|41 | 11111|1110001100000010| 0 |*******| 0 | 1000| 1001| 1 |
+|41+ | 11111|1110001100000011| 0 |*******| 0 | 1000| 1001| 1 |
+|42 | 11111|1110001100000011| 0 |*******| 0 | 1000| 1000| 1 |
+|42+ | 11111|1110001100000100| 0 |*******| 0 | 1000| 1000| 1 |
+|43 | 11111|1110001100000100| 0 |*******| 0 | 1000| 1001| 1 |
+|43+ | 11111|1110001100000101| 0 |*******| 0 | 1000| 1001| 1 |
+|44 | 11111|1110001100000101| 0 |*******| 0 | 1000| 1000| 1 |
+|44+ | 11111|1110001100000110| 0 |*******| 0 | 1000| 1000| 1 |
+|45 | 11111|1110001100000110| 0 |*******| 0 | 1000| 1001| 1 |
+|45+ | 11111|1110001100000111| 0 |*******| 0 | 1000| 1001| 1 |
+|46 | 11111|1110001100000111| 0 |*******| 0 | 1000| 1000| 1 |
+|46+ | 11111|1110001100000111| 1 |*******| 0 | 1000| 1000| 1 |
+|47 | 11111|1110001100000111| 1 |*******| 0 | 1000| 0| 1 |
+|47+ | 11111|0111111111111111| 0 |*******| 0 | 1000| 0| 1 |
+|48 | 11111|0111111111111111| 0 |*******| 0 |32767| 1| 1 |
diff --git a/src/lib/computer/testing/official/CPU.tst b/src/lib/computer/testing/official/CPU.tst
new file mode 100644
index 0000000..680a292
--- /dev/null
+++ b/src/lib/computer/testing/official/CPU.tst
@@ -0,0 +1,156 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/05/CPU.tst
+
+load CPU.hdl,
+output-file CPU.out,
+compare-to CPU.cmp,
+output-list time%S0.4.0 inM%D0.6.0 instruction%B0.16.0 reset%B2.1.2 outM%D1.6.0 writeM%B3.1.3 addressM%D0.5.0 pc%D0.5.0 DRegister[]%D1.6.1;
+
+
+set instruction %B0011000000111001, // @12345
+tick, output, tock, output;
+
+set instruction %B1110110000010000, // D=A
+tick, output, tock, output;
+
+set instruction %B0101101110100000, // @23456
+tick, output, tock, output;
+
+set instruction %B1110000111110000, // AD=A-D
+tick, output, tock, output;
+
+set instruction %B0000001111101011, // @1003
+tick, output, tock, output;
+
+set instruction %B1110001100001000, // M=D
+tick, output, tock, output;
+
+set instruction %B0000001111101100, // @1004
+tick, output, tock, output;
+
+set instruction %B1110001110011000, // MD=D-1
+tick, output, tock, output;
+
+set instruction %B0000001111101000, // @1000
+tick, output, tock, output;
+
+set instruction %B1111010011110000, // AD=D-M
+set inM 11111,
+tick, output, tock, output;
+
+set instruction %B0000000000001110, // @14
+tick, output, tock, output;
+
+set instruction %B1110001100000100, // D;jlt
+tick, output, tock, output;
+
+set instruction %B0000001111100111, // @999
+tick, output, tock, output;
+
+set instruction %B1111110111100000, // A=M+1
+tick, output, tock, output;
+
+set instruction %B1110001100101000, // AM=D
+tick, output, tock, output;
+
+set instruction %B0000000000010101, // @21
+tick, output, tock, output;
+
+set instruction %B1110011111000010, // D+1;jeq
+tick, output, tock, output;
+
+set instruction %B0000000000000010, // @2
+tick, output, tock, output;
+
+set instruction %B1110000010111000, // AMD=D+A
+tick, output, tock, output;
+
+set instruction %B1111110111001000, // M=M+1
+tick, output, tock, output;
+
+set instruction %B1111110010101000, // AM=M-1
+tick, output, tock, output;
+
+set instruction %B0000001111101000, // @1000
+tick, output, tock, output;
+
+set instruction %B1110111010010000, // D=-1
+tick, output, tock, output;
+
+set instruction %B1110001100000001, // D;JGT
+tick, output, tock, output;
+
+set instruction %B1110001100000010, // D;JEQ
+tick, output, tock, output;
+
+set instruction %B1110001100000011, // D;JGE
+tick, output, tock, output;
+
+set instruction %B1110001100000100, // D;JLT
+tick, output, tock, output;
+
+set instruction %B1110001100000101, // D;JNE
+tick, output, tock, output;
+
+set instruction %B1110001100000110, // D;JLE
+tick, output, tock, output;
+
+set instruction %B1110001100000111, // D;JMP
+tick, output, tock, output;
+
+set instruction %B1110101010010000, // D=0
+tick, output, tock, output;
+
+set instruction %B1110001100000001, // D;JGT
+tick, output, tock, output;
+
+set instruction %B1110001100000010, // D;JEQ
+tick, output, tock, output;
+
+set instruction %B1110001100000011, // D;JGE
+tick, output, tock, output;
+
+set instruction %B1110001100000100, // D;JLT
+tick, output, tock, output;
+
+set instruction %B1110001100000101, // D;JNE
+tick, output, tock, output;
+
+set instruction %B1110001100000110, // D;JLE
+tick, output, tock, output;
+
+set instruction %B1110001100000111, // D;JMP
+tick, output, tock, output;
+
+set instruction %B1110111111010000, // D=1
+tick, output, tock, output;
+
+set instruction %B1110001100000001, // D;JGT
+tick, output, tock, output;
+
+set instruction %B1110001100000010, // D;JEQ
+tick, output, tock, output;
+
+set instruction %B1110001100000011, // D;JGE
+tick, output, tock, output;
+
+set instruction %B1110001100000100, // D;JLT
+tick, output, tock, output;
+
+set instruction %B1110001100000101, // D;JNE
+tick, output, tock, output;
+
+set instruction %B1110001100000110, // D;JLE
+tick, output, tock, output;
+
+set instruction %B1110001100000111, // D;JMP
+tick, output, tock, output;
+
+set reset 1;
+tick, output, tock, output;
+
+set instruction %B0111111111111111, // @32767
+set reset 0;
+tick, output, tock, output;
diff --git a/src/lib/computer/testing/official/ComputerAdd-external.cmp b/src/lib/computer/testing/official/ComputerAdd-external.cmp
new file mode 100644
index 0000000..a3a8eaf
--- /dev/null
+++ b/src/lib/computer/testing/official/ComputerAdd-external.cmp
@@ -0,0 +1,15 @@
+| time |reset|RAM16K[0]|RAM16K[1]|RAM16K[2]|
+| 0 | 0 | 0 | 0 | 0 |
+| 1 | 0 | 0 | 0 | 0 |
+| 2 | 0 | 0 | 0 | 0 |
+| 3 | 0 | 0 | 0 | 0 |
+| 4 | 0 | 0 | 0 | 0 |
+| 5 | 0 | 0 | 0 | 0 |
+| 6 | 0 | 5 | 0 | 0 |
+| 7 | 1 | 0 | 0 | 0 |
+| 8 | 0 | 0 | 0 | 0 |
+| 9 | 0 | 0 | 0 | 0 |
+| 10 | 0 | 0 | 0 | 0 |
+| 11 | 0 | 0 | 0 | 0 |
+| 12 | 0 | 0 | 0 | 0 |
+| 13 | 0 | 5 | 0 | 0 |
diff --git a/src/lib/computer/testing/official/ComputerAdd-external.tst b/src/lib/computer/testing/official/ComputerAdd-external.tst
new file mode 100644
index 0000000..09cc1a7
--- /dev/null
+++ b/src/lib/computer/testing/official/ComputerAdd-external.tst
@@ -0,0 +1,32 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/05/ComputerAdd-external.tst
+
+load Computer.hdl,
+output-file ComputerAdd-external.out,
+compare-to ComputerAdd-external.cmp,
+output-list time%S1.4.1 reset%B2.1.2 RAM16K[0]%D1.7.1 RAM16K[1]%D1.7.1 RAM16K[2]%D1.7.1;
+
+// Load a program written in the Hack machine language.
+// The program adds the two constants 2 and 3 and writes the result in RAM[0].
+ROM32K load Add.hack,
+output;
+
+// First run (at the beginning PC=0)
+repeat 6 {
+ tick, tock, output;
+}
+
+// Reset the PC
+set reset 1,
+set RAM16K[0] 0,
+tick, tock, output;
+
+
+// Second run, to check that the PC was reset correctly.
+set reset 0,
+
+repeat 6 {
+ tick, tock, output;
+}
diff --git a/src/lib/computer/testing/official/ComputerAdd.cmp b/src/lib/computer/testing/official/ComputerAdd.cmp
new file mode 100644
index 0000000..f295464
--- /dev/null
+++ b/src/lib/computer/testing/official/ComputerAdd.cmp
@@ -0,0 +1,15 @@
+| time |reset|ARegister|DRegister|PC[]|RAM16K[0]|RAM16K[1]|RAM16K[2]|
+| 0 | 0 | 0 | 0 | 0| 0 | 0 | 0 |
+| 1 | 0 | 2 | 0 | 1| 0 | 0 | 0 |
+| 2 | 0 | 2 | 2 | 2| 0 | 0 | 0 |
+| 3 | 0 | 3 | 2 | 3| 0 | 0 | 0 |
+| 4 | 0 | 3 | 5 | 4| 0 | 0 | 0 |
+| 5 | 0 | 0 | 5 | 5| 0 | 0 | 0 |
+| 6 | 0 | 0 | 5 | 6| 5 | 0 | 0 |
+| 7 | 1 | 0 | 5 | 0| 0 | 0 | 0 |
+| 8 | 0 | 2 | 5 | 1| 0 | 0 | 0 |
+| 9 | 0 | 2 | 2 | 2| 0 | 0 | 0 |
+| 10 | 0 | 3 | 2 | 3| 0 | 0 | 0 |
+| 11 | 0 | 3 | 5 | 4| 0 | 0 | 0 |
+| 12 | 0 | 0 | 5 | 5| 0 | 0 | 0 |
+| 13 | 0 | 0 | 5 | 6| 5 | 0 | 0 |
diff --git a/src/lib/computer/testing/official/ComputerAdd.tst b/src/lib/computer/testing/official/ComputerAdd.tst
new file mode 100644
index 0000000..27f4411
--- /dev/null
+++ b/src/lib/computer/testing/official/ComputerAdd.tst
@@ -0,0 +1,32 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/05/ComputerAdd.tst
+
+load Computer.hdl,
+output-file ComputerAdd.out,
+compare-to ComputerAdd.cmp,
+output-list time%S1.4.1 reset%B2.1.2 ARegister[0]%D1.7.1 DRegister[0]%D1.7.1 PC[]%D0.4.0 RAM16K[0]%D1.7.1 RAM16K[1]%D1.7.1 RAM16K[2]%D1.7.1;
+
+// Load a program written in the Hack machine language.
+// The program adds the two constants 2 and 3 and writes the result in RAM[0].
+ROM32K load Add.hack,
+output;
+
+// First run (at the beginning PC=0)
+repeat 6 {
+ tick, tock, output;
+}
+
+// Reset the PC
+set reset 1,
+set RAM16K[0] 0,
+tick, tock, output;
+
+
+// Second run, to check that the PC was reset correctly.
+set reset 0,
+
+repeat 6 {
+ tick, tock, output;
+}
diff --git a/src/lib/computer/testing/official/ComputerMax-external.cmp b/src/lib/computer/testing/official/ComputerMax-external.cmp
new file mode 100644
index 0000000..f864733
--- /dev/null
+++ b/src/lib/computer/testing/official/ComputerMax-external.cmp
@@ -0,0 +1,28 @@
+| time |reset|RAM16K[0]|RAM16K[1]|RAM16K[2]|
+| 0 | 0 | 3 | 5 | 0 |
+| 1 | 0 | 3 | 5 | 0 |
+| 2 | 0 | 3 | 5 | 0 |
+| 3 | 0 | 3 | 5 | 0 |
+| 4 | 0 | 3 | 5 | 0 |
+| 5 | 0 | 3 | 5 | 0 |
+| 6 | 0 | 3 | 5 | 0 |
+| 7 | 0 | 3 | 5 | 0 |
+| 8 | 0 | 3 | 5 | 0 |
+| 9 | 0 | 3 | 5 | 0 |
+| 10 | 0 | 3 | 5 | 0 |
+| 11 | 0 | 3 | 5 | 0 |
+| 12 | 0 | 3 | 5 | 5 |
+| 13 | 0 | 3 | 5 | 5 |
+| 14 | 0 | 3 | 5 | 5 |
+| 15 | 1 | 3 | 5 | 5 |
+| 15 | 0 | 23456 | 12345 | 5 |
+| 16 | 0 | 23456 | 12345 | 5 |
+| 17 | 0 | 23456 | 12345 | 5 |
+| 18 | 0 | 23456 | 12345 | 5 |
+| 19 | 0 | 23456 | 12345 | 5 |
+| 20 | 0 | 23456 | 12345 | 5 |
+| 21 | 0 | 23456 | 12345 | 5 |
+| 22 | 0 | 23456 | 12345 | 5 |
+| 23 | 0 | 23456 | 12345 | 5 |
+| 24 | 0 | 23456 | 12345 | 5 |
+| 25 | 0 | 23456 | 12345 | 23456 |
diff --git a/src/lib/computer/testing/official/ComputerMax-external.tst b/src/lib/computer/testing/official/ComputerMax-external.tst
new file mode 100644
index 0000000..52b6bef
--- /dev/null
+++ b/src/lib/computer/testing/official/ComputerMax-external.tst
@@ -0,0 +1,38 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/05/ComputerMax-external.tst
+
+load Computer.hdl,
+output-file ComputerMax-external.out,
+compare-to ComputerMax-external.cmp,
+output-list time%S1.4.1 reset%B2.1.2 RAM16K[0]%D1.7.1 RAM16K[1]%D1.7.1 RAM16K[2]%D1.7.1;
+
+// Load a program written in the Hack machine language.
+// The program computes the maximum of RAM[0] and RAM[1]
+// and writes the result in RAM[2].
+ROM32K load Max.hack,
+
+// first run: compute max(3,5)
+set RAM16K[0] 3,
+set RAM16K[1] 5,
+output;
+
+repeat 14 {
+ tick, tock, output;
+}
+
+// reset the PC
+set reset 1,
+tick, tock, output;
+
+// second run: compute max(23456,12345)
+set reset 0,
+set RAM16K[0] 23456,
+set RAM16K[1] 12345,
+output;
+
+// The run on these inputs needs less cycles (different branching)
+repeat 10 {
+ tick, tock, output;
+}
diff --git a/src/lib/computer/testing/official/ComputerMax.cmp b/src/lib/computer/testing/official/ComputerMax.cmp
new file mode 100644
index 0000000..42276cd
--- /dev/null
+++ b/src/lib/computer/testing/official/ComputerMax.cmp
@@ -0,0 +1,28 @@
+| time |reset|ARegister|DRegister|PC[]|RAM16K[0]|RAM16K[1]|RAM16K[2]|
+| 0 | 0 | 0 | 0 | 0| 3 | 5 | 0 |
+| 1 | 0 | 0 | 0 | 1| 3 | 5 | 0 |
+| 2 | 0 | 0 | 3 | 2| 3 | 5 | 0 |
+| 3 | 0 | 1 | 3 | 3| 3 | 5 | 0 |
+| 4 | 0 | 1 | -2 | 4| 3 | 5 | 0 |
+| 5 | 0 | 10 | -2 | 5| 3 | 5 | 0 |
+| 6 | 0 | 10 | -2 | 6| 3 | 5 | 0 |
+| 7 | 0 | 1 | -2 | 7| 3 | 5 | 0 |
+| 8 | 0 | 1 | 5 | 8| 3 | 5 | 0 |
+| 9 | 0 | 12 | 5 | 9| 3 | 5 | 0 |
+| 10 | 0 | 12 | 5 | 12| 3 | 5 | 0 |
+| 11 | 0 | 2 | 5 | 13| 3 | 5 | 0 |
+| 12 | 0 | 2 | 5 | 14| 3 | 5 | 5 |
+| 13 | 0 | 14 | 5 | 15| 3 | 5 | 5 |
+| 14 | 0 | 14 | 5 | 14| 3 | 5 | 5 |
+| 15 | 1 | 14 | 5 | 0| 3 | 5 | 5 |
+| 15 | 0 | 14 | 5 | 0| 23456 | 12345 | 5 |
+| 16 | 0 | 0 | 5 | 1| 23456 | 12345 | 5 |
+| 17 | 0 | 0 | 23456 | 2| 23456 | 12345 | 5 |
+| 18 | 0 | 1 | 23456 | 3| 23456 | 12345 | 5 |
+| 19 | 0 | 1 | 11111 | 4| 23456 | 12345 | 5 |
+| 20 | 0 | 10 | 11111 | 5| 23456 | 12345 | 5 |
+| 21 | 0 | 10 | 11111 | 10| 23456 | 12345 | 5 |
+| 22 | 0 | 0 | 11111 | 11| 23456 | 12345 | 5 |
+| 23 | 0 | 0 | 23456 | 12| 23456 | 12345 | 5 |
+| 24 | 0 | 2 | 23456 | 13| 23456 | 12345 | 5 |
+| 25 | 0 | 2 | 23456 | 14| 23456 | 12345 | 23456 |
diff --git a/src/lib/computer/testing/official/ComputerMax.tst b/src/lib/computer/testing/official/ComputerMax.tst
new file mode 100644
index 0000000..e090754
--- /dev/null
+++ b/src/lib/computer/testing/official/ComputerMax.tst
@@ -0,0 +1,39 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/05/ComputerMax.tst
+
+load Computer.hdl,
+output-file ComputerMax.out,
+compare-to ComputerMax.cmp,
+output-list time%S1.4.1 reset%B2.1.2 ARegister[]%D1.7.1 DRegister[]%D1.7.1 PC[]%D0.4.0 RAM16K[0]%D1.7.1 RAM16K[1]%D1.7.1 RAM16K[2]%D1.7.1;
+
+// Load a program written in the Hack machine language.
+// The program computes the maximum of RAM[0] and RAM[1]
+// and writes the result in RAM[2].
+
+ROM32K load Max.hack,
+
+// first run: compute max(3,5)
+set RAM16K[0] 3,
+set RAM16K[1] 5,
+output;
+
+repeat 14 {
+ tick, tock, output;
+}
+
+// reset the PC
+set reset 1,
+tick, tock, output;
+
+// second run: compute max(23456,12345)
+set reset 0,
+set RAM16K[0] 23456,
+set RAM16K[1] 12345,
+output;
+
+// The run on these inputs needs less cycles (different branching)
+repeat 10 {
+ tick, tock, output;
+}
diff --git a/src/lib/computer/testing/official/ComputerRect-external.cmp b/src/lib/computer/testing/official/ComputerRect-external.cmp
new file mode 100644
index 0000000..f276922
--- /dev/null
+++ b/src/lib/computer/testing/official/ComputerRect-external.cmp
@@ -0,0 +1,65 @@
+| time |
+| 0 |
+| 1 |
+| 2 |
+| 3 |
+| 4 |
+| 5 |
+| 6 |
+| 7 |
+| 8 |
+| 9 |
+| 10 |
+| 11 |
+| 12 |
+| 13 |
+| 14 |
+| 15 |
+| 16 |
+| 17 |
+| 18 |
+| 19 |
+| 20 |
+| 21 |
+| 22 |
+| 23 |
+| 24 |
+| 25 |
+| 26 |
+| 27 |
+| 28 |
+| 29 |
+| 30 |
+| 31 |
+| 32 |
+| 33 |
+| 34 |
+| 35 |
+| 36 |
+| 37 |
+| 38 |
+| 39 |
+| 40 |
+| 41 |
+| 42 |
+| 43 |
+| 44 |
+| 45 |
+| 46 |
+| 47 |
+| 48 |
+| 49 |
+| 50 |
+| 51 |
+| 52 |
+| 53 |
+| 54 |
+| 55 |
+| 56 |
+| 57 |
+| 58 |
+| 59 |
+| 60 |
+| 61 |
+| 62 |
+| 63 |
diff --git a/src/lib/computer/testing/official/ComputerRect-external.tst b/src/lib/computer/testing/official/ComputerRect-external.tst
new file mode 100644
index 0000000..f9102f7
--- /dev/null
+++ b/src/lib/computer/testing/official/ComputerRect-external.tst
@@ -0,0 +1,26 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/05/ComputerRect-external.tst
+
+load Computer.hdl,
+output-file ComputerRect-external.out,
+compare-to ComputerRect-external.cmp,
+output-list time%S1.4.1;
+
+// Load a program written in the Hack machine language.
+// The program draws a rectangle of width 16 pixels and
+// length RAM[0] at the top left of the screen.
+ROM32K load Rect.hack,
+
+echo "Before you run this script, select the 'Screen' option from the 'View' menu";
+
+echo "A small rectangle should be drawn at the top left of the screen (the 'Screen' option of the 'View' menu should be selected.)";
+
+// draw a rectangle 16 pixels wide and 4 pixels long
+set RAM16K[0] 4,
+output;
+
+repeat 63 {
+ tick, tock, output;
+}
diff --git a/src/lib/computer/testing/official/ComputerRect.cmp b/src/lib/computer/testing/official/ComputerRect.cmp
new file mode 100644
index 0000000..a6b5cc9
--- /dev/null
+++ b/src/lib/computer/testing/official/ComputerRect.cmp
@@ -0,0 +1,65 @@
+| time |ARegister|DRegister|PC[]|RAM16K[0]|RAM16K[1]|RAM16K[2]|
+| 0 | 0 | 0 | 0| 4 | 0 | 0 |
+| 1 | 0 | 0 | 1| 4 | 0 | 0 |
+| 2 | 0 | 4 | 2| 4 | 0 | 0 |
+| 3 | 23 | 4 | 3| 4 | 0 | 0 |
+| 4 | 23 | 4 | 4| 4 | 0 | 0 |
+| 5 | 16 | 4 | 5| 4 | 0 | 0 |
+| 6 | 16 | 4 | 6| 4 | 0 | 0 |
+| 7 | 16384 | 4 | 7| 4 | 0 | 0 |
+| 8 | 16384 | 16384 | 8| 4 | 0 | 0 |
+| 9 | 17 | 16384 | 9| 4 | 0 | 0 |
+| 10 | 17 | 16384 | 10| 4 | 0 | 0 |
+| 11 | 17 | 16384 | 11| 4 | 0 | 0 |
+| 12 | 16384 | 16384 | 12| 4 | 0 | 0 |
+| 13 | 16384 | 16384 | 13| 4 | 0 | 0 |
+| 14 | 17 | 16384 | 14| 4 | 0 | 0 |
+| 15 | 17 | 16384 | 15| 4 | 0 | 0 |
+| 16 | 32 | 16384 | 16| 4 | 0 | 0 |
+| 17 | 32 | 16416 | 17| 4 | 0 | 0 |
+| 18 | 17 | 16416 | 18| 4 | 0 | 0 |
+| 19 | 17 | 16416 | 19| 4 | 0 | 0 |
+| 20 | 16 | 16416 | 20| 4 | 0 | 0 |
+| 21 | 16 | 3 | 21| 4 | 0 | 0 |
+| 22 | 10 | 3 | 22| 4 | 0 | 0 |
+| 23 | 10 | 3 | 10| 4 | 0 | 0 |
+| 24 | 17 | 3 | 11| 4 | 0 | 0 |
+| 25 | 16416 | 3 | 12| 4 | 0 | 0 |
+| 26 | 16416 | 3 | 13| 4 | 0 | 0 |
+| 27 | 17 | 3 | 14| 4 | 0 | 0 |
+| 28 | 17 | 16416 | 15| 4 | 0 | 0 |
+| 29 | 32 | 16416 | 16| 4 | 0 | 0 |
+| 30 | 32 | 16448 | 17| 4 | 0 | 0 |
+| 31 | 17 | 16448 | 18| 4 | 0 | 0 |
+| 32 | 17 | 16448 | 19| 4 | 0 | 0 |
+| 33 | 16 | 16448 | 20| 4 | 0 | 0 |
+| 34 | 16 | 2 | 21| 4 | 0 | 0 |
+| 35 | 10 | 2 | 22| 4 | 0 | 0 |
+| 36 | 10 | 2 | 10| 4 | 0 | 0 |
+| 37 | 17 | 2 | 11| 4 | 0 | 0 |
+| 38 | 16448 | 2 | 12| 4 | 0 | 0 |
+| 39 | 16448 | 2 | 13| 4 | 0 | 0 |
+| 40 | 17 | 2 | 14| 4 | 0 | 0 |
+| 41 | 17 | 16448 | 15| 4 | 0 | 0 |
+| 42 | 32 | 16448 | 16| 4 | 0 | 0 |
+| 43 | 32 | 16480 | 17| 4 | 0 | 0 |
+| 44 | 17 | 16480 | 18| 4 | 0 | 0 |
+| 45 | 17 | 16480 | 19| 4 | 0 | 0 |
+| 46 | 16 | 16480 | 20| 4 | 0 | 0 |
+| 47 | 16 | 1 | 21| 4 | 0 | 0 |
+| 48 | 10 | 1 | 22| 4 | 0 | 0 |
+| 49 | 10 | 1 | 10| 4 | 0 | 0 |
+| 50 | 17 | 1 | 11| 4 | 0 | 0 |
+| 51 | 16480 | 1 | 12| 4 | 0 | 0 |
+| 52 | 16480 | 1 | 13| 4 | 0 | 0 |
+| 53 | 17 | 1 | 14| 4 | 0 | 0 |
+| 54 | 17 | 16480 | 15| 4 | 0 | 0 |
+| 55 | 32 | 16480 | 16| 4 | 0 | 0 |
+| 56 | 32 | 16512 | 17| 4 | 0 | 0 |
+| 57 | 17 | 16512 | 18| 4 | 0 | 0 |
+| 58 | 17 | 16512 | 19| 4 | 0 | 0 |
+| 59 | 16 | 16512 | 20| 4 | 0 | 0 |
+| 60 | 16 | 0 | 21| 4 | 0 | 0 |
+| 61 | 10 | 0 | 22| 4 | 0 | 0 |
+| 62 | 10 | 0 | 23| 4 | 0 | 0 |
+| 63 | 23 | 0 | 24| 4 | 0 | 0 |
diff --git a/src/lib/computer/testing/official/ComputerRect.tst b/src/lib/computer/testing/official/ComputerRect.tst
new file mode 100644
index 0000000..b1e2126
--- /dev/null
+++ b/src/lib/computer/testing/official/ComputerRect.tst
@@ -0,0 +1,26 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/05/ComputerRect.tst
+
+load Computer.hdl,
+output-file ComputerRect.out,
+compare-to ComputerRect.cmp,
+output-list time%S1.4.1 ARegister[]%D1.7.1 DRegister[]%D1.7.1 PC[]%D0.4.0 RAM16K[0]%D1.7.1 RAM16K[1]%D1.7.1 RAM16K[2]%D1.7.1;
+
+// Load a program written in the Hack machine language.
+// The program draws a rectangle of width 16 pixels and
+// length RAM[0] at the top left of the screen.
+ROM32K load Rect.hack,
+
+echo "Before you run this script, select the 'Screen' option from the 'View' menu";
+
+echo "A small rectangle should be drawn at the top left of the screen (the 'Screen' option of the 'View' menu should be selected.)";
+
+// Draws a rectangle 16 pixels wide and 4 pixels long
+set RAM16K[0] 4,
+output;
+
+repeat 63 {
+ tick, tock, output;
+}
diff --git a/src/lib/computer/testing/official/DMux.cmp b/src/lib/computer/testing/official/DMux.cmp
new file mode 100644
index 0000000..6982094
--- /dev/null
+++ b/src/lib/computer/testing/official/DMux.cmp
@@ -0,0 +1,5 @@
+| in | sel | a | b |
+| 0 | 0 | 0 | 0 |
+| 0 | 1 | 0 | 0 |
+| 1 | 0 | 1 | 0 |
+| 1 | 1 | 0 | 1 |
diff --git a/src/lib/computer/testing/official/DMux.tst b/src/lib/computer/testing/official/DMux.tst
new file mode 100644
index 0000000..4adbc43
--- /dev/null
+++ b/src/lib/computer/testing/official/DMux.tst
@@ -0,0 +1,27 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/DMux.tst
+
+load DMux.hdl,
+output-file DMux.out,
+compare-to DMux.cmp,
+output-list in%B3.1.3 sel%B3.1.3 a%B3.1.3 b%B3.1.3;
+
+set in 0,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
+
+set in 1,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/DMux4Way.cmp b/src/lib/computer/testing/official/DMux4Way.cmp
new file mode 100644
index 0000000..eac35c4
--- /dev/null
+++ b/src/lib/computer/testing/official/DMux4Way.cmp
@@ -0,0 +1,9 @@
+| in | sel | a | b | c | d |
+| 0 | 00 | 0 | 0 | 0 | 0 |
+| 0 | 01 | 0 | 0 | 0 | 0 |
+| 0 | 10 | 0 | 0 | 0 | 0 |
+| 0 | 11 | 0 | 0 | 0 | 0 |
+| 1 | 00 | 1 | 0 | 0 | 0 |
+| 1 | 01 | 0 | 1 | 0 | 0 |
+| 1 | 10 | 0 | 0 | 1 | 0 |
+| 1 | 11 | 0 | 0 | 0 | 1 |
diff --git a/src/lib/computer/testing/official/DMux4Way.tst b/src/lib/computer/testing/official/DMux4Way.tst
new file mode 100644
index 0000000..6fbbb56
--- /dev/null
+++ b/src/lib/computer/testing/official/DMux4Way.tst
@@ -0,0 +1,43 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/DMux4Way.tst
+
+load DMux4Way.hdl,
+output-file DMux4Way.out,
+compare-to DMux4Way.cmp,
+output-list in%B2.1.2 sel%B2.2.2 a%B2.1.2 b%B2.1.2 c%B2.1.2 d%B2.1.2;
+
+set in 0,
+set sel %B00,
+eval,
+output;
+
+set sel %B01,
+eval,
+output;
+
+set sel %B10,
+eval,
+output;
+
+set sel %B11,
+eval,
+output;
+
+set in 1,
+set sel %B00,
+eval,
+output;
+
+set sel %B01,
+eval,
+output;
+
+set sel %B10,
+eval,
+output;
+
+set sel %B11,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/DMux8Way.cmp b/src/lib/computer/testing/official/DMux8Way.cmp
new file mode 100644
index 0000000..375d44a
--- /dev/null
+++ b/src/lib/computer/testing/official/DMux8Way.cmp
@@ -0,0 +1,17 @@
+| in | sel | a | b | c | d | e | f | g | h |
+| 0 | 000 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| 0 | 001 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| 0 | 010 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| 0 | 011 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| 0 | 100 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| 0 | 101 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| 0 | 110 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| 0 | 111 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| 1 | 000 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+| 1 | 001 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
+| 1 | 010 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
+| 1 | 011 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
+| 1 | 100 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
+| 1 | 101 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+| 1 | 110 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
+| 1 | 111 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
diff --git a/src/lib/computer/testing/official/DMux8Way.tst b/src/lib/computer/testing/official/DMux8Way.tst
new file mode 100644
index 0000000..56d827e
--- /dev/null
+++ b/src/lib/computer/testing/official/DMux8Way.tst
@@ -0,0 +1,75 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/DMux8Way.tst
+
+load DMux8Way.hdl,
+output-file DMux8Way.out,
+compare-to DMux8Way.cmp,
+output-list in%B2.1.2 sel%B2.3.2 a%B2.1.2 b%B2.1.2 c%B2.1.2 d%B2.1.2 e%B2.1.2 f%B2.1.2 g%B2.1.2 h%B2.1.2;
+
+set in 0,
+set sel %B000,
+eval,
+output;
+
+set sel %B001,
+eval,
+output;
+
+set sel %B010,
+eval,
+output;
+
+set sel %B011,
+eval,
+output;
+
+set sel %B100,
+eval,
+output;
+
+set sel %B101,
+eval,
+output;
+
+set sel %B110,
+eval,
+output;
+
+set sel %B111,
+eval,
+output;
+
+set in 1,
+set sel %B000,
+eval,
+output;
+
+set sel %B001,
+eval,
+output;
+
+set sel %B010,
+eval,
+output;
+
+set sel %B011,
+eval,
+output;
+
+set sel %B100,
+eval,
+output;
+
+set sel %B101,
+eval,
+output;
+
+set sel %B110,
+eval,
+output;
+
+set sel %B111,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/FullAdder.cmp b/src/lib/computer/testing/official/FullAdder.cmp
new file mode 100644
index 0000000..84551aa
--- /dev/null
+++ b/src/lib/computer/testing/official/FullAdder.cmp
@@ -0,0 +1,9 @@
+| a | b | c | sum | carry |
+| 0 | 0 | 0 | 0 | 0 |
+| 0 | 0 | 1 | 1 | 0 |
+| 0 | 1 | 0 | 1 | 0 |
+| 0 | 1 | 1 | 0 | 1 |
+| 1 | 0 | 0 | 1 | 0 |
+| 1 | 0 | 1 | 0 | 1 |
+| 1 | 1 | 0 | 0 | 1 |
+| 1 | 1 | 1 | 1 | 1 |
diff --git a/src/lib/computer/testing/official/FullAdder.tst b/src/lib/computer/testing/official/FullAdder.tst
new file mode 100644
index 0000000..5125cee
--- /dev/null
+++ b/src/lib/computer/testing/official/FullAdder.tst
@@ -0,0 +1,47 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/02/FullAdder.tst
+
+load FullAdder.hdl,
+output-file FullAdder.out,
+compare-to FullAdder.cmp,
+output-list a%B3.1.3 b%B3.1.3 c%B3.1.3 sum%B3.1.3 carry%B3.1.3;
+
+set a 0,
+set b 0,
+set c 0,
+eval,
+output;
+
+set c 1,
+eval,
+output;
+
+set b 1,
+set c 0,
+eval,
+output;
+
+set c 1,
+eval,
+output;
+
+set a 1,
+set b 0,
+set c 0,
+eval,
+output;
+
+set c 1,
+eval,
+output;
+
+set b 1,
+set c 0,
+eval,
+output;
+
+set c 1,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/HalfAdder.cmp b/src/lib/computer/testing/official/HalfAdder.cmp
new file mode 100644
index 0000000..911c770
--- /dev/null
+++ b/src/lib/computer/testing/official/HalfAdder.cmp
@@ -0,0 +1,5 @@
+| a | b | sum | carry |
+| 0 | 0 | 0 | 0 |
+| 0 | 1 | 1 | 0 |
+| 1 | 0 | 1 | 0 |
+| 1 | 1 | 0 | 1 |
diff --git a/src/lib/computer/testing/official/HalfAdder.tst b/src/lib/computer/testing/official/HalfAdder.tst
new file mode 100644
index 0000000..069b8ea
--- /dev/null
+++ b/src/lib/computer/testing/official/HalfAdder.tst
@@ -0,0 +1,29 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/02/HalfAdder.tst
+
+load HalfAdder.hdl,
+output-file HalfAdder.out,
+compare-to HalfAdder.cmp,
+output-list a%B3.1.3 b%B3.1.3 sum%B3.1.3 carry%B3.1.3;
+
+set a 0,
+set b 0,
+eval,
+output;
+
+set a 0,
+set b 1,
+eval,
+output;
+
+set a 1,
+set b 0,
+eval,
+output;
+
+set a 1,
+set b 1,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/Inc16.cmp b/src/lib/computer/testing/official/Inc16.cmp
new file mode 100644
index 0000000..451f563
--- /dev/null
+++ b/src/lib/computer/testing/official/Inc16.cmp
@@ -0,0 +1,5 @@
+| in | out |
+| 0000000000000000 | 0000000000000001 |
+| 1111111111111111 | 0000000000000000 |
+| 0000000000000101 | 0000000000000110 |
+| 1111111111111011 | 1111111111111100 |
diff --git a/src/lib/computer/testing/official/Inc16.tst b/src/lib/computer/testing/official/Inc16.tst
new file mode 100644
index 0000000..8537d86
--- /dev/null
+++ b/src/lib/computer/testing/official/Inc16.tst
@@ -0,0 +1,25 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/02/Inc16.tst
+
+load Inc16.hdl,
+output-file Inc16.out,
+compare-to Inc16.cmp,
+output-list in%B1.16.1 out%B1.16.1;
+
+set in %B0000000000000000, // in = 0
+eval,
+output;
+
+set in %B1111111111111111, // in = -1
+eval,
+output;
+
+set in %B0000000000000101, // in = 5
+eval,
+output;
+
+set in %B1111111111111011, // in = -5
+eval,
+output;
diff --git a/src/lib/computer/testing/official/LICENSE b/src/lib/computer/testing/official/LICENSE
new file mode 100644
index 0000000..da6f868
--- /dev/null
+++ b/src/lib/computer/testing/official/LICENSE
@@ -0,0 +1,12 @@
+MIT License
+
+© 2017 Shimon Schocken and Noam Nisan
+
+This software is based on Stefano Volpe's 'Nand2Tetris Tools'. Please check [here](https://github.com/foxyseta/nand-ide/blob/master/LICENSE) for further information.
+This software is based on Aviv Yaish's 'NAND IDE'. Please check [here](https://github.com/AvivYaish/nand-ide/blob/master/LICENSE) for further information.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/lib/computer/testing/official/Max.hack b/src/lib/computer/testing/official/Max.hack
new file mode 100644
index 0000000..2e04a8d
--- /dev/null
+++ b/src/lib/computer/testing/official/Max.hack
@@ -0,0 +1,16 @@
+0000000000000000
+1111110000010000
+0000000000000001
+1111010011010000
+0000000000001010
+1110001100000001
+0000000000000001
+1111110000010000
+0000000000001100
+1110101010000111
+0000000000000000
+1111110000010000
+0000000000000010
+1110001100001000
+0000000000001110
+1110101010000111
diff --git a/src/lib/computer/testing/official/Memory.cmp b/src/lib/computer/testing/official/Memory.cmp
new file mode 100644
index 0000000..2f4c727
--- /dev/null
+++ b/src/lib/computer/testing/official/Memory.cmp
@@ -0,0 +1,68 @@
+| in |load | address | out |
+| 12345 | 1 | 010000000000000 | 0 |
+| 12345 | 1 | 010000000000000 | 12345 |
+| 12345 | 1 | 100000000000000 | 0 |
+| 12345 | 1 | 100000000000000 | 12345 |
+| -1 | 1 | 000000000000000 | 0 |
+| -1 | 1 | 000000000000000 | -1 |
+| 9999 | 0 | 000000000000000 | -1 |
+| 9999 | 0 | 000000000000000 | -1 |
+| 9999 | 0 | 010000000000000 | 12345 |
+| 9999 | 0 | 100000000000000 | 12345 |
+| 12345 | 1 | 000000000000000 | -1 |
+| 12345 | 1 | 000000000000000 | 12345 |
+| 12345 | 1 | 100000000000000 | 12345 |
+| 12345 | 1 | 100000000000000 | 12345 |
+| 2222 | 1 | 010000000000000 | 12345 |
+| 2222 | 1 | 010000000000000 | 2222 |
+| 9999 | 0 | 010000000000000 | 2222 |
+| 9999 | 0 | 010000000000000 | 2222 |
+| 9999 | 0 | 000000000000000 | 12345 |
+| 9999 | 0 | 100000000000000 | 12345 |
+| 9999 | 0 | 000000000000001 | 0 |
+| 9999 | 0 | 000000000000010 | 0 |
+| 9999 | 0 | 000000000000100 | 0 |
+| 9999 | 0 | 000000000001000 | 0 |
+| 9999 | 0 | 000000000010000 | 0 |
+| 9999 | 0 | 000000000100000 | 0 |
+| 9999 | 0 | 000000001000000 | 0 |
+| 9999 | 0 | 000000010000000 | 0 |
+| 9999 | 0 | 000000100000000 | 0 |
+| 9999 | 0 | 000001000000000 | 0 |
+| 9999 | 0 | 000010000000000 | 0 |
+| 9999 | 0 | 000100000000000 | 0 |
+| 9999 | 0 | 001000000000000 | 0 |
+| 9999 | 0 | 010000000000000 | 2222 |
+| 1234 | 1 | 001001000110100 | 0 |
+| 1234 | 1 | 001001000110100 | 1234 |
+| 1234 | 0 | 010001000110100 | 0 |
+| 1234 | 0 | 110001000110100 | 0 |
+| 2345 | 1 | 010001101000101 | 0 |
+| 2345 | 1 | 010001101000101 | 2345 |
+| 2345 | 0 | 000001101000101 | 0 |
+| 2345 | 0 | 100001101000101 | 0 |
+| 0 | 1 | 100000000000000 | 12345 |
+| 0 | 1 | 100000000000000 | 0 |
+| 0 | 1 | 110000000000000 | 75 |
+| 12345 | 1 | 000111111001111 | 0 |
+| 12345 | 1 | 000111111001111 | 12345 |
+| 12345 | 1 | 010111111001111 | 0 |
+| 12345 | 1 | 010111111001111 | 12345 |
+| -1 | 1 | 100111111001111 | -1 |
+| -1 | 1 | 101000001001111 | -1 |
+| -1 | 1 | 000111111001111 | 12345 |
+| -1 | 1 | 010111111001111 | 12345 |
+| -1 | 0 | 100111111001110 | 0 |
+| -1 | 0 | 100111111001101 | 0 |
+| -1 | 0 | 100111111001011 | 0 |
+| -1 | 0 | 100111111000111 | 0 |
+| -1 | 0 | 100111111011111 | 0 |
+| -1 | 0 | 100111111101111 | 0 |
+| -1 | 0 | 100111110001111 | 0 |
+| -1 | 0 | 100111101001111 | 0 |
+| -1 | 0 | 100111011001111 | 0 |
+| -1 | 0 | 100110111001111 | 0 |
+| -1 | 0 | 100101111001111 | 0 |
+| -1 | 0 | 100011111001111 | 0 |
+| -1 | 0 | 101111111001111 | 0 |
+| -1 | 0 | 110000000000000 | 89 |
diff --git a/src/lib/computer/testing/official/Memory.tst b/src/lib/computer/testing/official/Memory.tst
new file mode 100644
index 0000000..63f233a
--- /dev/null
+++ b/src/lib/computer/testing/official/Memory.tst
@@ -0,0 +1,191 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/05/Memory.tst
+
+load Memory.hdl,
+output-file Memory.out,
+compare-to Memory.cmp,
+output-list in%D1.6.1 load%B2.1.2 address%B1.15.1 out%D1.6.1;
+
+echo "Before you run this script, select the 'Screen' option from the 'View' menu";
+
+
+// There is an interesting design error that has shown up in several students'
+// Memory.hdl files that causes zeros to be written in the corresponding offset
+// in the inactive memory segments to the actual write. To detect this, the
+// test must not only look for writes into the wrong segment, but changes.
+// The following initialization writes a signal number into the memory where
+// the bad writes may occur.
+
+//// Set RAM[2000], RAM[4000] = 12345 (for following overwrite test)
+set in 12345, set load 1, set address %X2000, tick, output; tock, output;
+set address %X4000, tick, output; tock, output;
+
+
+set in -1, // Set RAM[0] = -1
+set load 1,
+set address 0,
+tick,
+output;
+tock,
+output;
+
+set in 9999, // RAM[0] holds value
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set address %X2000, // Did not also write to upper RAM or Screen
+eval,
+output;
+set address %X4000,
+eval,
+output;
+
+
+//// Set RAM[0], RAM[4000] = 12345 (for following overwrite test)
+set in 12345, set load 1, set address %X0000, tick, output; tock, output;
+set address %X4000, tick, output; tock, output;
+
+
+set in 2222, // Set RAM[2000] = 2222
+set load 1,
+set address %X2000,
+tick,
+output;
+tock,
+output;
+
+set in 9999, // RAM[2000] holds value
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set address 0, // Did not also write to lower RAM or Screen
+eval,
+output;
+set address %X4000,
+eval,
+output;
+
+set load 0, // Low order address bits connected
+set address %X0001, eval, output;
+set address %X0002, eval, output;
+set address %X0004, eval, output;
+set address %X0008, eval, output;
+set address %X0010, eval, output;
+set address %X0020, eval, output;
+set address %X0040, eval, output;
+set address %X0080, eval, output;
+set address %X0100, eval, output;
+set address %X0200, eval, output;
+set address %X0400, eval, output;
+set address %X0800, eval, output;
+set address %X1000, eval, output;
+set address %X2000, eval, output;
+
+set address %X1234, // RAM[1234] = 1234
+set in 1234,
+set load 1,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %X2234, // Did not also write to upper RAM or Screen
+eval, output;
+set address %X6234,
+eval, output;
+
+set address %X2345, // RAM[2345] = 2345
+set in 2345,
+set load 1,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %X0345, // Did not also write to lower RAM or Screen
+eval, output;
+set address %X4345,
+eval, output;
+
+
+//// Clear the overwrite detection value from the screen
+set in 0, set load 1, set address %X4000, tick, output; tock, output;
+
+
+// Keyboard test
+
+set address 24576,
+echo "Click the Keyboard icon and hold down the 'K' key (uppercase) until you see the next message (it should appear shortly after that) ...",
+// It's important to keep holding the key down since if the system is busy,
+// the memory will zero itself before being outputted.
+
+while out <> 75 {
+ tick, tock; // tick, tock prevents hang if sync. parts used in KB path.
+}
+
+clear-echo,
+output;
+
+// Screen test
+
+//// Set RAM[0FCF], RAM[2FCF] = 12345 (for following overwrite test)
+set in 12345, set load 1, set address %X0FCF, tick, output; tock, output;
+set address %X2FCF, tick, output; tock, output;
+
+set load 1,
+set in -1,
+set address %X4FCF,
+tick,
+tock,
+output,
+
+set address %X504F,
+tick,
+tock,
+output;
+
+set address %X0FCF, // Did not also write to lower or upper RAM
+eval,
+output;
+set address %X2FCF,
+eval,
+output;
+
+set load 0, // Low order address bits connected
+set address %X4FCE, eval, output;
+set address %X4FCD, eval, output;
+set address %X4FCB, eval, output;
+set address %X4FC7, eval, output;
+set address %X4FDF, eval, output;
+set address %X4FEF, eval, output;
+set address %X4F8F, eval, output;
+set address %X4F4F, eval, output;
+set address %X4ECF, eval, output;
+set address %X4DCF, eval, output;
+set address %X4BCF, eval, output;
+set address %X47CF, eval, output;
+set address %X5FCF, eval, output;
+
+
+set load 0,
+set address 24576,
+echo "Make sure you see ONLY two horizontal lines in the middle of the screen. Hold down 'Y' (uppercase) until you see the next message ...",
+// It's important to keep holding the key down since if the system is busy,
+// the memory will zero itself before being outputted.
+
+while out <> 89 {
+ tick, tock; // tick, tock prevents hang if sync. parts used in KB path.
+}
+
+clear-echo,
+output;
diff --git a/src/lib/computer/testing/official/Mux.cmp b/src/lib/computer/testing/official/Mux.cmp
new file mode 100644
index 0000000..7a5cc5b
--- /dev/null
+++ b/src/lib/computer/testing/official/Mux.cmp
@@ -0,0 +1,9 @@
+| a | b | sel | out |
+| 0 | 0 | 0 | 0 |
+| 0 | 0 | 1 | 0 |
+| 0 | 1 | 0 | 0 |
+| 0 | 1 | 1 | 1 |
+| 1 | 0 | 0 | 1 |
+| 1 | 0 | 1 | 0 |
+| 1 | 1 | 0 | 1 |
+| 1 | 1 | 1 | 1 |
diff --git a/src/lib/computer/testing/official/Mux.tst b/src/lib/computer/testing/official/Mux.tst
new file mode 100644
index 0000000..9b7afd9
--- /dev/null
+++ b/src/lib/computer/testing/official/Mux.tst
@@ -0,0 +1,49 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/Mux.tst
+
+load Mux.hdl,
+output-file Mux.out,
+compare-to Mux.cmp,
+output-list a%B3.1.3 b%B3.1.3 sel%B3.1.3 out%B3.1.3;
+
+set a 0,
+set b 0,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
+
+set a 0,
+set b 1,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
+
+set a 1,
+set b 0,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
+
+set a 1,
+set b 1,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/Mux16.cmp b/src/lib/computer/testing/official/Mux16.cmp
new file mode 100644
index 0000000..661ee67
--- /dev/null
+++ b/src/lib/computer/testing/official/Mux16.cmp
@@ -0,0 +1,9 @@
+| a | b | sel | out |
+| 0000000000000000 | 0000000000000000 | 0 | 0000000000000000 |
+| 0000000000000000 | 0000000000000000 | 1 | 0000000000000000 |
+| 0000000000000000 | 0001001000110100 | 0 | 0000000000000000 |
+| 0000000000000000 | 0001001000110100 | 1 | 0001001000110100 |
+| 1001100001110110 | 0000000000000000 | 0 | 1001100001110110 |
+| 1001100001110110 | 0000000000000000 | 1 | 0000000000000000 |
+| 1010101010101010 | 0101010101010101 | 0 | 1010101010101010 |
+| 1010101010101010 | 0101010101010101 | 1 | 0101010101010101 |
diff --git a/src/lib/computer/testing/official/Mux16.tst b/src/lib/computer/testing/official/Mux16.tst
new file mode 100644
index 0000000..cf34155
--- /dev/null
+++ b/src/lib/computer/testing/official/Mux16.tst
@@ -0,0 +1,49 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/Mux16.tst
+
+load Mux16.hdl,
+output-file Mux16.out,
+compare-to Mux16.cmp,
+output-list a%B1.16.1 b%B1.16.1 sel%D2.1.2 out%B1.16.1;
+
+set a 0,
+set b 0,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
+
+set a %B0000000000000000,
+set b %B0001001000110100,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
+
+set a %B1001100001110110,
+set b %B0000000000000000,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
+
+set a %B1010101010101010,
+set b %B0101010101010101,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
\ No newline at end of file
diff --git a/src/lib/computer/testing/official/Mux4Way16.cmp b/src/lib/computer/testing/official/Mux4Way16.cmp
new file mode 100644
index 0000000..8704e79
--- /dev/null
+++ b/src/lib/computer/testing/official/Mux4Way16.cmp
@@ -0,0 +1,9 @@
+| a | b | c | d | sel | out |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 00 | 0000000000000000 |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 01 | 0000000000000000 |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 10 | 0000000000000000 |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 11 | 0000000000000000 |
+| 0001001000110100 | 1001100001110110 | 1010101010101010 | 0101010101010101 | 00 | 0001001000110100 |
+| 0001001000110100 | 1001100001110110 | 1010101010101010 | 0101010101010101 | 01 | 1001100001110110 |
+| 0001001000110100 | 1001100001110110 | 1010101010101010 | 0101010101010101 | 10 | 1010101010101010 |
+| 0001001000110100 | 1001100001110110 | 1010101010101010 | 0101010101010101 | 11 | 0101010101010101 |
diff --git a/src/lib/computer/testing/official/Mux4Way16.tst b/src/lib/computer/testing/official/Mux4Way16.tst
new file mode 100644
index 0000000..3f4efa3
--- /dev/null
+++ b/src/lib/computer/testing/official/Mux4Way16.tst
@@ -0,0 +1,49 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/Mux4Way16.tst
+
+load Mux4Way16.hdl,
+output-file Mux4Way16.out,
+compare-to Mux4Way16.cmp,
+output-list a%B1.16.1 b%B1.16.1 c%B1.16.1 d%B1.16.1 sel%B2.2.2 out%B1.16.1;
+
+set a 0,
+set b 0,
+set c 0,
+set d 0,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
+
+set sel 2,
+eval,
+output;
+
+set sel 3,
+eval,
+output;
+
+set a %B0001001000110100,
+set b %B1001100001110110,
+set c %B1010101010101010,
+set d %B0101010101010101,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
+
+set sel 2,
+eval,
+output;
+
+set sel 3,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/Mux8Way16.cmp b/src/lib/computer/testing/official/Mux8Way16.cmp
new file mode 100644
index 0000000..1484e0a
--- /dev/null
+++ b/src/lib/computer/testing/official/Mux8Way16.cmp
@@ -0,0 +1,17 @@
+| a | b | c | d | e | f | g | h | sel | out |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 000 | 0000000000000000 |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 001 | 0000000000000000 |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 010 | 0000000000000000 |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 011 | 0000000000000000 |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 100 | 0000000000000000 |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 101 | 0000000000000000 |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 110 | 0000000000000000 |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 111 | 0000000000000000 |
+| 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 000 | 0001001000110100 |
+| 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 001 | 0010001101000101 |
+| 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 010 | 0011010001010110 |
+| 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 011 | 0100010101100111 |
+| 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 100 | 0101011001111000 |
+| 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 101 | 0110011110001001 |
+| 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 110 | 0111100010011010 |
+| 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 111 | 1000100110101011 |
diff --git a/src/lib/computer/testing/official/Mux8Way16.tst b/src/lib/computer/testing/official/Mux8Way16.tst
new file mode 100644
index 0000000..59bb41c
--- /dev/null
+++ b/src/lib/computer/testing/official/Mux8Way16.tst
@@ -0,0 +1,89 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/Mux8Way16.tst
+
+load Mux8Way16.hdl,
+output-file Mux8Way16.out,
+compare-to Mux8Way16.cmp,
+output-list a%B1.16.1 b%B1.16.1 c%B1.16.1 d%B1.16.1 e%B1.16.1 f%B1.16.1 g%B1.16.1 h%B1.16.1 sel%B2.3.2 out%B1.16.1;
+
+set a 0,
+set b 0,
+set c 0,
+set d 0,
+set e 0,
+set f 0,
+set g 0,
+set h 0,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
+
+set sel 2,
+eval,
+output;
+
+set sel 3,
+eval,
+output;
+
+set sel 4,
+eval,
+output;
+
+set sel 5,
+eval,
+output;
+
+set sel 6,
+eval,
+output;
+
+set sel 7,
+eval,
+output;
+
+set a %B0001001000110100,
+set b %B0010001101000101,
+set c %B0011010001010110,
+set d %B0100010101100111,
+set e %B0101011001111000,
+set f %B0110011110001001,
+set g %B0111100010011010,
+set h %B1000100110101011,
+set sel 0,
+eval,
+output;
+
+set sel 1,
+eval,
+output;
+
+set sel 2,
+eval,
+output;
+
+set sel 3,
+eval,
+output;
+
+set sel 4,
+eval,
+output;
+
+set sel 5,
+eval,
+output;
+
+set sel 6,
+eval,
+output;
+
+set sel 7,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/Not.cmp b/src/lib/computer/testing/official/Not.cmp
new file mode 100644
index 0000000..e8c1191
--- /dev/null
+++ b/src/lib/computer/testing/official/Not.cmp
@@ -0,0 +1,3 @@
+| in | out |
+| 0 | 1 |
+| 1 | 0 |
diff --git a/src/lib/computer/testing/official/Not.tst b/src/lib/computer/testing/official/Not.tst
new file mode 100644
index 0000000..1e3bbe7
--- /dev/null
+++ b/src/lib/computer/testing/official/Not.tst
@@ -0,0 +1,17 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/Not.tst
+
+load Not.hdl,
+output-file Not.out,
+compare-to Not.cmp,
+output-list in%B3.1.3 out%B3.1.3;
+
+set in 0,
+eval,
+output;
+
+set in 1,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/Not16.cmp b/src/lib/computer/testing/official/Not16.cmp
new file mode 100644
index 0000000..68a5512
--- /dev/null
+++ b/src/lib/computer/testing/official/Not16.cmp
@@ -0,0 +1,6 @@
+| in | out |
+| 0000000000000000 | 1111111111111111 |
+| 1111111111111111 | 0000000000000000 |
+| 1010101010101010 | 0101010101010101 |
+| 0011110011000011 | 1100001100111100 |
+| 0001001000110100 | 1110110111001011 |
diff --git a/src/lib/computer/testing/official/Not16.tst b/src/lib/computer/testing/official/Not16.tst
new file mode 100644
index 0000000..e7e2c3b
--- /dev/null
+++ b/src/lib/computer/testing/official/Not16.tst
@@ -0,0 +1,29 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/Not16.tst
+
+load Not16.hdl,
+output-file Not16.out,
+compare-to Not16.cmp,
+output-list in%B1.16.1 out%B1.16.1;
+
+set in %B0000000000000000,
+eval,
+output;
+
+set in %B1111111111111111,
+eval,
+output;
+
+set in %B1010101010101010,
+eval,
+output;
+
+set in %B0011110011000011,
+eval,
+output;
+
+set in %B0001001000110100,
+eval,
+output;
\ No newline at end of file
diff --git a/src/lib/computer/testing/official/Or.cmp b/src/lib/computer/testing/official/Or.cmp
new file mode 100644
index 0000000..dab924c
--- /dev/null
+++ b/src/lib/computer/testing/official/Or.cmp
@@ -0,0 +1,5 @@
+| a | b | out |
+| 0 | 0 | 0 |
+| 0 | 1 | 1 |
+| 1 | 0 | 1 |
+| 1 | 1 | 1 |
diff --git a/src/lib/computer/testing/official/Or.tst b/src/lib/computer/testing/official/Or.tst
new file mode 100644
index 0000000..948b6b3
--- /dev/null
+++ b/src/lib/computer/testing/official/Or.tst
@@ -0,0 +1,29 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/Or.tst
+
+load Or.hdl,
+output-file Or.out,
+compare-to Or.cmp,
+output-list a%B3.1.3 b%B3.1.3 out%B3.1.3;
+
+set a 0,
+set b 0,
+eval,
+output;
+
+set a 0,
+set b 1,
+eval,
+output;
+
+set a 1,
+set b 0,
+eval,
+output;
+
+set a 1,
+set b 1,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/Or16.cmp b/src/lib/computer/testing/official/Or16.cmp
new file mode 100644
index 0000000..e2c3a30
--- /dev/null
+++ b/src/lib/computer/testing/official/Or16.cmp
@@ -0,0 +1,7 @@
+| a | b | out |
+| 0000000000000000 | 0000000000000000 | 0000000000000000 |
+| 0000000000000000 | 1111111111111111 | 1111111111111111 |
+| 1111111111111111 | 1111111111111111 | 1111111111111111 |
+| 1010101010101010 | 0101010101010101 | 1111111111111111 |
+| 0011110011000011 | 0000111111110000 | 0011111111110011 |
+| 0001001000110100 | 1001100001110110 | 1001101001110110 |
diff --git a/src/lib/computer/testing/official/Or16.tst b/src/lib/computer/testing/official/Or16.tst
new file mode 100644
index 0000000..ea7b944
--- /dev/null
+++ b/src/lib/computer/testing/official/Or16.tst
@@ -0,0 +1,39 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/Or16.tst
+
+load Or16.hdl,
+output-file Or16.out,
+compare-to Or16.cmp,
+output-list a%B1.16.1 b%B1.16.1 out%B1.16.1;
+
+set a %B0000000000000000,
+set b %B0000000000000000,
+eval,
+output;
+
+set a %B0000000000000000,
+set b %B1111111111111111,
+eval,
+output;
+
+set a %B1111111111111111,
+set b %B1111111111111111,
+eval,
+output;
+
+set a %B1010101010101010,
+set b %B0101010101010101,
+eval,
+output;
+
+set a %B0011110011000011,
+set b %B0000111111110000,
+eval,
+output;
+
+set a %B0001001000110100,
+set b %B1001100001110110,
+eval,
+output;
\ No newline at end of file
diff --git a/src/lib/computer/testing/official/Or8Way.cmp b/src/lib/computer/testing/official/Or8Way.cmp
new file mode 100644
index 0000000..3f9fd54
--- /dev/null
+++ b/src/lib/computer/testing/official/Or8Way.cmp
@@ -0,0 +1,6 @@
+| in | out |
+| 00000000 | 0 |
+| 11111111 | 1 |
+| 00010000 | 1 |
+| 00000001 | 1 |
+| 00100110 | 1 |
diff --git a/src/lib/computer/testing/official/Or8Way.tst b/src/lib/computer/testing/official/Or8Way.tst
new file mode 100644
index 0000000..e6fbba7
--- /dev/null
+++ b/src/lib/computer/testing/official/Or8Way.tst
@@ -0,0 +1,29 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/Or8Way.tst
+
+load Or8Way.hdl,
+output-file Or8Way.out,
+compare-to Or8Way.cmp,
+output-list in%B2.8.2 out%B2.1.2;
+
+set in %B00000000,
+eval,
+output;
+
+set in %B11111111,
+eval,
+output;
+
+set in %B00010000,
+eval,
+output;
+
+set in %B00000001,
+eval,
+output;
+
+set in %B00100110,
+eval,
+output;
\ No newline at end of file
diff --git a/src/lib/computer/testing/official/PC.cmp b/src/lib/computer/testing/official/PC.cmp
new file mode 100644
index 0000000..6a050d9
--- /dev/null
+++ b/src/lib/computer/testing/official/PC.cmp
@@ -0,0 +1,31 @@
+| time | in |reset|load | inc | out |
+| 0+ | 0 | 0 | 0 | 0 | 0 |
+| 1 | 0 | 0 | 0 | 0 | 0 |
+| 1+ | 0 | 0 | 0 | 1 | 0 |
+| 2 | 0 | 0 | 0 | 1 | 1 |
+| 2+ | -32123 | 0 | 0 | 1 | 1 |
+| 3 | -32123 | 0 | 0 | 1 | 2 |
+| 3+ | -32123 | 0 | 1 | 1 | 2 |
+| 4 | -32123 | 0 | 1 | 1 | -32123 |
+| 4+ | -32123 | 0 | 0 | 1 | -32123 |
+| 5 | -32123 | 0 | 0 | 1 | -32122 |
+| 5+ | -32123 | 0 | 0 | 1 | -32122 |
+| 6 | -32123 | 0 | 0 | 1 | -32121 |
+| 6+ | 12345 | 0 | 1 | 0 | -32121 |
+| 7 | 12345 | 0 | 1 | 0 | 12345 |
+| 7+ | 12345 | 1 | 1 | 0 | 12345 |
+| 8 | 12345 | 1 | 1 | 0 | 0 |
+| 8+ | 12345 | 0 | 1 | 1 | 0 |
+| 9 | 12345 | 0 | 1 | 1 | 12345 |
+| 9+ | 12345 | 1 | 1 | 1 | 12345 |
+| 10 | 12345 | 1 | 1 | 1 | 0 |
+| 10+ | 12345 | 0 | 0 | 1 | 0 |
+| 11 | 12345 | 0 | 0 | 1 | 1 |
+| 11+ | 12345 | 1 | 0 | 1 | 1 |
+| 12 | 12345 | 1 | 0 | 1 | 0 |
+| 12+ | 0 | 0 | 1 | 1 | 0 |
+| 13 | 0 | 0 | 1 | 1 | 0 |
+| 13+ | 0 | 0 | 0 | 1 | 0 |
+| 14 | 0 | 0 | 0 | 1 | 1 |
+| 14+ | 22222 | 1 | 0 | 0 | 1 |
+| 15 | 22222 | 1 | 0 | 0 | 0 |
diff --git a/src/lib/computer/testing/official/PC.tst b/src/lib/computer/testing/official/PC.tst
new file mode 100644
index 0000000..7f4f3cd
--- /dev/null
+++ b/src/lib/computer/testing/official/PC.tst
@@ -0,0 +1,125 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/03/a/PC.tst
+
+load PC.hdl,
+output-file PC.out,
+compare-to PC.cmp,
+output-list time%S1.4.1 in%D1.6.1 reset%B2.1.2 load%B2.1.2 inc%B2.1.2 out%D1.6.1;
+
+set in 0,
+set reset 0,
+set load 0,
+set inc 0,
+tick,
+output;
+
+tock,
+output;
+
+set inc 1,
+tick,
+output;
+
+tock,
+output;
+
+set in -32123,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+tick,
+output;
+
+tock,
+output;
+
+set in 12345,
+set load 1,
+set inc 0,
+tick,
+output;
+
+tock,
+output;
+
+set reset 1,
+tick,
+output;
+
+tock,
+output;
+
+set reset 0,
+set inc 1,
+tick,
+output;
+
+tock,
+output;
+
+set reset 1,
+tick,
+output;
+
+tock,
+output;
+
+set reset 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set reset 1,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set reset 0,
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set load 0,
+set inc 1,
+tick,
+output;
+
+tock,
+output;
+
+set in 22222,
+set reset 1,
+set inc 0,
+tick,
+output;
+
+tock,
+output;
diff --git a/src/lib/computer/testing/official/RAM16K.cmp b/src/lib/computer/testing/official/RAM16K.cmp
new file mode 100644
index 0000000..a1ad9db
--- /dev/null
+++ b/src/lib/computer/testing/official/RAM16K.cmp
@@ -0,0 +1,320 @@
+| time | in |load | address | out |
+| 0+ | 0 | 0 | 0 | 0 |
+| 1 | 0 | 0 | 0 | 0 |
+| 1+ | 0 | 1 | 0 | 0 |
+| 2 | 0 | 1 | 0 | 0 |
+| 2+ | 4321 | 0 | 0 | 0 |
+| 3 | 4321 | 0 | 0 | 0 |
+| 3+ | 4321 | 1 | 4321 | 0 |
+| 4 | 4321 | 1 | 4321 | 4321 |
+| 4+ | 4321 | 0 | 0 | 0 |
+| 5 | 4321 | 0 | 0 | 0 |
+| 5+ | 12345 | 0 | 12345 | 0 |
+| 6 | 12345 | 0 | 12345 | 0 |
+| 6+ | 12345 | 1 | 12345 | 0 |
+| 7 | 12345 | 1 | 12345 | 12345 |
+| 7+ | 12345 | 0 | 12345 | 12345 |
+| 8 | 12345 | 0 | 12345 | 12345 |
+| 8 | 12345 | 0 | 4321 | 4321 |
+| 8+ | 16383 | 0 | 4321 | 4321 |
+| 9 | 16383 | 0 | 4321 | 4321 |
+| 9+ | 16383 | 1 | 16383 | 0 |
+| 10 | 16383 | 1 | 16383 | 16383 |
+| 10+ | 16383 | 0 | 16383 | 16383 |
+| 11 | 16383 | 0 | 16383 | 16383 |
+| 11 | 16383 | 0 | 12345 | 12345 |
+| 11 | 16383 | 0 | 16383 | 16383 |
+| 11+ | 16383 | 0 | 10920 | 0 |
+| 12 | 16383 | 0 | 10920 | 0 |
+| 12 | 16383 | 0 | 10921 | 0 |
+| 12 | 16383 | 0 | 10922 | 0 |
+| 12 | 16383 | 0 | 10923 | 0 |
+| 12 | 16383 | 0 | 10924 | 0 |
+| 12 | 16383 | 0 | 10925 | 0 |
+| 12 | 16383 | 0 | 10926 | 0 |
+| 12 | 16383 | 0 | 10927 | 0 |
+| 12+ | 21845 | 1 | 10920 | 0 |
+| 13 | 21845 | 1 | 10920 | 21845 |
+| 13+ | 21845 | 1 | 10921 | 0 |
+| 14 | 21845 | 1 | 10921 | 21845 |
+| 14+ | 21845 | 1 | 10922 | 0 |
+| 15 | 21845 | 1 | 10922 | 21845 |
+| 15+ | 21845 | 1 | 10923 | 0 |
+| 16 | 21845 | 1 | 10923 | 21845 |
+| 16+ | 21845 | 1 | 10924 | 0 |
+| 17 | 21845 | 1 | 10924 | 21845 |
+| 17+ | 21845 | 1 | 10925 | 0 |
+| 18 | 21845 | 1 | 10925 | 21845 |
+| 18+ | 21845 | 1 | 10926 | 0 |
+| 19 | 21845 | 1 | 10926 | 21845 |
+| 19+ | 21845 | 1 | 10927 | 0 |
+| 20 | 21845 | 1 | 10927 | 21845 |
+| 20+ | 21845 | 0 | 10920 | 21845 |
+| 21 | 21845 | 0 | 10920 | 21845 |
+| 21 | 21845 | 0 | 10921 | 21845 |
+| 21 | 21845 | 0 | 10922 | 21845 |
+| 21 | 21845 | 0 | 10923 | 21845 |
+| 21 | 21845 | 0 | 10924 | 21845 |
+| 21 | 21845 | 0 | 10925 | 21845 |
+| 21 | 21845 | 0 | 10926 | 21845 |
+| 21 | 21845 | 0 | 10927 | 21845 |
+| 21+ | -21846 | 1 | 10920 | 21845 |
+| 22 | -21846 | 1 | 10920 | -21846 |
+| 22+ | -21846 | 0 | 10920 | -21846 |
+| 23 | -21846 | 0 | 10920 | -21846 |
+| 23 | -21846 | 0 | 10921 | 21845 |
+| 23 | -21846 | 0 | 10922 | 21845 |
+| 23 | -21846 | 0 | 10923 | 21845 |
+| 23 | -21846 | 0 | 10924 | 21845 |
+| 23 | -21846 | 0 | 10925 | 21845 |
+| 23 | -21846 | 0 | 10926 | 21845 |
+| 23 | -21846 | 0 | 10927 | 21845 |
+| 23+ | 21845 | 1 | 10920 | -21846 |
+| 24 | 21845 | 1 | 10920 | 21845 |
+| 24+ | -21846 | 1 | 10921 | 21845 |
+| 25 | -21846 | 1 | 10921 | -21846 |
+| 25+ | -21846 | 0 | 10920 | 21845 |
+| 26 | -21846 | 0 | 10920 | 21845 |
+| 26 | -21846 | 0 | 10921 | -21846 |
+| 26 | -21846 | 0 | 10922 | 21845 |
+| 26 | -21846 | 0 | 10923 | 21845 |
+| 26 | -21846 | 0 | 10924 | 21845 |
+| 26 | -21846 | 0 | 10925 | 21845 |
+| 26 | -21846 | 0 | 10926 | 21845 |
+| 26 | -21846 | 0 | 10927 | 21845 |
+| 26+ | 21845 | 1 | 10921 | -21846 |
+| 27 | 21845 | 1 | 10921 | 21845 |
+| 27+ | -21846 | 1 | 10922 | 21845 |
+| 28 | -21846 | 1 | 10922 | -21846 |
+| 28+ | -21846 | 0 | 10920 | 21845 |
+| 29 | -21846 | 0 | 10920 | 21845 |
+| 29 | -21846 | 0 | 10921 | 21845 |
+| 29 | -21846 | 0 | 10922 | -21846 |
+| 29 | -21846 | 0 | 10923 | 21845 |
+| 29 | -21846 | 0 | 10924 | 21845 |
+| 29 | -21846 | 0 | 10925 | 21845 |
+| 29 | -21846 | 0 | 10926 | 21845 |
+| 29 | -21846 | 0 | 10927 | 21845 |
+| 29+ | 21845 | 1 | 10922 | -21846 |
+| 30 | 21845 | 1 | 10922 | 21845 |
+| 30+ | -21846 | 1 | 10923 | 21845 |
+| 31 | -21846 | 1 | 10923 | -21846 |
+| 31+ | -21846 | 0 | 10920 | 21845 |
+| 32 | -21846 | 0 | 10920 | 21845 |
+| 32 | -21846 | 0 | 10921 | 21845 |
+| 32 | -21846 | 0 | 10922 | 21845 |
+| 32 | -21846 | 0 | 10923 | -21846 |
+| 32 | -21846 | 0 | 10924 | 21845 |
+| 32 | -21846 | 0 | 10925 | 21845 |
+| 32 | -21846 | 0 | 10926 | 21845 |
+| 32 | -21846 | 0 | 10927 | 21845 |
+| 32+ | 21845 | 1 | 10923 | -21846 |
+| 33 | 21845 | 1 | 10923 | 21845 |
+| 33+ | -21846 | 1 | 10924 | 21845 |
+| 34 | -21846 | 1 | 10924 | -21846 |
+| 34+ | -21846 | 0 | 10920 | 21845 |
+| 35 | -21846 | 0 | 10920 | 21845 |
+| 35 | -21846 | 0 | 10921 | 21845 |
+| 35 | -21846 | 0 | 10922 | 21845 |
+| 35 | -21846 | 0 | 10923 | 21845 |
+| 35 | -21846 | 0 | 10924 | -21846 |
+| 35 | -21846 | 0 | 10925 | 21845 |
+| 35 | -21846 | 0 | 10926 | 21845 |
+| 35 | -21846 | 0 | 10927 | 21845 |
+| 35+ | 21845 | 1 | 10924 | -21846 |
+| 36 | 21845 | 1 | 10924 | 21845 |
+| 36+ | -21846 | 1 | 10925 | 21845 |
+| 37 | -21846 | 1 | 10925 | -21846 |
+| 37+ | -21846 | 0 | 10920 | 21845 |
+| 38 | -21846 | 0 | 10920 | 21845 |
+| 38 | -21846 | 0 | 10921 | 21845 |
+| 38 | -21846 | 0 | 10922 | 21845 |
+| 38 | -21846 | 0 | 10923 | 21845 |
+| 38 | -21846 | 0 | 10924 | 21845 |
+| 38 | -21846 | 0 | 10925 | -21846 |
+| 38 | -21846 | 0 | 10926 | 21845 |
+| 38 | -21846 | 0 | 10927 | 21845 |
+| 38+ | 21845 | 1 | 10925 | -21846 |
+| 39 | 21845 | 1 | 10925 | 21845 |
+| 39+ | -21846 | 1 | 10926 | 21845 |
+| 40 | -21846 | 1 | 10926 | -21846 |
+| 40+ | -21846 | 0 | 10920 | 21845 |
+| 41 | -21846 | 0 | 10920 | 21845 |
+| 41 | -21846 | 0 | 10921 | 21845 |
+| 41 | -21846 | 0 | 10922 | 21845 |
+| 41 | -21846 | 0 | 10923 | 21845 |
+| 41 | -21846 | 0 | 10924 | 21845 |
+| 41 | -21846 | 0 | 10925 | 21845 |
+| 41 | -21846 | 0 | 10926 | -21846 |
+| 41 | -21846 | 0 | 10927 | 21845 |
+| 41+ | 21845 | 1 | 10926 | -21846 |
+| 42 | 21845 | 1 | 10926 | 21845 |
+| 42+ | -21846 | 1 | 10927 | 21845 |
+| 43 | -21846 | 1 | 10927 | -21846 |
+| 43+ | -21846 | 0 | 10920 | 21845 |
+| 44 | -21846 | 0 | 10920 | 21845 |
+| 44 | -21846 | 0 | 10921 | 21845 |
+| 44 | -21846 | 0 | 10922 | 21845 |
+| 44 | -21846 | 0 | 10923 | 21845 |
+| 44 | -21846 | 0 | 10924 | 21845 |
+| 44 | -21846 | 0 | 10925 | 21845 |
+| 44 | -21846 | 0 | 10926 | 21845 |
+| 44 | -21846 | 0 | 10927 | -21846 |
+| 44+ | 21845 | 1 | 10927 | -21846 |
+| 45 | 21845 | 1 | 10927 | 21845 |
+| 45+ | 21845 | 0 | 10920 | 21845 |
+| 46 | 21845 | 0 | 10920 | 21845 |
+| 46 | 21845 | 0 | 10921 | 21845 |
+| 46 | 21845 | 0 | 10922 | 21845 |
+| 46 | 21845 | 0 | 10923 | 21845 |
+| 46 | 21845 | 0 | 10924 | 21845 |
+| 46 | 21845 | 0 | 10925 | 21845 |
+| 46 | 21845 | 0 | 10926 | 21845 |
+| 46 | 21845 | 0 | 10927 | 21845 |
+| 46+ | 21845 | 0 | 1365 | 0 |
+| 47 | 21845 | 0 | 1365 | 0 |
+| 47 | 21845 | 0 | 3413 | 0 |
+| 47 | 21845 | 0 | 5461 | 0 |
+| 47 | 21845 | 0 | 7509 | 0 |
+| 47 | 21845 | 0 | 9557 | 0 |
+| 47 | 21845 | 0 | 11605 | 0 |
+| 47 | 21845 | 0 | 13653 | 0 |
+| 47 | 21845 | 0 | 15701 | 0 |
+| 47+ | 21845 | 1 | 1365 | 0 |
+| 48 | 21845 | 1 | 1365 | 21845 |
+| 48+ | 21845 | 1 | 3413 | 0 |
+| 49 | 21845 | 1 | 3413 | 21845 |
+| 49+ | 21845 | 1 | 5461 | 0 |
+| 50 | 21845 | 1 | 5461 | 21845 |
+| 50+ | 21845 | 1 | 7509 | 0 |
+| 51 | 21845 | 1 | 7509 | 21845 |
+| 51+ | 21845 | 1 | 9557 | 0 |
+| 52 | 21845 | 1 | 9557 | 21845 |
+| 52+ | 21845 | 1 | 11605 | 0 |
+| 53 | 21845 | 1 | 11605 | 21845 |
+| 53+ | 21845 | 1 | 13653 | 0 |
+| 54 | 21845 | 1 | 13653 | 21845 |
+| 54+ | 21845 | 1 | 15701 | 0 |
+| 55 | 21845 | 1 | 15701 | 21845 |
+| 55+ | 21845 | 0 | 1365 | 21845 |
+| 56 | 21845 | 0 | 1365 | 21845 |
+| 56 | 21845 | 0 | 3413 | 21845 |
+| 56 | 21845 | 0 | 5461 | 21845 |
+| 56 | 21845 | 0 | 7509 | 21845 |
+| 56 | 21845 | 0 | 9557 | 21845 |
+| 56 | 21845 | 0 | 11605 | 21845 |
+| 56 | 21845 | 0 | 13653 | 21845 |
+| 56 | 21845 | 0 | 15701 | 21845 |
+| 56+ | -21846 | 1 | 1365 | 21845 |
+| 57 | -21846 | 1 | 1365 | -21846 |
+| 57+ | -21846 | 0 | 1365 | -21846 |
+| 58 | -21846 | 0 | 1365 | -21846 |
+| 58 | -21846 | 0 | 3413 | 21845 |
+| 58 | -21846 | 0 | 5461 | 21845 |
+| 58 | -21846 | 0 | 7509 | 21845 |
+| 58 | -21846 | 0 | 9557 | 21845 |
+| 58 | -21846 | 0 | 11605 | 21845 |
+| 58 | -21846 | 0 | 13653 | 21845 |
+| 58 | -21846 | 0 | 15701 | 21845 |
+| 58+ | 21845 | 1 | 1365 | -21846 |
+| 59 | 21845 | 1 | 1365 | 21845 |
+| 59+ | -21846 | 1 | 3413 | 21845 |
+| 60 | -21846 | 1 | 3413 | -21846 |
+| 60+ | -21846 | 0 | 1365 | 21845 |
+| 61 | -21846 | 0 | 1365 | 21845 |
+| 61 | -21846 | 0 | 3413 | -21846 |
+| 61 | -21846 | 0 | 5461 | 21845 |
+| 61 | -21846 | 0 | 7509 | 21845 |
+| 61 | -21846 | 0 | 9557 | 21845 |
+| 61 | -21846 | 0 | 11605 | 21845 |
+| 61 | -21846 | 0 | 13653 | 21845 |
+| 61 | -21846 | 0 | 15701 | 21845 |
+| 61+ | 21845 | 1 | 3413 | -21846 |
+| 62 | 21845 | 1 | 3413 | 21845 |
+| 62+ | -21846 | 1 | 5461 | 21845 |
+| 63 | -21846 | 1 | 5461 | -21846 |
+| 63+ | -21846 | 0 | 1365 | 21845 |
+| 64 | -21846 | 0 | 1365 | 21845 |
+| 64 | -21846 | 0 | 3413 | 21845 |
+| 64 | -21846 | 0 | 5461 | -21846 |
+| 64 | -21846 | 0 | 7509 | 21845 |
+| 64 | -21846 | 0 | 9557 | 21845 |
+| 64 | -21846 | 0 | 11605 | 21845 |
+| 64 | -21846 | 0 | 13653 | 21845 |
+| 64 | -21846 | 0 | 15701 | 21845 |
+| 64+ | 21845 | 1 | 5461 | -21846 |
+| 65 | 21845 | 1 | 5461 | 21845 |
+| 65+ | -21846 | 1 | 7509 | 21845 |
+| 66 | -21846 | 1 | 7509 | -21846 |
+| 66+ | -21846 | 0 | 1365 | 21845 |
+| 67 | -21846 | 0 | 1365 | 21845 |
+| 67 | -21846 | 0 | 3413 | 21845 |
+| 67 | -21846 | 0 | 5461 | 21845 |
+| 67 | -21846 | 0 | 7509 | -21846 |
+| 67 | -21846 | 0 | 9557 | 21845 |
+| 67 | -21846 | 0 | 11605 | 21845 |
+| 67 | -21846 | 0 | 13653 | 21845 |
+| 67 | -21846 | 0 | 15701 | 21845 |
+| 67+ | 21845 | 1 | 7509 | -21846 |
+| 68 | 21845 | 1 | 7509 | 21845 |
+| 68+ | -21846 | 1 | 9557 | 21845 |
+| 69 | -21846 | 1 | 9557 | -21846 |
+| 69+ | -21846 | 0 | 1365 | 21845 |
+| 70 | -21846 | 0 | 1365 | 21845 |
+| 70 | -21846 | 0 | 3413 | 21845 |
+| 70 | -21846 | 0 | 5461 | 21845 |
+| 70 | -21846 | 0 | 7509 | 21845 |
+| 70 | -21846 | 0 | 9557 | -21846 |
+| 70 | -21846 | 0 | 11605 | 21845 |
+| 70 | -21846 | 0 | 13653 | 21845 |
+| 70 | -21846 | 0 | 15701 | 21845 |
+| 70+ | 21845 | 1 | 9557 | -21846 |
+| 71 | 21845 | 1 | 9557 | 21845 |
+| 71+ | -21846 | 1 | 11605 | 21845 |
+| 72 | -21846 | 1 | 11605 | -21846 |
+| 72+ | -21846 | 0 | 1365 | 21845 |
+| 73 | -21846 | 0 | 1365 | 21845 |
+| 73 | -21846 | 0 | 3413 | 21845 |
+| 73 | -21846 | 0 | 5461 | 21845 |
+| 73 | -21846 | 0 | 7509 | 21845 |
+| 73 | -21846 | 0 | 9557 | 21845 |
+| 73 | -21846 | 0 | 11605 | -21846 |
+| 73 | -21846 | 0 | 13653 | 21845 |
+| 73 | -21846 | 0 | 15701 | 21845 |
+| 73+ | 21845 | 1 | 11605 | -21846 |
+| 74 | 21845 | 1 | 11605 | 21845 |
+| 74+ | -21846 | 1 | 13653 | 21845 |
+| 75 | -21846 | 1 | 13653 | -21846 |
+| 75+ | -21846 | 0 | 1365 | 21845 |
+| 76 | -21846 | 0 | 1365 | 21845 |
+| 76 | -21846 | 0 | 3413 | 21845 |
+| 76 | -21846 | 0 | 5461 | 21845 |
+| 76 | -21846 | 0 | 7509 | 21845 |
+| 76 | -21846 | 0 | 9557 | 21845 |
+| 76 | -21846 | 0 | 11605 | 21845 |
+| 76 | -21846 | 0 | 13653 | -21846 |
+| 76 | -21846 | 0 | 15701 | 21845 |
+| 76+ | 21845 | 1 | 13653 | -21846 |
+| 77 | 21845 | 1 | 13653 | 21845 |
+| 77+ | -21846 | 1 | 15701 | 21845 |
+| 78 | -21846 | 1 | 15701 | -21846 |
+| 78+ | -21846 | 0 | 1365 | 21845 |
+| 79 | -21846 | 0 | 1365 | 21845 |
+| 79 | -21846 | 0 | 3413 | 21845 |
+| 79 | -21846 | 0 | 5461 | 21845 |
+| 79 | -21846 | 0 | 7509 | 21845 |
+| 79 | -21846 | 0 | 9557 | 21845 |
+| 79 | -21846 | 0 | 11605 | 21845 |
+| 79 | -21846 | 0 | 13653 | 21845 |
+| 79 | -21846 | 0 | 15701 | -21846 |
+| 79+ | 21845 | 1 | 15701 | -21846 |
+| 80 | 21845 | 1 | 15701 | 21845 |
+| 80+ | 21845 | 0 | 1365 | 21845 |
+| 81 | 21845 | 0 | 1365 | 21845 |
+| 81 | 21845 | 0 | 3413 | 21845 |
+| 81 | 21845 | 0 | 5461 | 21845 |
+| 81 | 21845 | 0 | 7509 | 21845 |
+| 81 | 21845 | 0 | 9557 | 21845 |
+| 81 | 21845 | 0 | 11605 | 21845 |
+| 81 | 21845 | 0 | 13653 | 21845 |
+| 81 | 21845 | 0 | 15701 | 21845 |
diff --git a/src/lib/computer/testing/official/RAM16K.tst b/src/lib/computer/testing/official/RAM16K.tst
new file mode 100644
index 0000000..e556ad4
--- /dev/null
+++ b/src/lib/computer/testing/official/RAM16K.tst
@@ -0,0 +1,1026 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/03/b/RAM16K.tst
+
+load RAM16K.hdl,
+output-file RAM16K.out,
+compare-to RAM16K.cmp,
+output-list time%S1.4.1 in%D1.6.1 load%B2.1.2 address%D2.5.2 out%D1.6.1;
+
+set in 0,
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+tick,
+output;
+tock,
+output;
+
+set in 4321,
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+set address 4321,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+
+set in 12345,
+set address 12345,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set address 4321,
+eval,
+output;
+
+set in 16383,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+set address 16383,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set address 12345,
+eval,
+output;
+
+set address 16383,
+eval,
+output;
+
+
+set load 0,
+set address %B10101010101000,
+tick,
+output;
+tock,
+output;
+set address %B10101010101001,
+eval,
+output;
+set address %B10101010101010,
+eval,
+output;
+set address %B10101010101011,
+eval,
+output;
+set address %B10101010101100,
+eval,
+output;
+set address %B10101010101101,
+eval,
+output;
+set address %B10101010101110,
+eval,
+output;
+set address %B10101010101111,
+eval,
+output;
+
+set load 1,
+set in %B0101010101010101,
+set address %B10101010101000,
+tick,
+output;
+tock,
+output;
+set address %B10101010101001,
+tick,
+output,
+tock,
+output;
+set address %B10101010101010,
+tick,
+output,
+tock,
+output;
+set address %B10101010101011,
+tick,
+output,
+tock,
+output;
+set address %B10101010101100,
+tick,
+output,
+tock,
+output;
+set address %B10101010101101,
+tick,
+output,
+tock,
+output;
+set address %B10101010101110,
+tick,
+output,
+tock,
+output;
+set address %B10101010101111,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B10101010101000,
+tick,
+output;
+tock,
+output;
+set address %B10101010101001,
+eval,
+output;
+set address %B10101010101010,
+eval,
+output;
+set address %B10101010101011,
+eval,
+output;
+set address %B10101010101100,
+eval,
+output;
+set address %B10101010101101,
+eval,
+output;
+set address %B10101010101110,
+eval,
+output;
+set address %B10101010101111,
+eval,
+output;
+
+set load 1,
+set address %B10101010101000,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B10101010101000,
+tick,
+output;
+tock,
+output;
+set address %B10101010101001,
+eval,
+output;
+set address %B10101010101010,
+eval,
+output;
+set address %B10101010101011,
+eval,
+output;
+set address %B10101010101100,
+eval,
+output;
+set address %B10101010101101,
+eval,
+output;
+set address %B10101010101110,
+eval,
+output;
+set address %B10101010101111,
+eval,
+output;
+
+set load 1,
+set address %B10101010101000,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B10101010101001,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B10101010101000,
+tick,
+output;
+tock,
+output;
+set address %B10101010101001,
+eval,
+output;
+set address %B10101010101010,
+eval,
+output;
+set address %B10101010101011,
+eval,
+output;
+set address %B10101010101100,
+eval,
+output;
+set address %B10101010101101,
+eval,
+output;
+set address %B10101010101110,
+eval,
+output;
+set address %B10101010101111,
+eval,
+output;
+
+set load 1,
+set address %B10101010101001,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B10101010101010,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B10101010101000,
+tick,
+output;
+tock,
+output;
+set address %B10101010101001,
+eval,
+output;
+set address %B10101010101010,
+eval,
+output;
+set address %B10101010101011,
+eval,
+output;
+set address %B10101010101100,
+eval,
+output;
+set address %B10101010101101,
+eval,
+output;
+set address %B10101010101110,
+eval,
+output;
+set address %B10101010101111,
+eval,
+output;
+
+set load 1,
+set address %B10101010101010,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B10101010101011,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B10101010101000,
+tick,
+output;
+tock,
+output;
+set address %B10101010101001,
+eval,
+output;
+set address %B10101010101010,
+eval,
+output;
+set address %B10101010101011,
+eval,
+output;
+set address %B10101010101100,
+eval,
+output;
+set address %B10101010101101,
+eval,
+output;
+set address %B10101010101110,
+eval,
+output;
+set address %B10101010101111,
+eval,
+output;
+
+set load 1,
+set address %B10101010101011,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B10101010101100,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B10101010101000,
+tick,
+output;
+tock,
+output;
+set address %B10101010101001,
+eval,
+output;
+set address %B10101010101010,
+eval,
+output;
+set address %B10101010101011,
+eval,
+output;
+set address %B10101010101100,
+eval,
+output;
+set address %B10101010101101,
+eval,
+output;
+set address %B10101010101110,
+eval,
+output;
+set address %B10101010101111,
+eval,
+output;
+
+set load 1,
+set address %B10101010101100,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B10101010101101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B10101010101000,
+tick,
+output;
+tock,
+output;
+set address %B10101010101001,
+eval,
+output;
+set address %B10101010101010,
+eval,
+output;
+set address %B10101010101011,
+eval,
+output;
+set address %B10101010101100,
+eval,
+output;
+set address %B10101010101101,
+eval,
+output;
+set address %B10101010101110,
+eval,
+output;
+set address %B10101010101111,
+eval,
+output;
+
+set load 1,
+set address %B10101010101101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B10101010101110,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B10101010101000,
+tick,
+output;
+tock,
+output;
+set address %B10101010101001,
+eval,
+output;
+set address %B10101010101010,
+eval,
+output;
+set address %B10101010101011,
+eval,
+output;
+set address %B10101010101100,
+eval,
+output;
+set address %B10101010101101,
+eval,
+output;
+set address %B10101010101110,
+eval,
+output;
+set address %B10101010101111,
+eval,
+output;
+
+set load 1,
+set address %B10101010101110,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B10101010101111,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B10101010101000,
+tick,
+output;
+tock,
+output;
+set address %B10101010101001,
+eval,
+output;
+set address %B10101010101010,
+eval,
+output;
+set address %B10101010101011,
+eval,
+output;
+set address %B10101010101100,
+eval,
+output;
+set address %B10101010101101,
+eval,
+output;
+set address %B10101010101110,
+eval,
+output;
+set address %B10101010101111,
+eval,
+output;
+
+set load 1,
+set address %B10101010101111,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B10101010101000,
+tick,
+output;
+tock,
+output;
+set address %B10101010101001,
+eval,
+output;
+set address %B10101010101010,
+eval,
+output;
+set address %B10101010101011,
+eval,
+output;
+set address %B10101010101100,
+eval,
+output;
+set address %B10101010101101,
+eval,
+output;
+set address %B10101010101110,
+eval,
+output;
+set address %B10101010101111,
+eval,
+output;
+
+
+set load 0,
+set address %B00010101010101,
+tick,
+output;
+tock,
+output;
+set address %B00110101010101,
+eval,
+output;
+set address %B01010101010101,
+eval,
+output;
+set address %B01110101010101,
+eval,
+output;
+set address %B10010101010101,
+eval,
+output;
+set address %B10110101010101,
+eval,
+output;
+set address %B11010101010101,
+eval,
+output;
+set address %B11110101010101,
+eval,
+output;
+
+set load 1,
+set in %B0101010101010101,
+set address %B00010101010101,
+tick,
+output;
+tock,
+output;
+set address %B00110101010101,
+tick,
+output,
+tock,
+output;
+set address %B01010101010101,
+tick,
+output,
+tock,
+output;
+set address %B01110101010101,
+tick,
+output,
+tock,
+output;
+set address %B10010101010101,
+tick,
+output,
+tock,
+output;
+set address %B10110101010101,
+tick,
+output,
+tock,
+output;
+set address %B11010101010101,
+tick,
+output,
+tock,
+output;
+set address %B11110101010101,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B00010101010101,
+tick,
+output;
+tock,
+output;
+set address %B00110101010101,
+eval,
+output;
+set address %B01010101010101,
+eval,
+output;
+set address %B01110101010101,
+eval,
+output;
+set address %B10010101010101,
+eval,
+output;
+set address %B10110101010101,
+eval,
+output;
+set address %B11010101010101,
+eval,
+output;
+set address %B11110101010101,
+eval,
+output;
+
+set load 1,
+set address %B00010101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B00010101010101,
+tick,
+output;
+tock,
+output;
+set address %B00110101010101,
+eval,
+output;
+set address %B01010101010101,
+eval,
+output;
+set address %B01110101010101,
+eval,
+output;
+set address %B10010101010101,
+eval,
+output;
+set address %B10110101010101,
+eval,
+output;
+set address %B11010101010101,
+eval,
+output;
+set address %B11110101010101,
+eval,
+output;
+
+set load 1,
+set address %B00010101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B00110101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B00010101010101,
+tick,
+output;
+tock,
+output;
+set address %B00110101010101,
+eval,
+output;
+set address %B01010101010101,
+eval,
+output;
+set address %B01110101010101,
+eval,
+output;
+set address %B10010101010101,
+eval,
+output;
+set address %B10110101010101,
+eval,
+output;
+set address %B11010101010101,
+eval,
+output;
+set address %B11110101010101,
+eval,
+output;
+
+set load 1,
+set address %B00110101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B01010101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B00010101010101,
+tick,
+output;
+tock,
+output;
+set address %B00110101010101,
+eval,
+output;
+set address %B01010101010101,
+eval,
+output;
+set address %B01110101010101,
+eval,
+output;
+set address %B10010101010101,
+eval,
+output;
+set address %B10110101010101,
+eval,
+output;
+set address %B11010101010101,
+eval,
+output;
+set address %B11110101010101,
+eval,
+output;
+
+set load 1,
+set address %B01010101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B01110101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B00010101010101,
+tick,
+output;
+tock,
+output;
+set address %B00110101010101,
+eval,
+output;
+set address %B01010101010101,
+eval,
+output;
+set address %B01110101010101,
+eval,
+output;
+set address %B10010101010101,
+eval,
+output;
+set address %B10110101010101,
+eval,
+output;
+set address %B11010101010101,
+eval,
+output;
+set address %B11110101010101,
+eval,
+output;
+
+set load 1,
+set address %B01110101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B10010101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B00010101010101,
+tick,
+output;
+tock,
+output;
+set address %B00110101010101,
+eval,
+output;
+set address %B01010101010101,
+eval,
+output;
+set address %B01110101010101,
+eval,
+output;
+set address %B10010101010101,
+eval,
+output;
+set address %B10110101010101,
+eval,
+output;
+set address %B11010101010101,
+eval,
+output;
+set address %B11110101010101,
+eval,
+output;
+
+set load 1,
+set address %B10010101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B10110101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B00010101010101,
+tick,
+output;
+tock,
+output;
+set address %B00110101010101,
+eval,
+output;
+set address %B01010101010101,
+eval,
+output;
+set address %B01110101010101,
+eval,
+output;
+set address %B10010101010101,
+eval,
+output;
+set address %B10110101010101,
+eval,
+output;
+set address %B11010101010101,
+eval,
+output;
+set address %B11110101010101,
+eval,
+output;
+
+set load 1,
+set address %B10110101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B11010101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B00010101010101,
+tick,
+output;
+tock,
+output;
+set address %B00110101010101,
+eval,
+output;
+set address %B01010101010101,
+eval,
+output;
+set address %B01110101010101,
+eval,
+output;
+set address %B10010101010101,
+eval,
+output;
+set address %B10110101010101,
+eval,
+output;
+set address %B11010101010101,
+eval,
+output;
+set address %B11110101010101,
+eval,
+output;
+
+set load 1,
+set address %B11010101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B11110101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B00010101010101,
+tick,
+output;
+tock,
+output;
+set address %B00110101010101,
+eval,
+output;
+set address %B01010101010101,
+eval,
+output;
+set address %B01110101010101,
+eval,
+output;
+set address %B10010101010101,
+eval,
+output;
+set address %B10110101010101,
+eval,
+output;
+set address %B11010101010101,
+eval,
+output;
+set address %B11110101010101,
+eval,
+output;
+
+set load 1,
+set address %B11110101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B00010101010101,
+tick,
+output;
+tock,
+output;
+set address %B00110101010101,
+eval,
+output;
+set address %B01010101010101,
+eval,
+output;
+set address %B01110101010101,
+eval,
+output;
+set address %B10010101010101,
+eval,
+output;
+set address %B10110101010101,
+eval,
+output;
+set address %B11010101010101,
+eval,
+output;
+set address %B11110101010101,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/RAM4K.cmp b/src/lib/computer/testing/official/RAM4K.cmp
new file mode 100644
index 0000000..a614796
--- /dev/null
+++ b/src/lib/computer/testing/official/RAM4K.cmp
@@ -0,0 +1,320 @@
+| time | in |load |address | out |
+| 0+ | 0 | 0 | 0 | 0 |
+| 1 | 0 | 0 | 0 | 0 |
+| 1+ | 0 | 1 | 0 | 0 |
+| 2 | 0 | 1 | 0 | 0 |
+| 2+ | 1111 | 0 | 0 | 0 |
+| 3 | 1111 | 0 | 0 | 0 |
+| 3+ | 1111 | 1 | 1111 | 0 |
+| 4 | 1111 | 1 | 1111 | 1111 |
+| 4+ | 1111 | 0 | 0 | 0 |
+| 5 | 1111 | 0 | 0 | 0 |
+| 5+ | 3513 | 0 | 3513 | 0 |
+| 6 | 3513 | 0 | 3513 | 0 |
+| 6+ | 3513 | 1 | 3513 | 0 |
+| 7 | 3513 | 1 | 3513 | 3513 |
+| 7+ | 3513 | 0 | 3513 | 3513 |
+| 8 | 3513 | 0 | 3513 | 3513 |
+| 8 | 3513 | 0 | 1111 | 1111 |
+| 8+ | 4095 | 0 | 1111 | 1111 |
+| 9 | 4095 | 0 | 1111 | 1111 |
+| 9+ | 4095 | 1 | 4095 | 0 |
+| 10 | 4095 | 1 | 4095 | 4095 |
+| 10+ | 4095 | 0 | 4095 | 4095 |
+| 11 | 4095 | 0 | 4095 | 4095 |
+| 11 | 4095 | 0 | 3513 | 3513 |
+| 11 | 4095 | 0 | 4095 | 4095 |
+| 11+ | 4095 | 0 | 2728 | 0 |
+| 12 | 4095 | 0 | 2728 | 0 |
+| 12 | 4095 | 0 | 2729 | 0 |
+| 12 | 4095 | 0 | 2730 | 0 |
+| 12 | 4095 | 0 | 2731 | 0 |
+| 12 | 4095 | 0 | 2732 | 0 |
+| 12 | 4095 | 0 | 2733 | 0 |
+| 12 | 4095 | 0 | 2734 | 0 |
+| 12 | 4095 | 0 | 2735 | 0 |
+| 12+ | 21845 | 1 | 2728 | 0 |
+| 13 | 21845 | 1 | 2728 | 21845 |
+| 13+ | 21845 | 1 | 2729 | 0 |
+| 14 | 21845 | 1 | 2729 | 21845 |
+| 14+ | 21845 | 1 | 2730 | 0 |
+| 15 | 21845 | 1 | 2730 | 21845 |
+| 15+ | 21845 | 1 | 2731 | 0 |
+| 16 | 21845 | 1 | 2731 | 21845 |
+| 16+ | 21845 | 1 | 2732 | 0 |
+| 17 | 21845 | 1 | 2732 | 21845 |
+| 17+ | 21845 | 1 | 2733 | 0 |
+| 18 | 21845 | 1 | 2733 | 21845 |
+| 18+ | 21845 | 1 | 2734 | 0 |
+| 19 | 21845 | 1 | 2734 | 21845 |
+| 19+ | 21845 | 1 | 2735 | 0 |
+| 20 | 21845 | 1 | 2735 | 21845 |
+| 20+ | 21845 | 0 | 2728 | 21845 |
+| 21 | 21845 | 0 | 2728 | 21845 |
+| 21 | 21845 | 0 | 2729 | 21845 |
+| 21 | 21845 | 0 | 2730 | 21845 |
+| 21 | 21845 | 0 | 2731 | 21845 |
+| 21 | 21845 | 0 | 2732 | 21845 |
+| 21 | 21845 | 0 | 2733 | 21845 |
+| 21 | 21845 | 0 | 2734 | 21845 |
+| 21 | 21845 | 0 | 2735 | 21845 |
+| 21+ | -21846 | 1 | 2728 | 21845 |
+| 22 | -21846 | 1 | 2728 | -21846 |
+| 22+ | -21846 | 0 | 2728 | -21846 |
+| 23 | -21846 | 0 | 2728 | -21846 |
+| 23 | -21846 | 0 | 2729 | 21845 |
+| 23 | -21846 | 0 | 2730 | 21845 |
+| 23 | -21846 | 0 | 2731 | 21845 |
+| 23 | -21846 | 0 | 2732 | 21845 |
+| 23 | -21846 | 0 | 2733 | 21845 |
+| 23 | -21846 | 0 | 2734 | 21845 |
+| 23 | -21846 | 0 | 2735 | 21845 |
+| 23+ | 21845 | 1 | 2728 | -21846 |
+| 24 | 21845 | 1 | 2728 | 21845 |
+| 24+ | -21846 | 1 | 2729 | 21845 |
+| 25 | -21846 | 1 | 2729 | -21846 |
+| 25+ | -21846 | 0 | 2728 | 21845 |
+| 26 | -21846 | 0 | 2728 | 21845 |
+| 26 | -21846 | 0 | 2729 | -21846 |
+| 26 | -21846 | 0 | 2730 | 21845 |
+| 26 | -21846 | 0 | 2731 | 21845 |
+| 26 | -21846 | 0 | 2732 | 21845 |
+| 26 | -21846 | 0 | 2733 | 21845 |
+| 26 | -21846 | 0 | 2734 | 21845 |
+| 26 | -21846 | 0 | 2735 | 21845 |
+| 26+ | 21845 | 1 | 2729 | -21846 |
+| 27 | 21845 | 1 | 2729 | 21845 |
+| 27+ | -21846 | 1 | 2730 | 21845 |
+| 28 | -21846 | 1 | 2730 | -21846 |
+| 28+ | -21846 | 0 | 2728 | 21845 |
+| 29 | -21846 | 0 | 2728 | 21845 |
+| 29 | -21846 | 0 | 2729 | 21845 |
+| 29 | -21846 | 0 | 2730 | -21846 |
+| 29 | -21846 | 0 | 2731 | 21845 |
+| 29 | -21846 | 0 | 2732 | 21845 |
+| 29 | -21846 | 0 | 2733 | 21845 |
+| 29 | -21846 | 0 | 2734 | 21845 |
+| 29 | -21846 | 0 | 2735 | 21845 |
+| 29+ | 21845 | 1 | 2730 | -21846 |
+| 30 | 21845 | 1 | 2730 | 21845 |
+| 30+ | -21846 | 1 | 2731 | 21845 |
+| 31 | -21846 | 1 | 2731 | -21846 |
+| 31+ | -21846 | 0 | 2728 | 21845 |
+| 32 | -21846 | 0 | 2728 | 21845 |
+| 32 | -21846 | 0 | 2729 | 21845 |
+| 32 | -21846 | 0 | 2730 | 21845 |
+| 32 | -21846 | 0 | 2731 | -21846 |
+| 32 | -21846 | 0 | 2732 | 21845 |
+| 32 | -21846 | 0 | 2733 | 21845 |
+| 32 | -21846 | 0 | 2734 | 21845 |
+| 32 | -21846 | 0 | 2735 | 21845 |
+| 32+ | 21845 | 1 | 2731 | -21846 |
+| 33 | 21845 | 1 | 2731 | 21845 |
+| 33+ | -21846 | 1 | 2732 | 21845 |
+| 34 | -21846 | 1 | 2732 | -21846 |
+| 34+ | -21846 | 0 | 2728 | 21845 |
+| 35 | -21846 | 0 | 2728 | 21845 |
+| 35 | -21846 | 0 | 2729 | 21845 |
+| 35 | -21846 | 0 | 2730 | 21845 |
+| 35 | -21846 | 0 | 2731 | 21845 |
+| 35 | -21846 | 0 | 2732 | -21846 |
+| 35 | -21846 | 0 | 2733 | 21845 |
+| 35 | -21846 | 0 | 2734 | 21845 |
+| 35 | -21846 | 0 | 2735 | 21845 |
+| 35+ | 21845 | 1 | 2732 | -21846 |
+| 36 | 21845 | 1 | 2732 | 21845 |
+| 36+ | -21846 | 1 | 2733 | 21845 |
+| 37 | -21846 | 1 | 2733 | -21846 |
+| 37+ | -21846 | 0 | 2728 | 21845 |
+| 38 | -21846 | 0 | 2728 | 21845 |
+| 38 | -21846 | 0 | 2729 | 21845 |
+| 38 | -21846 | 0 | 2730 | 21845 |
+| 38 | -21846 | 0 | 2731 | 21845 |
+| 38 | -21846 | 0 | 2732 | 21845 |
+| 38 | -21846 | 0 | 2733 | -21846 |
+| 38 | -21846 | 0 | 2734 | 21845 |
+| 38 | -21846 | 0 | 2735 | 21845 |
+| 38+ | 21845 | 1 | 2733 | -21846 |
+| 39 | 21845 | 1 | 2733 | 21845 |
+| 39+ | -21846 | 1 | 2734 | 21845 |
+| 40 | -21846 | 1 | 2734 | -21846 |
+| 40+ | -21846 | 0 | 2728 | 21845 |
+| 41 | -21846 | 0 | 2728 | 21845 |
+| 41 | -21846 | 0 | 2729 | 21845 |
+| 41 | -21846 | 0 | 2730 | 21845 |
+| 41 | -21846 | 0 | 2731 | 21845 |
+| 41 | -21846 | 0 | 2732 | 21845 |
+| 41 | -21846 | 0 | 2733 | 21845 |
+| 41 | -21846 | 0 | 2734 | -21846 |
+| 41 | -21846 | 0 | 2735 | 21845 |
+| 41+ | 21845 | 1 | 2734 | -21846 |
+| 42 | 21845 | 1 | 2734 | 21845 |
+| 42+ | -21846 | 1 | 2735 | 21845 |
+| 43 | -21846 | 1 | 2735 | -21846 |
+| 43+ | -21846 | 0 | 2728 | 21845 |
+| 44 | -21846 | 0 | 2728 | 21845 |
+| 44 | -21846 | 0 | 2729 | 21845 |
+| 44 | -21846 | 0 | 2730 | 21845 |
+| 44 | -21846 | 0 | 2731 | 21845 |
+| 44 | -21846 | 0 | 2732 | 21845 |
+| 44 | -21846 | 0 | 2733 | 21845 |
+| 44 | -21846 | 0 | 2734 | 21845 |
+| 44 | -21846 | 0 | 2735 | -21846 |
+| 44+ | 21845 | 1 | 2735 | -21846 |
+| 45 | 21845 | 1 | 2735 | 21845 |
+| 45+ | 21845 | 0 | 2728 | 21845 |
+| 46 | 21845 | 0 | 2728 | 21845 |
+| 46 | 21845 | 0 | 2729 | 21845 |
+| 46 | 21845 | 0 | 2730 | 21845 |
+| 46 | 21845 | 0 | 2731 | 21845 |
+| 46 | 21845 | 0 | 2732 | 21845 |
+| 46 | 21845 | 0 | 2733 | 21845 |
+| 46 | 21845 | 0 | 2734 | 21845 |
+| 46 | 21845 | 0 | 2735 | 21845 |
+| 46+ | 21845 | 0 | 341 | 0 |
+| 47 | 21845 | 0 | 341 | 0 |
+| 47 | 21845 | 0 | 853 | 0 |
+| 47 | 21845 | 0 | 1365 | 0 |
+| 47 | 21845 | 0 | 1877 | 0 |
+| 47 | 21845 | 0 | 2389 | 0 |
+| 47 | 21845 | 0 | 2901 | 0 |
+| 47 | 21845 | 0 | 3413 | 0 |
+| 47 | 21845 | 0 | 3925 | 0 |
+| 47+ | 21845 | 1 | 341 | 0 |
+| 48 | 21845 | 1 | 341 | 21845 |
+| 48+ | 21845 | 1 | 853 | 0 |
+| 49 | 21845 | 1 | 853 | 21845 |
+| 49+ | 21845 | 1 | 1365 | 0 |
+| 50 | 21845 | 1 | 1365 | 21845 |
+| 50+ | 21845 | 1 | 1877 | 0 |
+| 51 | 21845 | 1 | 1877 | 21845 |
+| 51+ | 21845 | 1 | 2389 | 0 |
+| 52 | 21845 | 1 | 2389 | 21845 |
+| 52+ | 21845 | 1 | 2901 | 0 |
+| 53 | 21845 | 1 | 2901 | 21845 |
+| 53+ | 21845 | 1 | 3413 | 0 |
+| 54 | 21845 | 1 | 3413 | 21845 |
+| 54+ | 21845 | 1 | 3925 | 0 |
+| 55 | 21845 | 1 | 3925 | 21845 |
+| 55+ | 21845 | 0 | 341 | 21845 |
+| 56 | 21845 | 0 | 341 | 21845 |
+| 56 | 21845 | 0 | 853 | 21845 |
+| 56 | 21845 | 0 | 1365 | 21845 |
+| 56 | 21845 | 0 | 1877 | 21845 |
+| 56 | 21845 | 0 | 2389 | 21845 |
+| 56 | 21845 | 0 | 2901 | 21845 |
+| 56 | 21845 | 0 | 3413 | 21845 |
+| 56 | 21845 | 0 | 3925 | 21845 |
+| 56+ | -21846 | 1 | 341 | 21845 |
+| 57 | -21846 | 1 | 341 | -21846 |
+| 57+ | -21846 | 0 | 341 | -21846 |
+| 58 | -21846 | 0 | 341 | -21846 |
+| 58 | -21846 | 0 | 853 | 21845 |
+| 58 | -21846 | 0 | 1365 | 21845 |
+| 58 | -21846 | 0 | 1877 | 21845 |
+| 58 | -21846 | 0 | 2389 | 21845 |
+| 58 | -21846 | 0 | 2901 | 21845 |
+| 58 | -21846 | 0 | 3413 | 21845 |
+| 58 | -21846 | 0 | 3925 | 21845 |
+| 58+ | 21845 | 1 | 341 | -21846 |
+| 59 | 21845 | 1 | 341 | 21845 |
+| 59+ | -21846 | 1 | 853 | 21845 |
+| 60 | -21846 | 1 | 853 | -21846 |
+| 60+ | -21846 | 0 | 341 | 21845 |
+| 61 | -21846 | 0 | 341 | 21845 |
+| 61 | -21846 | 0 | 853 | -21846 |
+| 61 | -21846 | 0 | 1365 | 21845 |
+| 61 | -21846 | 0 | 1877 | 21845 |
+| 61 | -21846 | 0 | 2389 | 21845 |
+| 61 | -21846 | 0 | 2901 | 21845 |
+| 61 | -21846 | 0 | 3413 | 21845 |
+| 61 | -21846 | 0 | 3925 | 21845 |
+| 61+ | 21845 | 1 | 853 | -21846 |
+| 62 | 21845 | 1 | 853 | 21845 |
+| 62+ | -21846 | 1 | 1365 | 21845 |
+| 63 | -21846 | 1 | 1365 | -21846 |
+| 63+ | -21846 | 0 | 341 | 21845 |
+| 64 | -21846 | 0 | 341 | 21845 |
+| 64 | -21846 | 0 | 853 | 21845 |
+| 64 | -21846 | 0 | 1365 | -21846 |
+| 64 | -21846 | 0 | 1877 | 21845 |
+| 64 | -21846 | 0 | 2389 | 21845 |
+| 64 | -21846 | 0 | 2901 | 21845 |
+| 64 | -21846 | 0 | 3413 | 21845 |
+| 64 | -21846 | 0 | 3925 | 21845 |
+| 64+ | 21845 | 1 | 1365 | -21846 |
+| 65 | 21845 | 1 | 1365 | 21845 |
+| 65+ | -21846 | 1 | 1877 | 21845 |
+| 66 | -21846 | 1 | 1877 | -21846 |
+| 66+ | -21846 | 0 | 341 | 21845 |
+| 67 | -21846 | 0 | 341 | 21845 |
+| 67 | -21846 | 0 | 853 | 21845 |
+| 67 | -21846 | 0 | 1365 | 21845 |
+| 67 | -21846 | 0 | 1877 | -21846 |
+| 67 | -21846 | 0 | 2389 | 21845 |
+| 67 | -21846 | 0 | 2901 | 21845 |
+| 67 | -21846 | 0 | 3413 | 21845 |
+| 67 | -21846 | 0 | 3925 | 21845 |
+| 67+ | 21845 | 1 | 1877 | -21846 |
+| 68 | 21845 | 1 | 1877 | 21845 |
+| 68+ | -21846 | 1 | 2389 | 21845 |
+| 69 | -21846 | 1 | 2389 | -21846 |
+| 69+ | -21846 | 0 | 341 | 21845 |
+| 70 | -21846 | 0 | 341 | 21845 |
+| 70 | -21846 | 0 | 853 | 21845 |
+| 70 | -21846 | 0 | 1365 | 21845 |
+| 70 | -21846 | 0 | 1877 | 21845 |
+| 70 | -21846 | 0 | 2389 | -21846 |
+| 70 | -21846 | 0 | 2901 | 21845 |
+| 70 | -21846 | 0 | 3413 | 21845 |
+| 70 | -21846 | 0 | 3925 | 21845 |
+| 70+ | 21845 | 1 | 2389 | -21846 |
+| 71 | 21845 | 1 | 2389 | 21845 |
+| 71+ | -21846 | 1 | 2901 | 21845 |
+| 72 | -21846 | 1 | 2901 | -21846 |
+| 72+ | -21846 | 0 | 341 | 21845 |
+| 73 | -21846 | 0 | 341 | 21845 |
+| 73 | -21846 | 0 | 853 | 21845 |
+| 73 | -21846 | 0 | 1365 | 21845 |
+| 73 | -21846 | 0 | 1877 | 21845 |
+| 73 | -21846 | 0 | 2389 | 21845 |
+| 73 | -21846 | 0 | 2901 | -21846 |
+| 73 | -21846 | 0 | 3413 | 21845 |
+| 73 | -21846 | 0 | 3925 | 21845 |
+| 73+ | 21845 | 1 | 2901 | -21846 |
+| 74 | 21845 | 1 | 2901 | 21845 |
+| 74+ | -21846 | 1 | 3413 | 21845 |
+| 75 | -21846 | 1 | 3413 | -21846 |
+| 75+ | -21846 | 0 | 341 | 21845 |
+| 76 | -21846 | 0 | 341 | 21845 |
+| 76 | -21846 | 0 | 853 | 21845 |
+| 76 | -21846 | 0 | 1365 | 21845 |
+| 76 | -21846 | 0 | 1877 | 21845 |
+| 76 | -21846 | 0 | 2389 | 21845 |
+| 76 | -21846 | 0 | 2901 | 21845 |
+| 76 | -21846 | 0 | 3413 | -21846 |
+| 76 | -21846 | 0 | 3925 | 21845 |
+| 76+ | 21845 | 1 | 3413 | -21846 |
+| 77 | 21845 | 1 | 3413 | 21845 |
+| 77+ | -21846 | 1 | 3925 | 21845 |
+| 78 | -21846 | 1 | 3925 | -21846 |
+| 78+ | -21846 | 0 | 341 | 21845 |
+| 79 | -21846 | 0 | 341 | 21845 |
+| 79 | -21846 | 0 | 853 | 21845 |
+| 79 | -21846 | 0 | 1365 | 21845 |
+| 79 | -21846 | 0 | 1877 | 21845 |
+| 79 | -21846 | 0 | 2389 | 21845 |
+| 79 | -21846 | 0 | 2901 | 21845 |
+| 79 | -21846 | 0 | 3413 | 21845 |
+| 79 | -21846 | 0 | 3925 | -21846 |
+| 79+ | 21845 | 1 | 3925 | -21846 |
+| 80 | 21845 | 1 | 3925 | 21845 |
+| 80+ | 21845 | 0 | 341 | 21845 |
+| 81 | 21845 | 0 | 341 | 21845 |
+| 81 | 21845 | 0 | 853 | 21845 |
+| 81 | 21845 | 0 | 1365 | 21845 |
+| 81 | 21845 | 0 | 1877 | 21845 |
+| 81 | 21845 | 0 | 2389 | 21845 |
+| 81 | 21845 | 0 | 2901 | 21845 |
+| 81 | 21845 | 0 | 3413 | 21845 |
+| 81 | 21845 | 0 | 3925 | 21845 |
diff --git a/src/lib/computer/testing/official/RAM4K.tst b/src/lib/computer/testing/official/RAM4K.tst
new file mode 100644
index 0000000..7a5aa12
--- /dev/null
+++ b/src/lib/computer/testing/official/RAM4K.tst
@@ -0,0 +1,1026 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/03/b/RAM4K.tst
+
+load RAM4K.hdl,
+output-file RAM4K.out,
+compare-to RAM4K.cmp,
+output-list time%S1.4.1 in%D1.6.1 load%B2.1.2 address%D2.4.2 out%D1.6.1;
+
+set in 0,
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+tick,
+output;
+tock,
+output;
+
+set in 1111,
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+set address 1111,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+
+set in 3513,
+set address 3513,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set address 1111,
+eval,
+output;
+
+set in 4095,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+set address 4095,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set address 3513,
+eval,
+output;
+
+set address 4095,
+eval,
+output;
+
+
+set load 0,
+set address %B101010101000,
+tick,
+output;
+tock,
+output;
+set address %B101010101001,
+eval,
+output;
+set address %B101010101010,
+eval,
+output;
+set address %B101010101011,
+eval,
+output;
+set address %B101010101100,
+eval,
+output;
+set address %B101010101101,
+eval,
+output;
+set address %B101010101110,
+eval,
+output;
+set address %B101010101111,
+eval,
+output;
+
+set load 1,
+set in %B0101010101010101,
+set address %B101010101000,
+tick,
+output;
+tock,
+output;
+set address %B101010101001,
+tick,
+output,
+tock,
+output;
+set address %B101010101010,
+tick,
+output,
+tock,
+output;
+set address %B101010101011,
+tick,
+output,
+tock,
+output;
+set address %B101010101100,
+tick,
+output,
+tock,
+output;
+set address %B101010101101,
+tick,
+output,
+tock,
+output;
+set address %B101010101110,
+tick,
+output,
+tock,
+output;
+set address %B101010101111,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B101010101000,
+tick,
+output;
+tock,
+output;
+set address %B101010101001,
+eval,
+output;
+set address %B101010101010,
+eval,
+output;
+set address %B101010101011,
+eval,
+output;
+set address %B101010101100,
+eval,
+output;
+set address %B101010101101,
+eval,
+output;
+set address %B101010101110,
+eval,
+output;
+set address %B101010101111,
+eval,
+output;
+
+set load 1,
+set address %B101010101000,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101010101000,
+tick,
+output;
+tock,
+output;
+set address %B101010101001,
+eval,
+output;
+set address %B101010101010,
+eval,
+output;
+set address %B101010101011,
+eval,
+output;
+set address %B101010101100,
+eval,
+output;
+set address %B101010101101,
+eval,
+output;
+set address %B101010101110,
+eval,
+output;
+set address %B101010101111,
+eval,
+output;
+
+set load 1,
+set address %B101010101000,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101010101001,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101010101000,
+tick,
+output;
+tock,
+output;
+set address %B101010101001,
+eval,
+output;
+set address %B101010101010,
+eval,
+output;
+set address %B101010101011,
+eval,
+output;
+set address %B101010101100,
+eval,
+output;
+set address %B101010101101,
+eval,
+output;
+set address %B101010101110,
+eval,
+output;
+set address %B101010101111,
+eval,
+output;
+
+set load 1,
+set address %B101010101001,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101010101010,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101010101000,
+tick,
+output;
+tock,
+output;
+set address %B101010101001,
+eval,
+output;
+set address %B101010101010,
+eval,
+output;
+set address %B101010101011,
+eval,
+output;
+set address %B101010101100,
+eval,
+output;
+set address %B101010101101,
+eval,
+output;
+set address %B101010101110,
+eval,
+output;
+set address %B101010101111,
+eval,
+output;
+
+set load 1,
+set address %B101010101010,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101010101011,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101010101000,
+tick,
+output;
+tock,
+output;
+set address %B101010101001,
+eval,
+output;
+set address %B101010101010,
+eval,
+output;
+set address %B101010101011,
+eval,
+output;
+set address %B101010101100,
+eval,
+output;
+set address %B101010101101,
+eval,
+output;
+set address %B101010101110,
+eval,
+output;
+set address %B101010101111,
+eval,
+output;
+
+set load 1,
+set address %B101010101011,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101010101100,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101010101000,
+tick,
+output;
+tock,
+output;
+set address %B101010101001,
+eval,
+output;
+set address %B101010101010,
+eval,
+output;
+set address %B101010101011,
+eval,
+output;
+set address %B101010101100,
+eval,
+output;
+set address %B101010101101,
+eval,
+output;
+set address %B101010101110,
+eval,
+output;
+set address %B101010101111,
+eval,
+output;
+
+set load 1,
+set address %B101010101100,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101010101101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101010101000,
+tick,
+output;
+tock,
+output;
+set address %B101010101001,
+eval,
+output;
+set address %B101010101010,
+eval,
+output;
+set address %B101010101011,
+eval,
+output;
+set address %B101010101100,
+eval,
+output;
+set address %B101010101101,
+eval,
+output;
+set address %B101010101110,
+eval,
+output;
+set address %B101010101111,
+eval,
+output;
+
+set load 1,
+set address %B101010101101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101010101110,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101010101000,
+tick,
+output;
+tock,
+output;
+set address %B101010101001,
+eval,
+output;
+set address %B101010101010,
+eval,
+output;
+set address %B101010101011,
+eval,
+output;
+set address %B101010101100,
+eval,
+output;
+set address %B101010101101,
+eval,
+output;
+set address %B101010101110,
+eval,
+output;
+set address %B101010101111,
+eval,
+output;
+
+set load 1,
+set address %B101010101110,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101010101111,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101010101000,
+tick,
+output;
+tock,
+output;
+set address %B101010101001,
+eval,
+output;
+set address %B101010101010,
+eval,
+output;
+set address %B101010101011,
+eval,
+output;
+set address %B101010101100,
+eval,
+output;
+set address %B101010101101,
+eval,
+output;
+set address %B101010101110,
+eval,
+output;
+set address %B101010101111,
+eval,
+output;
+
+set load 1,
+set address %B101010101111,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B101010101000,
+tick,
+output;
+tock,
+output;
+set address %B101010101001,
+eval,
+output;
+set address %B101010101010,
+eval,
+output;
+set address %B101010101011,
+eval,
+output;
+set address %B101010101100,
+eval,
+output;
+set address %B101010101101,
+eval,
+output;
+set address %B101010101110,
+eval,
+output;
+set address %B101010101111,
+eval,
+output;
+
+
+set load 0,
+set address %B000101010101,
+tick,
+output;
+tock,
+output;
+set address %B001101010101,
+eval,
+output;
+set address %B010101010101,
+eval,
+output;
+set address %B011101010101,
+eval,
+output;
+set address %B100101010101,
+eval,
+output;
+set address %B101101010101,
+eval,
+output;
+set address %B110101010101,
+eval,
+output;
+set address %B111101010101,
+eval,
+output;
+
+set load 1,
+set in %B0101010101010101,
+set address %B000101010101,
+tick,
+output;
+tock,
+output;
+set address %B001101010101,
+tick,
+output,
+tock,
+output;
+set address %B010101010101,
+tick,
+output,
+tock,
+output;
+set address %B011101010101,
+tick,
+output,
+tock,
+output;
+set address %B100101010101,
+tick,
+output,
+tock,
+output;
+set address %B101101010101,
+tick,
+output,
+tock,
+output;
+set address %B110101010101,
+tick,
+output,
+tock,
+output;
+set address %B111101010101,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B000101010101,
+tick,
+output;
+tock,
+output;
+set address %B001101010101,
+eval,
+output;
+set address %B010101010101,
+eval,
+output;
+set address %B011101010101,
+eval,
+output;
+set address %B100101010101,
+eval,
+output;
+set address %B101101010101,
+eval,
+output;
+set address %B110101010101,
+eval,
+output;
+set address %B111101010101,
+eval,
+output;
+
+set load 1,
+set address %B000101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010101,
+tick,
+output;
+tock,
+output;
+set address %B001101010101,
+eval,
+output;
+set address %B010101010101,
+eval,
+output;
+set address %B011101010101,
+eval,
+output;
+set address %B100101010101,
+eval,
+output;
+set address %B101101010101,
+eval,
+output;
+set address %B110101010101,
+eval,
+output;
+set address %B111101010101,
+eval,
+output;
+
+set load 1,
+set address %B000101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B001101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010101,
+tick,
+output;
+tock,
+output;
+set address %B001101010101,
+eval,
+output;
+set address %B010101010101,
+eval,
+output;
+set address %B011101010101,
+eval,
+output;
+set address %B100101010101,
+eval,
+output;
+set address %B101101010101,
+eval,
+output;
+set address %B110101010101,
+eval,
+output;
+set address %B111101010101,
+eval,
+output;
+
+set load 1,
+set address %B001101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B010101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010101,
+tick,
+output;
+tock,
+output;
+set address %B001101010101,
+eval,
+output;
+set address %B010101010101,
+eval,
+output;
+set address %B011101010101,
+eval,
+output;
+set address %B100101010101,
+eval,
+output;
+set address %B101101010101,
+eval,
+output;
+set address %B110101010101,
+eval,
+output;
+set address %B111101010101,
+eval,
+output;
+
+set load 1,
+set address %B010101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B011101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010101,
+tick,
+output;
+tock,
+output;
+set address %B001101010101,
+eval,
+output;
+set address %B010101010101,
+eval,
+output;
+set address %B011101010101,
+eval,
+output;
+set address %B100101010101,
+eval,
+output;
+set address %B101101010101,
+eval,
+output;
+set address %B110101010101,
+eval,
+output;
+set address %B111101010101,
+eval,
+output;
+
+set load 1,
+set address %B011101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B100101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010101,
+tick,
+output;
+tock,
+output;
+set address %B001101010101,
+eval,
+output;
+set address %B010101010101,
+eval,
+output;
+set address %B011101010101,
+eval,
+output;
+set address %B100101010101,
+eval,
+output;
+set address %B101101010101,
+eval,
+output;
+set address %B110101010101,
+eval,
+output;
+set address %B111101010101,
+eval,
+output;
+
+set load 1,
+set address %B100101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010101,
+tick,
+output;
+tock,
+output;
+set address %B001101010101,
+eval,
+output;
+set address %B010101010101,
+eval,
+output;
+set address %B011101010101,
+eval,
+output;
+set address %B100101010101,
+eval,
+output;
+set address %B101101010101,
+eval,
+output;
+set address %B110101010101,
+eval,
+output;
+set address %B111101010101,
+eval,
+output;
+
+set load 1,
+set address %B101101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B110101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010101,
+tick,
+output;
+tock,
+output;
+set address %B001101010101,
+eval,
+output;
+set address %B010101010101,
+eval,
+output;
+set address %B011101010101,
+eval,
+output;
+set address %B100101010101,
+eval,
+output;
+set address %B101101010101,
+eval,
+output;
+set address %B110101010101,
+eval,
+output;
+set address %B111101010101,
+eval,
+output;
+
+set load 1,
+set address %B110101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B111101010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010101,
+tick,
+output;
+tock,
+output;
+set address %B001101010101,
+eval,
+output;
+set address %B010101010101,
+eval,
+output;
+set address %B011101010101,
+eval,
+output;
+set address %B100101010101,
+eval,
+output;
+set address %B101101010101,
+eval,
+output;
+set address %B110101010101,
+eval,
+output;
+set address %B111101010101,
+eval,
+output;
+
+set load 1,
+set address %B111101010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B000101010101,
+tick,
+output;
+tock,
+output;
+set address %B001101010101,
+eval,
+output;
+set address %B010101010101,
+eval,
+output;
+set address %B011101010101,
+eval,
+output;
+set address %B100101010101,
+eval,
+output;
+set address %B101101010101,
+eval,
+output;
+set address %B110101010101,
+eval,
+output;
+set address %B111101010101,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/RAM512.cmp b/src/lib/computer/testing/official/RAM512.cmp
new file mode 100644
index 0000000..6f756ca
--- /dev/null
+++ b/src/lib/computer/testing/official/RAM512.cmp
@@ -0,0 +1,320 @@
+| time | in |load |address| out |
+| 0+ | 0 | 0 | 0 | 0 |
+| 1 | 0 | 0 | 0 | 0 |
+| 1+ | 0 | 1 | 0 | 0 |
+| 2 | 0 | 1 | 0 | 0 |
+| 2+ | 13099 | 0 | 0 | 0 |
+| 3 | 13099 | 0 | 0 | 0 |
+| 3+ | 13099 | 1 | 130 | 0 |
+| 4 | 13099 | 1 | 130 | 13099 |
+| 4+ | 13099 | 0 | 0 | 0 |
+| 5 | 13099 | 0 | 0 | 0 |
+| 5+ | 4729 | 0 | 472 | 0 |
+| 6 | 4729 | 0 | 472 | 0 |
+| 6+ | 4729 | 1 | 472 | 0 |
+| 7 | 4729 | 1 | 472 | 4729 |
+| 7+ | 4729 | 0 | 472 | 4729 |
+| 8 | 4729 | 0 | 472 | 4729 |
+| 8 | 4729 | 0 | 130 | 13099 |
+| 8+ | 5119 | 0 | 130 | 13099 |
+| 9 | 5119 | 0 | 130 | 13099 |
+| 9+ | 5119 | 1 | 511 | 0 |
+| 10 | 5119 | 1 | 511 | 5119 |
+| 10+ | 5119 | 0 | 511 | 5119 |
+| 11 | 5119 | 0 | 511 | 5119 |
+| 11 | 5119 | 0 | 472 | 4729 |
+| 11 | 5119 | 0 | 511 | 5119 |
+| 11+ | 5119 | 0 | 168 | 0 |
+| 12 | 5119 | 0 | 168 | 0 |
+| 12 | 5119 | 0 | 169 | 0 |
+| 12 | 5119 | 0 | 170 | 0 |
+| 12 | 5119 | 0 | 171 | 0 |
+| 12 | 5119 | 0 | 172 | 0 |
+| 12 | 5119 | 0 | 173 | 0 |
+| 12 | 5119 | 0 | 174 | 0 |
+| 12 | 5119 | 0 | 175 | 0 |
+| 12+ | 21845 | 1 | 168 | 0 |
+| 13 | 21845 | 1 | 168 | 21845 |
+| 13+ | 21845 | 1 | 169 | 0 |
+| 14 | 21845 | 1 | 169 | 21845 |
+| 14+ | 21845 | 1 | 170 | 0 |
+| 15 | 21845 | 1 | 170 | 21845 |
+| 15+ | 21845 | 1 | 171 | 0 |
+| 16 | 21845 | 1 | 171 | 21845 |
+| 16+ | 21845 | 1 | 172 | 0 |
+| 17 | 21845 | 1 | 172 | 21845 |
+| 17+ | 21845 | 1 | 173 | 0 |
+| 18 | 21845 | 1 | 173 | 21845 |
+| 18+ | 21845 | 1 | 174 | 0 |
+| 19 | 21845 | 1 | 174 | 21845 |
+| 19+ | 21845 | 1 | 175 | 0 |
+| 20 | 21845 | 1 | 175 | 21845 |
+| 20+ | 21845 | 0 | 168 | 21845 |
+| 21 | 21845 | 0 | 168 | 21845 |
+| 21 | 21845 | 0 | 169 | 21845 |
+| 21 | 21845 | 0 | 170 | 21845 |
+| 21 | 21845 | 0 | 171 | 21845 |
+| 21 | 21845 | 0 | 172 | 21845 |
+| 21 | 21845 | 0 | 173 | 21845 |
+| 21 | 21845 | 0 | 174 | 21845 |
+| 21 | 21845 | 0 | 175 | 21845 |
+| 21+ | -21846 | 1 | 168 | 21845 |
+| 22 | -21846 | 1 | 168 | -21846 |
+| 22+ | -21846 | 0 | 168 | -21846 |
+| 23 | -21846 | 0 | 168 | -21846 |
+| 23 | -21846 | 0 | 169 | 21845 |
+| 23 | -21846 | 0 | 170 | 21845 |
+| 23 | -21846 | 0 | 171 | 21845 |
+| 23 | -21846 | 0 | 172 | 21845 |
+| 23 | -21846 | 0 | 173 | 21845 |
+| 23 | -21846 | 0 | 174 | 21845 |
+| 23 | -21846 | 0 | 175 | 21845 |
+| 23+ | 21845 | 1 | 168 | -21846 |
+| 24 | 21845 | 1 | 168 | 21845 |
+| 24+ | -21846 | 1 | 169 | 21845 |
+| 25 | -21846 | 1 | 169 | -21846 |
+| 25+ | -21846 | 0 | 168 | 21845 |
+| 26 | -21846 | 0 | 168 | 21845 |
+| 26 | -21846 | 0 | 169 | -21846 |
+| 26 | -21846 | 0 | 170 | 21845 |
+| 26 | -21846 | 0 | 171 | 21845 |
+| 26 | -21846 | 0 | 172 | 21845 |
+| 26 | -21846 | 0 | 173 | 21845 |
+| 26 | -21846 | 0 | 174 | 21845 |
+| 26 | -21846 | 0 | 175 | 21845 |
+| 26+ | 21845 | 1 | 169 | -21846 |
+| 27 | 21845 | 1 | 169 | 21845 |
+| 27+ | -21846 | 1 | 170 | 21845 |
+| 28 | -21846 | 1 | 170 | -21846 |
+| 28+ | -21846 | 0 | 168 | 21845 |
+| 29 | -21846 | 0 | 168 | 21845 |
+| 29 | -21846 | 0 | 169 | 21845 |
+| 29 | -21846 | 0 | 170 | -21846 |
+| 29 | -21846 | 0 | 171 | 21845 |
+| 29 | -21846 | 0 | 172 | 21845 |
+| 29 | -21846 | 0 | 173 | 21845 |
+| 29 | -21846 | 0 | 174 | 21845 |
+| 29 | -21846 | 0 | 175 | 21845 |
+| 29+ | 21845 | 1 | 170 | -21846 |
+| 30 | 21845 | 1 | 170 | 21845 |
+| 30+ | -21846 | 1 | 171 | 21845 |
+| 31 | -21846 | 1 | 171 | -21846 |
+| 31+ | -21846 | 0 | 168 | 21845 |
+| 32 | -21846 | 0 | 168 | 21845 |
+| 32 | -21846 | 0 | 169 | 21845 |
+| 32 | -21846 | 0 | 170 | 21845 |
+| 32 | -21846 | 0 | 171 | -21846 |
+| 32 | -21846 | 0 | 172 | 21845 |
+| 32 | -21846 | 0 | 173 | 21845 |
+| 32 | -21846 | 0 | 174 | 21845 |
+| 32 | -21846 | 0 | 175 | 21845 |
+| 32+ | 21845 | 1 | 171 | -21846 |
+| 33 | 21845 | 1 | 171 | 21845 |
+| 33+ | -21846 | 1 | 172 | 21845 |
+| 34 | -21846 | 1 | 172 | -21846 |
+| 34+ | -21846 | 0 | 168 | 21845 |
+| 35 | -21846 | 0 | 168 | 21845 |
+| 35 | -21846 | 0 | 169 | 21845 |
+| 35 | -21846 | 0 | 170 | 21845 |
+| 35 | -21846 | 0 | 171 | 21845 |
+| 35 | -21846 | 0 | 172 | -21846 |
+| 35 | -21846 | 0 | 173 | 21845 |
+| 35 | -21846 | 0 | 174 | 21845 |
+| 35 | -21846 | 0 | 175 | 21845 |
+| 35+ | 21845 | 1 | 172 | -21846 |
+| 36 | 21845 | 1 | 172 | 21845 |
+| 36+ | -21846 | 1 | 173 | 21845 |
+| 37 | -21846 | 1 | 173 | -21846 |
+| 37+ | -21846 | 0 | 168 | 21845 |
+| 38 | -21846 | 0 | 168 | 21845 |
+| 38 | -21846 | 0 | 169 | 21845 |
+| 38 | -21846 | 0 | 170 | 21845 |
+| 38 | -21846 | 0 | 171 | 21845 |
+| 38 | -21846 | 0 | 172 | 21845 |
+| 38 | -21846 | 0 | 173 | -21846 |
+| 38 | -21846 | 0 | 174 | 21845 |
+| 38 | -21846 | 0 | 175 | 21845 |
+| 38+ | 21845 | 1 | 173 | -21846 |
+| 39 | 21845 | 1 | 173 | 21845 |
+| 39+ | -21846 | 1 | 174 | 21845 |
+| 40 | -21846 | 1 | 174 | -21846 |
+| 40+ | -21846 | 0 | 168 | 21845 |
+| 41 | -21846 | 0 | 168 | 21845 |
+| 41 | -21846 | 0 | 169 | 21845 |
+| 41 | -21846 | 0 | 170 | 21845 |
+| 41 | -21846 | 0 | 171 | 21845 |
+| 41 | -21846 | 0 | 172 | 21845 |
+| 41 | -21846 | 0 | 173 | 21845 |
+| 41 | -21846 | 0 | 174 | -21846 |
+| 41 | -21846 | 0 | 175 | 21845 |
+| 41+ | 21845 | 1 | 174 | -21846 |
+| 42 | 21845 | 1 | 174 | 21845 |
+| 42+ | -21846 | 1 | 175 | 21845 |
+| 43 | -21846 | 1 | 175 | -21846 |
+| 43+ | -21846 | 0 | 168 | 21845 |
+| 44 | -21846 | 0 | 168 | 21845 |
+| 44 | -21846 | 0 | 169 | 21845 |
+| 44 | -21846 | 0 | 170 | 21845 |
+| 44 | -21846 | 0 | 171 | 21845 |
+| 44 | -21846 | 0 | 172 | 21845 |
+| 44 | -21846 | 0 | 173 | 21845 |
+| 44 | -21846 | 0 | 174 | 21845 |
+| 44 | -21846 | 0 | 175 | -21846 |
+| 44+ | 21845 | 1 | 175 | -21846 |
+| 45 | 21845 | 1 | 175 | 21845 |
+| 45+ | 21845 | 0 | 168 | 21845 |
+| 46 | 21845 | 0 | 168 | 21845 |
+| 46 | 21845 | 0 | 169 | 21845 |
+| 46 | 21845 | 0 | 170 | 21845 |
+| 46 | 21845 | 0 | 171 | 21845 |
+| 46 | 21845 | 0 | 172 | 21845 |
+| 46 | 21845 | 0 | 173 | 21845 |
+| 46 | 21845 | 0 | 174 | 21845 |
+| 46 | 21845 | 0 | 175 | 21845 |
+| 46+ | 21845 | 0 | 42 | 0 |
+| 47 | 21845 | 0 | 42 | 0 |
+| 47 | 21845 | 0 | 106 | 0 |
+| 47 | 21845 | 0 | 170 | 21845 |
+| 47 | 21845 | 0 | 234 | 0 |
+| 47 | 21845 | 0 | 298 | 0 |
+| 47 | 21845 | 0 | 362 | 0 |
+| 47 | 21845 | 0 | 426 | 0 |
+| 47 | 21845 | 0 | 490 | 0 |
+| 47+ | 21845 | 1 | 42 | 0 |
+| 48 | 21845 | 1 | 42 | 21845 |
+| 48+ | 21845 | 1 | 106 | 0 |
+| 49 | 21845 | 1 | 106 | 21845 |
+| 49+ | 21845 | 1 | 170 | 21845 |
+| 50 | 21845 | 1 | 170 | 21845 |
+| 50+ | 21845 | 1 | 234 | 0 |
+| 51 | 21845 | 1 | 234 | 21845 |
+| 51+ | 21845 | 1 | 298 | 0 |
+| 52 | 21845 | 1 | 298 | 21845 |
+| 52+ | 21845 | 1 | 362 | 0 |
+| 53 | 21845 | 1 | 362 | 21845 |
+| 53+ | 21845 | 1 | 426 | 0 |
+| 54 | 21845 | 1 | 426 | 21845 |
+| 54+ | 21845 | 1 | 490 | 0 |
+| 55 | 21845 | 1 | 490 | 21845 |
+| 55+ | 21845 | 0 | 42 | 21845 |
+| 56 | 21845 | 0 | 42 | 21845 |
+| 56 | 21845 | 0 | 106 | 21845 |
+| 56 | 21845 | 0 | 170 | 21845 |
+| 56 | 21845 | 0 | 234 | 21845 |
+| 56 | 21845 | 0 | 298 | 21845 |
+| 56 | 21845 | 0 | 362 | 21845 |
+| 56 | 21845 | 0 | 426 | 21845 |
+| 56 | 21845 | 0 | 490 | 21845 |
+| 56+ | -21846 | 1 | 42 | 21845 |
+| 57 | -21846 | 1 | 42 | -21846 |
+| 57+ | -21846 | 0 | 42 | -21846 |
+| 58 | -21846 | 0 | 42 | -21846 |
+| 58 | -21846 | 0 | 106 | 21845 |
+| 58 | -21846 | 0 | 170 | 21845 |
+| 58 | -21846 | 0 | 234 | 21845 |
+| 58 | -21846 | 0 | 298 | 21845 |
+| 58 | -21846 | 0 | 362 | 21845 |
+| 58 | -21846 | 0 | 426 | 21845 |
+| 58 | -21846 | 0 | 490 | 21845 |
+| 58+ | 21845 | 1 | 42 | -21846 |
+| 59 | 21845 | 1 | 42 | 21845 |
+| 59+ | -21846 | 1 | 106 | 21845 |
+| 60 | -21846 | 1 | 106 | -21846 |
+| 60+ | -21846 | 0 | 42 | 21845 |
+| 61 | -21846 | 0 | 42 | 21845 |
+| 61 | -21846 | 0 | 106 | -21846 |
+| 61 | -21846 | 0 | 170 | 21845 |
+| 61 | -21846 | 0 | 234 | 21845 |
+| 61 | -21846 | 0 | 298 | 21845 |
+| 61 | -21846 | 0 | 362 | 21845 |
+| 61 | -21846 | 0 | 426 | 21845 |
+| 61 | -21846 | 0 | 490 | 21845 |
+| 61+ | 21845 | 1 | 106 | -21846 |
+| 62 | 21845 | 1 | 106 | 21845 |
+| 62+ | -21846 | 1 | 170 | 21845 |
+| 63 | -21846 | 1 | 170 | -21846 |
+| 63+ | -21846 | 0 | 42 | 21845 |
+| 64 | -21846 | 0 | 42 | 21845 |
+| 64 | -21846 | 0 | 106 | 21845 |
+| 64 | -21846 | 0 | 170 | -21846 |
+| 64 | -21846 | 0 | 234 | 21845 |
+| 64 | -21846 | 0 | 298 | 21845 |
+| 64 | -21846 | 0 | 362 | 21845 |
+| 64 | -21846 | 0 | 426 | 21845 |
+| 64 | -21846 | 0 | 490 | 21845 |
+| 64+ | 21845 | 1 | 170 | -21846 |
+| 65 | 21845 | 1 | 170 | 21845 |
+| 65+ | -21846 | 1 | 234 | 21845 |
+| 66 | -21846 | 1 | 234 | -21846 |
+| 66+ | -21846 | 0 | 42 | 21845 |
+| 67 | -21846 | 0 | 42 | 21845 |
+| 67 | -21846 | 0 | 106 | 21845 |
+| 67 | -21846 | 0 | 170 | 21845 |
+| 67 | -21846 | 0 | 234 | -21846 |
+| 67 | -21846 | 0 | 298 | 21845 |
+| 67 | -21846 | 0 | 362 | 21845 |
+| 67 | -21846 | 0 | 426 | 21845 |
+| 67 | -21846 | 0 | 490 | 21845 |
+| 67+ | 21845 | 1 | 234 | -21846 |
+| 68 | 21845 | 1 | 234 | 21845 |
+| 68+ | -21846 | 1 | 298 | 21845 |
+| 69 | -21846 | 1 | 298 | -21846 |
+| 69+ | -21846 | 0 | 42 | 21845 |
+| 70 | -21846 | 0 | 42 | 21845 |
+| 70 | -21846 | 0 | 106 | 21845 |
+| 70 | -21846 | 0 | 170 | 21845 |
+| 70 | -21846 | 0 | 234 | 21845 |
+| 70 | -21846 | 0 | 298 | -21846 |
+| 70 | -21846 | 0 | 362 | 21845 |
+| 70 | -21846 | 0 | 426 | 21845 |
+| 70 | -21846 | 0 | 490 | 21845 |
+| 70+ | 21845 | 1 | 298 | -21846 |
+| 71 | 21845 | 1 | 298 | 21845 |
+| 71+ | -21846 | 1 | 362 | 21845 |
+| 72 | -21846 | 1 | 362 | -21846 |
+| 72+ | -21846 | 0 | 42 | 21845 |
+| 73 | -21846 | 0 | 42 | 21845 |
+| 73 | -21846 | 0 | 106 | 21845 |
+| 73 | -21846 | 0 | 170 | 21845 |
+| 73 | -21846 | 0 | 234 | 21845 |
+| 73 | -21846 | 0 | 298 | 21845 |
+| 73 | -21846 | 0 | 362 | -21846 |
+| 73 | -21846 | 0 | 426 | 21845 |
+| 73 | -21846 | 0 | 490 | 21845 |
+| 73+ | 21845 | 1 | 362 | -21846 |
+| 74 | 21845 | 1 | 362 | 21845 |
+| 74+ | -21846 | 1 | 426 | 21845 |
+| 75 | -21846 | 1 | 426 | -21846 |
+| 75+ | -21846 | 0 | 42 | 21845 |
+| 76 | -21846 | 0 | 42 | 21845 |
+| 76 | -21846 | 0 | 106 | 21845 |
+| 76 | -21846 | 0 | 170 | 21845 |
+| 76 | -21846 | 0 | 234 | 21845 |
+| 76 | -21846 | 0 | 298 | 21845 |
+| 76 | -21846 | 0 | 362 | 21845 |
+| 76 | -21846 | 0 | 426 | -21846 |
+| 76 | -21846 | 0 | 490 | 21845 |
+| 76+ | 21845 | 1 | 426 | -21846 |
+| 77 | 21845 | 1 | 426 | 21845 |
+| 77+ | -21846 | 1 | 490 | 21845 |
+| 78 | -21846 | 1 | 490 | -21846 |
+| 78+ | -21846 | 0 | 42 | 21845 |
+| 79 | -21846 | 0 | 42 | 21845 |
+| 79 | -21846 | 0 | 106 | 21845 |
+| 79 | -21846 | 0 | 170 | 21845 |
+| 79 | -21846 | 0 | 234 | 21845 |
+| 79 | -21846 | 0 | 298 | 21845 |
+| 79 | -21846 | 0 | 362 | 21845 |
+| 79 | -21846 | 0 | 426 | 21845 |
+| 79 | -21846 | 0 | 490 | -21846 |
+| 79+ | 21845 | 1 | 490 | -21846 |
+| 80 | 21845 | 1 | 490 | 21845 |
+| 80+ | 21845 | 0 | 42 | 21845 |
+| 81 | 21845 | 0 | 42 | 21845 |
+| 81 | 21845 | 0 | 106 | 21845 |
+| 81 | 21845 | 0 | 170 | 21845 |
+| 81 | 21845 | 0 | 234 | 21845 |
+| 81 | 21845 | 0 | 298 | 21845 |
+| 81 | 21845 | 0 | 362 | 21845 |
+| 81 | 21845 | 0 | 426 | 21845 |
+| 81 | 21845 | 0 | 490 | 21845 |
diff --git a/src/lib/computer/testing/official/RAM512.tst b/src/lib/computer/testing/official/RAM512.tst
new file mode 100644
index 0000000..4ec6fc2
--- /dev/null
+++ b/src/lib/computer/testing/official/RAM512.tst
@@ -0,0 +1,1027 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/03/b/RAM512.tst
+
+load RAM512.hdl,
+output-file RAM512.out,
+compare-to RAM512.cmp,
+output-list time%S1.4.1 in%D1.6.1 load%B2.1.2 address%D2.3.2 out%D1.6.1;
+
+set in 0,
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+tick,
+output;
+tock,
+output;
+
+set in 13099,
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+set address 130,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+
+set in 4729,
+set address 472,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set address 130,
+eval,
+output;
+
+set in 5119,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+set address 511,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set address 472,
+eval,
+output;
+
+set address 511,
+eval,
+output;
+
+
+set load 0,
+set address %B010101000,
+tick,
+output;
+tock,
+output;
+set address %B010101001,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B010101011,
+eval,
+output;
+set address %B010101100,
+eval,
+output;
+set address %B010101101,
+eval,
+output;
+set address %B010101110,
+eval,
+output;
+set address %B010101111,
+eval,
+output;
+
+set load 1,
+set in %B0101010101010101,
+set address %B010101000,
+tick,
+output;
+tock,
+output;
+set address %B010101001,
+tick,
+output,
+tock,
+output;
+set address %B010101010,
+tick,
+output,
+tock,
+output;
+set address %B010101011,
+tick,
+output,
+tock,
+output;
+set address %B010101100,
+tick,
+output,
+tock,
+output;
+set address %B010101101,
+tick,
+output,
+tock,
+output;
+set address %B010101110,
+tick,
+output,
+tock,
+output;
+set address %B010101111,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B010101000,
+tick,
+output;
+tock,
+output;
+set address %B010101001,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B010101011,
+eval,
+output;
+set address %B010101100,
+eval,
+output;
+set address %B010101101,
+eval,
+output;
+set address %B010101110,
+eval,
+output;
+set address %B010101111,
+eval,
+output;
+
+set load 1,
+set address %B010101000,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B010101000,
+tick,
+output;
+tock,
+output;
+set address %B010101001,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B010101011,
+eval,
+output;
+set address %B010101100,
+eval,
+output;
+set address %B010101101,
+eval,
+output;
+set address %B010101110,
+eval,
+output;
+set address %B010101111,
+eval,
+output;
+
+set load 1,
+set address %B010101000,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B010101001,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B010101000,
+tick,
+output;
+tock,
+output;
+set address %B010101001,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B010101011,
+eval,
+output;
+set address %B010101100,
+eval,
+output;
+set address %B010101101,
+eval,
+output;
+set address %B010101110,
+eval,
+output;
+set address %B010101111,
+eval,
+output;
+
+set load 1,
+set address %B010101001,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B010101010,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B010101000,
+tick,
+output;
+tock,
+output;
+set address %B010101001,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B010101011,
+eval,
+output;
+set address %B010101100,
+eval,
+output;
+set address %B010101101,
+eval,
+output;
+set address %B010101110,
+eval,
+output;
+set address %B010101111,
+eval,
+output;
+
+set load 1,
+set address %B010101010,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B010101011,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B010101000,
+tick,
+output;
+tock,
+output;
+set address %B010101001,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B010101011,
+eval,
+output;
+set address %B010101100,
+eval,
+output;
+set address %B010101101,
+eval,
+output;
+set address %B010101110,
+eval,
+output;
+set address %B010101111,
+eval,
+output;
+
+set load 1,
+set address %B010101011,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B010101100,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B010101000,
+tick,
+output;
+tock,
+output;
+set address %B010101001,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B010101011,
+eval,
+output;
+set address %B010101100,
+eval,
+output;
+set address %B010101101,
+eval,
+output;
+set address %B010101110,
+eval,
+output;
+set address %B010101111,
+eval,
+output;
+
+set load 1,
+set address %B010101100,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B010101101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B010101000,
+tick,
+output;
+tock,
+output;
+set address %B010101001,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B010101011,
+eval,
+output;
+set address %B010101100,
+eval,
+output;
+set address %B010101101,
+eval,
+output;
+set address %B010101110,
+eval,
+output;
+set address %B010101111,
+eval,
+output;
+
+set load 1,
+set address %B010101101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B010101110,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B010101000,
+tick,
+output;
+tock,
+output;
+set address %B010101001,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B010101011,
+eval,
+output;
+set address %B010101100,
+eval,
+output;
+set address %B010101101,
+eval,
+output;
+set address %B010101110,
+eval,
+output;
+set address %B010101111,
+eval,
+output;
+
+set load 1,
+set address %B010101110,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B010101111,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B010101000,
+tick,
+output;
+tock,
+output;
+set address %B010101001,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B010101011,
+eval,
+output;
+set address %B010101100,
+eval,
+output;
+set address %B010101101,
+eval,
+output;
+set address %B010101110,
+eval,
+output;
+set address %B010101111,
+eval,
+output;
+
+set load 1,
+set address %B010101111,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B010101000,
+tick,
+output;
+tock,
+output;
+set address %B010101001,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B010101011,
+eval,
+output;
+set address %B010101100,
+eval,
+output;
+set address %B010101101,
+eval,
+output;
+set address %B010101110,
+eval,
+output;
+set address %B010101111,
+eval,
+output;
+
+
+set load 0,
+set address %B000101010,
+tick,
+output;
+tock,
+output;
+set address %B001101010,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B011101010,
+eval,
+output;
+set address %B100101010,
+eval,
+output;
+set address %B101101010,
+eval,
+output;
+set address %B110101010,
+eval,
+output;
+set address %B111101010,
+eval,
+output;
+
+set load 1,
+set in %B0101010101010101,
+set address %B000101010,
+tick,
+output;
+tock,
+output;
+set address %B001101010,
+tick,
+output,
+tock,
+output;
+set address %B010101010,
+tick,
+output,
+tock,
+output;
+set address %B011101010,
+tick,
+output,
+tock,
+output;
+set address %B100101010,
+tick,
+output,
+tock,
+output;
+set address %B101101010,
+tick,
+output,
+tock,
+output;
+set address %B110101010,
+tick,
+output,
+tock,
+output;
+set address %B111101010,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B000101010,
+tick,
+output;
+tock,
+output;
+set address %B001101010,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B011101010,
+eval,
+output;
+set address %B100101010,
+eval,
+output;
+set address %B101101010,
+eval,
+output;
+set address %B110101010,
+eval,
+output;
+set address %B111101010,
+eval,
+output;
+
+set load 1,
+set address %B000101010,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010,
+tick,
+output;
+tock,
+output;
+set address %B001101010,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B011101010,
+eval,
+output;
+set address %B100101010,
+eval,
+output;
+set address %B101101010,
+eval,
+output;
+set address %B110101010,
+eval,
+output;
+set address %B111101010,
+eval,
+output;
+
+set load 1,
+set address %B000101010,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B001101010,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010,
+tick,
+output;
+tock,
+output;
+set address %B001101010,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B011101010,
+eval,
+output;
+set address %B100101010,
+eval,
+output;
+set address %B101101010,
+eval,
+output;
+set address %B110101010,
+eval,
+output;
+set address %B111101010,
+eval,
+output;
+
+set load 1,
+set address %B001101010,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B010101010,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010,
+tick,
+output;
+tock,
+output;
+set address %B001101010,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B011101010,
+eval,
+output;
+set address %B100101010,
+eval,
+output;
+set address %B101101010,
+eval,
+output;
+set address %B110101010,
+eval,
+output;
+set address %B111101010,
+eval,
+output;
+
+set load 1,
+set address %B010101010,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B011101010,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010,
+tick,
+output;
+tock,
+output;
+set address %B001101010,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B011101010,
+eval,
+output;
+set address %B100101010,
+eval,
+output;
+set address %B101101010,
+eval,
+output;
+set address %B110101010,
+eval,
+output;
+set address %B111101010,
+eval,
+output;
+
+set load 1,
+set address %B011101010,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B100101010,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010,
+tick,
+output;
+tock,
+output;
+set address %B001101010,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B011101010,
+eval,
+output;
+set address %B100101010,
+eval,
+output;
+set address %B101101010,
+eval,
+output;
+set address %B110101010,
+eval,
+output;
+set address %B111101010,
+eval,
+output;
+
+set load 1,
+set address %B100101010,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101101010,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010,
+tick,
+output;
+tock,
+output;
+set address %B001101010,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B011101010,
+eval,
+output;
+set address %B100101010,
+eval,
+output;
+set address %B101101010,
+eval,
+output;
+set address %B110101010,
+eval,
+output;
+set address %B111101010,
+eval,
+output;
+
+set load 1,
+set address %B101101010,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B110101010,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010,
+tick,
+output;
+tock,
+output;
+set address %B001101010,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B011101010,
+eval,
+output;
+set address %B100101010,
+eval,
+output;
+set address %B101101010,
+eval,
+output;
+set address %B110101010,
+eval,
+output;
+set address %B111101010,
+eval,
+output;
+
+set load 1,
+set address %B110101010,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B111101010,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101010,
+tick,
+output;
+tock,
+output;
+set address %B001101010,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B011101010,
+eval,
+output;
+set address %B100101010,
+eval,
+output;
+set address %B101101010,
+eval,
+output;
+set address %B110101010,
+eval,
+output;
+set address %B111101010,
+eval,
+output;
+
+set load 1,
+set address %B111101010,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B000101010,
+tick,
+output;
+tock,
+output;
+set address %B001101010,
+eval,
+output;
+set address %B010101010,
+eval,
+output;
+set address %B011101010,
+eval,
+output;
+set address %B100101010,
+eval,
+output;
+set address %B101101010,
+eval,
+output;
+set address %B110101010,
+eval,
+output;
+set address %B111101010,
+eval,
+output;
+
diff --git a/src/lib/computer/testing/official/RAM64.cmp b/src/lib/computer/testing/official/RAM64.cmp
new file mode 100644
index 0000000..fdb7745
--- /dev/null
+++ b/src/lib/computer/testing/official/RAM64.cmp
@@ -0,0 +1,320 @@
+| time | in |load |address| out |
+| 0+ | 0 | 0 | 0 | 0 |
+| 1 | 0 | 0 | 0 | 0 |
+| 1+ | 0 | 1 | 0 | 0 |
+| 2 | 0 | 1 | 0 | 0 |
+| 2+ | 1313 | 0 | 0 | 0 |
+| 3 | 1313 | 0 | 0 | 0 |
+| 3+ | 1313 | 1 | 13 | 0 |
+| 4 | 1313 | 1 | 13 | 1313 |
+| 4+ | 1313 | 0 | 0 | 0 |
+| 5 | 1313 | 0 | 0 | 0 |
+| 5+ | 4747 | 0 | 47 | 0 |
+| 6 | 4747 | 0 | 47 | 0 |
+| 6+ | 4747 | 1 | 47 | 0 |
+| 7 | 4747 | 1 | 47 | 4747 |
+| 7+ | 4747 | 0 | 47 | 4747 |
+| 8 | 4747 | 0 | 47 | 4747 |
+| 8 | 4747 | 0 | 13 | 1313 |
+| 8+ | 6363 | 0 | 13 | 1313 |
+| 9 | 6363 | 0 | 13 | 1313 |
+| 9+ | 6363 | 1 | 63 | 0 |
+| 10 | 6363 | 1 | 63 | 6363 |
+| 10+ | 6363 | 0 | 63 | 6363 |
+| 11 | 6363 | 0 | 63 | 6363 |
+| 11 | 6363 | 0 | 47 | 4747 |
+| 11 | 6363 | 0 | 63 | 6363 |
+| 11+ | 6363 | 0 | 40 | 0 |
+| 12 | 6363 | 0 | 40 | 0 |
+| 12 | 6363 | 0 | 41 | 0 |
+| 12 | 6363 | 0 | 42 | 0 |
+| 12 | 6363 | 0 | 43 | 0 |
+| 12 | 6363 | 0 | 44 | 0 |
+| 12 | 6363 | 0 | 45 | 0 |
+| 12 | 6363 | 0 | 46 | 0 |
+| 12 | 6363 | 0 | 47 | 4747 |
+| 12+ | 21845 | 1 | 40 | 0 |
+| 13 | 21845 | 1 | 40 | 21845 |
+| 13+ | 21845 | 1 | 41 | 0 |
+| 14 | 21845 | 1 | 41 | 21845 |
+| 14+ | 21845 | 1 | 42 | 0 |
+| 15 | 21845 | 1 | 42 | 21845 |
+| 15+ | 21845 | 1 | 43 | 0 |
+| 16 | 21845 | 1 | 43 | 21845 |
+| 16+ | 21845 | 1 | 44 | 0 |
+| 17 | 21845 | 1 | 44 | 21845 |
+| 17+ | 21845 | 1 | 45 | 0 |
+| 18 | 21845 | 1 | 45 | 21845 |
+| 18+ | 21845 | 1 | 46 | 0 |
+| 19 | 21845 | 1 | 46 | 21845 |
+| 19+ | 21845 | 1 | 47 | 4747 |
+| 20 | 21845 | 1 | 47 | 21845 |
+| 20+ | 21845 | 0 | 40 | 21845 |
+| 21 | 21845 | 0 | 40 | 21845 |
+| 21 | 21845 | 0 | 41 | 21845 |
+| 21 | 21845 | 0 | 42 | 21845 |
+| 21 | 21845 | 0 | 43 | 21845 |
+| 21 | 21845 | 0 | 44 | 21845 |
+| 21 | 21845 | 0 | 45 | 21845 |
+| 21 | 21845 | 0 | 46 | 21845 |
+| 21 | 21845 | 0 | 47 | 21845 |
+| 21+ | -21846 | 1 | 40 | 21845 |
+| 22 | -21846 | 1 | 40 | -21846 |
+| 22+ | -21846 | 0 | 40 | -21846 |
+| 23 | -21846 | 0 | 40 | -21846 |
+| 23 | -21846 | 0 | 41 | 21845 |
+| 23 | -21846 | 0 | 42 | 21845 |
+| 23 | -21846 | 0 | 43 | 21845 |
+| 23 | -21846 | 0 | 44 | 21845 |
+| 23 | -21846 | 0 | 45 | 21845 |
+| 23 | -21846 | 0 | 46 | 21845 |
+| 23 | -21846 | 0 | 47 | 21845 |
+| 23+ | 21845 | 1 | 40 | -21846 |
+| 24 | 21845 | 1 | 40 | 21845 |
+| 24+ | -21846 | 1 | 41 | 21845 |
+| 25 | -21846 | 1 | 41 | -21846 |
+| 25+ | -21846 | 0 | 40 | 21845 |
+| 26 | -21846 | 0 | 40 | 21845 |
+| 26 | -21846 | 0 | 41 | -21846 |
+| 26 | -21846 | 0 | 42 | 21845 |
+| 26 | -21846 | 0 | 43 | 21845 |
+| 26 | -21846 | 0 | 44 | 21845 |
+| 26 | -21846 | 0 | 45 | 21845 |
+| 26 | -21846 | 0 | 46 | 21845 |
+| 26 | -21846 | 0 | 47 | 21845 |
+| 26+ | 21845 | 1 | 41 | -21846 |
+| 27 | 21845 | 1 | 41 | 21845 |
+| 27+ | -21846 | 1 | 42 | 21845 |
+| 28 | -21846 | 1 | 42 | -21846 |
+| 28+ | -21846 | 0 | 40 | 21845 |
+| 29 | -21846 | 0 | 40 | 21845 |
+| 29 | -21846 | 0 | 41 | 21845 |
+| 29 | -21846 | 0 | 42 | -21846 |
+| 29 | -21846 | 0 | 43 | 21845 |
+| 29 | -21846 | 0 | 44 | 21845 |
+| 29 | -21846 | 0 | 45 | 21845 |
+| 29 | -21846 | 0 | 46 | 21845 |
+| 29 | -21846 | 0 | 47 | 21845 |
+| 29+ | 21845 | 1 | 42 | -21846 |
+| 30 | 21845 | 1 | 42 | 21845 |
+| 30+ | -21846 | 1 | 43 | 21845 |
+| 31 | -21846 | 1 | 43 | -21846 |
+| 31+ | -21846 | 0 | 40 | 21845 |
+| 32 | -21846 | 0 | 40 | 21845 |
+| 32 | -21846 | 0 | 41 | 21845 |
+| 32 | -21846 | 0 | 42 | 21845 |
+| 32 | -21846 | 0 | 43 | -21846 |
+| 32 | -21846 | 0 | 44 | 21845 |
+| 32 | -21846 | 0 | 45 | 21845 |
+| 32 | -21846 | 0 | 46 | 21845 |
+| 32 | -21846 | 0 | 47 | 21845 |
+| 32+ | 21845 | 1 | 43 | -21846 |
+| 33 | 21845 | 1 | 43 | 21845 |
+| 33+ | -21846 | 1 | 44 | 21845 |
+| 34 | -21846 | 1 | 44 | -21846 |
+| 34+ | -21846 | 0 | 40 | 21845 |
+| 35 | -21846 | 0 | 40 | 21845 |
+| 35 | -21846 | 0 | 41 | 21845 |
+| 35 | -21846 | 0 | 42 | 21845 |
+| 35 | -21846 | 0 | 43 | 21845 |
+| 35 | -21846 | 0 | 44 | -21846 |
+| 35 | -21846 | 0 | 45 | 21845 |
+| 35 | -21846 | 0 | 46 | 21845 |
+| 35 | -21846 | 0 | 47 | 21845 |
+| 35+ | 21845 | 1 | 44 | -21846 |
+| 36 | 21845 | 1 | 44 | 21845 |
+| 36+ | -21846 | 1 | 45 | 21845 |
+| 37 | -21846 | 1 | 45 | -21846 |
+| 37+ | -21846 | 0 | 40 | 21845 |
+| 38 | -21846 | 0 | 40 | 21845 |
+| 38 | -21846 | 0 | 41 | 21845 |
+| 38 | -21846 | 0 | 42 | 21845 |
+| 38 | -21846 | 0 | 43 | 21845 |
+| 38 | -21846 | 0 | 44 | 21845 |
+| 38 | -21846 | 0 | 45 | -21846 |
+| 38 | -21846 | 0 | 46 | 21845 |
+| 38 | -21846 | 0 | 47 | 21845 |
+| 38+ | 21845 | 1 | 45 | -21846 |
+| 39 | 21845 | 1 | 45 | 21845 |
+| 39+ | -21846 | 1 | 46 | 21845 |
+| 40 | -21846 | 1 | 46 | -21846 |
+| 40+ | -21846 | 0 | 40 | 21845 |
+| 41 | -21846 | 0 | 40 | 21845 |
+| 41 | -21846 | 0 | 41 | 21845 |
+| 41 | -21846 | 0 | 42 | 21845 |
+| 41 | -21846 | 0 | 43 | 21845 |
+| 41 | -21846 | 0 | 44 | 21845 |
+| 41 | -21846 | 0 | 45 | 21845 |
+| 41 | -21846 | 0 | 46 | -21846 |
+| 41 | -21846 | 0 | 47 | 21845 |
+| 41+ | 21845 | 1 | 46 | -21846 |
+| 42 | 21845 | 1 | 46 | 21845 |
+| 42+ | -21846 | 1 | 47 | 21845 |
+| 43 | -21846 | 1 | 47 | -21846 |
+| 43+ | -21846 | 0 | 40 | 21845 |
+| 44 | -21846 | 0 | 40 | 21845 |
+| 44 | -21846 | 0 | 41 | 21845 |
+| 44 | -21846 | 0 | 42 | 21845 |
+| 44 | -21846 | 0 | 43 | 21845 |
+| 44 | -21846 | 0 | 44 | 21845 |
+| 44 | -21846 | 0 | 45 | 21845 |
+| 44 | -21846 | 0 | 46 | 21845 |
+| 44 | -21846 | 0 | 47 | -21846 |
+| 44+ | 21845 | 1 | 47 | -21846 |
+| 45 | 21845 | 1 | 47 | 21845 |
+| 45+ | 21845 | 0 | 40 | 21845 |
+| 46 | 21845 | 0 | 40 | 21845 |
+| 46 | 21845 | 0 | 41 | 21845 |
+| 46 | 21845 | 0 | 42 | 21845 |
+| 46 | 21845 | 0 | 43 | 21845 |
+| 46 | 21845 | 0 | 44 | 21845 |
+| 46 | 21845 | 0 | 45 | 21845 |
+| 46 | 21845 | 0 | 46 | 21845 |
+| 46 | 21845 | 0 | 47 | 21845 |
+| 46+ | 21845 | 0 | 5 | 0 |
+| 47 | 21845 | 0 | 5 | 0 |
+| 47 | 21845 | 0 | 13 | 1313 |
+| 47 | 21845 | 0 | 21 | 0 |
+| 47 | 21845 | 0 | 29 | 0 |
+| 47 | 21845 | 0 | 37 | 0 |
+| 47 | 21845 | 0 | 45 | 21845 |
+| 47 | 21845 | 0 | 53 | 0 |
+| 47 | 21845 | 0 | 61 | 0 |
+| 47+ | 21845 | 1 | 5 | 0 |
+| 48 | 21845 | 1 | 5 | 21845 |
+| 48+ | 21845 | 1 | 13 | 1313 |
+| 49 | 21845 | 1 | 13 | 21845 |
+| 49+ | 21845 | 1 | 21 | 0 |
+| 50 | 21845 | 1 | 21 | 21845 |
+| 50+ | 21845 | 1 | 29 | 0 |
+| 51 | 21845 | 1 | 29 | 21845 |
+| 51+ | 21845 | 1 | 37 | 0 |
+| 52 | 21845 | 1 | 37 | 21845 |
+| 52+ | 21845 | 1 | 45 | 21845 |
+| 53 | 21845 | 1 | 45 | 21845 |
+| 53+ | 21845 | 1 | 53 | 0 |
+| 54 | 21845 | 1 | 53 | 21845 |
+| 54+ | 21845 | 1 | 61 | 0 |
+| 55 | 21845 | 1 | 61 | 21845 |
+| 55+ | 21845 | 0 | 5 | 21845 |
+| 56 | 21845 | 0 | 5 | 21845 |
+| 56 | 21845 | 0 | 13 | 21845 |
+| 56 | 21845 | 0 | 21 | 21845 |
+| 56 | 21845 | 0 | 29 | 21845 |
+| 56 | 21845 | 0 | 37 | 21845 |
+| 56 | 21845 | 0 | 45 | 21845 |
+| 56 | 21845 | 0 | 53 | 21845 |
+| 56 | 21845 | 0 | 61 | 21845 |
+| 56+ | -21846 | 1 | 5 | 21845 |
+| 57 | -21846 | 1 | 5 | -21846 |
+| 57+ | -21846 | 0 | 5 | -21846 |
+| 58 | -21846 | 0 | 5 | -21846 |
+| 58 | -21846 | 0 | 13 | 21845 |
+| 58 | -21846 | 0 | 21 | 21845 |
+| 58 | -21846 | 0 | 29 | 21845 |
+| 58 | -21846 | 0 | 37 | 21845 |
+| 58 | -21846 | 0 | 45 | 21845 |
+| 58 | -21846 | 0 | 53 | 21845 |
+| 58 | -21846 | 0 | 61 | 21845 |
+| 58+ | 21845 | 1 | 5 | -21846 |
+| 59 | 21845 | 1 | 5 | 21845 |
+| 59+ | -21846 | 1 | 13 | 21845 |
+| 60 | -21846 | 1 | 13 | -21846 |
+| 60+ | -21846 | 0 | 5 | 21845 |
+| 61 | -21846 | 0 | 5 | 21845 |
+| 61 | -21846 | 0 | 13 | -21846 |
+| 61 | -21846 | 0 | 21 | 21845 |
+| 61 | -21846 | 0 | 29 | 21845 |
+| 61 | -21846 | 0 | 37 | 21845 |
+| 61 | -21846 | 0 | 45 | 21845 |
+| 61 | -21846 | 0 | 53 | 21845 |
+| 61 | -21846 | 0 | 61 | 21845 |
+| 61+ | 21845 | 1 | 13 | -21846 |
+| 62 | 21845 | 1 | 13 | 21845 |
+| 62+ | -21846 | 1 | 21 | 21845 |
+| 63 | -21846 | 1 | 21 | -21846 |
+| 63+ | -21846 | 0 | 5 | 21845 |
+| 64 | -21846 | 0 | 5 | 21845 |
+| 64 | -21846 | 0 | 13 | 21845 |
+| 64 | -21846 | 0 | 21 | -21846 |
+| 64 | -21846 | 0 | 29 | 21845 |
+| 64 | -21846 | 0 | 37 | 21845 |
+| 64 | -21846 | 0 | 45 | 21845 |
+| 64 | -21846 | 0 | 53 | 21845 |
+| 64 | -21846 | 0 | 61 | 21845 |
+| 64+ | 21845 | 1 | 21 | -21846 |
+| 65 | 21845 | 1 | 21 | 21845 |
+| 65+ | -21846 | 1 | 29 | 21845 |
+| 66 | -21846 | 1 | 29 | -21846 |
+| 66+ | -21846 | 0 | 5 | 21845 |
+| 67 | -21846 | 0 | 5 | 21845 |
+| 67 | -21846 | 0 | 13 | 21845 |
+| 67 | -21846 | 0 | 21 | 21845 |
+| 67 | -21846 | 0 | 29 | -21846 |
+| 67 | -21846 | 0 | 37 | 21845 |
+| 67 | -21846 | 0 | 45 | 21845 |
+| 67 | -21846 | 0 | 53 | 21845 |
+| 67 | -21846 | 0 | 61 | 21845 |
+| 67+ | 21845 | 1 | 29 | -21846 |
+| 68 | 21845 | 1 | 29 | 21845 |
+| 68+ | -21846 | 1 | 37 | 21845 |
+| 69 | -21846 | 1 | 37 | -21846 |
+| 69+ | -21846 | 0 | 5 | 21845 |
+| 70 | -21846 | 0 | 5 | 21845 |
+| 70 | -21846 | 0 | 13 | 21845 |
+| 70 | -21846 | 0 | 21 | 21845 |
+| 70 | -21846 | 0 | 29 | 21845 |
+| 70 | -21846 | 0 | 37 | -21846 |
+| 70 | -21846 | 0 | 45 | 21845 |
+| 70 | -21846 | 0 | 53 | 21845 |
+| 70 | -21846 | 0 | 61 | 21845 |
+| 70+ | 21845 | 1 | 37 | -21846 |
+| 71 | 21845 | 1 | 37 | 21845 |
+| 71+ | -21846 | 1 | 45 | 21845 |
+| 72 | -21846 | 1 | 45 | -21846 |
+| 72+ | -21846 | 0 | 5 | 21845 |
+| 73 | -21846 | 0 | 5 | 21845 |
+| 73 | -21846 | 0 | 13 | 21845 |
+| 73 | -21846 | 0 | 21 | 21845 |
+| 73 | -21846 | 0 | 29 | 21845 |
+| 73 | -21846 | 0 | 37 | 21845 |
+| 73 | -21846 | 0 | 45 | -21846 |
+| 73 | -21846 | 0 | 53 | 21845 |
+| 73 | -21846 | 0 | 61 | 21845 |
+| 73+ | 21845 | 1 | 45 | -21846 |
+| 74 | 21845 | 1 | 45 | 21845 |
+| 74+ | -21846 | 1 | 53 | 21845 |
+| 75 | -21846 | 1 | 53 | -21846 |
+| 75+ | -21846 | 0 | 5 | 21845 |
+| 76 | -21846 | 0 | 5 | 21845 |
+| 76 | -21846 | 0 | 13 | 21845 |
+| 76 | -21846 | 0 | 21 | 21845 |
+| 76 | -21846 | 0 | 29 | 21845 |
+| 76 | -21846 | 0 | 37 | 21845 |
+| 76 | -21846 | 0 | 45 | 21845 |
+| 76 | -21846 | 0 | 53 | -21846 |
+| 76 | -21846 | 0 | 61 | 21845 |
+| 76+ | 21845 | 1 | 53 | -21846 |
+| 77 | 21845 | 1 | 53 | 21845 |
+| 77+ | -21846 | 1 | 61 | 21845 |
+| 78 | -21846 | 1 | 61 | -21846 |
+| 78+ | -21846 | 0 | 5 | 21845 |
+| 79 | -21846 | 0 | 5 | 21845 |
+| 79 | -21846 | 0 | 13 | 21845 |
+| 79 | -21846 | 0 | 21 | 21845 |
+| 79 | -21846 | 0 | 29 | 21845 |
+| 79 | -21846 | 0 | 37 | 21845 |
+| 79 | -21846 | 0 | 45 | 21845 |
+| 79 | -21846 | 0 | 53 | 21845 |
+| 79 | -21846 | 0 | 61 | -21846 |
+| 79+ | 21845 | 1 | 61 | -21846 |
+| 80 | 21845 | 1 | 61 | 21845 |
+| 80+ | 21845 | 0 | 5 | 21845 |
+| 81 | 21845 | 0 | 5 | 21845 |
+| 81 | 21845 | 0 | 13 | 21845 |
+| 81 | 21845 | 0 | 21 | 21845 |
+| 81 | 21845 | 0 | 29 | 21845 |
+| 81 | 21845 | 0 | 37 | 21845 |
+| 81 | 21845 | 0 | 45 | 21845 |
+| 81 | 21845 | 0 | 53 | 21845 |
+| 81 | 21845 | 0 | 61 | 21845 |
diff --git a/src/lib/computer/testing/official/RAM64.tst b/src/lib/computer/testing/official/RAM64.tst
new file mode 100644
index 0000000..e1a1409
--- /dev/null
+++ b/src/lib/computer/testing/official/RAM64.tst
@@ -0,0 +1,1026 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/03/a/RAM64.tst
+
+load RAM64.hdl,
+output-file RAM64.out,
+compare-to RAM64.cmp,
+output-list time%S1.4.1 in%D1.6.1 load%B2.1.2 address%D2.3.2 out%D1.6.1;
+
+set in 0,
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+tick,
+output;
+tock,
+output;
+
+set in 1313,
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+set address 13,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+
+set in 4747,
+set address 47,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set address 13,
+eval,
+output;
+
+set in 6363,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+set address 63,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set address 47,
+eval,
+output;
+
+set address 63,
+eval,
+output;
+
+
+set load 0,
+set address %B101000,
+tick,
+output;
+tock,
+output;
+set address %B101001,
+eval,
+output;
+set address %B101010,
+eval,
+output;
+set address %B101011,
+eval,
+output;
+set address %B101100,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B101110,
+eval,
+output;
+set address %B101111,
+eval,
+output;
+
+set load 1,
+set in %B0101010101010101,
+set address %B101000,
+tick,
+output;
+tock,
+output;
+set address %B101001,
+tick,
+output,
+tock,
+output;
+set address %B101010,
+tick,
+output,
+tock,
+output;
+set address %B101011,
+tick,
+output,
+tock,
+output;
+set address %B101100,
+tick,
+output,
+tock,
+output;
+set address %B101101,
+tick,
+output,
+tock,
+output;
+set address %B101110,
+tick,
+output,
+tock,
+output;
+set address %B101111,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B101000,
+tick,
+output;
+tock,
+output;
+set address %B101001,
+eval,
+output;
+set address %B101010,
+eval,
+output;
+set address %B101011,
+eval,
+output;
+set address %B101100,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B101110,
+eval,
+output;
+set address %B101111,
+eval,
+output;
+
+set load 1,
+set address %B101000,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101000,
+tick,
+output;
+tock,
+output;
+set address %B101001,
+eval,
+output;
+set address %B101010,
+eval,
+output;
+set address %B101011,
+eval,
+output;
+set address %B101100,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B101110,
+eval,
+output;
+set address %B101111,
+eval,
+output;
+
+set load 1,
+set address %B101000,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101001,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101000,
+tick,
+output;
+tock,
+output;
+set address %B101001,
+eval,
+output;
+set address %B101010,
+eval,
+output;
+set address %B101011,
+eval,
+output;
+set address %B101100,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B101110,
+eval,
+output;
+set address %B101111,
+eval,
+output;
+
+set load 1,
+set address %B101001,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101010,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101000,
+tick,
+output;
+tock,
+output;
+set address %B101001,
+eval,
+output;
+set address %B101010,
+eval,
+output;
+set address %B101011,
+eval,
+output;
+set address %B101100,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B101110,
+eval,
+output;
+set address %B101111,
+eval,
+output;
+
+set load 1,
+set address %B101010,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101011,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101000,
+tick,
+output;
+tock,
+output;
+set address %B101001,
+eval,
+output;
+set address %B101010,
+eval,
+output;
+set address %B101011,
+eval,
+output;
+set address %B101100,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B101110,
+eval,
+output;
+set address %B101111,
+eval,
+output;
+
+set load 1,
+set address %B101011,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101100,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101000,
+tick,
+output;
+tock,
+output;
+set address %B101001,
+eval,
+output;
+set address %B101010,
+eval,
+output;
+set address %B101011,
+eval,
+output;
+set address %B101100,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B101110,
+eval,
+output;
+set address %B101111,
+eval,
+output;
+
+set load 1,
+set address %B101100,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101000,
+tick,
+output;
+tock,
+output;
+set address %B101001,
+eval,
+output;
+set address %B101010,
+eval,
+output;
+set address %B101011,
+eval,
+output;
+set address %B101100,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B101110,
+eval,
+output;
+set address %B101111,
+eval,
+output;
+
+set load 1,
+set address %B101101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101110,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101000,
+tick,
+output;
+tock,
+output;
+set address %B101001,
+eval,
+output;
+set address %B101010,
+eval,
+output;
+set address %B101011,
+eval,
+output;
+set address %B101100,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B101110,
+eval,
+output;
+set address %B101111,
+eval,
+output;
+
+set load 1,
+set address %B101110,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101111,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B101000,
+tick,
+output;
+tock,
+output;
+set address %B101001,
+eval,
+output;
+set address %B101010,
+eval,
+output;
+set address %B101011,
+eval,
+output;
+set address %B101100,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B101110,
+eval,
+output;
+set address %B101111,
+eval,
+output;
+
+set load 1,
+set address %B101111,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B101000,
+tick,
+output;
+tock,
+output;
+set address %B101001,
+eval,
+output;
+set address %B101010,
+eval,
+output;
+set address %B101011,
+eval,
+output;
+set address %B101100,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B101110,
+eval,
+output;
+set address %B101111,
+eval,
+output;
+
+
+set load 0,
+set address %B000101,
+tick,
+output;
+tock,
+output;
+set address %B001101,
+eval,
+output;
+set address %B010101,
+eval,
+output;
+set address %B011101,
+eval,
+output;
+set address %B100101,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B110101,
+eval,
+output;
+set address %B111101,
+eval,
+output;
+
+set load 1,
+set in %B0101010101010101,
+set address %B000101,
+tick,
+output;
+tock,
+output;
+set address %B001101,
+tick,
+output,
+tock,
+output;
+set address %B010101,
+tick,
+output,
+tock,
+output;
+set address %B011101,
+tick,
+output,
+tock,
+output;
+set address %B100101,
+tick,
+output,
+tock,
+output;
+set address %B101101,
+tick,
+output,
+tock,
+output;
+set address %B110101,
+tick,
+output,
+tock,
+output;
+set address %B111101,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B000101,
+tick,
+output;
+tock,
+output;
+set address %B001101,
+eval,
+output;
+set address %B010101,
+eval,
+output;
+set address %B011101,
+eval,
+output;
+set address %B100101,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B110101,
+eval,
+output;
+set address %B111101,
+eval,
+output;
+
+set load 1,
+set address %B000101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101,
+tick,
+output;
+tock,
+output;
+set address %B001101,
+eval,
+output;
+set address %B010101,
+eval,
+output;
+set address %B011101,
+eval,
+output;
+set address %B100101,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B110101,
+eval,
+output;
+set address %B111101,
+eval,
+output;
+
+set load 1,
+set address %B000101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B001101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101,
+tick,
+output;
+tock,
+output;
+set address %B001101,
+eval,
+output;
+set address %B010101,
+eval,
+output;
+set address %B011101,
+eval,
+output;
+set address %B100101,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B110101,
+eval,
+output;
+set address %B111101,
+eval,
+output;
+
+set load 1,
+set address %B001101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B010101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101,
+tick,
+output;
+tock,
+output;
+set address %B001101,
+eval,
+output;
+set address %B010101,
+eval,
+output;
+set address %B011101,
+eval,
+output;
+set address %B100101,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B110101,
+eval,
+output;
+set address %B111101,
+eval,
+output;
+
+set load 1,
+set address %B010101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B011101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101,
+tick,
+output;
+tock,
+output;
+set address %B001101,
+eval,
+output;
+set address %B010101,
+eval,
+output;
+set address %B011101,
+eval,
+output;
+set address %B100101,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B110101,
+eval,
+output;
+set address %B111101,
+eval,
+output;
+
+set load 1,
+set address %B011101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B100101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101,
+tick,
+output;
+tock,
+output;
+set address %B001101,
+eval,
+output;
+set address %B010101,
+eval,
+output;
+set address %B011101,
+eval,
+output;
+set address %B100101,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B110101,
+eval,
+output;
+set address %B111101,
+eval,
+output;
+
+set load 1,
+set address %B100101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B101101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101,
+tick,
+output;
+tock,
+output;
+set address %B001101,
+eval,
+output;
+set address %B010101,
+eval,
+output;
+set address %B011101,
+eval,
+output;
+set address %B100101,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B110101,
+eval,
+output;
+set address %B111101,
+eval,
+output;
+
+set load 1,
+set address %B101101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B110101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101,
+tick,
+output;
+tock,
+output;
+set address %B001101,
+eval,
+output;
+set address %B010101,
+eval,
+output;
+set address %B011101,
+eval,
+output;
+set address %B100101,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B110101,
+eval,
+output;
+set address %B111101,
+eval,
+output;
+
+set load 1,
+set address %B110101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address %B111101,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address %B000101,
+tick,
+output;
+tock,
+output;
+set address %B001101,
+eval,
+output;
+set address %B010101,
+eval,
+output;
+set address %B011101,
+eval,
+output;
+set address %B100101,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B110101,
+eval,
+output;
+set address %B111101,
+eval,
+output;
+
+set load 1,
+set address %B111101,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address %B000101,
+tick,
+output;
+tock,
+output;
+set address %B001101,
+eval,
+output;
+set address %B010101,
+eval,
+output;
+set address %B011101,
+eval,
+output;
+set address %B100101,
+eval,
+output;
+set address %B101101,
+eval,
+output;
+set address %B110101,
+eval,
+output;
+set address %B111101,
+eval,
+output;
diff --git a/src/lib/computer/testing/official/RAM8.cmp b/src/lib/computer/testing/official/RAM8.cmp
new file mode 100644
index 0000000..536c6ef
--- /dev/null
+++ b/src/lib/computer/testing/official/RAM8.cmp
@@ -0,0 +1,173 @@
+| time | in |load |address| out |
+| 0+ | 0 | 0 | 0 | 0 |
+| 1 | 0 | 0 | 0 | 0 |
+| 1+ | 0 | 1 | 0 | 0 |
+| 2 | 0 | 1 | 0 | 0 |
+| 2+ | 11111 | 0 | 0 | 0 |
+| 3 | 11111 | 0 | 0 | 0 |
+| 3+ | 11111 | 1 | 1 | 0 |
+| 4 | 11111 | 1 | 1 | 11111 |
+| 4+ | 11111 | 0 | 0 | 0 |
+| 5 | 11111 | 0 | 0 | 0 |
+| 5+ | 3333 | 0 | 3 | 0 |
+| 6 | 3333 | 0 | 3 | 0 |
+| 6+ | 3333 | 1 | 3 | 0 |
+| 7 | 3333 | 1 | 3 | 3333 |
+| 7+ | 3333 | 0 | 3 | 3333 |
+| 8 | 3333 | 0 | 3 | 3333 |
+| 8 | 3333 | 0 | 1 | 11111 |
+| 8+ | 7777 | 0 | 1 | 11111 |
+| 9 | 7777 | 0 | 1 | 11111 |
+| 9+ | 7777 | 1 | 7 | 0 |
+| 10 | 7777 | 1 | 7 | 7777 |
+| 10+ | 7777 | 0 | 7 | 7777 |
+| 11 | 7777 | 0 | 7 | 7777 |
+| 11 | 7777 | 0 | 3 | 3333 |
+| 11 | 7777 | 0 | 7 | 7777 |
+| 11+ | 7777 | 0 | 0 | 0 |
+| 12 | 7777 | 0 | 0 | 0 |
+| 12 | 7777 | 0 | 1 | 11111 |
+| 12 | 7777 | 0 | 2 | 0 |
+| 12 | 7777 | 0 | 3 | 3333 |
+| 12 | 7777 | 0 | 4 | 0 |
+| 12 | 7777 | 0 | 5 | 0 |
+| 12 | 7777 | 0 | 6 | 0 |
+| 12 | 7777 | 0 | 7 | 7777 |
+| 12+ | 21845 | 1 | 0 | 0 |
+| 13 | 21845 | 1 | 0 | 21845 |
+| 13+ | 21845 | 1 | 1 | 11111 |
+| 14 | 21845 | 1 | 1 | 21845 |
+| 14+ | 21845 | 1 | 2 | 0 |
+| 15 | 21845 | 1 | 2 | 21845 |
+| 15+ | 21845 | 1 | 3 | 3333 |
+| 16 | 21845 | 1 | 3 | 21845 |
+| 16+ | 21845 | 1 | 4 | 0 |
+| 17 | 21845 | 1 | 4 | 21845 |
+| 17+ | 21845 | 1 | 5 | 0 |
+| 18 | 21845 | 1 | 5 | 21845 |
+| 18+ | 21845 | 1 | 6 | 0 |
+| 19 | 21845 | 1 | 6 | 21845 |
+| 19+ | 21845 | 1 | 7 | 7777 |
+| 20 | 21845 | 1 | 7 | 21845 |
+| 20+ | 21845 | 0 | 0 | 21845 |
+| 21 | 21845 | 0 | 0 | 21845 |
+| 21 | 21845 | 0 | 1 | 21845 |
+| 21 | 21845 | 0 | 2 | 21845 |
+| 21 | 21845 | 0 | 3 | 21845 |
+| 21 | 21845 | 0 | 4 | 21845 |
+| 21 | 21845 | 0 | 5 | 21845 |
+| 21 | 21845 | 0 | 6 | 21845 |
+| 21 | 21845 | 0 | 7 | 21845 |
+| 21+ | -21846 | 1 | 0 | 21845 |
+| 22 | -21846 | 1 | 0 | -21846 |
+| 22+ | -21846 | 0 | 0 | -21846 |
+| 23 | -21846 | 0 | 0 | -21846 |
+| 23 | -21846 | 0 | 1 | 21845 |
+| 23 | -21846 | 0 | 2 | 21845 |
+| 23 | -21846 | 0 | 3 | 21845 |
+| 23 | -21846 | 0 | 4 | 21845 |
+| 23 | -21846 | 0 | 5 | 21845 |
+| 23 | -21846 | 0 | 6 | 21845 |
+| 23 | -21846 | 0 | 7 | 21845 |
+| 23+ | 21845 | 1 | 0 | -21846 |
+| 24 | 21845 | 1 | 0 | 21845 |
+| 24+ | -21846 | 1 | 1 | 21845 |
+| 25 | -21846 | 1 | 1 | -21846 |
+| 25+ | -21846 | 0 | 0 | 21845 |
+| 26 | -21846 | 0 | 0 | 21845 |
+| 26 | -21846 | 0 | 1 | -21846 |
+| 26 | -21846 | 0 | 2 | 21845 |
+| 26 | -21846 | 0 | 3 | 21845 |
+| 26 | -21846 | 0 | 4 | 21845 |
+| 26 | -21846 | 0 | 5 | 21845 |
+| 26 | -21846 | 0 | 6 | 21845 |
+| 26 | -21846 | 0 | 7 | 21845 |
+| 26+ | 21845 | 1 | 1 | -21846 |
+| 27 | 21845 | 1 | 1 | 21845 |
+| 27+ | -21846 | 1 | 2 | 21845 |
+| 28 | -21846 | 1 | 2 | -21846 |
+| 28+ | -21846 | 0 | 0 | 21845 |
+| 29 | -21846 | 0 | 0 | 21845 |
+| 29 | -21846 | 0 | 1 | 21845 |
+| 29 | -21846 | 0 | 2 | -21846 |
+| 29 | -21846 | 0 | 3 | 21845 |
+| 29 | -21846 | 0 | 4 | 21845 |
+| 29 | -21846 | 0 | 5 | 21845 |
+| 29 | -21846 | 0 | 6 | 21845 |
+| 29 | -21846 | 0 | 7 | 21845 |
+| 29+ | 21845 | 1 | 2 | -21846 |
+| 30 | 21845 | 1 | 2 | 21845 |
+| 30+ | -21846 | 1 | 3 | 21845 |
+| 31 | -21846 | 1 | 3 | -21846 |
+| 31+ | -21846 | 0 | 0 | 21845 |
+| 32 | -21846 | 0 | 0 | 21845 |
+| 32 | -21846 | 0 | 1 | 21845 |
+| 32 | -21846 | 0 | 2 | 21845 |
+| 32 | -21846 | 0 | 3 | -21846 |
+| 32 | -21846 | 0 | 4 | 21845 |
+| 32 | -21846 | 0 | 5 | 21845 |
+| 32 | -21846 | 0 | 6 | 21845 |
+| 32 | -21846 | 0 | 7 | 21845 |
+| 32+ | 21845 | 1 | 3 | -21846 |
+| 33 | 21845 | 1 | 3 | 21845 |
+| 33+ | -21846 | 1 | 4 | 21845 |
+| 34 | -21846 | 1 | 4 | -21846 |
+| 34+ | -21846 | 0 | 0 | 21845 |
+| 35 | -21846 | 0 | 0 | 21845 |
+| 35 | -21846 | 0 | 1 | 21845 |
+| 35 | -21846 | 0 | 2 | 21845 |
+| 35 | -21846 | 0 | 3 | 21845 |
+| 35 | -21846 | 0 | 4 | -21846 |
+| 35 | -21846 | 0 | 5 | 21845 |
+| 35 | -21846 | 0 | 6 | 21845 |
+| 35 | -21846 | 0 | 7 | 21845 |
+| 35+ | 21845 | 1 | 4 | -21846 |
+| 36 | 21845 | 1 | 4 | 21845 |
+| 36+ | -21846 | 1 | 5 | 21845 |
+| 37 | -21846 | 1 | 5 | -21846 |
+| 37+ | -21846 | 0 | 0 | 21845 |
+| 38 | -21846 | 0 | 0 | 21845 |
+| 38 | -21846 | 0 | 1 | 21845 |
+| 38 | -21846 | 0 | 2 | 21845 |
+| 38 | -21846 | 0 | 3 | 21845 |
+| 38 | -21846 | 0 | 4 | 21845 |
+| 38 | -21846 | 0 | 5 | -21846 |
+| 38 | -21846 | 0 | 6 | 21845 |
+| 38 | -21846 | 0 | 7 | 21845 |
+| 38+ | 21845 | 1 | 5 | -21846 |
+| 39 | 21845 | 1 | 5 | 21845 |
+| 39+ | -21846 | 1 | 6 | 21845 |
+| 40 | -21846 | 1 | 6 | -21846 |
+| 40+ | -21846 | 0 | 0 | 21845 |
+| 41 | -21846 | 0 | 0 | 21845 |
+| 41 | -21846 | 0 | 1 | 21845 |
+| 41 | -21846 | 0 | 2 | 21845 |
+| 41 | -21846 | 0 | 3 | 21845 |
+| 41 | -21846 | 0 | 4 | 21845 |
+| 41 | -21846 | 0 | 5 | 21845 |
+| 41 | -21846 | 0 | 6 | -21846 |
+| 41 | -21846 | 0 | 7 | 21845 |
+| 41+ | 21845 | 1 | 6 | -21846 |
+| 42 | 21845 | 1 | 6 | 21845 |
+| 42+ | -21846 | 1 | 7 | 21845 |
+| 43 | -21846 | 1 | 7 | -21846 |
+| 43+ | -21846 | 0 | 0 | 21845 |
+| 44 | -21846 | 0 | 0 | 21845 |
+| 44 | -21846 | 0 | 1 | 21845 |
+| 44 | -21846 | 0 | 2 | 21845 |
+| 44 | -21846 | 0 | 3 | 21845 |
+| 44 | -21846 | 0 | 4 | 21845 |
+| 44 | -21846 | 0 | 5 | 21845 |
+| 44 | -21846 | 0 | 6 | 21845 |
+| 44 | -21846 | 0 | 7 | -21846 |
+| 44+ | 21845 | 1 | 7 | -21846 |
+| 45 | 21845 | 1 | 7 | 21845 |
+| 45+ | 21845 | 0 | 0 | 21845 |
+| 46 | 21845 | 0 | 0 | 21845 |
+| 46 | 21845 | 0 | 1 | 21845 |
+| 46 | 21845 | 0 | 2 | 21845 |
+| 46 | 21845 | 0 | 3 | 21845 |
+| 46 | 21845 | 0 | 4 | 21845 |
+| 46 | 21845 | 0 | 5 | 21845 |
+| 46 | 21845 | 0 | 6 | 21845 |
+| 46 | 21845 | 0 | 7 | 21845 |
diff --git a/src/lib/computer/testing/official/RAM8.tst b/src/lib/computer/testing/official/RAM8.tst
new file mode 100644
index 0000000..9b6069c
--- /dev/null
+++ b/src/lib/computer/testing/official/RAM8.tst
@@ -0,0 +1,560 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/03/a/RAM8.tst
+
+load RAM8.hdl,
+output-file RAM8.out,
+compare-to RAM8.cmp,
+output-list time%S1.4.1 in%D1.6.1 load%B2.1.2 address%D3.1.3 out%D1.6.1;
+
+set in 0,
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+tick,
+output;
+tock,
+output;
+
+set in 11111,
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+set address 1,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+
+set in 3333,
+set address 3,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set address 1,
+eval,
+output;
+
+set in 7777,
+tick,
+output;
+tock,
+output;
+
+set load 1,
+set address 7,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+tick,
+output;
+tock,
+output;
+
+set address 3,
+eval,
+output;
+
+set address 7,
+eval,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+set address 1,
+eval,
+output;
+set address 2,
+eval,
+output;
+set address 3,
+eval,
+output;
+set address 4,
+eval,
+output;
+set address 5,
+eval,
+output;
+set address 6,
+eval,
+output;
+set address 7,
+eval,
+output;
+
+set load 1,
+set in %B0101010101010101,
+set address 0,
+tick,
+output;
+tock,
+output;
+set address 1,
+tick,
+output,
+tock,
+output;
+set address 2,
+tick,
+output,
+tock,
+output;
+set address 3,
+tick,
+output,
+tock,
+output;
+set address 4,
+tick,
+output,
+tock,
+output;
+set address 5,
+tick,
+output,
+tock,
+output;
+set address 6,
+tick,
+output,
+tock,
+output;
+set address 7,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+set address 1,
+eval,
+output;
+set address 2,
+eval,
+output;
+set address 3,
+eval,
+output;
+set address 4,
+eval,
+output;
+set address 5,
+eval,
+output;
+set address 6,
+eval,
+output;
+set address 7,
+eval,
+output;
+
+set load 1,
+set address 0,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+set address 1,
+eval,
+output;
+set address 2,
+eval,
+output;
+set address 3,
+eval,
+output;
+set address 4,
+eval,
+output;
+set address 5,
+eval,
+output;
+set address 6,
+eval,
+output;
+set address 7,
+eval,
+output;
+
+set load 1,
+set address 0,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address 1,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+set address 1,
+eval,
+output;
+set address 2,
+eval,
+output;
+set address 3,
+eval,
+output;
+set address 4,
+eval,
+output;
+set address 5,
+eval,
+output;
+set address 6,
+eval,
+output;
+set address 7,
+eval,
+output;
+
+set load 1,
+set address 1,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address 2,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+set address 1,
+eval,
+output;
+set address 2,
+eval,
+output;
+set address 3,
+eval,
+output;
+set address 4,
+eval,
+output;
+set address 5,
+eval,
+output;
+set address 6,
+eval,
+output;
+set address 7,
+eval,
+output;
+
+set load 1,
+set address 2,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address 3,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+set address 1,
+eval,
+output;
+set address 2,
+eval,
+output;
+set address 3,
+eval,
+output;
+set address 4,
+eval,
+output;
+set address 5,
+eval,
+output;
+set address 6,
+eval,
+output;
+set address 7,
+eval,
+output;
+
+set load 1,
+set address 3,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address 4,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+set address 1,
+eval,
+output;
+set address 2,
+eval,
+output;
+set address 3,
+eval,
+output;
+set address 4,
+eval,
+output;
+set address 5,
+eval,
+output;
+set address 6,
+eval,
+output;
+set address 7,
+eval,
+output;
+
+set load 1,
+set address 4,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address 5,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+set address 1,
+eval,
+output;
+set address 2,
+eval,
+output;
+set address 3,
+eval,
+output;
+set address 4,
+eval,
+output;
+set address 5,
+eval,
+output;
+set address 6,
+eval,
+output;
+set address 7,
+eval,
+output;
+
+set load 1,
+set address 5,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address 6,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+set address 1,
+eval,
+output;
+set address 2,
+eval,
+output;
+set address 3,
+eval,
+output;
+set address 4,
+eval,
+output;
+set address 5,
+eval,
+output;
+set address 6,
+eval,
+output;
+set address 7,
+eval,
+output;
+
+set load 1,
+set address 6,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+set address 7,
+set in %B1010101010101010,
+tick,
+output;
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+set address 1,
+eval,
+output;
+set address 2,
+eval,
+output;
+set address 3,
+eval,
+output;
+set address 4,
+eval,
+output;
+set address 5,
+eval,
+output;
+set address 6,
+eval,
+output;
+set address 7,
+eval,
+output;
+
+set load 1,
+set address 7,
+set in %B0101010101010101,
+tick,
+output,
+tock,
+output;
+
+set load 0,
+set address 0,
+tick,
+output;
+tock,
+output;
+set address 1,
+eval,
+output;
+set address 2,
+eval,
+output;
+set address 3,
+eval,
+output;
+set address 4,
+eval,
+output;
+set address 5,
+eval,
+output;
+set address 6,
+eval,
+output;
+set address 7,
+eval,
+output;
+
diff --git a/src/lib/computer/testing/official/README.md b/src/lib/computer/testing/official/README.md
new file mode 100644
index 0000000..711a27d
--- /dev/null
+++ b/src/lib/computer/testing/official/README.md
@@ -0,0 +1,21 @@
+# Official hardware contract fixtures
+
+These unchanged `.tst` and `.cmp` files are from the official
+[nand2tetris/projects](https://github.com/nand2tetris/projects) repository,
+commit `5bd2184edfd4945ff8a28eb0b237c12cdbe9e498`, projects 01, 02, 03,
+and project 05's test, comparison, and machine-code program files. Original attribution comments and the
+repository's MIT `LICENSE` are retained here. No completed student HDL solutions
+are included.
+
+`hdl.test.ts` constructs a generic Probe around each primitive and executes every
+set/eval/tick/tock/output command against the supplied expected output. It skips
+only file-selection directives, parses the declared output columns (comparison
+headers may be truncated), and deliberately ignores wildcard comparison cells and
+the display-only time column. Unknown commands throw rather than silently skip.
+
+Separate structural tests verify bus slices, internal wires, dependency graphs,
+clocked feedback, synchronous state changes, mapped memory, and ROM-backed computer
+execution. The fixture suite tests the builtin contracts; it does not assert that
+all possible user circuits are correct.
+
+`testing.test.ts` also exercises the production TDL runner against all Part I hardware scripts, including CPU internal-state inspection, ROM-loading Computer tests, repeated clock cycles, and the interactive Memory test with controlled keyboard responses. Test-language semantics were cross-checked against the MIT-licensed [official web IDE](https://github.com/nand2tetris/web-ide) grammar and chip test runner. The new parser and runner are independent implementations; no web-IDE source code is bundled here.
diff --git a/src/lib/computer/testing/official/Rect.hack b/src/lib/computer/testing/official/Rect.hack
new file mode 100644
index 0000000..ee017ab
--- /dev/null
+++ b/src/lib/computer/testing/official/Rect.hack
@@ -0,0 +1,25 @@
+0000000000000000
+1111110000010000
+0000000000010111
+1110001100000110
+0000000000010000
+1110001100001000
+0100000000000000
+1110110000010000
+0000000000010001
+1110001100001000
+0000000000010001
+1111110000100000
+1110111010001000
+0000000000010001
+1111110000010000
+0000000000100000
+1110000010010000
+0000000000010001
+1110001100001000
+0000000000010000
+1111110010011000
+0000000000001010
+1110001100000001
+0000000000010111
+1110101010000111
diff --git a/src/lib/computer/testing/official/Register.cmp b/src/lib/computer/testing/official/Register.cmp
new file mode 100644
index 0000000..a899f27
--- /dev/null
+++ b/src/lib/computer/testing/official/Register.cmp
@@ -0,0 +1,149 @@
+| time | in |load | out |
+| 0+ | 0 | 0 | 0 |
+| 1 | 0 | 0 | 0 |
+| 1+ | 0 | 1 | 0 |
+| 2 | 0 | 1 | 0 |
+| 2+ | -32123 | 0 | 0 |
+| 3 | -32123 | 0 | 0 |
+| 3+ | 11111 | 0 | 0 |
+| 4 | 11111 | 0 | 0 |
+| 4+ | -32123 | 1 | 0 |
+| 5 | -32123 | 1 | -32123 |
+| 5+ | -32123 | 1 | -32123 |
+| 6 | -32123 | 1 | -32123 |
+| 6+ | -32123 | 0 | -32123 |
+| 7 | -32123 | 0 | -32123 |
+| 7+ | 12345 | 1 | -32123 |
+| 8 | 12345 | 1 | 12345 |
+| 8+ | 0 | 0 | 12345 |
+| 9 | 0 | 0 | 12345 |
+| 9+ | 0 | 1 | 12345 |
+| 10 | 0 | 1 | 0 |
+| 10+ | 1 | 0 | 0 |
+| 11 | 1 | 0 | 0 |
+| 11+ | 1 | 1 | 0 |
+| 12 | 1 | 1 | 1 |
+| 12+ | 2 | 0 | 1 |
+| 13 | 2 | 0 | 1 |
+| 13+ | 2 | 1 | 1 |
+| 14 | 2 | 1 | 2 |
+| 14+ | 4 | 0 | 2 |
+| 15 | 4 | 0 | 2 |
+| 15+ | 4 | 1 | 2 |
+| 16 | 4 | 1 | 4 |
+| 16+ | 8 | 0 | 4 |
+| 17 | 8 | 0 | 4 |
+| 17+ | 8 | 1 | 4 |
+| 18 | 8 | 1 | 8 |
+| 18+ | 16 | 0 | 8 |
+| 19 | 16 | 0 | 8 |
+| 19+ | 16 | 1 | 8 |
+| 20 | 16 | 1 | 16 |
+| 20+ | 32 | 0 | 16 |
+| 21 | 32 | 0 | 16 |
+| 21+ | 32 | 1 | 16 |
+| 22 | 32 | 1 | 32 |
+| 22+ | 64 | 0 | 32 |
+| 23 | 64 | 0 | 32 |
+| 23+ | 64 | 1 | 32 |
+| 24 | 64 | 1 | 64 |
+| 24+ | 128 | 0 | 64 |
+| 25 | 128 | 0 | 64 |
+| 25+ | 128 | 1 | 64 |
+| 26 | 128 | 1 | 128 |
+| 26+ | 256 | 0 | 128 |
+| 27 | 256 | 0 | 128 |
+| 27+ | 256 | 1 | 128 |
+| 28 | 256 | 1 | 256 |
+| 28+ | 512 | 0 | 256 |
+| 29 | 512 | 0 | 256 |
+| 29+ | 512 | 1 | 256 |
+| 30 | 512 | 1 | 512 |
+| 30+ | 1024 | 0 | 512 |
+| 31 | 1024 | 0 | 512 |
+| 31+ | 1024 | 1 | 512 |
+| 32 | 1024 | 1 | 1024 |
+| 32+ | 2048 | 0 | 1024 |
+| 33 | 2048 | 0 | 1024 |
+| 33+ | 2048 | 1 | 1024 |
+| 34 | 2048 | 1 | 2048 |
+| 34+ | 4096 | 0 | 2048 |
+| 35 | 4096 | 0 | 2048 |
+| 35+ | 4096 | 1 | 2048 |
+| 36 | 4096 | 1 | 4096 |
+| 36+ | 8192 | 0 | 4096 |
+| 37 | 8192 | 0 | 4096 |
+| 37+ | 8192 | 1 | 4096 |
+| 38 | 8192 | 1 | 8192 |
+| 38+ | 16384 | 0 | 8192 |
+| 39 | 16384 | 0 | 8192 |
+| 39+ | 16384 | 1 | 8192 |
+| 40 | 16384 | 1 | 16384 |
+| 40+ | -32768 | 0 | 16384 |
+| 41 | -32768 | 0 | 16384 |
+| 41+ | -32768 | 1 | 16384 |
+| 42 | -32768 | 1 | -32768 |
+| 42+ | -2 | 0 | -32768 |
+| 43 | -2 | 0 | -32768 |
+| 43+ | -2 | 1 | -32768 |
+| 44 | -2 | 1 | -2 |
+| 44+ | -3 | 0 | -2 |
+| 45 | -3 | 0 | -2 |
+| 45+ | -3 | 1 | -2 |
+| 46 | -3 | 1 | -3 |
+| 46+ | -5 | 0 | -3 |
+| 47 | -5 | 0 | -3 |
+| 47+ | -5 | 1 | -3 |
+| 48 | -5 | 1 | -5 |
+| 48+ | -9 | 0 | -5 |
+| 49 | -9 | 0 | -5 |
+| 49+ | -9 | 1 | -5 |
+| 50 | -9 | 1 | -9 |
+| 50+ | -17 | 0 | -9 |
+| 51 | -17 | 0 | -9 |
+| 51+ | -17 | 1 | -9 |
+| 52 | -17 | 1 | -17 |
+| 52+ | -33 | 0 | -17 |
+| 53 | -33 | 0 | -17 |
+| 53+ | -33 | 1 | -17 |
+| 54 | -33 | 1 | -33 |
+| 54+ | -65 | 0 | -33 |
+| 55 | -65 | 0 | -33 |
+| 55+ | -65 | 1 | -33 |
+| 56 | -65 | 1 | -65 |
+| 56+ | -129 | 0 | -65 |
+| 57 | -129 | 0 | -65 |
+| 57+ | -129 | 1 | -65 |
+| 58 | -129 | 1 | -129 |
+| 58+ | -257 | 0 | -129 |
+| 59 | -257 | 0 | -129 |
+| 59+ | -257 | 1 | -129 |
+| 60 | -257 | 1 | -257 |
+| 60+ | -513 | 0 | -257 |
+| 61 | -513 | 0 | -257 |
+| 61+ | -513 | 1 | -257 |
+| 62 | -513 | 1 | -513 |
+| 62+ | -1025 | 0 | -513 |
+| 63 | -1025 | 0 | -513 |
+| 63+ | -1025 | 1 | -513 |
+| 64 | -1025 | 1 | -1025 |
+| 64+ | -2049 | 0 | -1025 |
+| 65 | -2049 | 0 | -1025 |
+| 65+ | -2049 | 1 | -1025 |
+| 66 | -2049 | 1 | -2049 |
+| 66+ | -4097 | 0 | -2049 |
+| 67 | -4097 | 0 | -2049 |
+| 67+ | -4097 | 1 | -2049 |
+| 68 | -4097 | 1 | -4097 |
+| 68+ | -8193 | 0 | -4097 |
+| 69 | -8193 | 0 | -4097 |
+| 69+ | -8193 | 1 | -4097 |
+| 70 | -8193 | 1 | -8193 |
+| 70+ | -16385 | 0 | -8193 |
+| 71 | -16385 | 0 | -8193 |
+| 71+ | -16385 | 1 | -8193 |
+| 72 | -16385 | 1 | -16385 |
+| 72+ | 32767 | 0 | -16385 |
+| 73 | 32767 | 0 | -16385 |
+| 73+ | 32767 | 1 | -16385 |
+| 74 | 32767 | 1 | 32767 |
diff --git a/src/lib/computer/testing/official/Register.tst b/src/lib/computer/testing/official/Register.tst
new file mode 100644
index 0000000..aeec166
--- /dev/null
+++ b/src/lib/computer/testing/official/Register.tst
@@ -0,0 +1,569 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/03/a/Register.tst
+
+load Register.hdl,
+output-file Register.out,
+compare-to Register.cmp,
+output-list time%S1.4.1 in%D1.6.1 load%B2.1.2 out%D1.6.1;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in -32123,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 11111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in -32123,
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in -32123,
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in -32123,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 12345,
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set in 0,
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0000000000000001,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0000000000000010,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0000000000000100,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0000000000001000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0000000000010000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0000000000100000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0000000001000000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0000000010000000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0000000100000000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0000001000000000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0000010000000000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0000100000000000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0001000000000000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0010000000000000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0100000000000000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1000000000000000,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1111111111111110,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1111111111111101,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1111111111111011,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1111111111110111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1111111111101111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1111111111011111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1111111110111111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1111111101111111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1111111011111111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1111110111111111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1111101111111111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1111011111111111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1110111111111111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1101111111111111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B1011111111111111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
+
+set in %B0111111111111111,
+set load 0,
+tick,
+output;
+
+tock,
+output;
+
+set load 1,
+tick,
+output;
+
+tock,
+output;
diff --git a/src/lib/computer/testing/official/Xor.cmp b/src/lib/computer/testing/official/Xor.cmp
new file mode 100644
index 0000000..a1e07b2
--- /dev/null
+++ b/src/lib/computer/testing/official/Xor.cmp
@@ -0,0 +1,5 @@
+| a | b | out |
+| 0 | 0 | 0 |
+| 0 | 1 | 1 |
+| 1 | 0 | 1 |
+| 1 | 1 | 0 |
diff --git a/src/lib/computer/testing/official/Xor.tst b/src/lib/computer/testing/official/Xor.tst
new file mode 100644
index 0000000..658cbe5
--- /dev/null
+++ b/src/lib/computer/testing/official/Xor.tst
@@ -0,0 +1,29 @@
+// This file is part of www.nand2tetris.org
+// and the book "The Elements of Computing Systems"
+// by Nisan and Schocken, MIT Press.
+// File name: projects/01/Xor.tst
+
+load Xor.hdl,
+output-file Xor.out,
+compare-to Xor.cmp,
+output-list a%B3.1.3 b%B3.1.3 out%B3.1.3;
+
+set a 0,
+set b 0,
+eval,
+output;
+
+set a 0,
+set b 1,
+eval,
+output;
+
+set a 1,
+set b 0,
+eval,
+output;
+
+set a 1,
+set b 1,
+eval,
+output;
diff --git a/src/lib/computer/workspace.css b/src/lib/computer/workspace.css
new file mode 100644
index 0000000..9615cf1
--- /dev/null
+++ b/src/lib/computer/workspace.css
@@ -0,0 +1,181 @@
+.machine-lab {
+ max-width: 1400px;
+}
+.machine-lab .workspace-toolbar {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+ align-items: end;
+ margin: 26px 0;
+}
+.machine-lab .workspace-toolbar label {
+ flex: 1 1 140px;
+ max-width: 280px;
+}
+.machine-lab button.action {
+ min-height: 44px;
+ border: 1px solid #858ba2;
+ border-radius: 4px;
+ padding: 10px 17px;
+ background: #1c2133;
+ color: #f3f3fc;
+ font-size: 13px;
+}
+.machine-lab button.primary {
+ background: #b5a6f2;
+ border-color: #cabdff;
+ color: #10121c;
+ font-weight: 600;
+}
+.machine-lab button:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+.machine-lab .machine-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+ gap: 24px;
+ align-items: start;
+}
+.machine-lab .machine-grid.single {
+ grid-template-columns: minmax(0, 1fr);
+}
+.machine-lab .code-panel,
+.machine-lab .machine-panel {
+ min-width: 0;
+}
+.machine-lab textarea {
+ display: block;
+ width: 100%;
+ min-width: 0;
+ min-height: 320px;
+ resize: vertical;
+ padding: 18px;
+ border: 1px solid #62697f;
+ border-radius: 4px;
+ color: #eeeaff;
+ background: #10131f;
+ font:
+ 13px/1.8 ui-monospace,
+ monospace;
+ tab-size: 2;
+}
+.machine-lab textarea:focus-visible {
+ outline: 2px solid #d0c7ff;
+ outline-offset: 4px;
+}
+.machine-lab .code-label {
+ display: flex;
+ justify-content: space-between;
+ gap: 12px;
+ margin-bottom: 12px;
+}
+.machine-lab .readouts {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 10px;
+ margin: 0 0 24px;
+}
+.machine-lab .readouts div {
+ padding: 14px;
+ border: 1px solid #525b74;
+ background: #151a2a;
+ border-radius: 4px;
+}
+.machine-lab .readouts dt {
+ font:
+ 11px/1.5 ui-monospace,
+ monospace;
+ color: #bbc2d5;
+}
+.machine-lab .readouts dd {
+ font:
+ 24px/1.5 ui-monospace,
+ monospace;
+ margin: 8px 0 0;
+ color: #f3f3fc;
+}
+.machine-lab .scroll-region {
+ max-height: 360px;
+ overflow: auto;
+ border: 1px solid #41465b;
+ border-radius: 4px;
+}
+.machine-lab .scroll-region:focus-visible {
+ outline: 2px solid #d0c7ff;
+ outline-offset: 4px;
+}
+.machine-lab .scroll-region table {
+ white-space: nowrap;
+}
+.machine-lab .scroll-region th,
+.machine-lab .scroll-region td {
+ padding: 10px 12px;
+}
+.machine-lab .current-row {
+ background: #38305e;
+}
+.machine-lab .status {
+ color: #c8c0e9;
+ font:
+ 12px/1.7 ui-monospace,
+ monospace;
+ margin: 14px 0;
+}
+.machine-lab .field-row {
+ display: flex;
+ align-items: end;
+ flex-wrap: wrap;
+ gap: 12px;
+ margin: 18px 0;
+}
+.machine-lab .field-row label {
+ flex: 1 1 110px;
+ min-width: 0;
+}
+.machine-lab .output-list {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
+ gap: 14px;
+ margin: 20px 0;
+}
+.machine-lab .output-list div {
+ border-left: 2px solid #b8a8ff;
+ padding: 8px 16px;
+}
+.machine-lab .output-list dt {
+ color: #b8bbd0;
+ font:
+ 12px/1.6 ui-monospace,
+ monospace;
+}
+.machine-lab .output-list dd {
+ margin: 6px 0 0;
+ font:
+ 24px/1.5 ui-monospace,
+ monospace;
+}
+.machine-lab .notice {
+ color: #b8bbd0;
+ font-size: 13px;
+ line-height: 1.6;
+}
+@media (max-width: 820px) {
+ .machine-lab .machine-grid {
+ grid-template-columns: minmax(0, 1fr);
+ }
+}
+@media (max-width: 420px) {
+ .machine-lab .readouts {
+ gap: 6px;
+ }
+ .machine-lab .readouts div {
+ padding: 10px;
+ }
+ .machine-lab .readouts dd {
+ font-size: 20px;
+ }
+ .machine-lab .panel {
+ padding: 16px;
+ }
+}
diff --git a/src/lib/course/Chapter.svelte b/src/lib/course/Chapter.svelte
new file mode 100644
index 0000000..0766f66
--- /dev/null
+++ b/src/lib/course/Chapter.svelte
@@ -0,0 +1,351 @@
+
+
+{chapter.title} — Chips and Code
+
+
+
+
+
{taskIndex + 1} / {chapter.tasks.length}
+
+ Steps in this layer
+
+ {#each chapter.tasks as item, index (item.id)}
+ choose(index)}
+ >{item.title}{completed.includes(taskKey(chapter, item))
+ ? 'Complete'
+ : index === taskIndex
+ ? 'Current'
+ : ''}
+ {/each}
+
+
+
+ {task.explanation}
+ {#if task.kind === 'symbols'}
+ {symbolProgram} {/if}
+ {#if task.kind === 'hdl'}
+
+ ViewVisual Code Split {task.chip}.hdl
+
+
+ {:else}{task.kind === 'assembler'
+ ? 'Assembler source'
+ : task.kind === 'assembly'
+ ? 'Assembly source'
+ : task.kind === 'symbols'
+ ? 'Symbol addresses'
+ : 'Machine code answer'} {/if}
+
+ {verifying ? 'Checking…' : 'Check my work'} Draft saved on this device
+
+ {#if result}
+
{result.passed ? 'It works.' : 'Keep building.'}
+
{result.message}
+ {#if result.passed}{#if taskIndex < chapter.tasks.length - 1}
choose(taskIndex + 1)}>Continue → {:else if nextChapter}
Continue to {nextChapter.title.toLowerCase()} → {:else}
+ You have reached the assembler. Your hardware and software now meet in machine code.
+
+
Open the computer tool → {/if}{/if}
+
{:else if done}
+ Previously completed. Edit and check again to verify this draft.
+
{/if}
+
+ {#if notice}{notice}
{/if}
+
+
diff --git a/src/lib/course/ChipEditor.svelte b/src/lib/course/ChipEditor.svelte
new file mode 100644
index 0000000..af48ca4
--- /dev/null
+++ b/src/lib/course/ChipEditor.svelte
@@ -0,0 +1,189 @@
+
+
+
+ {#if mode !== 'code'}
+
+ {#if !readable}
+ This code uses incomplete syntax or repeated pin bindings. Edit it in Code view; the
+ visual editor preserves your source.
+
+ {:else}
+
+ Part{#each choices as name (name)}{name} {/each} Add part
+
+ {#if !parts.length}
+ Add a part, then connect its pins to inputs, outputs, or named internal wires.
+
{/if}
+
+ {#each parts as part, index (index)} (selected = index)}>{index + 1} {part.type} {/each}
+
+ {#if parts[selected]}
+ {@const part = parts[selected]}
+
+ {/if}
+ {/if}
+
+ {/if}
+ {#if mode !== 'visual'}
HDL source {/if}
+
diff --git a/src/lib/course/Path.svelte b/src/lib/course/Path.svelte
new file mode 100644
index 0000000..8e76411
--- /dev/null
+++ b/src/lib/course/Path.svelte
@@ -0,0 +1,64 @@
+
+
+The computer path — Chips and Code
+
+ ← Learn
+
+
+ New here? Start with a signal and your first gates.
+
+
+ {#each courseChapters as chapter (chapter.id)}
+ {@const count = chapter.tasks.filter((task) =>
+ completed.includes(taskKey(chapter, task)),
+ ).length}
+
+ 0{chapter.project} {chapter.title}
+ {chapter.description}
{count === chapter.tasks.length ? 'Complete' : `${count} / ${chapter.tasks.length}`}
+ →
+
+ {/each}
+
+
+ Adapted from Nand2Tetris Projects 1–6 . Your designs and progress stay on this device.
+
+
diff --git a/src/lib/course/course.css b/src/lib/course/course.css
new file mode 100644
index 0000000..a5e5209
--- /dev/null
+++ b/src/lib/course/course.css
@@ -0,0 +1,586 @@
+.course-page {
+ --course-ink: #f1f1fa;
+ --course-muted: #b9c2d7;
+ --course-panel: #131725;
+ --course-border: #525b73;
+ --course-accent: #c2b6ff;
+ max-width: 1180px;
+ margin: auto;
+ padding: 36px 5% 90px;
+ color: var(--course-ink);
+ box-sizing: border-box;
+}
+.course-page * {
+ box-sizing: border-box;
+}
+.course-page a {
+ color: var(--course-accent);
+ text-underline-offset: 4px;
+}
+.course-page button,
+.course-page input,
+.course-page select,
+.course-page textarea {
+ font: inherit;
+}
+.course-page button,
+.course-page summary,
+.course-page select {
+ cursor: pointer;
+}
+.course-page :is(button, a, input, select, textarea, summary, pre):focus-visible {
+ outline: 3px solid #d0c6ff !important;
+ outline-offset: 4px;
+}
+.course-page .back-link {
+ display: inline-flex;
+ align-items: center;
+ min-height: 40px;
+ font-size: 14px;
+}
+.course-topline {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 20px;
+ font-size: 13px;
+}
+.course-heading {
+ max-width: 820px;
+ margin: 42px 0 30px;
+}
+.course-page .eyebrow {
+ font:
+ 11px/1.5 ui-monospace,
+ monospace;
+ color: var(--course-accent);
+ letter-spacing: 0.1em;
+ margin: 0 0 18px;
+}
+.course-page h1 {
+ font-size: clamp(34px, 5vw, 60px);
+ font-weight: 500;
+ line-height: 1.08;
+ letter-spacing: -0.04em;
+ margin: 0;
+}
+.course-heading > p:last-child {
+ color: var(--course-muted);
+ font-size: 17px;
+ line-height: 1.7;
+ margin: 22px 0 0;
+}
+.course-page h2 {
+ font-size: 24px;
+ font-weight: 500;
+ letter-spacing: -0.025em;
+ margin: 0 0 9px;
+}
+.course-page h3 {
+ font-size: 17px;
+ font-weight: 500;
+ margin: 0;
+}
+.course-page p {
+ line-height: 1.7;
+}
+.course-page .muted,
+.course-footnote,
+.path-attribution {
+ color: var(--course-muted);
+ font-size: 13px;
+ line-height: 1.7;
+}
+.foundation-link {
+ margin: 0 0 35px;
+ color: var(--course-muted);
+ font-size: 14px;
+}
+.chapter-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ border-top: 1px solid var(--course-border);
+}
+.chapter-list li {
+ border-bottom: 1px solid var(--course-border);
+}
+.chapter-list a {
+ display: grid;
+ grid-template-columns: 44px 1fr auto;
+ gap: 28px;
+ align-items: center;
+ padding: 30px 12px;
+ text-decoration: none;
+ color: var(--course-ink);
+}
+.chapter-list a:hover,
+.chapter-list a.next {
+ background: #111524;
+}
+.chapter-number {
+ font:
+ 14px ui-monospace,
+ monospace;
+ color: var(--course-accent);
+}
+.chapter-list p {
+ color: var(--course-muted);
+ font-size: 14px;
+ margin: 0;
+}
+.chapter-status {
+ display: flex;
+ gap: 20px;
+ white-space: nowrap;
+ color: var(--course-muted);
+ font:
+ 12px ui-monospace,
+ monospace;
+}
+.path-attribution {
+ margin-top: 28px;
+}
+.task-position {
+ display: flex;
+ align-items: flex-start;
+ gap: 22px;
+ padding: 17px 0;
+ border-top: 1px solid var(--course-border);
+ border-bottom: 1px solid var(--course-border);
+ font-size: 13px;
+}
+.task-position > span {
+ color: var(--course-accent);
+ font-family: ui-monospace, monospace;
+ padding: 2px 0;
+ white-space: nowrap;
+}
+.task-position details {
+ flex: 1;
+}
+.course-page summary {
+ min-height: 28px;
+}
+.task-position ol {
+ padding: 0;
+ margin: 16px 0 0;
+ list-style: none;
+}
+.task-position li button {
+ display: flex;
+ justify-content: space-between;
+ gap: 14px;
+ border: 0;
+ width: 100%;
+ text-align: left;
+ background: none;
+ color: var(--course-muted);
+ padding: 12px 10px;
+}
+.task-position li button[aria-current='step'] {
+ color: #fff;
+ background: #27233d;
+}
+.task-position li button span {
+ font-size: 11px;
+ color: var(--course-muted);
+}
+.concept-copy {
+ max-width: 790px;
+ color: var(--course-muted);
+ font-size: 15px;
+ margin: 28px 0;
+}
+.workspace-toolbar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 15px;
+ border-bottom: 1px solid var(--course-border);
+ padding: 15px 0;
+ color: var(--course-muted);
+ font:
+ 12px ui-monospace,
+ monospace;
+}
+.workspace-toolbar label {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+}
+.course-page input,
+.course-page select {
+ border: 1px solid #737e99;
+ border-radius: 3px;
+ background: #181d2c;
+ color: var(--course-ink);
+ padding: 10px;
+ min-height: 42px;
+ max-width: 100%;
+ color-scheme: dark;
+}
+.course-page select {
+ padding-right: 28px;
+}
+.course-page button {
+ border-radius: 3px;
+ min-height: 42px;
+ touch-action: manipulation;
+}
+.course-page .primary {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 12px;
+ background: #b3a3f3;
+ color: #0e1020;
+ border: 1px solid #b3a3f3;
+ padding: 12px 21px;
+ text-decoration: none;
+ font-size: 14px;
+ font-weight: 600;
+ min-height: 44px;
+}
+.course-page button:disabled {
+ opacity: 0.6;
+ cursor: wait;
+}
+.course-page .secondary {
+ background: #252b40;
+ border: 1px solid #78829f;
+ color: #f0edff;
+ padding: 10px 15px;
+ font-size: 13px;
+}
+.course-page .text-action {
+ color: var(--course-accent);
+ background: none;
+ border: 0;
+ text-decoration: underline;
+ text-underline-offset: 4px;
+ padding: 7px;
+ font-size: 12px;
+}
+.construction {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr);
+ margin-top: 16px;
+ gap: 18px;
+}
+.construction.split {
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+}
+.visual-construction {
+ min-width: 0;
+ border: 1px solid var(--course-border);
+ background: var(--course-panel);
+ padding: 20px;
+}
+.part-controls {
+ display: flex;
+ align-items: flex-end;
+ gap: 12px;
+}
+.part-controls label {
+ display: grid;
+ gap: 8px;
+ font-size: 12px;
+ flex: 1;
+}
+.part-controls select {
+ width: 100%;
+}
+.construction-empty {
+ color: var(--course-muted);
+ font-size: 14px;
+ padding: 30px 0;
+ margin: 0;
+ max-width: 420px;
+}
+.part-strip {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 7px;
+ margin: 22px 0;
+}
+.part-strip button {
+ background: #151a29;
+ color: var(--course-muted);
+ border: 1px solid #73809c;
+ padding: 8px 12px;
+ font:
+ 12px ui-monospace,
+ monospace;
+}
+.part-strip button.selected {
+ background: #3b326b;
+ color: #fff;
+ border-color: #c2b6ff;
+}
+.part-strip span {
+ color: var(--course-muted);
+ font-size: 10px;
+}
+.part-title {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 10px;
+ margin-bottom: 18px;
+}
+.part-title h3 span {
+ display: block;
+ color: var(--course-muted);
+ font-size: 11px;
+ margin-top: 6px;
+}
+.connection-row {
+ display: grid;
+ grid-template-columns: minmax(50px, 0.5fr) 14px minmax(0, 1fr);
+ gap: 10px;
+ align-items: center;
+ margin: 12px 0;
+ font:
+ 13px ui-monospace,
+ monospace;
+}
+.connection-row small {
+ display: block;
+ font:
+ 10px ui-monospace,
+ monospace;
+ color: var(--course-muted);
+ margin-top: 5px;
+}
+.connection-row input {
+ width: 100%;
+ min-width: 0;
+ font-size: 12px;
+}
+.pin-slices {
+ border-top: 1px solid var(--course-border);
+ padding-top: 16px;
+ margin-top: 20px;
+ font-size: 13px;
+}
+.pin-slices label {
+ display: grid;
+ gap: 6px;
+ margin: 12px 0;
+}
+.source-editor {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ font:
+ 12px/1.5 ui-monospace,
+ monospace;
+ color: var(--course-muted);
+ min-width: 0;
+}
+.source-editor textarea {
+ font:
+ 13px/1.8 ui-monospace,
+ monospace;
+ tab-size: 4;
+ resize: vertical;
+ width: 100%;
+ min-height: 360px;
+ padding: 18px;
+ white-space: pre;
+ overflow: auto;
+ color: #eceafa;
+ background: #10131f;
+ border: 1px solid var(--course-border);
+ border-radius: 3px;
+ color-scheme: dark;
+}
+.construction .source-editor textarea {
+ flex: 1;
+}
+.verification-bar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ padding: 22px 0;
+}
+.check-result {
+ border: 1px solid #8c788e;
+ background: #201a29;
+ padding: 22px;
+ margin: 0 0 25px;
+}
+.check-result.passed {
+ border-color: #638874;
+ background: #14231f;
+}
+.check-result strong {
+ font-size: 18px;
+ font-weight: 500;
+}
+.check-result p {
+ color: var(--course-muted);
+ font-size: 14px;
+ overflow-wrap: anywhere;
+}
+.check-result .primary {
+ margin-top: 6px;
+}
+.saved-completion {
+ font-size: 13px;
+ color: #b6e3c8;
+}
+.course-extras {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 24px;
+ margin-top: 20px;
+}
+.course-extras > details {
+ border-top: 1px solid var(--course-border);
+ padding-top: 18px;
+ min-width: 0;
+ font-size: 14px;
+}
+.course-extras p {
+ color: var(--course-muted);
+ font-size: 14px;
+}
+.course-extras .secondary {
+ margin: 12px 8px 12px 0;
+}
+.signal-values {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
+ gap: 14px;
+ margin: 16px 0;
+}
+.signal-values label {
+ display: grid;
+ gap: 6px;
+ font:
+ 13px ui-monospace,
+ monospace;
+}
+.signal-values input {
+ width: 100%;
+}
+.clock-controls {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 7px;
+}
+.clock-controls > span {
+ font-size: 12px;
+ color: var(--course-muted);
+}
+.live-outputs {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
+ gap: 16px;
+ padding: 18px;
+ background: #131725;
+}
+.live-outputs dt {
+ font:
+ 11px ui-monospace,
+ monospace;
+ color: var(--course-muted);
+}
+.live-outputs dd {
+ font:
+ 22px ui-monospace,
+ monospace;
+ margin: 10px 0 0;
+}
+.live-outputs small {
+ display: block;
+ margin-top: 8px;
+ font:
+ 10px ui-monospace,
+ monospace;
+ color: var(--course-muted);
+ overflow-wrap: anywhere;
+}
+.course-warning {
+ color: #f2c4d1 !important;
+ font-size: 13px;
+ overflow-wrap: anywhere;
+}
+.program-example {
+ background: #131725;
+ padding: 22px;
+ border: 1px solid var(--course-border);
+ overflow: auto;
+ font:
+ 13px/1.8 ui-monospace,
+ monospace;
+ white-space: pre;
+}
+.course-footnote {
+ margin-top: 64px;
+ border-top: 1px solid var(--course-border);
+ padding-top: 22px;
+}
+.course-page code {
+ font-family: ui-monospace, monospace;
+}
+@media (max-width: 720px) {
+ .course-page {
+ padding: 24px 20px 60px;
+ }
+ .course-heading {
+ margin-top: 28px;
+ }
+ .course-topline {
+ font-size: 12px;
+ gap: 14px;
+ }
+ .construction.split,
+ .course-extras {
+ grid-template-columns: minmax(0, 1fr);
+ }
+ .chapter-list a {
+ grid-template-columns: 28px 1fr;
+ gap: 18px;
+ padding: 24px 0;
+ }
+ .chapter-status {
+ grid-column: 2;
+ }
+ .chapter-list h2 {
+ font-size: 23px;
+ }
+ .verification-bar {
+ align-items: flex-start;
+ flex-direction: column;
+ }
+ .visual-construction {
+ padding: 15px;
+ }
+ .source-editor textarea {
+ padding: 12px;
+ font-size: 12px;
+ }
+ .part-controls {
+ flex-wrap: wrap;
+ }
+ .part-controls label {
+ min-width: 140px;
+ }
+ .course-page .primary {
+ max-width: 100%;
+ text-align: left;
+ }
+ .course-footnote {
+ margin-top: 42px;
+ }
+}
+@media (prefers-reduced-motion: reduce) {
+ .course-page * {
+ scroll-behavior: auto !important;
+ }
+}
diff --git a/src/lib/course/data.ts b/src/lib/course/data.ts
new file mode 100644
index 0000000..74ef99c
--- /dev/null
+++ b/src/lib/course/data.ts
@@ -0,0 +1,382 @@
+export type ChapterId =
+ 'buses' | 'arithmetic' | 'memory' | 'machine-language' | 'architecture' | 'assembler';
+export type TaskKind = 'hdl' | 'assembly' | 'encode' | 'symbols' | 'assembler';
+export interface CourseTask {
+ id: string;
+ title: string;
+ chip?: string;
+ kind: TaskKind;
+ goal: string;
+ explanation: string;
+ hint: string;
+ inputs?: Record;
+ outputs?: Record;
+ starter: string;
+}
+export interface CourseChapter {
+ id: ChapterId;
+ project: number;
+ title: string;
+ description: string;
+ reference: `/learn/reference/${string}`;
+ tasks: CourseTask[];
+}
+const pins = (values: Record) =>
+ Object.entries(values)
+ .map(([name, width]) => name + (width === 1 ? '' : `[${width}]`))
+ .join(', ');
+function chip(
+ name: string,
+ title: string,
+ inputs: Record,
+ outputs: Record,
+ goal: string,
+ explanation: string,
+ hint: string,
+): CourseTask {
+ return {
+ id: name.toLowerCase(),
+ chip: name,
+ title,
+ kind: 'hdl',
+ inputs,
+ outputs,
+ goal,
+ explanation,
+ hint,
+ starter: `CHIP ${name} {\n${Object.keys(inputs).length ? ` IN ${pins(inputs)};\n` : ''}${Object.keys(outputs).length ? ` OUT ${pins(outputs)};\n` : ''}\n PARTS:\n // Connect the parts here.\n}\n`,
+ };
+}
+const word = { in: 16 },
+ out = { out: 16 };
+const words = (count: number) =>
+ Object.fromEntries(Array.from({ length: count }, (_, i) => [String.fromCharCode(97 + i), 16]));
+const outputs = (count: number) =>
+ Object.fromEntries(Array.from({ length: count }, (_, i) => [String.fromCharCode(97 + i), 1]));
+export const courseChapters: CourseChapter[] = [
+ {
+ id: 'buses',
+ project: 1,
+ title: 'Work with words',
+ description: 'The same logic, sixteen bits at a time.',
+ reference: '/learn/reference/boolean-logic/project#buses',
+ tasks: [
+ chip(
+ 'Not16',
+ 'Invert a word',
+ word,
+ out,
+ 'Invert every bit of a 16-bit input.',
+ 'A bus is a group of wires. Bit 0 is the least significant bit; in[0] connects one wire, and in[0..7] connects eight.',
+ 'Repeat the single-bit operation for each position. Outputs can be wired to slices such as out[0].',
+ ),
+ chip(
+ 'And16',
+ 'Combine two words',
+ words(2),
+ out,
+ 'AND matching bit positions in a and b.',
+ 'Bitwise logic treats every position independently. There is no carry between columns.',
+ 'Connect a[i] and b[i] to the single-bit gate for each i.',
+ ),
+ chip(
+ 'Or16',
+ 'Merge two words',
+ words(2),
+ out,
+ 'OR matching bit positions in a and b.',
+ 'A bit is set when either input word has that bit set.',
+ 'The structure is parallel, like And16, but uses a different operation.',
+ ),
+ chip(
+ 'Mux16',
+ 'Choose a whole word',
+ { ...words(2), sel: 1 },
+ out,
+ 'Route a when sel=0, and b when sel=1.',
+ 'A shared selector controls sixteen independent data choices. The selector does not change the data.',
+ 'Use one Mux per bit and connect the same sel to every part.',
+ ),
+ chip(
+ 'Or8Way',
+ 'Reduce eight bits',
+ { in: 8 },
+ { out: 1 },
+ 'Output 1 if any of the eight inputs is 1.',
+ 'Reduction combines many bits into one answer. It differs from bitwise OR, which preserves the word width.',
+ 'Build a tree of two-input Or gates.',
+ ),
+ chip(
+ 'Mux4Way16',
+ 'Choose among four',
+ { ...words(4), sel: 2 },
+ out,
+ 'Selectors 00, 01, 10, 11 route a, b, c, d.',
+ 'Two selector bits encode four choices. sel[0] is the low-order selector bit.',
+ 'First choose within each pair; then choose between the two pair outputs.',
+ ),
+ chip(
+ 'Mux8Way16',
+ 'Choose among eight',
+ { ...words(8), sel: 3 },
+ out,
+ 'Route the selected one of eight words.',
+ 'Hierarchy keeps a large circuit understandable: larger selectors reuse smaller selectors.',
+ 'Use two four-way selectors and a final two-way selector.',
+ ),
+ chip(
+ 'DMux4Way',
+ 'Route to one of four',
+ { in: 1, sel: 2 },
+ outputs(4),
+ 'Send in to the selected output; all others must be 0.',
+ 'A demultiplexor distributes a value. When in is 0, all outputs remain 0.',
+ 'Split the input into halves, then split each half again.',
+ ),
+ chip(
+ 'DMux8Way',
+ 'Route to one of eight',
+ { in: 1, sel: 3 },
+ outputs(8),
+ 'Send in to the selected output a–h, leaving the rest at 0.',
+ 'Three decisions select one of eight paths. The same hierarchy will later address memory.',
+ 'Combine two four-way routing networks behind an initial split.',
+ ),
+ ],
+ },
+ {
+ id: 'arithmetic',
+ project: 2,
+ title: 'Make logic calculate',
+ description: 'From a single carry to a programmable ALU.',
+ reference: '/learn/reference/boolean-arithmetic',
+ tasks: [
+ chip(
+ 'HalfAdder',
+ 'Add two bits',
+ { a: 1, b: 1 },
+ { sum: 1, carry: 1 },
+ 'Add a and b. Return the low bit as sum and the high bit as carry.',
+ 'Two ones add to binary 10. Arithmetic needs two outputs because one bit cannot hold the result.',
+ 'Compare the sum column with XOR, and the carry column with AND.',
+ ),
+ chip(
+ 'FullAdder',
+ 'Carry a result forward',
+ { a: 1, b: 1, c: 1 },
+ { sum: 1, carry: 1 },
+ 'Add a, b, and incoming carry c.',
+ 'A column in a multi-bit addition may receive a carry from the previous column.',
+ 'Combine two half adders, then combine their carry signals.',
+ ),
+ chip(
+ 'Add16',
+ 'Add two words',
+ words(2),
+ out,
+ 'Output (a+b) modulo 65536.',
+ 'Carry travels from bit 0 toward bit 15. Overflow beyond the word is discarded. The same circuit adds signed two’s-complement values.',
+ 'Chain full adders. The first carry-in is false.',
+ ),
+ chip(
+ 'Inc16',
+ 'Advance by one',
+ word,
+ out,
+ 'Output (in+1) modulo 65536.',
+ 'An incrementer is useful for addresses, counters, and the next instruction.',
+ 'Use an adder with the other input set to the constant one; constants can connect to slices.',
+ ),
+ chip(
+ 'ALU',
+ 'Control a calculation',
+ { x: 16, y: 16, zx: 1, nx: 1, zy: 1, ny: 1, f: 1, no: 1 },
+ { out: 16, zr: 1, ng: 1 },
+ 'Apply zx/nx to x, zy/ny to y; choose AND (f=0) or addition (f=1); optionally negate the output. Set zr when out=0, ng from bit 15.',
+ 'Six control bits select a useful family of functions. The status flags describe the final output, after no is applied.',
+ 'Build the data path in stages. Use muxes for zeroing and conditional inversion; reduce all output bits for zr.',
+ ),
+ ],
+ },
+ {
+ id: 'memory',
+ project: 3,
+ title: 'Let a value stay',
+ description: 'Introduce time, state, and addressable memory.',
+ reference: '/learn/reference/memory',
+ tasks: [
+ chip(
+ 'Bit',
+ 'Remember one bit',
+ { in: 1, load: 1 },
+ { out: 1 },
+ 'At the next clock edge, store in if load=1. Otherwise retain the previous value.',
+ 'The supplied DFF captures its input on tick and publishes that state on tock. Feedback through a DFF is state, not a combinational loop.',
+ 'Choose between the new input and the previous output before the DFF.',
+ ),
+ chip(
+ 'Register',
+ 'Remember a word',
+ { in: 16, load: 1 },
+ out,
+ 'Store all sixteen input bits together when load=1.',
+ 'A register is sixteen one-bit memories sharing a load signal and the clock.',
+ 'Connect one Bit per position with the same load.',
+ ),
+ ...(['RAM8', 'RAM64', 'RAM512', 'RAM4K', 'RAM16K'] as const).map((name, index) =>
+ chip(
+ name,
+ `Address ${[8, 64, 512, 4096, 16384][index].toLocaleString('en-US')} words`,
+ { in: 16, load: 1, address: [3, 6, 9, 12, 14][index] },
+ out,
+ 'Read the addressed word immediately. On a clock edge, write only that word when load=1.',
+ 'The address has two jobs: select the word being read and direct the load signal to exactly one storage location.',
+ 'Partition the address into a bank selector and an address within the bank. Route load down; select data back up.',
+ ),
+ ),
+ chip(
+ 'PC',
+ 'Choose the next instruction',
+ { in: 16, load: 1, inc: 1, reset: 1 },
+ out,
+ 'On the next clock edge: reset wins, then load, then increment, otherwise hold.',
+ 'The program counter combines state with a small arithmetic path. Its priority rules matter when controls overlap.',
+ 'Work from lowest to highest priority using a cascade of muxes before the register.',
+ ),
+ ],
+ },
+ {
+ id: 'machine-language',
+ project: 4,
+ title: 'Tell the machine what to do',
+ description: 'Registers, addresses, jumps, and memory-mapped input/output.',
+ reference: '/learn/reference/machine-language',
+ tasks: [
+ {
+ id: 'instruction',
+ title: 'Read an instruction',
+ kind: 'encode',
+ goal: 'Encode @21 and D=A as two 16-bit machine instructions, one per line.',
+ explanation:
+ 'An A-instruction loads a 15-bit value into A. A C-instruction computes a value, chooses destinations, and may jump. The CPU receives bits, not the assembly spelling.',
+ hint: 'A-instructions start with 0. C-instructions use 111, then seven comp bits, three dest bits, and three jump bits. Use the full explanation for the encoding table.',
+ starter: '// Enter two binary words, one per line.\n',
+ },
+ {
+ id: 'mult',
+ title: 'Multiply with the instructions you have',
+ kind: 'assembly',
+ goal: 'Multiply nonnegative RAM[0] and RAM[1], placing the result in RAM[2]. Tests use products that fit in 15 bits.',
+ explanation:
+ 'Hack has addition but no multiply instruction. Repeated work and a conditional jump can implement multiplication. End in a stable loop so the result remains available.',
+ hint: 'Think of one input as a counter and accumulate the other. Handle a zero counter before the first addition.',
+ starter: '// R0 × R1 → R2\n// Write your assembly here.\n',
+ },
+ {
+ id: 'fill',
+ title: 'Connect a key to the screen',
+ kind: 'assembly',
+ goal: 'While a key is pressed, make every screen word -1. When released, make every screen word 0. Keep checking the keyboard forever.',
+ explanation:
+ 'SCREEN begins at address 16384 and contains 8192 words. Each word controls sixteen pixels. KBD at 24576 reports the pressed key, or zero.',
+ hint: 'Keep a screen pointer, choose the fill value from KBD, and visit every screen address. Repeat so a later key change is observed.',
+ starter: '// Read KBD. Fill the screen. Repeat.\n',
+ },
+ ],
+ },
+ {
+ id: 'architecture',
+ project: 5,
+ title: 'Build the whole computer',
+ description: 'Bring calculation, storage, and instructions together.',
+ reference: '/learn/reference/computer-architecture',
+ tasks: [
+ chip(
+ 'Memory',
+ 'Map the address space',
+ { in: 16, load: 1, address: 15 },
+ out,
+ 'Map 0–16383 to RAM16K, 16384–24575 to Screen, and 24576 to Keyboard. Writes affect RAM or screen only.',
+ 'Devices can share an address space. The CPU reads the keyboard as a memory location and writes pixels through the screen region.',
+ 'Decode the high address bits and route load separately from the read-output selection.',
+ ),
+ chip(
+ 'CPU',
+ 'Execute one instruction',
+ { inM: 16, instruction: 16, reset: 1 },
+ { outM: 16, writeM: 1, addressM: 15, pc: 15 },
+ 'Implement the Hack instruction set with A/D registers, the ALU, and a program counter. Reset sends pc to 0 at the next edge.',
+ 'A C-instruction may store its result and jump on the same clock edge. Memory writes and jump targets use the old A value, even when A is also a destination.',
+ 'Separate instruction decoding, the ALU data path, destination loads, and jump logic. Reuse ARegister, DRegister, ALU, and PC.',
+ ),
+ chip(
+ 'Computer',
+ 'Run a program on your computer',
+ { reset: 1 },
+ {},
+ 'Connect ROM32K, CPU, and Memory so the assembled program can execute.',
+ 'The program counter addresses instruction ROM. The A register addresses data memory. The CPU connects both paths into a complete machine.',
+ 'Wire the CPU memory interface to Memory and use pc to read the instruction ROM. This chip has no output pins; verification inspects its memory.',
+ ),
+ ],
+ },
+ {
+ id: 'assembler',
+ project: 6,
+ title: 'Turn names into instructions',
+ description: 'Build the translator between assembly and your computer.',
+ reference: '/learn/reference/assembler',
+ tasks: [
+ {
+ id: 'encode',
+ title: 'Encode a computation',
+ kind: 'encode',
+ goal: 'Translate @7, D=A, @3, D=D+A, @0, M=D into six machine words, one per line.',
+ explanation:
+ 'Assembly is a readable representation of machine instructions. A translator uses fixed comp, dest, and jump encodings; it does not execute the computation.',
+ hint: 'Keep source order. The a bit in comp chooses A or M; destination bits are A, D, M.',
+ starter: '// Six 16-bit binary words.\n',
+ },
+ {
+ id: 'symbols',
+ title: 'Give names an address',
+ kind: 'symbols',
+ goal: 'For the shown program, enter the addresses of LOOP, value, and END as JSON.',
+ explanation:
+ 'The first pass records labels using instruction addresses, ignoring comments and label declarations. The second pass allocates new variables starting at RAM[16]. Labels and variables share a symbol table.',
+ hint: 'Labels do not consume ROM words. LOOP names the first instruction. value is the first new variable. Count the real instructions before END.',
+ starter: '{\n "LOOP": 0,\n "value": 0,\n "END": 0\n}',
+ },
+ {
+ id: 'assembler',
+ title: 'Build your assembler',
+ kind: 'assembler',
+ goal: 'Write assemble(source), returning newline-separated 16-bit binary words. Support all Hack instructions, labels, variables, predefined symbols, whitespace, and comments.',
+ explanation:
+ 'Your JavaScript runs in an isolated frame with no network or site storage access. Verification compares your output with independent reference translations. Build the two passes separately, then test them together.',
+ hint: 'Pass 1 records label addresses. Pass 2 resolves @ operands and encodes C-instructions using the reference tables. Repeated variables must keep the same address.',
+ starter:
+ 'function assemble(source) {\n // 1. Remove comments and empty lines.\n // 2. Record labels and their instruction addresses.\n // 3. Resolve symbols and encode each instruction.\n // Return a string containing one 16-bit word per line.\n return "";\n}\n',
+ },
+ ],
+ },
+];
+export const symbolProgram = '(LOOP)\n@value\nM=1\n@END\n0;JMP\n(END)\n@LOOP\n0;JMP';
+export const chapterById = (id: string) => courseChapters.find((chapter) => chapter.id === id);
+export const courseProgressKey = 'chipsandcode.part-one.progress.v1';
+export const taskKey = (chapter: CourseChapter, task: CourseTask) => `${chapter.id}/${task.id}`;
+export function permittedParts(task: CourseTask): string[] {
+ const available = ['Nand', 'Not', 'And', 'Or', 'Xor', 'Mux', 'DMux'];
+ for (const chapter of courseChapters) {
+ for (const item of chapter.tasks) {
+ if (item.id === task.id && item.chip === task.chip) {
+ if (chapter.id === 'memory' || chapter.id === 'architecture') available.push('DFF');
+ if (chapter.id === 'architecture')
+ available.push('Screen', 'Keyboard', 'ROM32K', 'ARegister', 'DRegister');
+ return [...new Set(available)].filter((name) => name !== task.chip);
+ }
+ if (item.chip) available.push(item.chip);
+ }
+ }
+ return available;
+}
diff --git a/src/lib/course/sandbox.test.ts b/src/lib/course/sandbox.test.ts
new file mode 100644
index 0000000..77a634b
--- /dev/null
+++ b/src/lib/course/sandbox.test.ts
@@ -0,0 +1,80 @@
+import { beforeEach, afterEach, expect, it, vi } from 'vitest';
+import { assemble } from '#lib/computer/hack.js';
+import { assemblerCases } from './verify.js';
+import { verifyStudentAssembler } from './sandbox.js';
+type SandboxMessage = {
+ nonce?: string;
+ source?: string;
+ cancel?: boolean;
+ outputs?: string[];
+ error?: string;
+};
+type FrameEvent = { source: object; data: SandboxMessage };
+type TestFrame = {
+ hidden: boolean;
+ srcdoc: string;
+ setAttribute: ReturnType;
+ remove: ReturnType;
+ contentWindow: { postMessage: ReturnType };
+ onload?: () => void;
+};
+let receiver: (event: FrameEvent) => void;
+let frame: TestFrame;
+let payload: SandboxMessage;
+beforeEach(() => {
+ vi.useFakeTimers();
+ frame = {
+ hidden: false,
+ srcdoc: '',
+ setAttribute: vi.fn(),
+ remove: vi.fn(),
+ contentWindow: {
+ postMessage: vi.fn((data: SandboxMessage) => {
+ if (data.source) payload = data;
+ }),
+ },
+ onload: undefined,
+ };
+ vi.stubGlobal('document', {
+ createElement: () => frame,
+ body: { append: () => frame.onload?.() },
+ });
+ vi.stubGlobal('window', {
+ addEventListener: (_name: string, fn: (event: FrameEvent) => void) => {
+ receiver = fn;
+ },
+ removeEventListener: vi.fn(),
+ setTimeout,
+ });
+});
+afterEach(() => {
+ vi.useRealTimers();
+ vi.unstubAllGlobals();
+});
+it('isolates code behind a restrictive frame and validates its response', async () => {
+ const promise = verifyStudentAssembler('function assemble(){}');
+ expect(frame.srcdoc).toContain('');
+ expect(frame.srcdoc).toContain("connect-src 'none'");
+ expect(frame.srcdoc).toContain('new Worker');
+ expect(frame.setAttribute).toHaveBeenCalledWith('sandbox', 'allow-scripts');
+ receiver({ source: {}, data: { nonce: payload.nonce, outputs: [] } });
+ expect(frame.remove).not.toHaveBeenCalled();
+ receiver({
+ source: frame.contentWindow,
+ data: { nonce: payload.nonce, outputs: assemblerCases.map((s) => assemble(s).binary) },
+ });
+ expect((await promise).passed).toBe(true);
+ expect(frame.remove).toHaveBeenCalledOnce();
+});
+it('bounds execution time and disposes an infinite computation', async () => {
+ const promise = verifyStudentAssembler('while(true){}');
+ vi.advanceTimersByTime(4000);
+ expect((await promise).message).toContain('4 seconds');
+ expect(frame.contentWindow.postMessage).toHaveBeenCalledWith({ cancel: true }, '*');
+});
+it('surfaces errors and rejects oversized code', async () => {
+ const promise = verifyStudentAssembler('bad code');
+ receiver({ source: frame.contentWindow, data: { nonce: payload.nonce, error: 'Syntax error' } });
+ expect((await promise).message).toBe('Syntax error');
+ expect((await verifyStudentAssembler('x'.repeat(60001))).passed).toBe(false);
+});
diff --git a/src/lib/course/sandbox.ts b/src/lib/course/sandbox.ts
new file mode 100644
index 0000000..0e5da45
--- /dev/null
+++ b/src/lib/course/sandbox.ts
@@ -0,0 +1,51 @@
+import { assemblerCases, gradeAssemblerOutputs, type CheckResult } from './verify.js';
+/** Student code executes off the UI thread, in an opaque-origin frame with no network permission. */
+export function verifyStudentAssembler(source: string): Promise {
+ if (source.length > 60000)
+ return Promise.resolve({
+ passed: false,
+ message: 'Keep the assembler source below 60,000 characters.',
+ cases: 0,
+ });
+ return new Promise((resolve) => {
+ const frame = document.createElement('iframe');
+ frame.hidden = true;
+ frame.setAttribute('sandbox', 'allow-scripts');
+ frame.setAttribute('title', 'Isolated assembler verification');
+ const nonce = crypto.randomUUID();
+ let settled = false;
+ const finish = (result: CheckResult) => {
+ if (settled) return;
+ settled = true;
+ clearTimeout(timer);
+ window.removeEventListener('message', receive);
+ frame.contentWindow?.postMessage({ cancel: true }, '*');
+ frame.remove();
+ resolve(result);
+ };
+ const receive = (event: MessageEvent) => {
+ if (event.source !== frame.contentWindow || event.data?.nonce !== nonce) return;
+ const data = event.data;
+ if (data.error)
+ finish({ passed: false, message: String(data.error).slice(0, 400), cases: 0 });
+ else finish(gradeAssemblerOutputs(data.outputs));
+ };
+ const timer = window.setTimeout(
+ () =>
+ finish({
+ passed: false,
+ message:
+ 'Verification stopped after 4 seconds. Check for an infinite loop or excessive work.',
+ cases: 0,
+ }),
+ 4000,
+ );
+ window.addEventListener('message', receive);
+ const workerCode = `onmessage = ({data}) => { try { const fn = new Function('"use strict";'+data.source+'; return assemble;')(); if(typeof fn !== 'function') throw Error('Define function assemble(source).'); const outputs=data.programs.map(p=>fn(p)); if(outputs.some(v=>typeof v !== 'string'||v.length>200000)) throw Error('Return machine code as a string under 200,000 characters.'); postMessage({outputs}); } catch(error) { postMessage({error:String(error.message||error)}); } };`;
+ const scriptEnd = '' + 'script>';
+ frame.srcdoc = `
+
+
+
+
`${pin} ${Number(value)}`)
+ .join(', ')
+ : 'unconnected'
+ }`}
+ >
+
+ {#each Array(13) as _, index} {/each}
+ {#each channels as channel, index}
+ {channel.pin}
+
+
+ {channel.kind === 'inputs'
+ ? Number(inputs[channel.pin])
+ : outputs
+ ? Number(outputs[channel.pin])
+ : '—'}
+ {/each}
+
+
+
+
+
diff --git a/src/lib/game/ComputerJourney.svelte b/src/lib/game/ComputerJourney.svelte
new file mode 100644
index 0000000..c0b724a
--- /dev/null
+++ b/src/lib/game/ComputerJourney.svelte
@@ -0,0 +1,445 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {#each [0, 1, 2, 3] as row}
+
+
+ {/each}
+
+
+ {#each [[31, 22], [387, 22], [31, 115], [387, 115]] as [x, y]}
+
+ {/each}
+
+
+
+
+
+ {#each [0, 1, 2, 3] as index}
+
+ {/each}
+ {#each Array.from({ length: 18 }) as _, index}
+
+ {/each}
+
+
+
+
+
+
+ {#each Array.from({ length: 12 }) as _, index}
+
+ {/each}
+
+
+
+
+ {#each Array.from({ length: 7 }) as _, index}
+
+ {/each}
+
+
+
+
+
+
+
+
+
+
+
+
+ {#each Array.from({ length: 5 }) as _, row}
+ {#each Array.from({ length: 13 }) as _, column}
+
+ {/each}
+ {/each}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hello, world.
+ const message = "Hello, world.";
+ console.log(message);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DISPLAY
+ MAINBOARD
+ PROCESSOR
+ MEMORY
+ KEYBOARD
+
+
+
+
+
+
+
+
+ {#each [[221, 170], [382, 204], [429, 157], [226, 474], [375, 441], [415, 481], [133, 269], [605, 257]] as [x, y]}
+
+ {/each}
+
+
+
+
+
+
+
+
+
+ 0
+ 1
+ 0
+ OFF
+ ON
+ OFF
+
+
+
+
diff --git a/src/lib/game/FieldGuide.svelte b/src/lib/game/FieldGuide.svelte
new file mode 100644
index 0000000..7b0a652
--- /dev/null
+++ b/src/lib/game/FieldGuide.svelte
@@ -0,0 +1,1282 @@
+
+
+
+
+
+
+
+ {#each chapters as item}
+ (chapter = item.id)}
+ >{item.number} {item.title}↗
+ {/each}
+
+
+
+ {#if chapter === 'signals'}
+
Signals and gates
+
+ A Boolean signal is 0 or 1 . Choose a gate and toggle its
+ inputs to inspect the output.
+
+
+
+ {#each gates as kind}
+ (gate = kind)}>{kind}
+ {/each}
+
+
+
+
+
+ logic gate {gate} IN → OUT
+
+
+
+ OUT {Number(result)} {result ? 'high' : 'low'}
+
+
+
{descriptions[gate]}
+
+
+
+
Truth tables
+
+ A truth table lists every possible input and its output. The highlighted row is the
+ state you're exploring. For a two-input gate there are four cases; for a three-input
+ gate there are eight.
+
+
+ Lit wires represent 1. This model shows logical states, not electrical voltage.
+
+
+
+ {gate} truth table
+ {gate === 'NOT' ? 'in' : 'A'} {#if gate !== 'NOT'}B {/if}OUT
+ {#each rows as [x, y]}{Number(x)} {#if gate !== 'NOT'}{Number(y)} {/if}{Number(evaluate(gate, x, y))} {/each}
+
+
+ {:else if chapter === 'expressions'}
+
Boolean expressions
+
+ “A or B is on, and C is off” defines a function. An expression, a circuit, and a truth
+ table can all describe that same behavior.
+
+
f = (a OR b) AND NOT c
+
+
(a = !a)}>a {Number(a)} toggle
+
(b = !b)}>b {Number(b)} toggle
+
(c = !c)}>c {Number(c)} toggle
+
+ f {Number(expressionResult)} output
+
+
+
+ a OR b {Number(a || b)} NOT c {Number(!c)} both true? {Number(expressionResult)}
+
+
Build it from the rows that output 1.
+
+ There are three such rows. For each, AND together the inputs that describe it, using NOT
+ for a 0. Then OR those terms together. This is a canonical sum of products .
+
+
+ {#each ['(NOT a AND b AND NOT c)', '(a AND NOT b AND NOT c)', '(a AND b AND NOT c)'] as term, i}
+ {#if i > 0}
OR {/if}
+
{term}{Number(terms[i])}
+ {/each}
+
+
+ A general recipe: any Boolean function can be written using AND, OR, and NOT. Each of
+ those gates can itself be built from NAND.
+
+ {:else if chapter === 'blueprints'}
+
Interfaces and implementation
+
+ A chip has an interface—named inputs, outputs, and promised behavior. Its implementation
+ is the network of parts inside. The same interface can have more than one correct
+ implementation.
+
+
+
+
INTERFACE
+
in → NOT → out
+
Output is the opposite of input.
+
+
+
ONE IMPLEMENTATION
+
+ in ↗ in ↘ NAND → out
+
+
The same input feeds both NAND pins.
+
+
+
+
+
Hardware description language
+
+ HDL means hardware description language . It describes the structure
+ of a circuit, rather than a sequence of instructions.
+
+
+ CHIP / IN / OUT
+ Name the chip and its external pins.
+ PARTS
+ List the components and connect their pins.
+ Nand(a=in, b=in, out=out)
+
+ Connect both NAND inputs to the external input, and its output to the external
+ output.
+
+
+
+
+
Not.hdl / worked example
+
{notHDL}
+
+
+
+
Primitive and composite chips
+
+ A primitive is supplied as a working part: here, NAND. A composite is built by
+ connecting other parts. Once a composite chip works, its interface lets another designer
+ use it without needing to understand every wire inside.
+
+
+
+ Testing checks the blueprint against its contract. For small gates, test every input
+ combination. Fewer parts can be an optional design challenge after correctness.
+
+ {:else if chapter === 'scale'}
+
Buses and selectors
+
+ A word groups several bits. A selector routes one of several inputs. Explore both models
+ below, or open the buses and routing tool for 16-bit operations and 4-way or 8-way
+ routing.
+
+
A bus carries several bits
+
+ An 8-bit NOT applies the same inversion to each bit independently. Flip any bit below. A
+ 16-bit version follows the same pattern with sixteen wires.
+
+
+
IN
+
+ {#each bus as bit, i} (bus = bus.map((value, index) => (index === i ? !value : value)))}
+ >{7 - i} {' '}{Number(bit)} {/each}
+
+
NOT
+
+ {#each bus as bit, i}
+ {7 - i} {Number(!bit)}
+
{/each}
+
+
+
+
+
Selecting a signal
+
+ A multiplexor chooses one input to send to its output. With two selector bits, a
+ four-way multiplexor can choose among four inputs.
+
+
+ A demultiplexor routes in the other direction: one input to a selected output, with
+ the other outputs set to 0.
+
+
+ An eight-way selector needs 3 select bits. Multi-bit selectors route an entire bus.
+
+
+
+
4-WAY / 4-BIT MUX
+
+ {#each words as word, i} (selector = i)}
+ >{String.fromCharCode(97 + i)} {word}sel {i.toString(2).padStart(2, '0')} {/each}
+
+
+ sel {selector.toString(2).padStart(2, '0')} → OUT
+ {words[selector]}
+
+
+
+ {:else}
+
Source material
+
Go deeper in the full explanations, or try the tools.
+
+
+
Attribution
+
+ This reference adapts the existing Chips and Code Boolean logic material, based on Nand2Tetris . Nand2Tetris content is licensed under
+ CC BY-NC-SA 3.0 .
+
+
+ Chips and Code is not affiliated with or endorsed by Nand2Tetris. Software is MIT
+ licensed. Project background & credits ↗
+
+
+ {/if}
+ {#if fullExplanations[chapter]}
+
+ {/if}
+
+
+
+
+
+
diff --git a/src/lib/game/Game.svelte b/src/lib/game/Game.svelte
new file mode 100644
index 0000000..68a454d
--- /dev/null
+++ b/src/lib/game/Game.svelte
@@ -0,0 +1,410 @@
+
+
+
+
+ {#if view !== 'collection' && completed.length} setView('collection')}
+ >Your chips {/if}
+ Reference
+
+
+
+ {#if view === 'signal' || (view === 'guide' && referenceReturn === 'signal')}
+
+ goto('/')} />
+
+ {/if}
+ {#if view === 'workbench' || (view === 'guide' && referenceReturn === 'workbench')}
+
+ {#key selected} goto('/')}
+ />{/key}
+
+ {/if}
+ {#if view === 'guide'}
+ setView(referenceReturn)} />
+ {:else if view === 'milestone'}
+
+ ✓
+
+ {lastCompleted === 'nand'
+ ? 'NAND, explored.'
+ : `${lastMission.chip.toUpperCase()} works.`}
+
+
+ {lastCompleted === 'nand'
+ ? 'Its output is 0 only when both inputs are 1.'
+ : lastMission.goal}
+
+ {#if nextMission}
+
+
Next
+
{nextMission.title}
+
{nextMission.brief}
+
+ Continue →
+ {:else}
+
+
Take logic further.
+
+ Six circuits, built from one primitive. Next, use the same ideas with whole words of
+ bits and multi-way routing.
+
+
Continue with buses and selectors →
+
+ setView('collection')}
+ >Review your chips →
+ {/if}
+
+ {:else if view === 'collection'}
+
+ Your chips.
+ Each one is a building block for what comes next.
+
+ {#each verifiedMissions as mission}
+ reopenMission(mission.id)}
+ aria-label={`Reopen ${mission.chip} ${mission.title}`}
+ >
+ {mission.chip}
+ {mission.title}
+ ↗
+
+ {/each}
+
+ {#if !nextMission}Continue through the computer → {/if}
+ {#if nextMission}Continue learning → {/if}
+
+ {/if}
+
+
+ {#if notice}
{notice}
{/if}
+
+
+
diff --git a/src/lib/game/IntroVideo.svelte b/src/lib/game/IntroVideo.svelte
new file mode 100644
index 0000000..ce5a05a
--- /dev/null
+++ b/src/lib/game/IntroVideo.svelte
@@ -0,0 +1,146 @@
+
+
+
+
+
+
From signals to software
+
Visual introduction · 48 seconds
+
+
dialog.close()}
+ >×
+
+ (unavailable = true)}
+ >
+
+
+
+ {#if unavailable}
+ The video could not load. Read the transcript below.
+
{/if}
+
+
+
+
diff --git a/src/lib/game/Landing.svelte b/src/lib/game/Landing.svelte
new file mode 100644
index 0000000..b1914fe
--- /dev/null
+++ b/src/lib/game/Landing.svelte
@@ -0,0 +1,644 @@
+
+
+
+
+
+ {#each chapters as chapter, index}
+
+
+ {#if index === 0}
+
+ Break down the magic of computers.
+
+
By building your own.
+
{continuing ? 'Continue learning' : 'Start learning'}↗
+
No prerequisites. Free in your browser.
+ {:else}
+
0{index} {chapter.label}
+
{chapter.title}
+
{chapter.body}
+ {/if}
+
+
+
+
+ {#if index === 0}
+ ↓ Scroll to look inside
+
{/if}
+
+ {/each}
+
+
+
+
+
+ CHIPS AND CODE
+ {String(Math.min(3, Math.max(0, Math.round(progress)))).padStart(2, '0')} / 03
+
+
+
+
+
+
+
+
FROM SIGNALS TO SOFTWARE
+
Then build it{' '} back up.
+
+ Combine signals with gates. Build working circuits. Understand what your code is built on.
+
+
{continuing ? 'Continue learning' : 'Start learning'}↗
+
Build from signals through a working computer and assembler.
+
Watch the introduction ↗
+
+
+
+ </> Code
+
+
+
+
+
+ 0 1 Signals You start here
+
+
+
+
+
+
diff --git a/src/lib/game/MissionWorkbench.svelte b/src/lib/game/MissionWorkbench.svelte
new file mode 100644
index 0000000..b7af9f4
--- /dev/null
+++ b/src/lib/game/MissionWorkbench.svelte
@@ -0,0 +1,2019 @@
+
+
+{#if missionId === 'nand'}
+ oncomplete(missionId)} {onclose} />
+{:else}
+
+
+
+ {#if showGuide}{/if}
+
+
+
+
+ CHALLENGE {String(mission.number).padStart(2, '0')} /
+ {mission.location}
+
+
{mission.title}
+
{mission.goal}
+
+
+
+ {#if live.result}
+
+ INPUT SIGNALS
+ {#each mission.inputs as pin}
+ toggleInput(pin)}
+ >{pin} {Number(inputValues[pin])}
+ {/each}
+
+ {/if}
+
+ {#if codeError}
+
+
+
HDL could not be applied.
+
{codeError}
+
Your source is preserved. Simulation is paused until it compiles.
+
+
Use last valid circuit
+
+ {/if}
+
+
+ {#if editorMode !== 'code'}
+
+
+
+
Circuit
+
+ {#each mission.availableParts as type} addGate(type)}
+ disabled={!!codeError || circuit.gates.length >= 24}
+ >+ {type} {/each}
+
+
+
+ {#if missionId !== 'nand'}
+
+
⌁
+
{guidedInstruction}
+ {#if selectedSource}
{
+ selectedSource = '';
+ wiringMessage =
+ 'Choose a source dot, then a destination pin to connect them.';
+ }}>Cancel wire {/if}
+
+ {/if}
+
+
+
+
+
+
+
+ INPUT
+ OUTPUT
+ {#each circuit.gates as gate, index}
+ {@const position = gatePosition(index)}
+ {#each gatePins(gate.type) as pin, pinIndex}
+ {#if gate.inputs[pin]}
+
+ {/if}
+ {/each}
+ {/each}
+ {#each mission.outputs as pin, index}
+ {#if circuit.outputs[pin]}
+
+ {/if}
+ {/each}
+ {#each mission.inputs as pin, index}
+
+
+ {Number(inputValues[pin])}
+ {pin}
+
+
+ selectSource(pin)}>
+
+
+ {/each}
+ {#each circuit.gates as gate, index}
+ {@const position = gatePosition(index)}
+
+
+
+
+ {gate.type.toUpperCase()}
+ PART {String(index + 1).padStart(2, '0')}
+ {#each gatePins(gate.type) as pin, pinIndex}
+
+ {pin}
+ {#if missionId !== 'nand'}
+
+ connectPin(gate.id, pin)}>
+
+ {/if}
+ {/each}
+
+ {signal(gate.id, liveSignals) === null
+ ? '·'
+ : Number(signal(gate.id, liveSignals))}
+ {#if missionId !== 'nand'}
+
+ selectSource(gate.id)}>
+
+ {/if}
+
+ {/each}
+ {#if circuit.gates.length === 0}
+
+
+ +
+ YOUR CIRCUIT
+
+ Add a gate above to start your circuit.
+ {/if}
+ {#each mission.outputs as pin, index}
+ {@const outputValue = live.result?.outputs[pin]}
+
+ {#if outputValue} {/if}
+
+ {outputValue === undefined ? '?' : Number(outputValue)}
+ {pin}
+ {#if missionId !== 'nand'}
+
+ connectOutput(pin)}>
+
+ {/if}
+
+ {/each}
+
+
+
+ {live.result
+ ? `Live output: ${Object.entries(live.result.outputs)
+ .map(([pin, value]) => `${pin} ${Number(value)}`)
+ .join(', ')}`
+ : 'Circuit is not yet fully connected.'}
+
+
+
+ {#if missionId !== 'nand'}
+
+
+ Connections
+
+ {#if undoCircuit}Undo clear {/if} !circuit.outputs[pin])}>Clear circuit
+
+
+ {#if circuit.gates.length > 0}
+
+ {#each circuit.gates as gate, index (gate.id)}
+
+
+ {String(index + 1).padStart(2, '0')} {gate.type} removeGate(gate.id)}>×
+
+ {#each gatePins(gate.type) as pin}
+
Pin {pin}
+ setConnection(gate.id, pin, event.currentTarget.value)}
+ >Choose source… {#each availableSources(mission, circuit, gate.id) as source}{sourceLabel(source)} {/each}
+ {/each}
+
+ {/each}
+
+ {/if}
+
+ CHIP OUTPUTS {#each mission.outputs as pin}Output {pin} setOutput(pin, event.currentTarget.value)}
+ >Choose source… {#each availableSources(mission, circuit) as source}{sourceLabel(source)} {/each} {/each}
+
+
+
+ {/if}
+
+ {/if}
+ {#if editorMode !== 'visual'}
+
+
+ </> {mission.chip}.hdl{copied ? 'Copied' : 'Copy code'}
+
+ {#if editorMode === 'code' && !live.result && !codeError && mission.outputs.every((pin) => !!circuit.outputs[pin])}
+
+ {/if}
+
+
+
+ {#each code.split('\n') as _, index}{index + 1} {/each}
+
+
+
+
+
+ {codeError ? 'HDL ERROR' : live.result ? 'COMPILED' : 'DRAFT'} HDL · {code.split('\n').length} lines
+
+
+ {missionId === 'nand'
+ ? 'NAND is supplied by the simulator; its HDL is read-only.'
+ : 'Edit either view. Visual edits rewrite the HDL.'}
+
+ Open Hardware simulator ↗
+
+ {/if}
+
+
+
{saveNotice || 'Drafts are saved on this device.'}
+
+
+ Signal history
+
+
+
+ {#if report || reportError}
+
+ Test results
+
+ PROVE YOUR CIRCUIT {scenarios.length} CASES
+
+ {#if reportError}
+
Circuit cannot run.
+
{reportError}
+
{/if}
+ {#if report}
+
+ {report.success ? 'Signal confirmed.' : 'Specification mismatch.'} {report.passed} of {report.total} combinations work.
+
+
+
+ Click a case to inspect its live signal. {#each mission.inputs as pin}{pin} {/each}Wanted {mission.outputs.length > 1 ? mission.outputs.join('/') : ''} Yours {mission.outputs.length > 1 ? mission.outputs.join('/') : ''} Result {#each report.rows as row, index}{#each mission.inputs as pin}{Number(row.inputs[pin])} {/each}{mission.outputs.map((pin) => Number(row.expected[pin])).join(' / ')} {mission.outputs.map((pin) => Number(row.actual[pin])).join(' / ')} {
+ inputValues = { ...row.inputs };
+ }}
+ aria-label={`Inspect case ${index + 1}, ${row.passed ? 'passes' : 'needs work'}`}
+ >{row.passed ? '✓' : '↗'} {/each}
+
+
+ {#if !report.success}
+ The board is showing the first mismatching input. Follow its signal and change a
+ connection.
+
{/if}
+ {/if}
+
+ {/if}
+
+
+ Need a hint?
+ {#if hintCount > 0}
+ {#each mission.hints.slice(0, hintCount) as hint}{hint} {/each}
+ {/if}
+ (hintCount = Math.min(mission.hints.length, hintCount + 1))}
+ disabled={hintCount >= mission.hints.length}
+ >
+ {hintCount === 0
+ ? 'Reveal a hint'
+ : hintCount >= mission.hints.length
+ ? 'All hints revealed'
+ : 'Next hint'}
+
+
+
+
+
+{/if}
+
+
diff --git a/src/lib/game/NandDiscovery.svelte b/src/lib/game/NandDiscovery.svelte
new file mode 100644
index 0000000..9d762a5
--- /dev/null
+++ b/src/lib/game/NandDiscovery.svelte
@@ -0,0 +1,515 @@
+
+
+
+ ← Back
+
+
+
+
+ {#each ['a', 'b'] as pin}
+ toggle(pin as 'a' | 'b')}
+ >
+ {pin} {' '}{Number(inputs[pin as 'a' | 'b'])}
+
+ {/each}
+
+
+
+
+
+
+
+ NAND
+
+
+ out {Number(output)}
+
+
+
+
+
{Math.min(step + 1, cases.length)} of {cases.length}
+
{instruction}
+ {#if confirmed}
+
{feedback}
+ {#if finished}
+
NAND outputs 0 only when both inputs are 1.
+
+ Why build from NAND?
+
+ One kind of gate is enough to build every Boolean function. We’ll use NAND as our
+ starting part, then build the NOT and AND gates you just explored.
+
+
+ Go deeper: why NAND is universal
+
+ Connect the same signal to both NAND inputs. Its answer is now always the opposite:
+ you have made NOT.
+
+ NOT(a) = NAND(a, a)
+
+ Next, flip the output of a NAND. That restores the AND answer. This uses two NAND
+ gates: one to combine the inputs, one with its inputs tied together to invert.
+
+ n = NAND(a, b) AND(a, b) = NAND(n, n)
+
+ Invert both inputs before a NAND and you get OR. Any truth table can be written using
+ AND, OR, and NOT, so these three recipes let NAND express any Boolean function.
+
+ OR(a, b) = NAND(NAND(a, a), NAND(b, b))
+
+ This describes combinational logic: outputs depend on the inputs now. Remembering an
+ earlier value adds state, which comes later.
+
+ Read the full explanation →
+
+
+ {/if}
+
{finished ? 'Continue' : 'Next combination'}
+ →
+ {:else}
+
+ answer(false)}>Output 0
+ answer(true)}>Output 1
+
+
{feedback}
+ {/if}
+
+
+ {#if finished}
+
+ See its code
+ NAND is supplied by the simulator. Next, you will use it to build your own circuits.
+ CHIP Nand {
+ IN a, b;
+ OUT out;
+ BUILTIN Nand;
+}
+
+ {/if}
+
+
+
diff --git a/src/lib/game/SignalIntro.svelte b/src/lib/game/SignalIntro.svelte
new file mode 100644
index 0000000..10384da
--- /dev/null
+++ b/src/lib/game/SignalIntro.svelte
@@ -0,0 +1,555 @@
+
+
+
+ ← Back
+
+
+
{titles[stage]}
+
+ {#if stage === 'signal'}
+ A digital signal carries one of two values: 0 or 1 .
+ {:else if stage === 'not'}
+ A NOT gate gives the opposite value.
+ {:else}
+ AND gives 1 only when both inputs are 1 .
+ {/if}
+
+
+ {#if stage === 'signal'}
+
+
+ Signal
+
+
+ {Number(signal)}
+
+
+
+
+
Output
+
+ {Number(result)}
+
+
+
+ {:else}
+
+
+ {#if stage === 'not'}
+ in {Number(signal)}
+ {:else}
+ {#each ['a', 'b'] as pin}
+ toggleAnd(pin as 'a' | 'b')}
+ >{pin} {Number(pin === 'a' ? a : b)}
+ {/each}
+ {/if}
+
+
+ {#if stage === 'not'}
+
+
+
+
+ NOT
+ {:else}
+
+
+
+
+ AND
+ {/if}
+
+
+ out {Number(result)}
+
+
+ {/if}
+
+
+ {#if stage === 'signal'}
+ {#if observation === 0}
+
Set the signal to 1 .
+ {:else if observation === 1}
+
The output follows: 1 .
+
Set the signal back to 0.
+ {:else}
+
Same signal in. Same signal out.
+
Now let’s change what comes out.
+ {/if}
+ {:else if stage === 'not'}
+
{Number(signal)} in. {Number(result)} out.
+
+ {observation === 0
+ ? 'Set the input to 1. Watch the output.'
+ : observation === 1
+ ? 'Now set the input back to 0.'
+ : 'NOT flips a signal. Now try a gate with two inputs.'}
+
+ {:else}
+
+ {Number(a)} AND {Number(b)} gives
+ {Number(result)} .
+
+
{andInstruction}
+ {/if}
+
+
+ {#if explored}
+
Continue →
+ {/if}
+
+
+
+
diff --git a/src/lib/game/circuit.test.ts b/src/lib/game/circuit.test.ts
new file mode 100644
index 0000000..32528f8
--- /dev/null
+++ b/src/lib/game/circuit.test.ts
@@ -0,0 +1,434 @@
+import { describe, expect, it } from 'vitest';
+import {
+ availableSources,
+ createCircuit,
+ fromHDL,
+ isCircuitDraft,
+ simulateCircuit,
+ testCircuit,
+ toHDL,
+ toHDLDraft,
+} from './circuit';
+import type { Circuit, GateNode } from './circuit';
+import { getMission, missions, truthTable } from './missions';
+import type { MissionId } from './missions';
+
+const nand = (id: string, a: string, b: string): GateNode => ({
+ id,
+ type: 'Nand',
+ inputs: { a, b },
+});
+const examples: Record = {
+ nand: { gates: [nand('g1', 'a', 'b')], outputs: { out: 'g1' } },
+ not: { gates: [nand('g1', 'in', 'in')], outputs: { out: 'g1' } },
+ and: { gates: [nand('g1', 'a', 'b'), nand('g2', 'g1', 'g1')], outputs: { out: 'g2' } },
+ or: {
+ gates: [nand('g1', 'a', 'a'), nand('g2', 'b', 'b'), nand('g3', 'g1', 'g2')],
+ outputs: { out: 'g3' },
+ },
+ xor: {
+ gates: [
+ nand('g1', 'a', 'b'),
+ nand('g2', 'a', 'g1'),
+ nand('g3', 'b', 'g1'),
+ nand('g4', 'g2', 'g3'),
+ ],
+ outputs: { out: 'g4' },
+ },
+ mux: {
+ gates: [
+ nand('g1', 'sel', 'sel'),
+ nand('g2', 'a', 'g1'),
+ nand('g3', 'b', 'sel'),
+ nand('g4', 'g2', 'g3'),
+ ],
+ outputs: { out: 'g4' },
+ },
+ dmux: {
+ gates: [
+ nand('g1', 'sel', 'sel'),
+ nand('g2', 'in', 'g1'),
+ nand('g3', 'g2', 'g2'),
+ nand('g4', 'in', 'sel'),
+ nand('g5', 'g4', 'g4'),
+ ],
+ outputs: { a: 'g3', b: 'g5' },
+ },
+};
+
+describe('Chips and Code circuit authoring', () => {
+ it.each(missions)('accepts a real NAND construction for $chip across every input', (mission) => {
+ const report = testCircuit(mission, examples[mission.id]);
+ expect(report.success).toBe(true);
+ expect(report.passed).toBe(2 ** mission.inputs.length);
+ expect(report.rows.every((row) => row.passed)).toBe(true);
+ expect(report.hdl).toContain(`CHIP ${mission.chip}`);
+ });
+
+ it('starts builders empty and the NAND discovery with the supplied primitive', () => {
+ for (const mission of missions) {
+ const circuit = createCircuit(mission);
+ expect(isCircuitDraft(mission, circuit)).toBe(true);
+ expect(circuit.gates).toHaveLength(mission.id === 'nand' ? 1 : 0);
+ }
+ expect(testCircuit(getMission('nand'), createCircuit(getMission('nand'))).success).toBe(true);
+ });
+
+ it('accepts previously mastered primitive equivalents in later builds', () => {
+ const circuit: Circuit = {
+ gates: [
+ { id: 'g1', type: 'Nand', inputs: { a: 'a', b: 'b' } },
+ { id: 'g2', type: 'Not', inputs: { in: 'g1' } },
+ ],
+ outputs: { out: 'g2' },
+ };
+ const mission = getMission('and');
+ expect(testCircuit(mission, circuit).success).toBe(true);
+ expect(simulateCircuit(mission, circuit, { a: true, b: true })).toMatchObject({
+ outputs: { out: true },
+ signals: { a: true, b: true, g1: false, g2: true },
+ });
+ });
+
+ it.each([13, 24])(
+ 'runs a valid %i-stage visual inverter chain through the HDL simulator',
+ (length) => {
+ const mission = getMission('not');
+ const gates = Array.from({ length }, (_, index) => {
+ const source = index === 0 ? 'in' : `g${index}`;
+ return nand(`g${index + 1}`, source, source);
+ });
+ const circuit: Circuit = { gates, outputs: { out: `g${length}` } };
+
+ for (const input of [false, true]) {
+ const simulation = simulateCircuit(mission, circuit, { in: input });
+ expect(simulation.outputs.out).toBe(length % 2 === 0 ? input : !input);
+ gates.forEach((gate, index) => {
+ expect(simulation.signals[gate.id]).toBe(index % 2 === 0 ? !input : input);
+ });
+ }
+ expect(testCircuit(mission, circuit).success).toBe(length % 2 === 1);
+ },
+ );
+
+ it('detects a circuit that happens to pass the current input but fails the full specification', () => {
+ const mission = getMission('and');
+ const circuit: Circuit = { gates: [nand('g1', 'a', 'b')], outputs: { out: 'g1' } };
+ const report = testCircuit(mission, circuit);
+ expect(report.success).toBe(false);
+ expect(report.passed).toBe(0);
+ expect(report.rows[0]).toMatchObject({
+ inputs: { a: false, b: false },
+ expected: { out: false },
+ actual: { out: true },
+ passed: false,
+ });
+ });
+
+ it('requires both demultiplexor outputs, including the inactive destination', () => {
+ const mission = getMission('dmux');
+ const circuit = { ...examples.dmux, outputs: { a: 'g3', b: 'g3' } };
+ const report = testCircuit(mission, circuit);
+ expect(report.total).toBe(4);
+ expect(report.success).toBe(false);
+ expect(report.rows.filter((row) => !row.passed)).toHaveLength(2);
+ });
+
+ it('supports direct input wires with semantically equivalent exported HDL', () => {
+ const mission = getMission('mux');
+ const circuit: Circuit = { gates: [], outputs: { out: 'a' } };
+ expect(toHDL(mission, circuit)).toContain('gamebufferout');
+ expect(simulateCircuit(mission, circuit, { a: true, b: false, sel: false }).outputs.out).toBe(
+ true,
+ );
+ expect(simulateCircuit(mission, circuit, { a: false, b: true, sel: false }).outputs.out).toBe(
+ false,
+ );
+ });
+
+ it('offers only inputs and earlier nodes when connecting a gate', () => {
+ const mission = getMission('and');
+ expect(availableSources(mission, examples.and, 'g1')).toEqual(['a', 'b']);
+ expect(availableSources(mission, examples.and, 'g2')).toEqual(['a', 'b', 'g1']);
+ expect(availableSources(mission, examples.and)).toEqual(['a', 'b', 'g1', 'g2']);
+ expect(availableSources(mission, examples.and, 'missing')).toEqual(['a', 'b']);
+ });
+
+ it('retains incomplete but structurally safe drafts', () => {
+ const mission = getMission('not');
+ const circuit: Circuit = { gates: [nand('g1', '', '')], outputs: { out: '' } };
+ expect(isCircuitDraft(mission, circuit)).toBe(true);
+ expect(() => testCircuit(mission, circuit)).toThrow('Connect g1 a');
+ expect(() => testCircuit(mission, createCircuit(mission))).toThrow('Connect output out');
+ });
+
+ it('rejects unknown sources, missing output, forward edges and cycles before compiling', () => {
+ const mission = getMission('and');
+ expect(() =>
+ toHDL(mission, { gates: [nand('g1', 'nope', 'b')], outputs: { out: 'g1' } }),
+ ).toThrow('earlier gate');
+ expect(() =>
+ toHDL(mission, {
+ gates: [nand('g1', 'g2', 'b'), nand('g2', 'g1', 'b')],
+ outputs: { out: 'g2' },
+ }),
+ ).toThrow('Loops');
+ expect(() =>
+ toHDL(mission, { gates: [nand('g1', 'g1', 'b')], outputs: { out: 'g1' } }),
+ ).toThrow('Loops');
+ expect(() => toHDL(mission, { gates: [], outputs: { out: 'missing' } })).toThrow(
+ 'unknown signal',
+ );
+ });
+
+ it('rejects malformed saved drafts and inaccessible components', () => {
+ const mission = getMission('not');
+ const invalid: unknown[] = [
+ null,
+ [],
+ {},
+ { gates: [], outputs: {} },
+ { gates: [], outputs: { out: '', extra: '' } },
+ { gates: [{ id: 'g1', type: 'Not', inputs: { in: 'in' } }], outputs: { out: 'g1' } },
+ { gates: [{ id: 'in', type: 'Nand', inputs: { a: 'in', b: 'in' } }], outputs: { out: 'in' } },
+ { gates: [nand('g1', 'in', 'in'), nand('g1', 'in', 'in')], outputs: { out: 'g1' } },
+ {
+ gates: [{ id: 'g1', type: 'Nand', inputs: { a: 'in', b: 'in', bad: 'in' } }],
+ outputs: { out: 'g1' },
+ },
+ {
+ gates: Array.from({ length: 33 }, (_, i) => nand(`g${i}`, 'in', 'in')),
+ outputs: { out: '' },
+ },
+ {
+ gates: [{ id: 'x);Nand(', type: 'Nand', inputs: { a: 'in', b: 'in' } }],
+ outputs: { out: '' },
+ },
+ ];
+ for (const value of invalid) expect(isCircuitDraft(mission, value)).toBe(false);
+ expect(() => toHDL(mission, invalid[2] as Circuit)).toThrow('invalid components');
+ });
+
+ it('validates live input state and mission identity', () => {
+ expect(() => simulateCircuit(getMission('nand'), examples.nand, { a: true })).toThrow(
+ 'Input b',
+ );
+ expect(() => getMission('future-cpu')).toThrow('Unknown mission');
+ });
+
+ it('enumerates every input exactly once, including all eight selector cases', () => {
+ const rows = truthTable(getMission('mux'));
+ expect(rows).toHaveLength(8);
+ expect(new Set(rows.map((row) => JSON.stringify(row.inputs))).size).toBe(8);
+ expect(rows[3]).toEqual({ inputs: { a: false, b: true, sel: true }, expected: { out: true } });
+ expect(truthTable(getMission('dmux'))[2]).toEqual({
+ inputs: { in: true, sel: false },
+ expected: { a: true, b: false },
+ });
+ });
+});
+
+describe('editable HDL and visual circuit interoperability', () => {
+ const source = (parts: string) => `CHIP And { IN a, b; OUT out; PARTS: ${parts} }`;
+
+ it.each(missions)(
+ 'round-trips the $chip construction through the existing HDL language',
+ (mission) => {
+ const imported = fromHDL(mission, toHDL(mission, examples[mission.id]));
+ expect(imported).toEqual(examples[mission.id]);
+ expect(testCircuit(mission, imported).success).toBe(true);
+ },
+ );
+
+ it('accepts named internal wires and forward declarations without changing behavior', () => {
+ const mission = getMission('and');
+ const circuit = fromHDL(
+ mission,
+ source(`
+ Not(in=negative, out=out);
+ Nand(a=a, b=b, out=negative);
+ `),
+ );
+ expect(circuit).toEqual({
+ gates: [nand('g1', 'a', 'b'), { id: 'g2', type: 'Not', inputs: { in: 'g1' } }],
+ outputs: { out: 'g2' },
+ });
+ expect(testCircuit(mission, circuit).success).toBe(true);
+ });
+
+ it('resolves multiple aliases of the same part output and both DMux output pins', () => {
+ const mission = getMission('dmux');
+ const circuit = fromHDL(
+ mission,
+ `CHIP DMux {
+ IN in, sel; OUT a, b; PARTS:
+ Not(in=sel, out=negative, out=alias, out=alias);
+ And(a=in, b=negative, out=a);
+ And(a=in, b=sel, out=b);
+ Not(in=alias, out=unused);
+ }`,
+ );
+ expect(circuit.gates[1].inputs.b).toBe('g1');
+ expect(circuit.gates[3].inputs.in).toBe('g1');
+ expect(testCircuit(mission, circuit).success).toBe(true);
+ });
+
+ it('retains empty and incomplete visual designs as editable, parseable drafts', () => {
+ const mission = getMission('not');
+ const empty = createCircuit(mission);
+ expect(fromHDL(mission, toHDLDraft(mission, empty))).toEqual(empty);
+ expect(fromHDL(mission, 'CHIP Not { IN in; OUT out; PARTS: /* start here */ }')).toEqual(empty);
+ expect(fromHDL(mission, 'CHIP Not { IN in; OUT out; }')).toEqual(empty);
+ const partial: Circuit = {
+ gates: [nand('g1', 'in', ''), nand('g2', '', 'g1')],
+ outputs: { out: '' },
+ };
+ expect(fromHDL(mission, toHDLDraft(mission, partial))).toEqual(partial);
+ expect(() => testCircuit(mission, partial)).toThrow('Connect g1 b');
+ expect(() =>
+ toHDLDraft(mission, { gates: [nand('g1', 'missing', '')], outputs: { out: '' } }),
+ ).toThrow('earlier gate');
+ });
+
+ it('imports a part without a connected output as an unfinished draft', () => {
+ const circuit = fromHDL(getMission('not'), 'CHIP Not { IN in; OUT out; PARTS: Nand(a=in); }');
+ expect(circuit).toEqual({ gates: [nand('g1', 'in', '')], outputs: { out: '' } });
+ });
+
+ it('keeps the equivalent behavior of visual input-to-output wires after a code round-trip', () => {
+ const mission = getMission('mux');
+ const circuit: Circuit = { gates: [], outputs: { out: 'a' } };
+ const imported = fromHDL(mission, toHDLDraft(mission, circuit));
+ expect(imported).toEqual(circuit);
+ for (const { inputs } of truthTable(mission)) {
+ expect(simulateCircuit(mission, imported, inputs).outputs.out).toBe(inputs.a);
+ }
+ });
+
+ it.each(['not', 'dmux'] as const)(
+ 'round-trips 32 authored parts plus all direct output wires for %s, including a code comment edit',
+ (id) => {
+ const mission = getMission(id);
+ const gates = Array.from({ length: 32 }, (_, index) => {
+ const input = index === 0 ? 'in' : `g${index}`;
+ return nand(`g${index + 1}`, input, input);
+ });
+ const circuit: Circuit = {
+ gates,
+ outputs: Object.fromEntries(mission.outputs.map((pin) => [pin, 'in'])),
+ };
+ const source = toHDLDraft(mission, circuit);
+ expect(source.match(/ Nand\(/g)).toHaveLength(32 + mission.outputs.length * 2);
+ for (const hdl of [source, `${source}\n// A comment must not break the saved circuit.`]) {
+ const imported = fromHDL(mission, hdl);
+ expect(imported).toEqual(circuit);
+ for (const { inputs } of truthTable(mission)) {
+ expect(simulateCircuit(mission, imported, inputs).outputs).toEqual(
+ Object.fromEntries(mission.outputs.map((pin) => [pin, inputs.in])),
+ );
+ }
+ }
+ },
+ );
+
+ it.each([
+ ['Nand(a=a, b=a, out=authoredWire); Nand(a=authoredWire, b=authoredWire, out=out);', 2],
+ ['Nand(a=a, b=b, out=gamebufferout); Nand(a=gamebufferout, b=gamebufferout, out=out);', 2],
+ [
+ 'Nand(a=a, b=a, out=gamebufferout, out=alias); Nand(a=gamebufferout, b=gamebufferout, out=out);',
+ 2,
+ ],
+ [
+ 'Nand(a=a, b=a, out=gamebufferout); Nand(a=gamebufferout, b=gamebufferout, out=out, out=alias);',
+ 2,
+ ],
+ [
+ 'Nand(a=a, b=a, out=gamebufferout); Nand(a=gamebufferout, b=gamebufferout, out=out); Not(in=gamebufferout, out=extra);',
+ 3,
+ ],
+ [
+ 'Nand(a=a, b=a, out=gamebufferout); Nand(a=gamebufferout, b=gamebufferout, out=out); Not(in=out, out=extra);',
+ 3,
+ ],
+ ])(
+ 'preserves authored buffer-like parts when the generated adapter contract does not match: %s',
+ (parts, count) => {
+ const imported = fromHDL(getMission('and'), source(parts));
+ expect(imported.gates).toHaveLength(count);
+ expect(imported.outputs.out).toBe('g2');
+ },
+ );
+
+ it('does not hide conflicting drivers while normalizing generated wire adapters', () => {
+ expect(() =>
+ fromHDL(
+ getMission('and'),
+ source(`
+ Nand(a=a, b=a, out=gamebufferout);
+ Nand(a=gamebufferout, b=gamebufferout, out=out);
+ Not(in=b, out=gamebufferout);
+ `),
+ ),
+ ).toThrow('more than one driver');
+ });
+
+ it.each([
+ ['CHIP And { IN a; OUT out; }', 'IN a, b'],
+ ['CHIP And { IN a, a; OUT out; }', 'IN a, b'],
+ ['CHIP And { IN a, b, c; OUT out; }', 'IN a, b'],
+ ['CHIP And { IN a, b; OUT other; }', 'OUT out'],
+ ['CHIP Other { IN a, b; OUT out; }', 'Use CHIP And'],
+ [source('Nand(a=a, b=b, out=out);') + source('Nand(a=a, b=b, out=out);'), 'one CHIP'],
+ ['CHIP And { IN a, b; OUT out; BUILTIN And; }', 'BUILTIN and CLOCKED'],
+ ['CHIP And { IN a, b; OUT out; CLOCKED a; }', 'BUILTIN and CLOCKED'],
+ ['CHIP And { IN a[1], b; OUT out; }', 'single-bit'],
+ [source('Nand(a=a[0], b=b, out=out);'), 'single-bit'],
+ [source('Nand(a[0..1]=a, b=b, out=out);'), 'single-bit'],
+ [source('Nand(a=true, b=b, out=out);'), 'Constant signals'],
+ [source('Nand(a=false, b=b, out=out);'), 'Constant signals'],
+ [source('Mux(a=a, b=b, out=out);'), 'not available'],
+ [source('And(a=a, b=b, out=out);'), 'not available'],
+ [source('Nand(in=a, out=out);'), 'has no pin in'],
+ [source('Nand(a=a, a=b, out=out);'), 'connected more than once'],
+ [source('Nand(a=a, b=b, out=a);'), 'cannot be driven'],
+ [source('Nand(a=a, b=b, out=out); Not(in=a, out=out);'), 'more than one driver'],
+ [source('Nand(a=unknown, b=b, out=out);'), 'has no driver'],
+ [source('Nand(a=out, b=b, out=out);'), 'feedback'],
+ [source('Nand(a=next, b=b, out=first); Not(in=first, out=next);'), 'feedback'],
+ ])(
+ 'rejects unsupported or ambiguous HDL without accepting a partial graph: %s',
+ (hdl, message) => {
+ expect(() => fromHDL(getMission('and'), hdl)).toThrow(message);
+ },
+ );
+
+ it('reports syntax location and does not silently accept truncated source', () => {
+ expect(() => fromHDL(getMission('and'), source('\n Nand(a=a b=b, out=out);'))).toThrow(
+ 'line 2 col',
+ );
+ expect(() => fromHDL(getMission('and'), 'CHIP And { IN a, b; OUT out;')).toThrow(
+ 'closing brace',
+ );
+ expect(() => fromHDL(getMission('and'), '')).toThrow('CHIP declaration');
+ expect(() => fromHDL(getMission('and'), ' '.repeat(32_001))).toThrow('32,000 characters');
+ expect(() =>
+ fromHDL(
+ getMission('and'),
+ source(Array.from({ length: 33 }, (_, i) => `Nand(a=a, b=b, out=wire${i});`).join('\n')),
+ ),
+ ).toThrow('up to 32 parts');
+ });
+
+ it('preserves error line numbers when comments precede the invalid statement', () => {
+ expect(() =>
+ fromHDL(
+ getMission('and'),
+ `// first line\nCHIP And {
+ /* two\n lines */
+ IN a, b; OUT out;
+ PARTS: Nand(a=a b=b, out=out);
+ }`,
+ ),
+ ).toThrow('line 6 col');
+ });
+});
diff --git a/src/lib/game/circuit.ts b/src/lib/game/circuit.ts
new file mode 100644
index 0000000..25c142a
--- /dev/null
+++ b/src/lib/game/circuit.ts
@@ -0,0 +1,384 @@
+import parse from '../editor/hdl/parse';
+import type { ChipNode, IdentifierNode } from '../editor/hdl/tree';
+import ChipFactory from '../hardware-simulator/chips/ChipFactory';
+import type { GateKind, Mission, Signals, TruthCase } from './missions';
+import { truthTable } from './missions';
+
+export interface GateNode {
+ id: string;
+ type: GateKind;
+ /** Sources are input pin names or the id of an earlier gate. Empty means unwired. */
+ inputs: Record;
+}
+export interface Circuit {
+ gates: GateNode[];
+ outputs: Record;
+}
+export interface Simulation {
+ outputs: Signals;
+ signals: Signals;
+ hdl: string;
+}
+export interface TestRow extends TruthCase {
+ actual: Signals;
+ passed: boolean;
+}
+export interface TestResult {
+ rows: TestRow[];
+ passed: number;
+ total: number;
+ success: boolean;
+ hdl: string;
+}
+
+export function gatePins(type: GateKind): string[] {
+ return type === 'Not' ? ['in'] : ['a', 'b'];
+}
+
+export function createCircuit(mission: Mission): Circuit {
+ return mission.id === 'nand'
+ ? { gates: [{ id: 'g1', type: 'Nand', inputs: { a: 'a', b: 'b' } }], outputs: { out: 'g1' } }
+ : { gates: [], outputs: Object.fromEntries(mission.outputs.map((pin) => [pin, ''])) };
+}
+
+/** Draft shape validation deliberately permits unwired pins for local autosave. */
+export function isCircuitDraft(mission: Mission, value: unknown): value is Circuit {
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
+ const candidate = value as Circuit;
+ if (!Array.isArray(candidate.gates) || candidate.gates.length > 32) return false;
+ const output = candidate.outputs;
+ if (!output || typeof output !== 'object' || Array.isArray(output)) return false;
+ if (Object.keys(output).some((pin) => !mission.outputs.includes(pin))) return false;
+ if (!mission.outputs.every((pin) => typeof output[pin] === 'string' && output[pin].length < 80))
+ return false;
+ const ids = new Set();
+ for (const gate of candidate.gates) {
+ if (
+ !gate ||
+ typeof gate !== 'object' ||
+ typeof gate.id !== 'string' ||
+ !/^[A-Za-z_][A-Za-z0-9_]{0,63}$/.test(gate.id) ||
+ mission.inputs.includes(gate.id) ||
+ mission.outputs.includes(gate.id) ||
+ ids.has(gate.id) ||
+ !mission.availableParts.includes(gate.type)
+ )
+ return false;
+ ids.add(gate.id);
+ if (!gate.inputs || typeof gate.inputs !== 'object' || Array.isArray(gate.inputs)) return false;
+ const pins = gatePins(gate.type);
+ if (Object.keys(gate.inputs).some((pin) => !pins.includes(pin))) return false;
+ if (!pins.every((pin) => typeof gate.inputs[pin] === 'string' && gate.inputs[pin].length < 80))
+ return false;
+ }
+ return true;
+}
+
+export function availableSources(
+ mission: Mission,
+ circuit: Circuit,
+ beforeGateId?: string,
+): string[] {
+ const index =
+ beforeGateId === undefined
+ ? circuit.gates.length
+ : circuit.gates.findIndex((gate) => gate.id === beforeGateId);
+ return [...mission.inputs, ...circuit.gates.slice(0, Math.max(0, index)).map((gate) => gate.id)];
+}
+
+function validate(mission: Mission, circuit: Circuit, allowIncomplete = false) {
+ if (!isCircuitDraft(mission, circuit))
+ throw new Error('This circuit has invalid components. Start a fresh build.');
+ const known = new Set(mission.inputs);
+ for (const gate of circuit.gates) {
+ for (const pin of gatePins(gate.type)) {
+ const source = gate.inputs[pin];
+ if (!source && allowIncomplete) continue;
+ if (!source) throw new Error(`Connect ${gate.id} ${pin} to a signal.`);
+ if (!known.has(source))
+ throw new Error(
+ `${gate.id} ${pin} must use an input or an earlier gate. Loops are not supported.`,
+ );
+ }
+ known.add(gate.id);
+ }
+ for (const pin of mission.outputs) {
+ const source = circuit.outputs[pin];
+ if (!source && allowIncomplete) continue;
+ if (!source) throw new Error(`Connect output ${pin} to a signal.`);
+ if (!known.has(source)) throw new Error(`Output ${pin} is connected to an unknown signal.`);
+ }
+}
+
+/**
+ * The visual editor is an HDL authoring view, not a parallel toy simulator.
+ * Fan-out is expressed by repeated output connections on the same part.
+ * A direct input → output wire needs two NANDs because HDL has no wire alias syntax.
+ */
+export function toHDL(mission: Mission, circuit: Circuit): string {
+ return serializeHDL(mission, circuit, false);
+}
+
+/** Editable source for an unfinished visual board, with unwired inputs omitted. */
+export function toHDLDraft(mission: Mission, circuit: Circuit): string {
+ return serializeHDL(mission, circuit, true);
+}
+
+function serializeHDL(mission: Mission, circuit: Circuit, allowIncomplete: boolean): string {
+ validate(mission, circuit, allowIncomplete);
+ const wires = new Map(circuit.gates.map((gate, index) => [gate.id, `gamewire${index}`]));
+ const sourceName = (source: string) => wires.get(source) ?? source;
+ const lines = circuit.gates.map((gate) => {
+ const inputs = gatePins(gate.type)
+ .filter((pin) => gate.inputs[pin])
+ .map((pin) => `${pin}=${sourceName(gate.inputs[pin])}`);
+ const outputs = [
+ `out=${wires.get(gate.id)}`,
+ ...mission.outputs
+ .filter((pin) => circuit.outputs[pin] === gate.id)
+ .map((pin) => `out=${pin}`),
+ ];
+ return ` ${gate.type}(${[...inputs, ...outputs].join(', ')});`;
+ });
+ for (const pin of mission.outputs) {
+ const source = circuit.outputs[pin];
+ if (!mission.inputs.includes(source)) continue;
+ lines.push(` // Two NANDs preserve a direct input-to-output wire.`);
+ lines.push(` Nand(a=${source}, b=${source}, out=gamebuffer${pin});`);
+ lines.push(` Nand(a=gamebuffer${pin}, b=gamebuffer${pin}, out=${pin});`);
+ }
+ return [
+ `CHIP ${mission.chip} {`,
+ ` IN ${mission.inputs.join(', ')};`,
+ ` OUT ${mission.outputs.join(', ')};`,
+ '',
+ ' PARTS:',
+ ...(!lines.length ? [' // Add parts here.'] : []),
+ ...lines,
+ ...mission.outputs
+ .filter((pin) => !circuit.outputs[pin])
+ .map((pin) => ` // Connect output ${pin}.`),
+ '}',
+ ].join('\n');
+}
+
+/**
+ * Import the supported single-bit HDL subset into the same graph used by the
+ * visual editor. No circuit is changed until the whole source has been checked.
+ * Pins may be omitted while drafting; named wires must have exactly one driver.
+ */
+export function fromHDL(mission: Mission, source: string): Circuit {
+ if (source.length > 32_000) throw new Error('Keep this chip below 32,000 characters.');
+
+ // The existing language parser requires at least one statement after PARTS:.
+ // Accept an empty authoring skeleton without changing that shared grammar.
+ // Whitespace substitution preserves parser line/column positions.
+ const whitespace = (text: string) => text.replace(/[^\r\n]/g, ' ');
+ const parseable = source
+ .replace(/\/\/[^\n]*|\/\*[\s\S]*?\*\//g, whitespace)
+ .replace(/\bPARTS\s*:\s*(?=})/g, whitespace);
+ let chips: ChipNode[] | undefined;
+ try {
+ chips = parse(parseable);
+ } catch (error) {
+ const detail = error instanceof Error ? error.message.split('\n')[0] : 'Invalid syntax.';
+ throw new Error(`HDL ${detail} Check parentheses, commas and semicolons.`);
+ }
+ if (!chips?.length)
+ throw new Error('Complete the CHIP declaration, including its closing brace.');
+ if (chips.length !== 1) throw new Error('Define one CHIP at a time in this workspace.');
+ const chip = chips[0];
+ if (chip.name.value !== mission.chip)
+ throw new Error(`Use CHIP ${mission.chip} for this challenge.`);
+ if (chip.body.some((section) => !['input', 'output', 'parts'].includes(section.type)))
+ throw new Error('Use PARTS to build this chip. BUILTIN and CLOCKED are not supported here.');
+
+ function checkScalar(pin: IdentifierNode) {
+ if ('width' in pin || 'length' in pin || 'selection' in pin)
+ throw new Error(
+ 'This layer uses single-bit pins. Buses and bit selections are not supported.',
+ );
+ if (pin.value === 'true' || pin.value === 'false')
+ throw new Error(
+ 'Constant signals are not supported here. Connect an input or a part output.',
+ );
+ }
+
+ for (const direction of ['input', 'output'] as const) {
+ const pins = chip.body.flatMap((section) => (section.type === direction ? section.pins : []));
+ pins.forEach(checkScalar);
+ const expected = direction === 'input' ? mission.inputs : mission.outputs;
+ const names = pins.map((pin) => pin.value);
+ if (
+ names.length !== expected.length ||
+ new Set(names).size !== expected.length ||
+ !expected.every((pin) => names.includes(pin))
+ )
+ throw new Error(
+ `Declare exactly ${direction === 'input' ? 'IN' : 'OUT'} ${expected.join(', ')}; for ${mission.chip}.`,
+ );
+ }
+
+ const statements = chip.body.flatMap((section) =>
+ section.type === 'parts' ? section.statements : [],
+ );
+ // A visual wire to an external output is exported as two NANDs. Keep a hard
+ // parser bound while allowing those adapters in addition to 32 authored parts.
+ if (statements.length > 32 + mission.outputs.length * 2)
+ throw new Error('This workspace supports up to 32 parts per chip.');
+ const drivers = new Map();
+ const parts = statements.map((statement, index) => {
+ const type = statement.chip.value as GateKind;
+ if (!mission.availableParts.includes(type))
+ throw new Error(
+ `${type} is not available for ${mission.chip}. Use ${mission.availableParts.join(', ')}.`,
+ );
+ const inputPins = gatePins(type);
+ const inputs: Record = Object.fromEntries(inputPins.map((pin) => [pin, '']));
+ for (const connection of statement.connections) {
+ checkScalar(connection.left);
+ checkScalar(connection.right);
+ const pin = connection.left.value;
+ const wire = connection.right.value;
+ if (pin === 'out') {
+ if (mission.inputs.includes(wire))
+ throw new Error(`Input ${wire} cannot be driven by a part output.`);
+ if (drivers.has(wire) && drivers.get(wire) !== index)
+ throw new Error(
+ `Signal ${wire} has more than one driver. Give each part its own output wire.`,
+ );
+ drivers.set(wire, index);
+ } else if (inputPins.includes(pin)) {
+ if (inputs[pin]) throw new Error(`${type} input ${pin} is connected more than once.`);
+ inputs[pin] = wire;
+ } else {
+ throw new Error(`${type} has no pin ${pin}. Use ${[...inputPins, 'out'].join(', ')}.`);
+ }
+ }
+ return { type, inputs };
+ });
+
+ // Resolve all drivers before sorting, so HDL declaration order is unrestricted.
+ for (const part of parts) {
+ for (const wire of Object.values(part.inputs)) {
+ if (wire && !mission.inputs.includes(wire) && !drivers.has(wire))
+ throw new Error(
+ `Signal ${wire} has no driver. Connect it to a part output or use a chip input.`,
+ );
+ }
+ }
+
+ // Recover only the exact adapters emitted by serializeHDL. Validate all source
+ // statements first, and require exclusive ownership of both intermediate and
+ // output wires so no authored fan-out or aliases can disappear in conversion.
+ const adapters = new Set();
+ const directOutputs = new Map();
+ for (const output of mission.outputs) {
+ const buffer = `gamebuffer${output}`;
+ const first = drivers.get(buffer);
+ const last = drivers.get(output);
+ if (first === undefined || last === undefined || first === last) continue;
+ const before = parts[first];
+ const after = parts[last];
+ const exactNand = (index: number, a: string, b: string, out: string) =>
+ statements[index].chip.value === 'Nand' &&
+ statements[index].connections.length === 3 &&
+ statements[index].connections.every(
+ ({ left, right }) =>
+ (left.value === 'a' && right.value === a) ||
+ (left.value === 'b' && right.value === b) ||
+ (left.value === 'out' && right.value === out),
+ );
+ if (
+ !mission.inputs.includes(before.inputs.a) ||
+ before.inputs.a !== before.inputs.b ||
+ after.inputs.a !== buffer ||
+ after.inputs.b !== buffer ||
+ !exactNand(first, before.inputs.a, before.inputs.a, buffer) ||
+ !exactNand(last, buffer, buffer, output) ||
+ parts.some((part, index) =>
+ Object.values(part.inputs).some(
+ (wire) => wire === output || (wire === buffer && index !== last),
+ ),
+ )
+ )
+ continue;
+ adapters.add(first);
+ adapters.add(last);
+ directOutputs.set(output, before.inputs.a);
+ }
+ if (parts.length - adapters.size > 32)
+ throw new Error('This workspace supports up to 32 parts per chip.');
+
+ const order: number[] = [];
+ const pending = new Set(parts.map((_, index) => index).filter((index) => !adapters.has(index)));
+ while (pending.size) {
+ const ready = [...pending].find((index) =>
+ Object.values(parts[index].inputs).every(
+ (wire) => !wire || mission.inputs.includes(wire) || !pending.has(drivers.get(wire)!),
+ ),
+ );
+ if (ready === undefined)
+ throw new Error('This circuit contains feedback. Connect signals forward through the parts.');
+ order.push(ready);
+ pending.delete(ready);
+ }
+ const ids = new Map(order.map((index, position) => [index, `g${position + 1}`]));
+ const resolve = (wire: string) =>
+ !wire || mission.inputs.includes(wire) ? wire : ids.get(drivers.get(wire)!)!;
+ const circuit: Circuit = {
+ gates: order.map((index) => ({
+ id: ids.get(index)!,
+ type: parts[index].type,
+ inputs: Object.fromEntries(
+ Object.entries(parts[index].inputs).map(([pin, wire]) => [pin, resolve(wire)]),
+ ),
+ })),
+ outputs: Object.fromEntries(
+ mission.outputs.map((pin) => [
+ pin,
+ directOutputs.get(pin) ?? (drivers.has(pin) ? resolve(pin) : ''),
+ ]),
+ ),
+ };
+ validate(mission, circuit, true);
+ return circuit;
+}
+
+function compile(mission: Mission, circuit: Circuit) {
+ const hdl = toHDL(mission, circuit);
+ const ast = parse(hdl)?.[0];
+ if (!ast) throw new Error('The generated circuit could not be parsed.');
+ return { chip: new ChipFactory().fromAST(ast), hdl };
+}
+
+export function simulateCircuit(mission: Mission, circuit: Circuit, inputs: Signals): Simulation {
+ const { chip, hdl } = compile(mission, circuit);
+ for (const pin of mission.inputs) {
+ if (typeof inputs[pin] !== 'boolean') throw new Error(`Input ${pin} needs an on/off value.`);
+ chip.setInput(pin, inputs[pin]);
+ }
+ chip.run();
+ const signals: Signals = { ...inputs };
+ circuit.gates.forEach((gate, index) => {
+ signals[gate.id] = chip.getPins().get(`gamewire${index}`)?.state ?? false;
+ });
+ const outputs = Object.fromEntries(mission.outputs.map((pin) => [pin, chip.getOutput(pin)]));
+ return { outputs, signals, hdl };
+}
+
+/** Fresh simulation instances avoid carrying state between exhaustive truth cases. */
+export function testCircuit(mission: Mission, circuit: Circuit): TestResult {
+ const hdl = toHDL(mission, circuit);
+ const rows = truthTable(mission).map(({ inputs, expected }) => {
+ const actual = simulateCircuit(mission, circuit, inputs).outputs;
+ return {
+ inputs,
+ expected,
+ actual,
+ passed: mission.outputs.every((pin) => actual[pin] === expected[pin]),
+ };
+ });
+ const passed = rows.filter((row) => row.passed).length;
+ return { rows, passed, total: rows.length, success: passed === rows.length, hdl };
+}
diff --git a/src/lib/game/missions.ts b/src/lib/game/missions.ts
new file mode 100644
index 0000000..d27a564
--- /dev/null
+++ b/src/lib/game/missions.ts
@@ -0,0 +1,219 @@
+/** First layer, adapted from the existing Boolean Logic project. */
+export type MissionId = 'nand' | 'not' | 'and' | 'or' | 'xor' | 'mux' | 'dmux';
+export type GateKind = 'Nand' | 'Not' | 'And' | 'Or' | 'Xor';
+export type Signals = Record;
+
+export interface Mission {
+ id: MissionId;
+ chip: string;
+ number: number;
+ title: string;
+ location: string;
+ brief: string;
+ goal: string;
+ inputs: string[];
+ outputs: string[];
+ availableParts: GateKind[];
+ hints: string[];
+ explanation: string;
+ reward: string;
+ prerequisite: MissionId | null;
+}
+
+export const missions: Mission[] = [
+ {
+ id: 'nand',
+ chip: 'Nand',
+ number: 1,
+ title: 'Read the signal',
+ location: 'NAND primitive',
+ brief:
+ 'Two inputs. One output. Probe the NAND primitive and identify the only combination that produces a low signal.',
+ goal: 'Discover the output for all four switch combinations.',
+ inputs: ['a', 'b'],
+ outputs: ['out'],
+ availableParts: ['Nand'],
+ hints: [
+ 'Try each switch separately. What happens when both are on?',
+ 'NAND means NOT AND. Its output is off only when both inputs are on.',
+ ],
+ explanation:
+ 'A bit has two states: 0 (off) and 1 (on). A NAND gate outputs 1 for every input pair except 1,1. You start with this supplied primitive: it is the building block for everything in this layer.',
+ reward: 'NAND characterized. One primitive is enough to build every gate in this layer.',
+ prerequisite: null,
+ },
+ {
+ id: 'not',
+ chip: 'Not',
+ number: 2,
+ title: 'Invert a signal',
+ location: 'Inversion',
+ brief: 'Turn 0 into 1 and 1 into 0. Build an inverter using the NAND primitive.',
+ goal: 'Build an output that is always the opposite of input in.',
+ inputs: ['in'],
+ outputs: ['out'],
+ availableParts: ['Nand'],
+ hints: [
+ 'A NAND has two input pins. They can both receive the same signal.',
+ 'Look at the NAND cases 0,0 and 1,1. Can those two cases give you an inverter?',
+ ],
+ explanation:
+ 'NOT reverses a bit: 0 becomes 1 and 1 becomes 0. A gate input can feed more than one pin. This is called fan-out. Connecting one signal to both NAND inputs gives the behavior you need.',
+ reward: 'NOT verified. You can now invert any single-bit signal.',
+ prerequisite: 'nand',
+ },
+ {
+ id: 'and',
+ chip: 'And',
+ number: 3,
+ title: 'Combine conditions',
+ location: 'Conjunction',
+ brief:
+ 'A high output requires both inputs to be high. Compose a gate that implements this condition.',
+ goal: 'Output 1 only when a and b are both 1.',
+ inputs: ['a', 'b'],
+ outputs: ['out'],
+ availableParts: ['Nand', 'Not'],
+ hints: [
+ 'NAND already responds to both switches. What is different about its output?',
+ 'Try sending the NAND output through your inverter.',
+ ],
+ explanation:
+ 'AND outputs 1 only if both inputs are 1. NAND has exactly the opposite behavior, so inverting NAND produces AND. Internal connections let one chip feed another.',
+ reward: 'AND verified. Two conditions now control one output.',
+ prerequisite: 'not',
+ },
+ {
+ id: 'or',
+ chip: 'Or',
+ number: 4,
+ title: 'Merge two signals',
+ location: 'Disjunction',
+ brief:
+ 'Either input can drive the output high. Build the gate that stays low only when both inputs are low.',
+ goal: 'Output 1 when a, b, or both are 1.',
+ inputs: ['a', 'b'],
+ outputs: ['out'],
+ availableParts: ['Nand', 'Not', 'And'],
+ hints: [
+ 'Start with the only case that must give 0: a=0 and b=0.',
+ 'What happens if you invert both inputs before feeding them into NAND?',
+ ],
+ explanation:
+ 'OR outputs 1 when at least one input is 1. De Morgan’s law says NOT(NOT(a) AND NOT(b)) equals a OR b. Different networks can implement the same truth table: all correct constructions are accepted.',
+ reward: 'OR verified. Either input can now drive the output.',
+ prerequisite: 'and',
+ },
+ {
+ id: 'xor',
+ chip: 'Xor',
+ number: 5,
+ title: 'Detect a difference',
+ location: 'Exclusive OR',
+ brief:
+ 'Compare two bits. Produce a high signal when they differ, and a low signal when they match.',
+ goal: 'Output 1 when exactly one of a and b is 1.',
+ inputs: ['a', 'b'],
+ outputs: ['out'],
+ availableParts: ['Nand', 'Not', 'And', 'Or'],
+ hints: [
+ 'OR finds cases where at least one input is on, but also includes 1,1.',
+ 'Combine “at least one is on” with “not both are on”.',
+ ],
+ explanation:
+ 'XOR means exclusive OR. Its output is 1 for 0,1 and 1,0, but 0 for 0,0 and 1,1. One construction is (a OR b) AND NOT(a AND b). NAND-only solutions also work.',
+ reward: 'XOR verified. Your circuit detects a difference between two bits.',
+ prerequisite: 'or',
+ },
+ {
+ id: 'mux',
+ chip: 'Mux',
+ number: 6,
+ title: 'Select a data path',
+ location: 'Multiplexing',
+ brief:
+ 'Two data inputs share one output. Use a control bit to select which signal passes through.',
+ goal: 'When sel=0, out=a. When sel=1, out=b.',
+ inputs: ['a', 'b', 'sel'],
+ outputs: ['out'],
+ availableParts: ['Nand', 'Not', 'And', 'Or', 'Xor'],
+ hints: [
+ 'Make two paths: one for channel a and one for channel b. Only one path should be enabled at a time.',
+ 'Enable a with NOT(sel), enable b with sel, then combine their outputs.',
+ ],
+ explanation:
+ 'A multiplexor selects one of its data inputs. The selector is a control bit, not a data channel. There are eight possible input combinations, and your circuit must handle all eight. It can be composed from the elementary gates you have already built.',
+ reward: 'Mux verified. A control signal now selects the active data path.',
+ prerequisite: 'xor',
+ },
+ {
+ id: 'dmux',
+ chip: 'DMux',
+ number: 7,
+ title: 'Route a signal',
+ location: 'Demultiplexing',
+ brief:
+ 'Route one input to one of two outputs. The selector chooses the destination; the other output stays low.',
+ goal: 'Route in to a if sel=0, or to b if sel=1.',
+ inputs: ['in', 'sel'],
+ outputs: ['a', 'b'],
+ availableParts: ['Nand', 'Not', 'And', 'Or', 'Xor'],
+ hints: [
+ 'Unlike the last machine, this one has one data input and two outputs.',
+ 'Each output needs its own enable condition. What enables a? What enables b?',
+ ],
+ explanation:
+ 'A demultiplexor routes one input to a selected output. For a two-way DMux: a = in AND NOT(sel), and b = in AND sel. These are separate output pins. Both must be correct in every case.',
+ reward: 'DMux verified. All seven logic challenges are complete.',
+ prerequisite: 'mux',
+ },
+];
+
+export function getMission(id: string): Mission {
+ const mission = missions.find((item) => item.id === id);
+ if (!mission) throw new Error(`Unknown mission: ${id}`);
+ return mission;
+}
+
+export interface TruthCase {
+ inputs: Signals;
+ expected: Signals;
+}
+
+/** Exhaustive single-bit specifications, independent from the circuit under test. */
+export function truthTable(mission: Mission): TruthCase[] {
+ return Array.from({ length: 2 ** mission.inputs.length }, (_, index) => {
+ const inputs = Object.fromEntries(
+ mission.inputs.map((pin, offset) => [
+ pin,
+ Boolean(index & (1 << (mission.inputs.length - offset - 1))),
+ ]),
+ );
+ const { a, b, in: input, sel } = inputs;
+ let expected: Signals;
+ switch (mission.id) {
+ case 'nand':
+ expected = { out: !(a && b) };
+ break;
+ case 'not':
+ expected = { out: !input };
+ break;
+ case 'and':
+ expected = { out: a && b };
+ break;
+ case 'or':
+ expected = { out: a || b };
+ break;
+ case 'xor':
+ expected = { out: a !== b };
+ break;
+ case 'mux':
+ expected = { out: sel ? b : a };
+ break;
+ case 'dmux':
+ expected = { a: input && !sel, b: input && sel };
+ break;
+ }
+ return { inputs, expected };
+ });
+}
diff --git a/src/lib/hardware-simulator/chips/CustomChip.test.ts b/src/lib/hardware-simulator/chips/CustomChip.test.ts
index ae3ac41..004e5fe 100644
--- a/src/lib/hardware-simulator/chips/CustomChip.test.ts
+++ b/src/lib/hardware-simulator/chips/CustomChip.test.ts
@@ -3,6 +3,7 @@ import { describe, expect, it } from 'vitest';
import type { ChipPin } from './Chip';
import type Chip from './Chip';
import NotChip from './builtin/NotChip';
+import NandChip from './builtin/NandChip';
import CustomChip from './CustomChip';
const name = 'Foo';
@@ -98,4 +99,47 @@ describe('Custom Chip', () => {
expect(() => chip.run()).toThrowError(`Implementation contains a loop`);
});
+
+ it.each([13, 24])(
+ 'evaluates a %i-stage NAND inverter chain without mistaking fan-out for a loop',
+ (length) => {
+ const gates = Array.from({ length }, () => new NandChip());
+ const chainPins = new Map([
+ [
+ 'in',
+ {
+ state: false,
+ type: 'input',
+ connections: [
+ [gates[0], 'a'],
+ [gates[0], 'b'],
+ ],
+ },
+ ],
+ ['out', { state: false, type: 'output', connections: [] }],
+ ]);
+ const chainParts = new Map();
+ gates.forEach((gate, index) => {
+ const wire = index === length - 1 ? 'out' : `wire${index}`;
+ if (wire !== 'out') {
+ chainPins.set(wire, {
+ state: false,
+ type: 'internal',
+ connections: [
+ [gates[index + 1], 'a'],
+ [gates[index + 1], 'b'],
+ ],
+ });
+ }
+ chainParts.set(gate, [['out', wire]]);
+ });
+ const chip = new CustomChip('InverterChain', chainPins, chainParts);
+
+ for (const input of [false, true, false]) {
+ chip.setInput('in', input);
+ chip.run();
+ expect(chip.getOutput('out')).toBe(length % 2 === 0 ? input : !input);
+ }
+ },
+ );
});
diff --git a/src/lib/hardware-simulator/chips/CustomChip.ts b/src/lib/hardware-simulator/chips/CustomChip.ts
index 7886c15..37fbf91 100644
--- a/src/lib/hardware-simulator/chips/CustomChip.ts
+++ b/src/lib/hardware-simulator/chips/CustomChip.ts
@@ -87,14 +87,19 @@ class CustomChip implements Chip {
public run() {
// Execute using breadth-first exploring
const queue = new Denque();
+ const pending = new Set();
const explore = (pin: ChipPin) => {
for (const [chip, pinName] of pin.connections) {
// Set chip internal pin state
chip.setInput(pinName, pin.state);
- // Plan to visit the connected chip next
- queue.push(chip);
+ // A signal may feed several pins on the same chip. Update every pin,
+ // but evaluate a pending chip only once with its latest input values.
+ if (!pending.has(chip)) {
+ pending.add(chip);
+ queue.push(chip);
+ }
}
};
@@ -110,6 +115,9 @@ class CustomChip implements Chip {
let next = queue.shift();
while (next) {
+ // Remove before running so feedback can schedule another evaluation;
+ // real loops must still reach the iteration guard below.
+ pending.delete(next);
// 1. Run the chip logic
next.run();
diff --git a/src/lib/hardware-simulator/examples/ExerciseAnd.ts b/src/lib/hardware-simulator/examples/ExerciseAnd.ts
index 63aba26..a2ba3c5 100644
--- a/src/lib/hardware-simulator/examples/ExerciseAnd.ts
+++ b/src/lib/hardware-simulator/examples/ExerciseAnd.ts
@@ -4,7 +4,7 @@ export default {
id: 'ExerciseAnd',
name: 'Exercise - And',
code: `/**
- * Not gate
+ * And gate
*
* If a=b=1 then out=1 else out=0.
*/
diff --git a/src/lib/learning/ReferenceContent.svelte b/src/lib/learning/ReferenceContent.svelte
new file mode 100644
index 0000000..ac5cd7b
--- /dev/null
+++ b/src/lib/learning/ReferenceContent.svelte
@@ -0,0 +1,38 @@
+
+
+{#each children as node}
+ {#if typeof node === 'string' || typeof node === 'number'}
+ {node}
+ {:else if isTag(node)}
+ {#if node.name === 'table'}
+
+
+
+ {:else if node.name === 'th'}
+
+ {:else if node.name === 'pre'}
+
+
+
+ {:else if node.children?.length}
+
+
+
+ {:else}
+
+ {/if}
+ {/if}
+{/each}
diff --git a/src/lib/learning/reference.ts b/src/lib/learning/reference.ts
new file mode 100644
index 0000000..72d431a
--- /dev/null
+++ b/src/lib/learning/reference.ts
@@ -0,0 +1,58 @@
+export const referencePages = [
+ {
+ path: 'boolean-logic',
+ source: 'boolean-logic/intro',
+ label: 'Overview',
+ title: 'From signals to logic',
+ },
+ {
+ path: 'boolean-logic/background',
+ source: 'boolean-logic/background',
+ label: 'The explanation',
+ title: 'Logic, composition, and HDL',
+ },
+ {
+ path: 'boolean-logic/project',
+ source: 'boolean-logic/project',
+ label: 'Gate contracts',
+ title: 'Gate contracts and larger buses',
+ },
+ {
+ path: 'boolean-arithmetic',
+ source: 'boolean-arithmetic/intro',
+ label: 'Arithmetic and the ALU',
+ title: 'From bits to arithmetic',
+ },
+ {
+ path: 'memory',
+ source: 'memory/intro',
+ label: 'Memory and clocks',
+ title: 'Give the machine a memory',
+ },
+ {
+ path: 'machine-language',
+ source: 'machine-language/intro',
+ label: 'Machine language',
+ title: 'Tell the machine what to do',
+ },
+ {
+ path: 'computer-architecture',
+ source: 'computer-architecture/intro',
+ label: 'Computer architecture',
+ title: 'Put the computer together',
+ },
+ {
+ path: 'assembler',
+ source: 'assembler/intro',
+ label: 'The assembler',
+ title: 'Turn symbols into instructions',
+ },
+ {
+ path: 'meta/what-next',
+ source: 'meta/what-next',
+ label: 'What comes next',
+ title: 'Beyond the assembler',
+ },
+] as const;
+
+export const referenceUrl = (path: string) => `/learn/reference/${path}`;
diff --git a/src/lib/software/FileEditor.svelte b/src/lib/software/FileEditor.svelte
new file mode 100644
index 0000000..a9e4a7b
--- /dev/null
+++ b/src/lib/software/FileEditor.svelte
@@ -0,0 +1,121 @@
+
+
+
+ Source file{#each Object.keys(files) as name (name)}{name} {/each}
+
+Source code
+
+ Project files
+
+ New file name Add file
+
+
+ Import source files Remove selected file
+
+
+{#if error}{error}
{/if}
diff --git a/src/lib/software/index.test.ts b/src/lib/software/index.test.ts
new file mode 100644
index 0000000..350553a
--- /dev/null
+++ b/src/lib/software/index.test.ts
@@ -0,0 +1,278 @@
+import { afterEach, describe, expect, it, vi } from 'vitest';
+import { compileJack, createVM, SoftwareError } from './index';
+
+afterEach(() => {
+ vi.useRealTimers();
+ vi.unstubAllGlobals();
+});
+describe('Reference-backed Jack compiler', () => {
+ it('compiles and executes constructors, methods, arrays, loops, strings and native OS services across files', () => {
+ const result = compileJack({
+ 'Counter.jack': `class Counter {
+ field int value;
+ constructor Counter new(int start) { let value = start; return this; }
+ method void inc() { let value = value + 1; return; }
+ method int get() { return value; }
+ }`,
+ 'Main.jack': `class Main {
+ function void main() {
+ var Counter counter;
+ var Array values;
+ var int i, total;
+ let counter = Counter.new(7);
+ do counter.inc();
+ let values = Array.new(3);
+ let values[1] = counter.get();
+ let total = 0;
+ let i = 0;
+ while (i < 3) { let total = total + values[1]; let i = i + 1; }
+ if (total = 24) { do Memory.poke(1000, total); }
+ else { do Memory.poke(1000, 99); }
+ do Output.printString("Hi");
+ do Screen.setColor(true);
+ do Screen.drawPixel(10, 10);
+ do Memory.poke(1001, Keyboard.keyPressed());
+ do values.dispose();
+ return;
+ }
+ }`,
+ });
+ expect(result.errors).toEqual([]);
+ expect(Object.keys(result.files)).toEqual(['Counter.vm', 'Main.vm']);
+ expect(result.files['Counter.vm']).toContain('call Memory.alloc 1');
+ expect(result.files['Main.vm']).toContain('call Counter.inc 1');
+ const vm = createVM(result.files);
+ vm.setKeyboard(65);
+ vm.run(2000);
+ expect(vm.halted).toBe(true);
+ expect(vm.read(1000)).toBe(24);
+ expect(vm.read(1001)).toBe(65);
+ expect(vm.screen).toHaveLength(8192);
+ expect(vm.screen[320] & (1 << 10)).toBe(1 << 10);
+ expect(vm.screen.slice(0, 256).some(Boolean)).toBe(true);
+ vm.dispose();
+ });
+ it('reports original file and line for syntax and semantic errors without retaining partial compiled output', () => {
+ const syntax = compileJack({
+ 'Main.jack': 'class Main {\n function void main( { return; }\n}',
+ });
+ expect(syntax.errors[0]).toMatchObject({ file: 'Main.jack', line: 2 });
+ expect(syntax.errors[0].column).toBeGreaterThan(1);
+ expect(syntax.files).toEqual({});
+ const semantic = compileJack({
+ Other: 'class Other { function int valid() { return 1; } }',
+ Main: 'class Main { function void main() { let missing = 5; return; } }',
+ });
+ expect(semantic.errors[0].message).toContain('Undeclared variable');
+ expect(semantic.files).toEqual({});
+ expect(
+ compileJack({ Main: 'class Wrong { function void main() { return; } }' }).errors[0].message,
+ ).toContain("doesn't match");
+ });
+ it('validates file names, duplicate classes and bounded project sizes', () => {
+ expect(compileJack({}).errors[0].message).toContain('Add a Jack class');
+ expect(compileJack({ '../Main.jack': '' }).errors[0].message).toContain('class filename');
+ expect(compileJack({ Main: '', 'Main.jack': '' }).errors[0].message).toContain(
+ 'more than once',
+ );
+ expect(compileJack({ Main: ' '.repeat(1_000_001) }).errors[0].message).toContain('one million');
+ expect(
+ compileJack(Object.fromEntries(Array.from({ length: 101 }, (_, i) => [`File${i}`, ''])))
+ .errors[0].message,
+ ).toContain('100 source files');
+ });
+});
+
+describe('Reference-backed VM emulator', () => {
+ it('steps arithmetic with signed 16-bit values and exposes instruction, segments and stack', () => {
+ const vm = createVM({
+ Main: 'push constant 7\npush constant 8\nadd\npush constant 15\neq\nnot\npush constant 2\nsub\nneg',
+ });
+ expect(vm.current).toMatchObject({ file: 'Main.vm', line: 1, command: 'push constant 7' });
+ expect(vm.segments.SP).toBe(256);
+ expect(vm.callStack).toEqual(['__implicit']);
+ vm.step();
+ expect(vm.stack).toEqual([7]);
+ vm.step();
+ expect(vm.stack).toEqual([7, 8]);
+ vm.step();
+ expect(vm.stack).toEqual([15]);
+ vm.run(100);
+ expect(vm.stack).toEqual([2]);
+ expect(vm.halted).toBe(true);
+ expect(vm.current).toBeNull();
+ const count = vm.cycles;
+ vm.step();
+ expect(vm.cycles).toBe(count);
+ vm.reset();
+ expect(vm.cycles).toBe(0);
+ expect(vm.stack).toEqual([]);
+ vm.run(0);
+ expect(vm.cycles).toBe(0);
+ vm.dispose();
+ expect(vm.halted).toBe(true);
+ });
+ it('runs every segment and function-scoped branching/call/return with independent file statics', () => {
+ const vm = createVM({
+ 'Sys.vm': `function Sys.init 0
+ push constant 7
+ call Worker.twice 1
+ pop temp 0
+ push constant 11
+ pop static 0
+ push static 0
+ pop temp 1
+ push constant 0
+ call Sys.halt 0`,
+ 'Worker.vm': `function Worker.twice 1
+ push argument 0
+ pop local 0
+ push constant 3000
+ pop pointer 0
+ push constant 3010
+ pop pointer 1
+ push local 0
+ pop this 2
+ push this 2
+ pop that 3
+ push that 3
+ push constant 2
+ call Math.multiply 2
+ pop static 0
+ push static 0
+ push constant 14
+ eq
+ if-goto CORRECT
+ push constant 99
+ goto END
+ label CORRECT
+ push static 0
+ label END
+ return`,
+ });
+ vm.run(100);
+ expect(vm.halted).toBe(true);
+ expect(vm.read(5)).toBe(14);
+ expect(vm.read(6)).toBe(11);
+ expect(vm.read(3002)).toBe(7);
+ expect(vm.read(3013)).toBe(7);
+ expect(vm.segments.THIS).toBe(0);
+ vm.dispose();
+ });
+ it('rejects VM syntax, invalid names, duplicate definitions and bad calls', () => {
+ expect(() => createVM({})).toThrow('Add a VM file');
+ expect(() => createVM({ 'bad/name.vm': '' })).toThrow(SoftwareError);
+ expect(() => createVM({ Main: 'invalid instruction' })).toThrow(SoftwareError);
+ expect(() => createVM({ Main: 'function Other.f 0\nreturn' })).toThrow("doesn't match");
+ expect(() => createVM({ Main: 'call Missing.f 0' })).toThrow('Undefined function');
+ expect(() => createVM({ Main: 'call Math.multiply 1' })).toThrow('expects');
+ expect(() => createVM({ Main: 'pop pointer 2' })).toThrow();
+ });
+ it('reports runtime failures at their source line and can reset afterward', () => {
+ const vm = createVM({ Main: '// input\npop temp 0' });
+ expect(() => vm.step()).toThrow('Main.vm:2:');
+ expect(vm.halted).toBe(true);
+ vm.reset();
+ expect(vm.halted).toBe(false);
+ vm.dispose();
+ });
+ it('validates memory editing, run bounds and keyboard input', () => {
+ const vm = createVM({ Main: 'push constant 1' });
+ vm.write(100, -1);
+ expect(vm.read(100)).toBe(-1);
+ vm.setKeyboard(130);
+ expect(vm.read(24576)).toBe(130);
+ expect(() => vm.write(24576, 0)).toThrow('read-only');
+ for (const invalid of [-1, 24577, 0.5, NaN])
+ expect(() => vm.read(invalid)).toThrow('memory address');
+ for (const invalid of [-32769, 65536, 0.5, NaN])
+ expect(() => vm.write(0, invalid)).toThrow('16-bit');
+ for (const invalid of [-1, 32768, 0.5, NaN])
+ expect(() => vm.setKeyboard(invalid)).toThrow('Keyboard code');
+ for (const invalid of [-1, 100001, 0.5, NaN])
+ expect(() => vm.run(invalid)).toThrow('VM operations');
+ vm.dispose();
+ });
+ it('yields for Sys.wait and cancels pending timers on reset and disposal', () => {
+ vi.useFakeTimers();
+ const vm = createVM({ Main: 'push constant 10\ncall Sys.wait 1\npush constant 9\npop temp 0' });
+ vm.run(10);
+ expect(vm.blocked).toBe(true);
+ const cycles = vm.cycles;
+ vm.step();
+ expect(vm.cycles).toBe(cycles);
+ vi.advanceTimersByTime(10);
+ expect(vm.blocked).toBe(false);
+ vm.run(10);
+ expect(vm.read(5)).toBe(9);
+ vm.reset();
+ vm.run(10);
+ expect(vi.getTimerCount()).toBe(1);
+ vm.reset();
+ expect(vi.getTimerCount()).toBe(0);
+ vm.run(10);
+ vm.dispose();
+ expect(vi.getTimerCount()).toBe(0);
+ });
+ it('clears only the screen and reports OS errors for pixels beyond either screen edge', () => {
+ const vm = createVM({ Main: 'call Screen.clearScreen 0' });
+ vm.write(9000, 123);
+ vm.write(16384, -1);
+ vm.write(24575, -1);
+ vm.setKeyboard(65);
+ vm.run(10);
+ expect(vm.read(9000)).toBe(123);
+ expect(vm.read(24576)).toBe(65);
+ expect(vm.screen).toHaveLength(8192);
+ expect(vm.screen.every((value) => value === 0)).toBe(true);
+ vm.dispose();
+ for (const [x, y] of [
+ [512, 0],
+ [0, 256],
+ ]) {
+ const invalid = createVM({
+ Main: `push constant ${x}\npush constant ${y}\ncall Screen.drawPixel 2`,
+ });
+ expect(() => invalid.run(10)).toThrow('Main.vm:3: Jack OS stopped with error');
+ expect(invalid.halted).toBe(true);
+ invalid.dispose();
+ }
+ });
+ it('resumes Keyboard.readChar only after release and cancels animation frames when disposed', async () => {
+ let id = 0;
+ const frames = new Map();
+ vi.stubGlobal('requestAnimationFrame', (callback: FrameRequestCallback) => {
+ frames.set(++id, callback);
+ return id;
+ });
+ vi.stubGlobal('cancelAnimationFrame', (frame: number) => frames.delete(frame));
+ const tick = () => {
+ const callbacks = [...frames.values()];
+ frames.clear();
+ callbacks.forEach((callback) => callback(0));
+ };
+ const vm = createVM({ Main: 'call Keyboard.readChar 0\npop temp 0' });
+ vm.run(10);
+ expect(vm.blocked).toBe(true);
+ expect(frames.size).toBe(1);
+ vm.setKeyboard(65);
+ tick();
+ await Promise.resolve();
+ expect(vm.blocked).toBe(true);
+ vm.setKeyboard(0);
+ tick();
+ await Promise.resolve();
+ expect(vm.blocked).toBe(false);
+ vm.run(10);
+ expect(vm.read(5)).toBe(65);
+ expect(frames.size).toBe(0);
+ vm.reset();
+ vm.run(10);
+ expect(frames.size).toBe(1);
+ vm.reset();
+ expect(frames.size).toBe(0);
+ vm.run(10);
+ vm.dispose();
+ expect(frames.size).toBe(0);
+ });
+});
diff --git a/src/lib/software/index.ts b/src/lib/software/index.ts
new file mode 100644
index 0000000..db4df2c
--- /dev/null
+++ b/src/lib/software/index.ts
@@ -0,0 +1,210 @@
+import { Err, isErr, Ok } from '@davidsouther/jiffies/result.ts';
+import { compile } from './vendor/nand2tetris/jack/compiler.js';
+import { VM } from './vendor/nand2tetris/languages/vm.js';
+import type { VmInstruction } from './vendor/nand2tetris/languages/vm.js';
+import type { CompilationError } from './vendor/nand2tetris/languages/base.js';
+import { Vm } from './vendor/nand2tetris/vm/vm.js';
+
+export interface SoftwareDiagnostic {
+ file: string;
+ line: number;
+ column: number;
+ message: string;
+}
+export class SoftwareError extends Error {
+ constructor(public readonly diagnostics: SoftwareDiagnostic[]) {
+ super(diagnostics.map((item) => `${item.file}:${item.line}: ${item.message}`).join('\n'));
+ this.name = 'SoftwareError';
+ }
+}
+function diagnostic(file: string, source: string, error: CompilationError): SoftwareDiagnostic {
+ const start = error.span?.start ?? 0;
+ return {
+ file,
+ line: error.span?.line ?? 1,
+ column: start - source.lastIndexOf('\n', Math.max(0, start - 1)),
+ message: error.message || 'Unable to process this source.',
+ };
+}
+function normalizeFiles(
+ files: Record,
+ extension: 'jack' | 'vm',
+): Record {
+ const normalized: Record = Object.create(null);
+ if (Object.keys(files).length > 100) throw new Error('Load up to 100 source files at a time.');
+ for (const [filename, source] of Object.entries(files)) {
+ const name = filename.replace(new RegExp(`\\.${extension}$`), '');
+ if (
+ !/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) ||
+ ['__proto__', 'constructor', 'prototype'].includes(name)
+ )
+ throw new SoftwareError([
+ {
+ file: filename,
+ line: 1,
+ column: 1,
+ message: `Use a class filename such as Main.${extension}.`,
+ },
+ ]);
+ if (Object.hasOwn(normalized, name))
+ throw new SoftwareError([
+ { file: filename, line: 1, column: 1, message: 'This class is loaded more than once.' },
+ ]);
+ if (source.length > 1_000_000)
+ throw new Error('Each source file must be smaller than one million characters.');
+ normalized[name] = source;
+ }
+ return normalized;
+}
+export function compileJack(files: Record): {
+ files: Record;
+ errors: SoftwareDiagnostic[];
+} {
+ let normalized: Record;
+ try {
+ normalized = normalizeFiles(files, 'jack');
+ } catch (error) {
+ return {
+ files: {},
+ errors:
+ error instanceof SoftwareError
+ ? error.diagnostics
+ : [{ file: 'Project', line: 1, column: 1, message: (error as Error).message }],
+ };
+ }
+ if (!Object.keys(normalized).length)
+ return {
+ files: {},
+ errors: [{ file: 'Project', line: 1, column: 1, message: 'Add a Jack class to compile.' }],
+ };
+ const results = compile(normalized),
+ output: Record = {},
+ errors: SoftwareDiagnostic[] = [];
+ for (const [name, result] of Object.entries(results)) {
+ if (typeof result === 'string') output[`${name}.vm`] = result;
+ else errors.push(diagnostic(`${name}.jack`, normalized[name], result));
+ }
+ // An errored project cannot accidentally run a mixture of old and partial output.
+ return { files: errors.length ? {} : output, errors };
+}
+export interface VMPosition {
+ file: string;
+ line: number;
+ command: string;
+}
+function commandText(op: VmInstruction): string {
+ if (op.op === 'push' || op.op === 'pop') return `${op.op} ${op.segment} ${op.offset}`;
+ if (op.op === 'function') return `function ${op.name} ${op.nVars}`;
+ if (op.op === 'call') return `call ${op.name} ${op.nArgs}`;
+ if (op.op === 'label' || op.op === 'goto' || op.op === 'if-goto') return `${op.op} ${op.label}`;
+ return op.op;
+}
+export class VMRunner {
+ private vm: Vm;
+ private disposed = false;
+ private failed = false;
+ cycles = 0;
+ constructor(private readonly files: Record) {
+ const normalized = normalizeFiles(files, 'vm');
+ if (!Object.keys(normalized).length)
+ throw new SoftwareError([
+ { file: 'Project', line: 1, column: 1, message: 'Add a VM file to load.' },
+ ]);
+ const parsed = Object.entries(normalized).map(([name, source]) => {
+ const result = VM.parse(source);
+ if (isErr(result)) throw new SoftwareError([diagnostic(`${name}.vm`, source, Err(result))]);
+ return { name, instructions: Ok(result).instructions };
+ });
+ const built = Vm.buildFromFiles(parsed);
+ if (isErr(built)) throw new SoftwareError([diagnostic('Project', '', Err(built))]);
+ this.vm = Ok(built);
+ this.files = normalized;
+ }
+ get halted(): boolean {
+ return this.disposed || this.failed || this.vm.halted;
+ }
+ get blocked(): boolean {
+ return !this.halted && this.vm.blocked;
+ }
+ get current(): VMPosition | null {
+ if (this.halted) return null;
+ const op = this.vm.operation;
+ if (!op) return null;
+ const className = this.vm.currentFunction?.name.split('.')[0];
+ const file = Object.hasOwn(this.files, className)
+ ? `${className}.vm`
+ : `${Object.keys(this.files)[0]}.vm`;
+ return { file, line: op.span?.line ?? 1, command: commandText(op) };
+ }
+ get stack(): number[] {
+ return this.vm.memory.range(256, Math.max(256, Math.min(16384, this.vm.memory.SP)));
+ }
+ get segments(): { SP: number; LCL: number; ARG: number; THIS: number; THAT: number } {
+ const m = this.vm.memory;
+ return { SP: m.SP, LCL: m.LCL, ARG: m.ARG, THIS: m.THIS, THAT: m.THAT };
+ }
+ get callStack(): string[] {
+ return this.vm.executionStack.map((frame) => frame.function);
+ }
+ get screen(): Uint16Array {
+ return Uint16Array.from(this.vm.Screen.range());
+ }
+ read(address: number): number {
+ this.assertAddress(address);
+ return this.vm.memory.get(address);
+ }
+ write(address: number, value: number): void {
+ this.assertAddress(address);
+ if (address === 24576)
+ throw new Error('Use the keyboard control to change the read-only keyboard input.');
+ if (!Number.isInteger(value) || value < -32768 || value > 65535)
+ throw new Error('Enter a 16-bit word.');
+ this.vm.memory.set(address, value);
+ }
+ private assertAddress(address: number): void {
+ if (!Number.isInteger(address) || address < 0 || address > 24576)
+ throw new Error('Choose a memory address from 0 to 24576.');
+ }
+ setKeyboard(code: number): void {
+ if (!Number.isInteger(code) || code < 0 || code > 32767)
+ throw new Error('Keyboard code must be between 0 and 32767.');
+ this.vm.Keyboard.set(0, code);
+ }
+ step(): void {
+ if (this.halted || this.blocked) return;
+ const position = this.current;
+ try {
+ this.vm.step();
+ this.cycles++;
+ if (this.vm.exitCode !== 0)
+ throw new Error(`Jack OS stopped with error ${this.vm.exitCode}.`);
+ } catch (error) {
+ this.failed = true;
+ this.vm.dispose();
+ throw new SoftwareError([
+ {
+ file: position?.file ?? 'Project',
+ line: position?.line ?? 1,
+ column: 1,
+ message: (error as Error).message || String(error),
+ },
+ ]);
+ }
+ }
+ run(limit: number): void {
+ if (!Number.isInteger(limit) || limit < 0 || limit > 100_000)
+ throw new Error('Run between 0 and 100000 VM operations at a time.');
+ for (let n = 0; n < limit && !this.halted && !this.blocked; n++) this.step();
+ }
+ reset(): void {
+ this.vm.reset();
+ this.disposed = false;
+ this.failed = false;
+ this.cycles = 0;
+ }
+ dispose(): void {
+ this.vm.dispose();
+ this.disposed = true;
+ }
+}
+export const createVM = (files: Record) => new VMRunner(files);
diff --git a/src/lib/software/vendor/nand2tetris/LICENSE b/src/lib/software/vendor/nand2tetris/LICENSE
new file mode 100644
index 0000000..d3a73b1
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/LICENSE
@@ -0,0 +1,12 @@
+MIT License
+
+Copyright 2022 David Souther et al
+
+This software is based on Stefano Volpe's 'Nand2Tetris Tools'. Please check [here](https://github.com/foxyseta/nand-ide/blob/master/LICENSE) for further information.
+This software is based on Aviv Yaish's 'NAND IDE'. Please check [here](https://github.com/AvivYaish/nand-ide/blob/master/LICENSE) for further information.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/lib/software/vendor/nand2tetris/README.md b/src/lib/software/vendor/nand2tetris/README.md
new file mode 100644
index 0000000..73e85e0
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/README.md
@@ -0,0 +1,17 @@
+# Nand2Tetris reference runtime
+
+Source: https://github.com/nand2tetris/web-ide/tree/2070cd89065e49074563b33c7ca066d953aa8a8a/simulator/src
+
+Pinned commit: `2070cd89065e49074563b33c7ca066d953aa8a8a`. This directory retains only the dependency closure of the Jack compiler, VM parser, VM emulator, and native OS. The upstream UI, runner, and project corpus are not included.
+
+The repository MIT license is retained as LICENSE with original attribution and antecedent links. Upstream simulator/package.json declares ISC; the repository root supplies the included MIT license. Source headers are retained. External runtime dependencies remain separately installed and licensed: @davidsouther/jiffies 2026.26.1 and ohm-js 17.5.0.
+
+Local integration changes:
+
+- VM exposes halted/blocked status and disposal, without changing instruction semantics.
+- Sys.wait keeps and cancels its timeout on disposal, preventing late callbacks after reset/navigation.
+- Type-only imports are explicit for the host's verbatimModuleSyntax setting.
+- SubMemory range/loading stays within its own offset and size; clearing the screen must not clear heap RAM or the keyboard. Memory offset loading clears only beyond the loaded region.
+- Screen boundary validation excludes x=512 and y=256. Runtime OS errors are surfaced by the adapter.
+
+This vendor directory is excluded from first-party coverage accounting. The public adapter is covered by integration tests that compile and execute multi-file Jack and exercise VM arithmetic, segments, calls, returns, OS drawing, memory, strings, and errors.
diff --git a/src/lib/software/vendor/nand2tetris/cpu/alu.ts b/src/lib/software/vendor/nand2tetris/cpu/alu.ts
new file mode 100644
index 0000000..c24e7c2
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/cpu/alu.ts
@@ -0,0 +1,328 @@
+const commandASMValues = new Set([
+ "0",
+ "1",
+ "-1",
+ "D",
+ "A",
+ "!D",
+ "!A",
+ "-D",
+ "-A",
+ "D+1",
+ "A+1",
+ "D-1",
+ "A-1",
+ "D+A",
+ "D-A",
+ "A-D",
+ "D&A",
+ "D|A",
+] as const);
+
+export type COMMANDS_ASM =
+ typeof commandASMValues extends Set ? S : never;
+
+export function isCommandAsm(command: string): command is COMMANDS_ASM {
+ return (
+ commandASMValues.has(command as COMMANDS_ASM) ||
+ commandASMValues.has(command.replace("M", "A") as COMMANDS_ASM)
+ );
+}
+
+export type COMMANDS_OP =
+ | 0b101010
+ | 0b111111
+ | 0b111010
+ | 0b001100
+ | 0b110000
+ | 0b110000
+ | 0b001101
+ | 0b110001
+ | 0b001111
+ | 0b110011
+ | 0b011111
+ | 0b110111
+ | 0b001110
+ | 0b110010
+ | 0b000010
+ | 0b010011
+ | 0b010011
+ | 0b000111
+ | 0b000000
+ | 0b000000
+ | 0b010101
+ | 0b010101;
+
+//Usefull for the visualization of the ALU
+export type COMMANDS_ALU =
+ | "0"
+ | "1"
+ | "-1"
+ | "x"
+ | "y"
+ | "!x"
+ | "!y"
+ | "-x"
+ | "-y"
+ | "x+1"
+ | "y+1"
+ | "x-1"
+ | "y-1"
+ | "x+y"
+ | "x-y"
+ | "y-x"
+ | "x&y"
+ | "x|y";
+
+export const COMMANDS_ALU: {
+ op: Record;
+} = {
+ op: {
+ 0x2a: "0",
+ 0x3f: "1",
+ 0x3a: "-1",
+ 0x0c: "x",
+ 0x30: "y",
+ 0x0d: "!x",
+ 0x31: "!y",
+ 0x0f: "-x",
+ 0x33: "-y",
+ 0x1f: "x+1",
+ 0x37: "y+1",
+ 0x0e: "x-1",
+ 0x32: "y-1",
+ 0x02: "x+y",
+ 0x13: "x-y",
+ 0x07: "y-x",
+ 0x00: "x&y",
+ 0x15: "x|y",
+ },
+};
+
+export const COMMANDS: {
+ asm: Record;
+ op: Record;
+ getOp: (asm: string) => COMMANDS_OP;
+} = {
+ asm: {
+ "0": 0b101010, // 42 0x2A
+ "1": 0b111111, // 63 0x3F
+ "-1": 0b111010, // 58 0x3A
+ D: 0b001100, // 12 0x0C
+ A: 0b110000, // 48 0x30
+ "!D": 0b001101, // 13 0x0D
+ "!A": 0b110001, // 49 0x31
+ "-D": 0b001111, // 15 0x0F
+ "-A": 0b110011, // 51 0x33
+ "D+1": 0b011111, // 31 0x1F
+ "A+1": 0b110111, // 55 0x37
+ "D-1": 0b001110, // 14 0x0E
+ "A-1": 0b110010, // 50 0x32
+ "D+A": 0b000010, // 2 0x02
+ "D-A": 0b010011, // 19 0x13
+ "A-D": 0b000111, // 7 0x07
+ "D&A": 0b000000, // 0 0x00
+ "D|A": 0b010101, // 21 0x15
+ },
+ op: {
+ 0x2a: "0",
+ 0x3f: "1",
+ 0x3a: "-1",
+ 0x0c: "D",
+ 0x30: "A",
+ 0x0d: "!D",
+ 0x31: "!A",
+ 0x0f: "-D",
+ 0x33: "-A",
+ 0x1f: "D+1",
+ 0x37: "A+1",
+ 0x0e: "D-1",
+ 0x32: "A-1",
+ 0x02: "D+A",
+ 0x13: "D-A",
+ 0x07: "A-D",
+ 0x00: "D&A",
+ 0x15: "D|A",
+ },
+ getOp(asm: string) {
+ return COMMANDS.asm[asm.replace("M", "A") as COMMANDS_ASM];
+ },
+};
+
+const assignAsmValues = new Set([
+ "",
+ "M",
+ "D",
+ "MD",
+ "A",
+ "AM",
+ "AD",
+ "AMD",
+] as const);
+
+export type ASSIGN_ASM =
+ typeof assignAsmValues extends Set ? S : never;
+
+export type ASSIGN_OP = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
+
+export function isAssignAsm(assign: unknown): assign is ASSIGN_ASM {
+ return assignAsmValues.has(assign as ASSIGN_ASM);
+}
+
+export const ASSIGN: {
+ asm: Record;
+ op: Record;
+} = {
+ asm: {
+ "": 0x0,
+ M: 0b001,
+ D: 0b010,
+ MD: 0b011,
+ A: 0b100,
+ AM: 0b101,
+ AD: 0b110,
+ AMD: 0b111,
+ },
+ op: {
+ 0x0: "",
+ 0x1: "M",
+ 0x2: "D",
+ 0x3: "MD",
+ 0x4: "A",
+ 0x5: "AM",
+ 0x6: "AD",
+ 0x7: "AMD",
+ },
+};
+
+const jumpAsmValues = new Set([
+ "",
+ "JGT",
+ "JEQ",
+ "JGE",
+ "JLT",
+ "JNE",
+ "JLE",
+ "JMP",
+] as const);
+
+export type JUMP_ASM = typeof jumpAsmValues extends Set ? S : never;
+export type JUMP_OP = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
+
+export function isJumpAsm(jump: unknown): jump is JUMP_ASM {
+ return jumpAsmValues.has(jump as JUMP_ASM);
+}
+
+export const JUMP: {
+ asm: Record;
+ op: Record;
+} = {
+ asm: {
+ "": 0b0,
+ JGT: 0b001,
+ JEQ: 0b010,
+ JGE: 0b011,
+ JLT: 0b100,
+ JNE: 0b101,
+ JLE: 0b110,
+ JMP: 0b111,
+ },
+ op: {
+ 0x0: "",
+ 0x1: "JGT",
+ 0x2: "JEQ",
+ 0x3: "JGE",
+ 0x4: "JLT",
+ 0x5: "JNE",
+ 0x6: "JLE",
+ 0x7: "JMP",
+ },
+};
+
+export const Flags = {
+ 0x01: "Positive",
+ 0x00: "Zero",
+ 0x0f: "Negative",
+ Positive: 0x01,
+ Zero: 0x00,
+ Negative: 0x0f,
+};
+
+export function alu(op: number, d: number, a: number): [number, number] {
+ let o = 0;
+ switch (op) {
+ case 0x2a:
+ o = 0;
+ break;
+ case 0x3f:
+ o = 1;
+ break;
+ case 0x3a:
+ o = -1;
+ break;
+ case 0x0c:
+ o = d;
+ break;
+ case 0x30:
+ o = a;
+ break;
+ case 0x0d:
+ o = ~d;
+ break;
+ case 0x31:
+ o = ~a;
+ break;
+ case 0x0f:
+ o = -d;
+ break;
+ case 0x33:
+ o = -a;
+ break;
+ case 0x1f:
+ o = d + 1;
+ break;
+ case 0x37:
+ o = a + 1;
+ break;
+ case 0x0e:
+ o = d - 1;
+ break;
+ case 0x32:
+ o = a - 1;
+ break;
+ case 0x02:
+ o = d + a;
+ break;
+ case 0x13:
+ o = d - a;
+ break;
+ case 0x07:
+ o = a - d;
+ break;
+ case 0x00:
+ o = d & a;
+ break;
+ case 0x15:
+ o = d | a;
+ break;
+ }
+
+ o = o & 0xffff;
+ const flags =
+ o === 0 ? Flags.Zero : o & 0x8000 ? Flags.Negative : Flags.Positive;
+ return [o, flags];
+}
+
+export function alua(op: number, d: number, a: number): [number, number] {
+ if (op & 0b100000) d = 0;
+ if (op & 0b010000) d = ~d & 0xffff;
+ if (op & 0b001000) a = 0;
+ if (op & 0b000100) a = ~a & 0xffff;
+
+ let o = (op & 0b000010 ? d + a : d & a) & 0xffff;
+ if (op & 0b000001) o = ~o & 0xffff;
+
+ const flags =
+ o === 0 ? Flags.Zero : o & 0x8000 ? Flags.Negative : Flags.Positive;
+ return [o, flags];
+}
diff --git a/src/lib/software/vendor/nand2tetris/cpu/memory.ts b/src/lib/software/vendor/nand2tetris/cpu/memory.ts
new file mode 100644
index 0000000..507addf
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/cpu/memory.ts
@@ -0,0 +1,235 @@
+import { assert } from "@davidsouther/jiffies/assert.ts";
+import { FileSystem } from "@davidsouther/jiffies/fs.ts";
+import { load } from "../fs.js";
+import { op } from "../util/asm.js";
+import { int2, int10, int16 } from "../util/twos.js";
+
+export const FORMATS = ["bin", "dec", "hex", "asm"];
+export type Format = (typeof FORMATS)[number];
+
+export const SCREEN_OFFSET = 0x4000;
+export const SCREEN_ROWS = 256;
+export const SCREEN_COLS = 32; // These are 16-bit columns
+export const SCREEN_SIZE = SCREEN_ROWS * SCREEN_COLS;
+export const KEYBOARD_OFFSET = 0x6000;
+
+export interface MemoryAdapter {
+ size: number;
+ get(index: number): number;
+ set(index: number, value: number): void;
+ reset(): void;
+ update(cell: number, value: string, format: Format): void;
+ load(fs: FileSystem, path: string, offset?: number): Promise;
+ loadBytes(bytes: number[], offset?: number): void;
+ range(start?: number, end?: number): number[];
+ map(
+ fn: (index: number, value: number) => T,
+ start?: number,
+ end?: number,
+ ): Iterable;
+ [Symbol.iterator](): Iterable;
+}
+
+export interface KeyboardAdapter {
+ getKey(): number;
+ setKey(key: number): void;
+ clearKey(): void;
+}
+
+export class Memory implements MemoryAdapter {
+ private memory: Int16Array;
+
+ get size(): number {
+ return this.memory.length;
+ }
+
+ constructor(memory: ArrayBuffer | number) {
+ if (typeof memory === "number") {
+ this.memory = new Int16Array(memory);
+ } else {
+ this.memory = new Int16Array(memory);
+ }
+ }
+
+ get(index: number): number {
+ if (index < 0 || index >= this.size) {
+ return 0xffff;
+ }
+ return this.memory[index] ?? 0;
+ }
+
+ set(index: number, value: number): void {
+ if (index >= 0 && index < this.size) {
+ this.memory[index] = value & 0xffff;
+ }
+ }
+
+ reset(): void {
+ this.memory.fill(0);
+ }
+
+ update(cell: number, value: string, format: Format) {
+ let current: number | undefined;
+ switch (format) {
+ case "asm":
+ try {
+ current = op(value);
+ } catch {
+ current = undefined;
+ }
+ break;
+ case "bin":
+ current = int2(value);
+ break;
+ case "hex":
+ current = int16(value);
+ break;
+ case "dec":
+ default:
+ current = int10(value);
+ break;
+ }
+
+ if (current !== undefined && isFinite(current) && current <= 0xffff) {
+ this.set(cell, current);
+ }
+ }
+
+ async load(fs: FileSystem, path: string, offset?: number) {
+ try {
+ this.loadBytes(await load(fs, path), offset);
+ } catch (_cause) {
+ // throw new Error(`ROM32K Failed to load file ${path}`, { cause });
+ throw new Error(`Memory Failed to load file ${path}`);
+ }
+ }
+
+ loadBytes(bytes: number[], offset?: number): void {
+ this.memory.set(new Int16Array(bytes), offset);
+ this.memory.fill(0, (offset ?? 0) + bytes.length, this.size);
+ }
+
+ range(start = 0, end = this.size): number[] {
+ return [...this.memory.slice(start, end)];
+ }
+
+ *map(
+ fn: (index: number, value: number) => T,
+ start = 0,
+ end = this.size,
+ ): Iterable {
+ assert(start <= end);
+ for (let i = start; i < end; i++) {
+ yield fn(i, this.get(i));
+ }
+ }
+
+ [Symbol.iterator](): Iterable {
+ return this.map((_, v) => v);
+ }
+
+ isEmpty(): boolean {
+ return this.memory.every((word) => word === 0);
+ }
+}
+
+export class SubMemory implements MemoryAdapter {
+ constructor(
+ private readonly parent: MemoryAdapter,
+ readonly size: number,
+ private readonly offset: number,
+ ) {}
+
+ get(index: number): number {
+ if (index < 0 || index >= this.size) {
+ return 0xffff;
+ }
+ return this.parent.get(this.offset + index);
+ }
+
+ set(index: number, value: number, trackChange = true): void {
+ if (index >= 0 && index < this.size) {
+ this.parent.set(index + this.offset, value);
+ }
+ }
+
+ reset(): void {
+ for (let i = 0; i < this.size; i++) {
+ this.set(i, 0, false);
+ }
+ }
+
+ update(index: number, value: string, format: string): void {
+ if (index >= 0 && index < this.size) {
+ this.parent.update(index + this.offset, value, format);
+ }
+ }
+
+ load(fs: FileSystem, path: string): Promise {
+ return this.parent.load(fs, path, this.offset);
+ }
+
+ loadBytes(bytes: number[]): void {
+ if (bytes.length > this.size) throw new Error('Data exceeds this memory region.');
+ for (let i = 0; i < this.size; i++) this.set(i, bytes[i] ?? 0);
+ }
+
+ range(start = 0, end = this.size): number[] {
+ return this.parent.range(this.offset + start, this.offset + Math.min(end, this.size));
+ }
+
+ map(
+ fn: (index: number, value: number) => T,
+ start = 0,
+ end: number = this.size,
+ ): Iterable {
+ return this.parent.map(fn, start + this.offset, end + this.offset);
+ }
+
+ [Symbol.iterator](): Iterable {
+ return this.map((_, v) => v);
+ }
+}
+
+export class MemoryKeyboard extends SubMemory implements KeyboardAdapter {
+ constructor(memory: MemoryAdapter) {
+ super(memory, 1, 0x6000);
+ }
+
+ getKey(): number {
+ return this.get(0);
+ }
+
+ setKey(key: number): void {
+ this.set(0, key & 0xffff);
+ }
+
+ clearKey(): void {
+ this.set(0, 0);
+ }
+}
+
+export class ROM extends Memory {
+ static readonly SIZE = 0x8000;
+ constructor(program?: Int16Array) {
+ if (program) {
+ const arr = new Int16Array(ROM.SIZE);
+ arr.set(program);
+ super(arr.buffer);
+ } else {
+ super(ROM.SIZE);
+ }
+ }
+}
+
+export class RAM extends Memory {
+ keyboard = new SubMemory(this, 1, KEYBOARD_OFFSET);
+ screen = new SubMemory(this, SCREEN_SIZE, SCREEN_OFFSET);
+
+ // 4k main memory, 2k screen memory, 1 keyboard
+ static readonly SIZE = 0x4000 + 0x2000 + 0x0001;
+
+ constructor() {
+ super(RAM.SIZE);
+ }
+}
diff --git a/src/lib/software/vendor/nand2tetris/fs.ts b/src/lib/software/vendor/nand2tetris/fs.ts
new file mode 100644
index 0000000..31ae4bc
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/fs.ts
@@ -0,0 +1,25 @@
+import { FileSystem } from "@davidsouther/jiffies/fs.ts";
+import * as loader from "./loader.js";
+
+export async function load(fs: FileSystem, path: string): Promise {
+ if (path.endsWith(".hack")) {
+ return loadHack(fs, path);
+ }
+
+ if (path.endsWith(".asm")) {
+ return loadAsm(fs, path);
+ }
+
+ throw new Error(`Cannot load file without hack or asm extension ${path}`);
+}
+
+export async function loadAsm(fs: FileSystem, path: string): Promise {
+ return loader.loadAsm(await fs.readFile(path));
+}
+
+export async function loadHack(
+ fs: FileSystem,
+ path: string,
+): Promise {
+ return loader.loadHack(await fs.readFile(path));
+}
diff --git a/src/lib/software/vendor/nand2tetris/jack/compiler.ts b/src/lib/software/vendor/nand2tetris/jack/compiler.ts
new file mode 100644
index 0000000..5033f87
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/jack/compiler.ts
@@ -0,0 +1,646 @@
+import { Err, isErr, Ok, type Result } from "@davidsouther/jiffies/result.ts";
+import { type CompilationError, createError, type Span } from "../languages/base.js";
+import {
+ type ArrayAccess,
+ type Class,
+ type ClassVarDec,
+ type DoStatement,
+ type Expression,
+ type IfStatement,
+ isPrimitive,
+ JACK,
+ type KeywordConstant,
+ type LetStatement,
+ type Op,
+ type Parameter,
+ type ReturnStatement,
+ type Statement,
+ type Subroutine,
+ type SubroutineCall,
+ type Term,
+ type Type,
+ type UnaryOp,
+ type VarDec,
+ type Variable,
+ type WhileStatement,
+} from "../languages/jack.js";
+import { type Segment } from "../languages/vm.js";
+import {
+ makeInterface,
+ overridesOsCorrectly,
+ VM_BUILTINS,
+} from "../vm/builtins.js";
+import { validateSubroutine } from "./controlFlow.js";
+
+const osClasses = new Set([
+ "Sys",
+ "Screen",
+ "Output",
+ "Keyboard",
+ "String",
+ "Array",
+ "Memory",
+ "Math",
+]);
+
+function isOsClass(name: string): boolean {
+ return osClasses.has(name);
+}
+
+function isError(value: unknown): value is CompilationError {
+ return (value as CompilationError).message != undefined;
+}
+
+function capitalize(s: string) {
+ return s.charAt(0).toUpperCase() + s.slice(1);
+}
+
+export function compile(
+ files: Record,
+): Record {
+ const classes: Record = {};
+ for (const [name, content] of Object.entries(files)) {
+ const parsed = JACK.parse(content);
+ if (isErr(parsed)) {
+ classes[name] = Err(parsed);
+ } else {
+ const cls = Ok(parsed);
+ const result = validateClass(cls);
+ classes[name] =
+ cls.name.value == name
+ ? isErr(result)
+ ? Err(result)
+ : cls
+ : createError(
+ `Class name ${cls.name.value} doesn't match file name ${name}`,
+ cls.name.span,
+ );
+ }
+ }
+
+ const validClasses: Record = Object.fromEntries(
+ Object.entries(classes).filter(([_, parsed]) => !isError(parsed)),
+ ) as Record;
+
+ const vms: Record = {};
+ for (const [name, parsed] of Object.entries(classes)) {
+ if (isError(parsed)) {
+ vms[name] = parsed;
+ } else {
+ try {
+ const compiled = new Compiler().compile(parsed, validClasses);
+ if (isErr(compiled)) {
+ vms[name] = Err(compiled);
+ } else {
+ vms[name] = Ok(compiled);
+ }
+ } catch (e) {
+ vms[name] = e as CompilationError;
+ }
+ }
+ }
+ return vms;
+}
+
+function validateClass(cls: Class): Result {
+ const subroutineNames = new Set();
+ for (const subroutine of cls.subroutines) {
+ if (subroutineNames.has(subroutine.name.value)) {
+ return Err(
+ createError(
+ `Subroutine ${subroutine.name.value} already declared`,
+ subroutine.name.span,
+ ),
+ );
+ }
+ subroutineNames.add(subroutine.name.value);
+ const result = validateSubroutine(subroutine);
+ if (isErr(result)) {
+ return result;
+ }
+ }
+ return Ok();
+}
+
+interface VariableData {
+ type: Type;
+ segment: Segment;
+ index: number;
+}
+
+const ops: Record = {
+ "+": "add",
+ "-": "sub",
+ "*": "call Math.multiply 2",
+ "/": "call Math.divide 2",
+ "&": "and",
+ "|": "or",
+ "<": "lt",
+ ">": "gt",
+ "=": "eq",
+};
+
+const unaryOps: Record = {
+ "-": "neg",
+ "~": "not",
+};
+
+interface SubroutineCallAttributes {
+ className: string;
+ subroutineName: string;
+ object?: string; // object being acted upon if this is a method (undefined if function / constructor)
+}
+
+export class Compiler {
+ private instructions: string[] = [];
+ globalSymbolTable: Record = {};
+ localSymbolTable: Record = {};
+
+ className = "";
+ private classes: Record = {};
+
+ private labelNum = 0;
+ private fieldNum = 0;
+ private staticNum = 0;
+ private localNum = 0;
+
+ get output(): string[] {
+ return Array.from(this.instructions);
+ }
+
+ varData(name: string): VariableData | undefined {
+ return this.localSymbolTable[name] || this.globalSymbolTable[name];
+ }
+
+ var(name: string): string;
+ var(variable: Variable): string;
+ var(variable: ArrayAccess): string;
+ var(variable: LetStatement): string;
+ var(arg: string | Variable | ArrayAccess | LetStatement): string {
+ let name: string;
+ let span: Span | undefined;
+ if (typeof arg == "string") {
+ name = arg;
+ } else {
+ if (typeof arg.name == "string") {
+ name = arg.name;
+ span = arg.span;
+ } else {
+ name = arg.name.value;
+ span = arg.name.span;
+ }
+ }
+ const data = this.varData(name);
+ if (!data) {
+ throw createError(`Undeclared variable ${name}`, span);
+ }
+ return `${data.segment} ${data.index}`;
+ }
+
+ write(...lines: string[]) {
+ this.instructions.push(...lines);
+ }
+
+ getLabel() {
+ const label = `${this.className}_${this.labelNum}`;
+ this.labelNum += 1;
+ return label;
+ }
+
+ compile(
+ cls: Class,
+ other?: Record,
+ ): Result {
+ this.className = cls.name.value;
+ this.classes = other ?? {};
+ for (const varDec of cls.varDecs) {
+ this.compileClassVarDec(varDec);
+ }
+ for (const subroutine of cls.subroutines) {
+ this.compileSubroutineDec(subroutine);
+ }
+ return Ok(
+ this.instructions
+ .map((inst) =>
+ inst.startsWith("function") || inst.startsWith("label")
+ ? inst
+ : " ".concat(inst),
+ )
+ .join("\n"),
+ );
+ }
+
+ validateType(type: string, span?: Span) {
+ if (isPrimitive(type) || isOsClass(type) || this.classes[type]) {
+ return;
+ }
+ throw createError(`Unknown type ${type}`, span);
+ }
+
+ validateReturnType(returnType: string, span?: Span) {
+ if (returnType == "void") {
+ return;
+ }
+ this.validateType(returnType, span);
+ }
+
+ compileClassVarDec(dec: ClassVarDec) {
+ this.validateType(dec.type.value, dec.type.span);
+ for (const name of dec.names) {
+ if (dec.varType == "field") {
+ this.globalSymbolTable[name] = {
+ type: dec.type.value,
+ segment: "this",
+ index: this.fieldNum,
+ };
+ this.fieldNum += 1;
+ } else {
+ this.globalSymbolTable[name] = {
+ type: dec.type.value,
+ segment: "static",
+ index: this.staticNum,
+ };
+ this.staticNum += 1;
+ }
+ }
+ }
+
+ compileVarDec(dec: VarDec) {
+ this.validateType(dec.type.value, dec.type.span);
+ for (const name of dec.names) {
+ this.localSymbolTable[name] = {
+ type: dec.type.value,
+ segment: "local",
+ index: this.localNum,
+ };
+ this.localNum += 1;
+ }
+ }
+
+ registerArgs(params: Parameter[], offset = false) {
+ let argNum = 0;
+ for (const param of params) {
+ this.validateType(param.type.value, param.type.span);
+ this.localSymbolTable[param.name] = {
+ type: param.type.value,
+ segment: "argument",
+ index: argNum + (offset ? 1 : 0), // when compiling a method the first argument is this, so we offset the others by 1
+ };
+ argNum += 1;
+ }
+ }
+
+ validateSubroutineDec(subroutine: Subroutine) {
+ this.validateReturnType(
+ subroutine.returnType.value,
+ subroutine.returnType.span,
+ );
+
+ if (isOsClass(this.className)) {
+ const builtin = VM_BUILTINS[`${this.className}.${subroutine.name.value}`];
+
+ if (builtin && !overridesOsCorrectly(this.className, subroutine)) {
+ throw createError(
+ `OS subroutine ${this.className}.${subroutine.name.value} must follow the interface ${makeInterface(subroutine.name.value, builtin)})`,
+ );
+ }
+ }
+ }
+
+ compileSubroutineDec(subroutine: Subroutine) {
+ this.validateSubroutineDec(subroutine);
+ switch (subroutine.type) {
+ case "method":
+ this.compileMethod(subroutine);
+ break;
+ case "constructor":
+ this.compileConstructor(subroutine);
+ break;
+ case "function":
+ this.compileFunction(subroutine);
+ }
+ }
+
+ compileSubroutineStart(subroutine: Subroutine, isMethod = false) {
+ this.localSymbolTable = {};
+ this.localNum = 0;
+ this.registerArgs(subroutine.parameters, isMethod);
+
+ const localCount = subroutine.body.varDecs
+ .map((dec) => dec.names.length)
+ .reduce((a, b) => a + b, 0);
+ this.write(
+ `function ${this.className}.${subroutine.name.value} ${localCount}`,
+ );
+ for (const varDec of subroutine.body.varDecs) {
+ this.compileVarDec(varDec);
+ }
+ }
+
+ compileFunction(subroutine: Subroutine) {
+ this.compileSubroutineStart(subroutine);
+ this.compileStatements(subroutine.body.statements);
+ }
+
+ compileMethod(subroutine: Subroutine) {
+ this.compileSubroutineStart(subroutine, true);
+ this.write("push argument 0", "pop pointer 0");
+ this.compileStatements(subroutine.body.statements);
+ }
+
+ compileConstructor(subroutine: Subroutine) {
+ this.compileSubroutineStart(subroutine);
+
+ if (this.fieldNum > 0)
+ this.write(
+ `push constant ${this.fieldNum}`,
+ "call Memory.alloc 1",
+ "pop pointer 0",
+ );
+ else this.write("push constant 0", "pop pointer 0");
+
+ this.compileStatements(subroutine.body.statements);
+ }
+
+ compileExpression(expression: Expression) {
+ this.compileTerm(expression.term);
+ for (const part of expression.rest) {
+ this.compileTerm(part.term);
+ this.compileOp(part.op); // postfix
+ }
+ }
+
+ compileOp(op: Op) {
+ this.write(ops[op]);
+ }
+
+ compileTerm(term: Term) {
+ switch (term.termType) {
+ case "numericLiteral":
+ this.write(`push constant ${term.value}`);
+ break;
+ case "stringLiteral":
+ this.compileStringLiteral(term.value);
+ break;
+ case "variable":
+ this.write(`push ${this.var(term)}`);
+ break;
+ case "keywordLiteral":
+ this.compileKeywordLiteral(term.value);
+ break;
+ case "subroutineCall":
+ this.compileSubroutineCall(term);
+ break;
+ case "arrayAccess":
+ this.compileExpression(term.index);
+ this.write(
+ `push ${this.var(term)}`,
+ "add",
+ "pop pointer 1",
+ "push that 0",
+ );
+ break;
+ case "groupedExpression":
+ this.compileExpression(term.expression);
+ break;
+ case "unaryExpression":
+ this.compileTerm(term.term);
+ this.write(unaryOps[term.op]);
+ }
+ }
+
+ validateArgNum(name: string, expected: number, call: SubroutineCall) {
+ const received = call.parameters.length;
+ if (expected != received) {
+ throw createError(
+ `${name} expected ${expected} arguments, got ${received}`,
+ call.span,
+ );
+ }
+ }
+
+ validateSubroutineCall(
+ className: string,
+ subroutineName: string,
+ call: SubroutineCall,
+ isMethod: boolean,
+ ) {
+ const builtin = VM_BUILTINS[`${className}.${subroutineName}`];
+ if (builtin) {
+ if (builtin.type == "method" && !isMethod) {
+ throw createError(
+ `Method ${className}.${subroutineName} was called as a function/constructor`,
+ call.name.span,
+ );
+ }
+ if (builtin.type != "method" && isMethod) {
+ throw createError(
+ `${capitalize(
+ builtin.type,
+ )} ${className}.${subroutineName} was called as a method`,
+ call.name.span,
+ );
+ }
+ this.validateArgNum(
+ `${className}.${subroutineName}`,
+ builtin.args.length,
+ call,
+ );
+ return;
+ } else if (this.classes[className]) {
+ for (const subroutine of this.classes[className].subroutines) {
+ if (subroutine.name.value == subroutineName) {
+ if (subroutine.type == "method" && !isMethod) {
+ throw createError(
+ `Method ${className}.${subroutineName} was called as a function/constructor`,
+ call.name.span,
+ );
+ }
+ if (subroutine.type != "method" && isMethod) {
+ throw createError(
+ `${capitalize(
+ subroutine.name.value,
+ )} ${className}.${subroutineName} was called as a method`,
+ call.name.span,
+ );
+ }
+ this.validateArgNum(
+ `${className}.${subroutineName}`,
+ subroutine.parameters.length,
+ call,
+ );
+ return;
+ }
+ }
+ throw createError(
+ `Class ${className} doesn't contain a function/constructor ${subroutineName}`,
+ call.name.span,
+ );
+ } else {
+ throw createError(`Class ${className} doesn't exist`, call.name.span);
+ }
+ }
+
+ classifySubroutineCall(call: SubroutineCall): SubroutineCallAttributes {
+ let object: string | undefined;
+ let className = "";
+ let subroutineName = "";
+
+ if (call.name.value.includes(".")) {
+ const [prefix, suffix] = call.name.value.split(".", 2);
+ subroutineName = suffix;
+ const varData = this.varData(prefix);
+ if (varData) {
+ // external method call
+ object = this.var(prefix);
+ className = varData.type;
+ } else {
+ // function / constructor call
+ className = prefix;
+ }
+ } else {
+ object = "pointer 0"; // this
+ className = this.className;
+ subroutineName = call.name.value;
+ }
+
+ this.validateSubroutineCall(
+ className,
+ subroutineName,
+ call,
+ object != undefined,
+ );
+
+ return { className, subroutineName, object };
+ }
+
+ compileSubroutineCall(call: SubroutineCall) {
+ const attributes = this.classifySubroutineCall(call);
+
+ if (
+ attributes.className === "Memory" &&
+ attributes.subroutineName === "deAlloc" &&
+ this.fieldNum === 0
+ ) {
+ for (const param of call.parameters) {
+ this.compileExpression(param);
+ this.write("pop temp 0");
+ }
+
+ this.write("push constant 0");
+ return;
+ }
+
+ if (attributes.object) {
+ this.write(`push ${attributes.object}`);
+ }
+ for (const param of call.parameters) {
+ this.compileExpression(param);
+ }
+ this.write(
+ `call ${attributes.className}.${attributes.subroutineName} ${
+ call.parameters.length + (attributes.object ? 1 : 0)
+ }`,
+ );
+ }
+
+ compileStringLiteral(str: string) {
+ this.write(`push constant ${str.length}`, `call String.new 1`);
+ for (let i = 0; i < str.length; i++) {
+ this.write(
+ `push constant ${str.charCodeAt(i)}`,
+ `call String.appendChar 2`,
+ );
+ }
+ }
+
+ compileKeywordLiteral(keyword: KeywordConstant) {
+ switch (keyword) {
+ case "true":
+ this.write(`push constant 1`, `neg`);
+ break;
+ case "false":
+ this.write(`push constant 0`);
+ break;
+ case "null":
+ this.write(`push constant 0`);
+ break;
+ case "this":
+ this.write(`push pointer 0`);
+ }
+ }
+
+ compileStatements(statements: Statement[]) {
+ for (const statement of statements) {
+ this.compileStatement(statement);
+ }
+ }
+
+ compileStatement(statement: Statement) {
+ switch (statement.statementType) {
+ case "doStatement":
+ this.compileDoStatement(statement);
+ break;
+ case "ifStatement":
+ this.compileIf(statement);
+ break;
+ case "letStatement":
+ this.compileLet(statement);
+ break;
+ case "returnStatement":
+ this.compileReturn(statement);
+ break;
+ case "whileStatement":
+ this.compileWhile(statement);
+ }
+ }
+
+ compileReturn(statement: ReturnStatement) {
+ if (statement.value) {
+ this.compileExpression(statement.value);
+ } else {
+ this.write(`push constant 0`); // return 0
+ }
+ this.write(`return`);
+ }
+
+ compileLet(statement: LetStatement) {
+ if (statement.arrayIndex) {
+ this.compileExpression(statement.arrayIndex);
+ this.write(`push ${this.var(statement)}`, "add");
+ this.compileExpression(statement.value);
+ this.write("pop temp 0", "pop pointer 1", "push temp 0", "pop that 0");
+ } else {
+ this.compileExpression(statement.value);
+ this.write(`pop ${this.var(statement)}`);
+ }
+ }
+
+ compileDoStatement(statement: DoStatement) {
+ this.compileSubroutineCall(statement.call);
+ this.write(`pop temp 0`);
+ }
+
+ compileIf(statement: IfStatement) {
+ const condTrue = this.getLabel();
+ const condFalse = this.getLabel();
+
+ this.compileExpression(statement.condition);
+ this.write("not", `if-goto ${condFalse}`);
+ this.compileStatements(statement.body);
+ this.write(`goto ${condTrue}`, `label ${condFalse}`);
+ this.compileStatements(statement.else);
+ this.write(`label ${condTrue}`);
+ }
+
+ compileWhile(statement: WhileStatement) {
+ const loop = this.getLabel();
+ const exit = this.getLabel();
+
+ this.write(`label ${loop}`);
+ this.compileExpression(statement.condition);
+ this.write(`not`, `if-goto ${exit}`);
+ this.compileStatements(statement.body);
+ this.write(`goto ${loop}`, `label ${exit}`);
+ }
+}
diff --git a/src/lib/software/vendor/nand2tetris/jack/controlFlow.ts b/src/lib/software/vendor/nand2tetris/jack/controlFlow.ts
new file mode 100644
index 0000000..8d98ba1
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/jack/controlFlow.ts
@@ -0,0 +1,180 @@
+import {
+ Err,
+ isErr,
+ Ok,
+ type Result,
+ unwrap,
+} from "@davidsouther/jiffies/result.ts";
+import { type CompilationError, createError } from "../languages/base.js";
+import {
+ type IfStatement,
+ type ReturnType,
+ type Statement,
+ type Subroutine,
+ type WhileStatement,
+} from "../languages/jack.js";
+
+class CFGNode {
+ id: number;
+ hasReturn = false;
+ children: CFGNode[] = [];
+
+ static count = 0;
+
+ constructor() {
+ this.id = CFGNode.count;
+ CFGNode.count += 1;
+ }
+
+ alwaysReturns(): boolean {
+ const visited: Set = new Set();
+
+ function checkReturn(node: CFGNode): boolean {
+ if (node.hasReturn) {
+ return true;
+ } else if (node.children.length === 0) {
+ return false;
+ }
+ visited.add(node);
+ for (const child of node.children) {
+ if (!visited.has(child) && !checkReturn(child)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return checkReturn(this);
+ }
+
+ getLeafs(): CFGNode[] {
+ const leafs: Set = new Set();
+ const visited: Set = new Set();
+
+ function findLeafs(node: CFGNode) {
+ if (node.children.length === 0) {
+ leafs.add(node);
+ } else {
+ visited.add(node);
+ for (const child of node.children) {
+ if (!visited.has(child)) {
+ findLeafs(child);
+ }
+ }
+ }
+ }
+
+ findLeafs(this);
+ return Array.from(leafs);
+ }
+}
+
+function processIf(
+ statement: IfStatement,
+ returnType: ReturnType,
+ current: CFGNode,
+): Result {
+ const ifStart = new CFGNode();
+ current.children.push(ifStart);
+ current = ifStart;
+ const result1 = buildCFG(statement.body, returnType);
+ const result2 = buildCFG(statement.else, returnType);
+ if (isErr(result1)) {
+ return result1;
+ }
+ if (isErr(result2)) {
+ return result2;
+ }
+ const path1 = unwrap(result1);
+ const path2 = unwrap(result2);
+ current.children.push(path1, path2);
+ const leafs = path1.getLeafs().concat(path2.getLeafs());
+ current = new CFGNode();
+ for (const leaf of leafs) {
+ leaf.children.push(current);
+ }
+ return Ok(current);
+}
+
+function processWhile(
+ statement: WhileStatement,
+ returnType: ReturnType,
+ current: CFGNode,
+): Result {
+ const whileStart = new CFGNode();
+ current.children.push(whileStart);
+ current = whileStart;
+ const result = buildCFG(statement.body, returnType);
+ if (isErr(result)) {
+ return result;
+ }
+ const body = unwrap(result);
+ for (const leaf of body.getLeafs()) {
+ leaf.children.push(current);
+ }
+ const next = new CFGNode();
+ current.children.push(body, next);
+ current = next;
+ return Ok(current);
+}
+
+function buildCFG(
+ statements: Statement[],
+ returnType: ReturnType,
+): Result {
+ const root = new CFGNode();
+ let current = root;
+
+ let result: Result | undefined;
+ for (const statement of statements) {
+ switch (statement.statementType) {
+ case "letStatement":
+ case "doStatement":
+ break;
+ case "returnStatement":
+ if (returnType != "void" && statement.value == undefined) {
+ return Err(
+ createError(
+ `A non void subroutine must return a value`,
+ statement.span,
+ ),
+ );
+ }
+ current.hasReturn = true;
+ break;
+ case "ifStatement":
+ result = processIf(statement, returnType, current);
+ if (isErr(result)) {
+ return result;
+ }
+ current = unwrap(result);
+ break;
+ case "whileStatement":
+ result = processWhile(statement, returnType, current);
+ if (isErr(result)) {
+ return result;
+ }
+ current = unwrap(result);
+ break;
+ }
+ }
+ return Ok(root);
+}
+
+export function validateSubroutine(
+ subroutine: Subroutine,
+): Result {
+ const cfg = buildCFG(subroutine.body.statements, subroutine.returnType.value);
+ if (isErr(cfg)) {
+ return cfg;
+ }
+ if (!unwrap(cfg).alwaysReturns()) {
+ return Err(
+ createError(
+ `Subroutine ${subroutine.name.value}: not all code paths return a value`,
+ subroutine.name.span,
+ ),
+ );
+ }
+ return Ok();
+}
diff --git a/src/lib/software/vendor/nand2tetris/languages/asm.ts b/src/lib/software/vendor/nand2tetris/languages/asm.ts
new file mode 100644
index 0000000..d2dbf32
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/languages/asm.ts
@@ -0,0 +1,373 @@
+import { assertExists } from "@davidsouther/jiffies/assert.ts";
+import { Err, Ok, type Result } from "@davidsouther/jiffies/result.ts";
+import { type Node, grammar as ohmGrammar } from "ohm-js";
+import {
+ ASSIGN,
+ type ASSIGN_ASM,
+ type ASSIGN_OP,
+ COMMANDS,
+ type COMMANDS_ASM,
+ type COMMANDS_OP,
+ isAssignAsm,
+ isCommandAsm,
+ JUMP,
+ type JUMP_ASM,
+ type JUMP_OP,
+} from "../cpu/alu.js";
+import { KEYBOARD_OFFSET, SCREEN_OFFSET } from "../cpu/memory.js";
+import { makeC } from "../util/asm.js";
+import {
+ baseSemantics,
+ type CompilationError,
+ createError,
+ grammars,
+ makeParser,
+ type Span,
+ span,
+} from "./base.js";
+import asmGrammar from "./grammars/asm.ohm.js";
+
+export const grammar = ohmGrammar(asmGrammar, grammars);
+export const asmSemantics = grammar.extendSemantics(baseSemantics);
+
+export interface Asm {
+ instructions: AsmInstruction[];
+}
+
+export type AsmInstruction =
+ | AsmAInstruction
+ | AsmCInstruction
+ | AsmLabelInstruction;
+
+export type AsmAInstruction = AsmALabelInstruction | AsmAValueInstruction;
+export interface AsmALabelInstruction {
+ type: "A";
+ label: string;
+ span?: Span;
+}
+
+export interface AsmAValueInstruction {
+ type: "A";
+ value: number;
+ span?: Span;
+}
+
+export function isAValueInstruction(
+ inst: AsmInstruction,
+): inst is AsmAValueInstruction {
+ return inst.type == "A" && (inst as AsmAValueInstruction).value !== undefined;
+}
+
+function isALabelInstruction(
+ inst: AsmInstruction,
+): inst is AsmALabelInstruction {
+ return inst.type == "A" && (inst as AsmALabelInstruction).label !== undefined;
+}
+
+export interface AsmCInstruction {
+ type: "C";
+ op: COMMANDS_OP;
+ isM: boolean;
+ store?: ASSIGN_OP;
+ jump?: JUMP_OP;
+ span?: Span;
+}
+
+export interface AsmLabelInstruction {
+ type: "L";
+ label: string;
+ span?: Span;
+}
+
+asmSemantics.addAttribute("root", {
+ Root(_) {
+ return this.asm;
+ },
+});
+
+asmSemantics.addAttribute("asm", {
+ ASM(asm, last) {
+ const instructions =
+ asm.children.map(
+ (node) => node.intermediateInstruction as AsmInstruction,
+ ) ?? [];
+ return {
+ instructions: last.child(0)
+ ? [...instructions, last.child(0).instruction]
+ : instructions,
+ };
+ },
+});
+
+asmSemantics.addAttribute("intermediateInstruction", {
+ intermediateInstruction(inst, _n) {
+ return inst.instruction;
+ },
+});
+
+function getAsmAssign(assignN: Node) {
+ let assign = assignN.child(0)?.child(0)?.sourceString ?? "";
+
+ // The book (figure 4.5) specifies DM and ADM as the correct forms for destination,
+ // but since the desktop simulators accept only MD and AMD we have decided to accept both */
+ if (assign == "DM") {
+ assign = "MD";
+ }
+ if (assign == "ADM") {
+ assign = "AMD";
+ }
+ if (assign != "" && !isAssignAsm(assign)) {
+ const reversed = assign.split("").reverse().join("");
+ const suggestion = isAssignAsm(reversed)
+ ? `. Did you mean ${reversed}?`
+ : "";
+ throw createError(
+ `Invalid ASM target: ${assign}${suggestion}`,
+ span(assignN.source),
+ );
+ }
+
+ return assign;
+}
+
+function getAsmOp(opN: Node) {
+ const op = opN.sourceString;
+
+ if (!isCommandAsm(op)) {
+ const reversed = op.split("").reverse().join("");
+ const suggestion = isCommandAsm(reversed)
+ ? `. Did you mean ${reversed}?`
+ : "";
+ throw createError(
+ `Invalid ASM value: ${opN.sourceString}${suggestion}`,
+ span(opN.source),
+ );
+ }
+
+ return op;
+}
+
+asmSemantics.addAttribute("instruction", {
+ aInstruction(_at, name): AsmAInstruction {
+ if (typeof name.value === "string") return A(name.value, span(this.source));
+ else return A(parseInt(name.value.join(""), 10), span(this.source));
+ },
+ cInstruction(assignN, opN, jmpN): AsmCInstruction {
+ const assign = getAsmAssign(assignN);
+
+ const op = getAsmOp(opN) as COMMANDS_ASM;
+ const jmp = (jmpN.child(0)?.child(1)?.sourceString ?? "") as JUMP_ASM;
+ return C(assign as ASSIGN_ASM, op, jmp, span(this.source));
+ },
+ label(_o, { name }, _c): AsmLabelInstruction {
+ return L(name, span(this.source));
+ },
+});
+
+export type Pointer =
+ | "R0"
+ | "R1"
+ | "R2"
+ | "R3"
+ | "R4"
+ | "R5"
+ | "R6"
+ | "R7"
+ | "R8"
+ | "R9"
+ | "R10"
+ | "R11"
+ | "R12"
+ | "R13"
+ | "R14"
+ | "R15"
+ | "SP"
+ | "LCL"
+ | "ARG"
+ | "THIS"
+ | "THAT"
+ | "SCREEN"
+ | "KBD";
+
+export function fillLabel(
+ asm: Asm,
+ symbolCallback?: (name: string, value: number, isVar: boolean) => void,
+): Result {
+ let nextLabel = 16;
+ const symbols = new Map([
+ ["R0", 0],
+ ["R1", 1],
+ ["R2", 2],
+ ["R3", 3],
+ ["R4", 4],
+ ["R5", 5],
+ ["R6", 6],
+ ["R7", 7],
+ ["R8", 8],
+ ["R9", 9],
+ ["R10", 10],
+ ["R11", 11],
+ ["R12", 12],
+ ["R13", 13],
+ ["R14", 14],
+ ["R15", 15],
+ ["SP", 0],
+ ["LCL", 1],
+ ["ARG", 2],
+ ["THIS", 3],
+ ["THAT", 4],
+ ["SCREEN", SCREEN_OFFSET],
+ ["KBD", KEYBOARD_OFFSET],
+ ]);
+
+ function getLabelValue(label: string) {
+ if (!symbols.has(label)) {
+ symbols.set(label, nextLabel);
+ symbolCallback?.(label, nextLabel, true);
+ nextLabel += 1;
+ }
+ return assertExists(symbols.get(label), `Label not in symbols: ${label}`);
+ }
+
+ function transmuteAInstruction(instruction: AsmALabelInstruction) {
+ const value = getLabelValue(instruction.label);
+ (instruction as unknown as AsmAValueInstruction).value = value;
+ delete (instruction as unknown as { label: undefined }).label;
+ }
+
+ const unfilled: AsmALabelInstruction[] = [];
+ let line = 0;
+ for (const instruction of asm.instructions) {
+ if (instruction.type === "L") {
+ if (symbols.has(instruction.label)) {
+ return Err(
+ createError(`Duplicate label ${instruction.label}`, instruction.span),
+ );
+ } else {
+ symbols.set(instruction.label, line);
+ symbolCallback?.(instruction.label, line, false);
+ }
+ continue;
+ }
+
+ line += 1;
+
+ if (instruction.type === "A") {
+ if (isALabelInstruction(instruction)) {
+ unfilled.push(instruction);
+ }
+ }
+ }
+
+ unfilled.forEach(transmuteAInstruction);
+ return Ok();
+}
+
+function writeCInst(inst: AsmCInstruction): string {
+ return (
+ (inst.store ? `${ASSIGN.op[inst.store]}=` : "") +
+ COMMANDS.op[inst.op] +
+ (inst.jump ? `;${JUMP.op[inst.jump]}` : "")
+ );
+}
+
+export const AsmToString = (inst: AsmInstruction | string): string => {
+ if (typeof inst === "string") return inst;
+ switch (inst.type) {
+ case "A":
+ return isALabelInstruction(inst) ? `@${inst.label}` : `@${inst.value}`;
+ case "L":
+ return `(${inst.label})`;
+ case "C":
+ return writeCInst(inst);
+ }
+};
+
+export function translateInstruction(inst: AsmInstruction): number | undefined {
+ if (inst.type === "A") {
+ if (isALabelInstruction(inst)) {
+ throw new Error(`ASM Emitting unfilled A instruction`);
+ }
+ return inst.value;
+ }
+ if (inst.type === "C") {
+ return makeC(
+ inst.isM,
+ inst.op,
+ (inst.store ?? 0) as ASSIGN_OP,
+ (inst.jump ?? 0) as ASSIGN_OP,
+ );
+ }
+ return undefined;
+}
+
+export function emit(asm: Asm): number[] {
+ return asm.instructions
+ .map(translateInstruction)
+ .filter((op): op is number => op !== undefined);
+}
+
+const A = (source: string | number, span?: Span): AsmAInstruction => {
+ if (typeof source === "number" && (source > 32767 || source < 0)) {
+ throw createError(
+ `${source} is invalid for an A instruction (should be 0 to 32767)`,
+ span,
+ );
+ }
+ return typeof source === "string"
+ ? {
+ type: "A",
+ label: source,
+ span,
+ }
+ : {
+ type: "A",
+ value: source,
+ span,
+ };
+};
+
+const C = (
+ assign: ASSIGN_ASM,
+ op: COMMANDS_ASM,
+ jmp?: JUMP_ASM,
+ span?: Span,
+): AsmCInstruction => {
+ const inst: AsmCInstruction = {
+ type: "C",
+ op: COMMANDS.getOp(op),
+ isM: op.includes("M"),
+ span,
+ };
+ if (jmp) inst.jump = JUMP.asm[jmp];
+ if (assign) inst.store = ASSIGN.asm[assign];
+ return inst;
+};
+
+const AC = (
+ source: string | number,
+ assign: ASSIGN_ASM,
+ op: COMMANDS_ASM,
+ jmp?: JUMP_ASM,
+) => [A(source), C(assign, op, jmp)];
+
+const L = (label: string, span?: Span): AsmLabelInstruction => ({
+ type: "L",
+ label,
+ span,
+});
+
+export const ASM = {
+ grammar: asmGrammar,
+ semantics: asmSemantics,
+ parser: grammar,
+ parse: makeParser(grammar, asmSemantics),
+ passes: {
+ fillLabel,
+ emit,
+ },
+ A,
+ C,
+ AC,
+ L,
+};
diff --git a/src/lib/software/vendor/nand2tetris/languages/base.ts b/src/lib/software/vendor/nand2tetris/languages/base.ts
new file mode 100644
index 0000000..5944031
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/languages/base.ts
@@ -0,0 +1,127 @@
+import { Err, Ok, type Result } from "@davidsouther/jiffies/result.ts";
+import {
+ type Dict,
+ type Grammar,
+ grammar,
+ type Interval,
+ type Semantics,
+} from "ohm-js";
+import { int2, int10, int16 } from "../util/twos.js";
+
+import baseGrammar from "./grammars/base.ohm.js";
+export const grammars = {
+ Base: grammar(baseGrammar),
+};
+
+export const baseSemantics = grammars.Base.createSemantics();
+
+baseSemantics.extendOperation("asIteration", {
+ List(list, _) {
+ return list.asIteration();
+ },
+});
+
+baseSemantics.addAttribute("value", {
+ decNumber(_, digits): number {
+ return int10(digits.sourceString);
+ },
+ wholeDec(_, digits): number {
+ return int10(digits.sourceString);
+ },
+ binNumber(_, digits) {
+ return int2(digits.sourceString);
+ },
+ hexNumber(_, digits) {
+ return int16(digits.sourceString);
+ },
+ Number(num) {
+ return num.value;
+ },
+ Name(ident) {
+ return ident.name;
+ },
+ identifier(_, __): string {
+ return this.sourceString;
+ },
+ _iter(...children) {
+ return children.map((c) => c.value);
+ },
+ _terminal() {
+ return this.sourceString;
+ },
+});
+
+baseSemantics.addAttribute("name", {
+ identifier(_, __): string {
+ return this.sourceString;
+ },
+ Name(_): string {
+ return this.child(0)?.name;
+ },
+});
+
+baseSemantics.addAttribute("String", {
+ String(_a, str, _b) {
+ return str.sourceString;
+ },
+});
+
+export interface CompilationError {
+ message: string;
+ span?: Span;
+}
+
+const UNKNOWN_HDL_ERROR = `HDL statement has a syntax error`;
+
+export function createError(
+ description: string,
+ span?: Span,
+): CompilationError {
+ const match = description.match(/Line \d+, col \d+: (?.*)/);
+ const message = match?.groups?.message ? match.groups.message : description;
+ return {
+ message: `${
+ span?.line != undefined ? `Line ${span.line}: ` : ""
+ }${message}`,
+ span: span,
+ };
+}
+
+export function makeParser(
+ grammar: Grammar,
+ semantics: Semantics,
+ property: (obj: Dict) => ResultType = ({ root }) => root,
+): (source: string) => Result {
+ return function parse(source) {
+ try {
+ const match = grammar.match(source);
+ if (match.failed()) {
+ return Err(
+ createError(
+ match.shortMessage ?? UNKNOWN_HDL_ERROR,
+ span(match.getInterval()),
+ ),
+ );
+ }
+ const parsed = semantics(match);
+ const parse = property(parsed);
+ return Ok(parse);
+ } catch (e) {
+ return Err(e as Error);
+ }
+ };
+}
+
+export interface Span {
+ start: number;
+ end: number;
+ line: number;
+}
+
+export function span(span: Interval): Span {
+ return {
+ start: span.startIdx,
+ end: span.endIdx,
+ line: span.getLineAndColumn().lineNum,
+ };
+}
diff --git a/src/lib/software/vendor/nand2tetris/languages/grammars/asm.ohm.js b/src/lib/software/vendor/nand2tetris/languages/grammars/asm.ohm.js
new file mode 100644
index 0000000..76182dc
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/languages/grammars/asm.ohm.js
@@ -0,0 +1,22 @@
+const asm = `ASM <: Base {
+ Root := ASM
+ ASM = intermediateInstruction* instruction?
+
+ instruction = label|aInstruction|cInstruction
+ intermediateInstruction = instruction space+
+
+ identifier := (letter|underscore|dot|dollar|colon) (alnum|underscore|dot|dollar|colon)*
+
+ label = openParen identifier closeParen
+ aInstruction = at (identifier | digit+)
+ cInstruction = assign? op jmp?
+
+ assignChar = "A" | "M" | "D"
+ opChar = assignChar | "0" | "1" | "!" | "-" | "+" | "|" | "&"
+
+ assign = assignChar+ equal
+ op = opChar+
+
+ jmp = semi ("JGT" | "JEQ" | "JGE" | "JLT" | "JNE" | "JLE" | "JMP")
+}`;
+export default asm;
diff --git a/src/lib/software/vendor/nand2tetris/languages/grammars/base.ohm.js b/src/lib/software/vendor/nand2tetris/languages/grammars/base.ohm.js
new file mode 100644
index 0000000..acce3f4
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/languages/grammars/base.ohm.js
@@ -0,0 +1,79 @@
+const base = `
+Base {
+ Root = Value*
+
+ At = at
+ Bang = bang
+ Bar = bar
+ CloseAngle = closeAngle
+ CloseBrace = closeBrace
+ CloseParen = closeParen
+ CloseSquare = closeSquare
+ Comma = comma
+ Dollar = dollar
+ Dot = dot
+ DoubleQuote = doubleQuote
+ Equal = equal
+ OpenAngle = openAngle
+ OpenBrace = openBrace
+ OpenParen = openParen
+ OpenSquare = openSquare
+ Percent = percent
+ Semi = semi
+ Underscore = underscore
+
+ at = "@"
+ bang = "!"
+ bar = "|"
+ closeAngle = ">"
+ closeBrace = "}"
+ closeParen = ")"
+ closeSquare = "]"
+ comma = ","
+ dollar = "$"
+ dot = "."
+ doubleQuote = "\\""
+ equal = "="
+ minus = "-"
+ newline = "\\r"? "\\n"
+ openAngle = "<"
+ openBrace = "{"
+ openParen = "("
+ openSquare = "["
+ percent = "%"
+ semi = ";"
+ underscore = "_"
+ colon = ":"
+
+ Value = identifier | number | boolean
+
+ boolean = true | false
+ True = true
+ False = false
+ true = "true"
+ false = "false"
+
+ Name = identifier
+ identifier = (letter|underscore|dot|dollar) (alnum|underscore|dot|dollar)*
+
+ Number = number
+ number = hexNumber | decNumber | binNumber
+ binNumber = ("%B") ("0"|"1")+
+ hexNumber = ("%X") hexDigit+
+ decNumber = ("%D")? (wholeDec | realDec)
+ wholeDec = minus? digit+
+ realDec = minus? digit* "." digit+
+
+ String = DoubleQuote (~doubleQuote any)* doubleQuote
+
+ spaces := (lineComment | comment | space)*
+ commentStart = "/*"
+ commentEnd = "*/"
+ comment = commentStart (~commentEnd any)* commentEnd
+ lineCommentStart = "//"
+ lineComment = lineCommentStart (~"\\n" any)*
+
+ List = NonemptyListOf sep?
+ EmptyList = EmptyList sep?
+}`;
+export default base;
diff --git a/src/lib/software/vendor/nand2tetris/languages/grammars/jack.ohm.js b/src/lib/software/vendor/nand2tetris/languages/grammars/jack.ohm.js
new file mode 100644
index 0000000..c1431ce
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/languages/grammars/jack.ohm.js
@@ -0,0 +1,80 @@
+const jack = `Jack <: Base {
+ Root := Class
+
+ whitespace = (lineComment | comment | space)
+
+ class = "class" whitespace+
+ Class = class jackIdentifier OpenBrace ClassVarDec* SubroutineDec* CloseBrace
+
+ type = ("int" | "char" | "boolean" | jackIdentifier) whitespace+
+
+ classVarType = ("static" | "field") whitespace+
+ ClassVarDec = classVarType type jackIdentifier TrailingIdentifier* Semi
+ TrailingIdentifier = Comma jackIdentifier
+
+ void = "void" whitespace+
+ returnType = (type | void)
+ subroutineType = ("constructor" | "function" | "method") whitespace+
+ SubroutineDec = subroutineType returnType jackIdentifier OpenParen ParameterList CloseParen SubroutineBody
+
+
+ Parameter = type jackIdentifier
+ Parameters = Parameter TrailingParameter*
+ TrailingParameter = Comma Parameter
+ ParameterList = Parameters?
+
+ SubroutineBody = OpenBrace VarDec* Statement* CloseBrace
+
+ var = "var" whitespace+
+ VarDec = var type jackIdentifier TrailingIdentifier* Semi
+
+ Statement = LetStatement | IfStatement | WhileStatement | DoStatement | ReturnStatement
+
+ arrayAccessStart = jackIdentifier openSquare
+ ArrayAccess = arrayAccessStart Expression CloseSquare
+
+ let = "let" whitespace+
+ LetTarget = ArrayAccess | jackIdentifier
+ LetStatement = let LetTarget Equal Expression Semi
+
+ IfStatement = "if" OpenParen Expression CloseParen OpenBrace Statement* CloseBrace ElseBlock?
+ ElseBlock = "else" OpenBrace Statement* CloseBrace
+
+ WhileStatement = "while" OpenParen Expression CloseParen OpenBrace Statement* CloseBrace
+
+ do = "do" whitespace+
+ DoStatement = do SubroutineCall Semi
+
+ return = "return"
+ returnWithSpace = "return" whitespace+
+ ReturnStatement = EmptyReturn | ReturnValue
+ EmptyReturn = return Semi
+ ReturnValue = returnWithSpace Expression Semi
+
+ op = "+" | "-" | "*" | "/" | "&" | "|" | "<" | ">" | "="
+ ExpressionPart = op Term
+ Expression = Term ExpressionPart*
+
+ integerConstant = digit+
+ stringConstant = doubleQuote (~doubleQuote ~newline any)* doubleQuote
+ keywordConstant = "true" | "false" | "null" | "this"
+
+ GroupedExpression = OpenParen Expression CloseParen
+
+ unaryOp = "-" | "~"
+ UnaryExpression = unaryOp Term
+
+ Term = integerConstant | stringConstant | keywordConstant | SubroutineCall | ArrayAccess | jackIdentifier | GroupedExpression | UnaryExpression
+
+ compoundIdentifier = jackIdentifier dot jackIdentifier
+ SubroutineName = compoundIdentifier | jackIdentifier
+ SubroutineCall = SubroutineName OpenParen ExpressionList CloseParen
+
+ ExpressionList = Expressions?
+ Expressions = Expression TrailingExpression*
+ TrailingExpression = Comma Expression
+
+ jackIdentifier = letter (alnum | underscore)*
+}`;
+
+export default jack;
diff --git a/src/lib/software/vendor/nand2tetris/languages/grammars/vm.ohm.js b/src/lib/software/vendor/nand2tetris/languages/grammars/vm.ohm.js
new file mode 100644
index 0000000..6c08bdc
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/languages/grammars/vm.ohm.js
@@ -0,0 +1,57 @@
+const vm = `Vm <: Base {
+ Root := Vm
+
+ Vm = newline* VmInstructionLine* VmInstruction?
+
+ space := comment | " " | "\t"
+ whitespace = lineComment | comment | space
+
+ VmInstructionLine = VmInstruction newline+
+ VmInstruction =
+ | StackInstruction
+ | OpInstruction
+ | FunctionInstruction
+ | CallInstruction
+ | ReturnInstruction
+ | GotoInstruction
+ | LabelInstruction
+
+ StackInstruction = (push | pop) MemorySegment Number
+ OpInstruction = Add | Sub | Neg | Lt | Gt | Eq | And | Or | Not
+ FunctionInstruction = function Name Number
+ CallInstruction = call Name Number
+ ReturnInstruction = return
+ LabelInstruction = label Name
+ GotoInstruction = (goto | ifGoto) Name
+
+ MemorySegment = argument | local | static | constant | this | that | pointer | temp
+
+ push = "push" whitespace+
+ pop = "pop" whitespace+
+ function = "function" whitespace+
+ call = "call" whitespace+
+ return = "return"
+ goto = "goto" whitespace+
+ ifGoto = "if-goto" whitespace+
+ label = "label" whitespace+
+
+ argument = "argument" whitespace+
+ local = "local" whitespace+
+ static = "static" whitespace+
+ constant = "constant" whitespace+
+ this = "this" whitespace+
+ that = "that" whitespace+
+ pointer = "pointer" whitespace+
+ temp = "temp" whitespace+
+
+ Add = "add"
+ Sub = "sub"
+ Neg = "neg"
+ Eq = "eq"
+ Lt = "lt"
+ Gt = "gt"
+ And = "and"
+ Or = "or"
+ Not = "not"
+}`;
+export default vm;
diff --git a/src/lib/software/vendor/nand2tetris/languages/jack.ts b/src/lib/software/vendor/nand2tetris/languages/jack.ts
new file mode 100644
index 0000000..928d722
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/languages/jack.ts
@@ -0,0 +1,438 @@
+import { type Node, grammar as ohmGrammar } from "ohm-js";
+import { baseSemantics, grammars, makeParser, type Span, span } from "./base.js";
+import jackGrammar from "./grammars/jack.ohm.js";
+
+const primitives = new Set(["int", "boolean", "char"] as const);
+export type Primitive = typeof primitives extends Set ? S : never;
+
+export function isPrimitive(value: string): value is Primitive {
+ return primitives.has(value as Primitive);
+}
+
+export type Type = Primitive | string;
+
+export interface Class {
+ name: { value: string; span: Span };
+ varDecs: ClassVarDec[];
+ subroutines: Subroutine[];
+}
+
+export type ClassVarType = "static" | "field";
+
+export interface ClassVarDec {
+ varType: ClassVarType;
+ type: { value: Type; span: Span };
+ names: string[];
+}
+
+export interface Parameter {
+ type: { value: Type; span: Span };
+ name: string;
+}
+
+export type ReturnType = Type | "void";
+export type SubroutineType = "constructor" | "function" | "method";
+
+export interface Subroutine {
+ type: SubroutineType;
+ name: { value: string; span: Span };
+ returnType: { value: ReturnType; span: Span };
+ parameters: Parameter[];
+ body: SubroutineBody;
+}
+
+export interface SubroutineBody {
+ varDecs: VarDec[];
+ statements: Statement[];
+}
+
+export interface VarDec {
+ type: { value: Type; span: Span };
+ names: string[];
+}
+
+export type Statement =
+ | LetStatement
+ | IfStatement
+ | WhileStatement
+ | DoStatement
+ | ReturnStatement;
+
+export interface LetStatement {
+ statementType: "letStatement";
+ name: { value: string; span: Span };
+ arrayIndex?: Expression;
+ value: Expression;
+ span: Span;
+}
+
+export interface IfStatement {
+ statementType: "ifStatement";
+ condition: Expression;
+ body: Statement[];
+ else: Statement[];
+}
+
+export interface WhileStatement {
+ statementType: "whileStatement";
+ condition: Expression;
+ body: Statement[];
+}
+
+export interface DoStatement {
+ statementType: "doStatement";
+ call: SubroutineCall;
+}
+
+export interface ReturnStatement {
+ statementType: "returnStatement";
+ value?: Expression;
+ span: Span;
+}
+
+export type Op = "+" | "-" | "*" | "/" | "&" | "|" | "<" | ">" | "=";
+export type KeywordConstant = "true" | "false" | "null" | "this";
+export type UnaryOp = "-" | "~";
+
+export type Term =
+ | NumericLiteral
+ | StringLiteral
+ | Variable
+ | KeywordLiteral
+ | SubroutineCall
+ | ArrayAccess
+ | GroupedExpression
+ | UnaryExpression;
+
+export interface NumericLiteral {
+ termType: "numericLiteral";
+ value: number;
+}
+
+export interface StringLiteral {
+ termType: "stringLiteral";
+ value: string;
+}
+
+export interface KeywordLiteral {
+ termType: "keywordLiteral";
+ value: KeywordConstant;
+}
+
+export interface Variable {
+ termType: "variable";
+ name: string;
+ span: Span;
+}
+
+export interface GroupedExpression {
+ termType: "groupedExpression";
+ expression: Expression;
+}
+
+export interface UnaryExpression {
+ termType: "unaryExpression";
+ op: UnaryOp;
+ term: Term;
+}
+
+export interface ArrayAccess {
+ termType: "arrayAccess";
+ name: { value: string; span: Span };
+ index: Expression;
+ span: Span;
+}
+
+export interface SubroutineCall {
+ termType: "subroutineCall";
+ name: { value: string; span: Span };
+ span: Span;
+ parameters: Expression[];
+}
+
+export interface ExpressionPart {
+ op: Op;
+ term: Term;
+}
+
+export interface Expression {
+ term: Term;
+ rest: ExpressionPart[];
+}
+
+export const grammar = ohmGrammar(jackGrammar, grammars);
+export const jackSemantics = grammar.extendSemantics(baseSemantics);
+
+function statements(node: Node) {
+ return node.children.map((n) => n.statement);
+}
+
+jackSemantics.addAttribute("Root", {
+ Root(_) {
+ return this.class;
+ },
+});
+
+jackSemantics.addAttribute("class", {
+ Class(_a, name, _b, varDecs, subroutines, _c) {
+ return {
+ name: { value: name.sourceString, span: span(name.source) },
+ varDecs: varDecs.children.map((n) => n.classVarDec),
+ subroutines: subroutines.children.map((n) => n.subroutineDec),
+ };
+ },
+});
+
+jackSemantics.addAttribute("classVarDec", {
+ ClassVarDec(varType, type, name, rest, _) {
+ return {
+ varType: varType.sourceString.trim() as ClassVarType,
+ type: {
+ value: type.sourceString.trim() as Type,
+ span: span(type.source),
+ },
+ names: [
+ name.sourceString,
+ ...rest.children.map((n) => n.child(1).sourceString),
+ ],
+ };
+ },
+});
+
+jackSemantics.addAttribute("subroutineDec", {
+ SubroutineDec(type, returnType, name, _a, parameters, _b, body) {
+ return {
+ type: type.sourceString.trim() as SubroutineType,
+ returnType: {
+ value: returnType.sourceString.trim() as ReturnType,
+ span: span(returnType.source),
+ },
+ name: { value: name.sourceString, span: span(name.source) },
+ parameters: parameters.parameterList,
+ body: body.subroutineBody,
+ };
+ },
+});
+
+jackSemantics.addAttribute("parameter", {
+ Parameter(type, name) {
+ return {
+ type: {
+ value: type.sourceString.trim() as Type,
+ span: span(type.source),
+ },
+ name: name.sourceString,
+ };
+ },
+});
+
+jackSemantics.addAttribute("parameterList", {
+ ParameterList(node) {
+ return node.child(0)?.parameters ?? [];
+ },
+});
+
+jackSemantics.addAttribute("parameters", {
+ Parameters(first, rest) {
+ return [first.parameter, ...rest.children.map((n) => n.child(1).parameter)];
+ },
+});
+
+jackSemantics.addAttribute("subroutineBody", {
+ SubroutineBody(_a, varDecs, statementList, _b) {
+ return {
+ varDecs: varDecs.children.map((n) => n.varDec),
+ statements: statements(statementList),
+ };
+ },
+});
+
+jackSemantics.addAttribute("varDec", {
+ VarDec(_a, type, name, rest, _b) {
+ return {
+ type: {
+ value: type.sourceString.trim() as Type,
+ span: span(type.source),
+ },
+ names: [
+ name.sourceString,
+ ...rest.children.map((n) => n.child(1).sourceString),
+ ],
+ };
+ },
+});
+
+// jackSemantics.addAttribute("letTarget", {
+// LetTarget() {
+// jackI
+// }
+// })
+
+jackSemantics.addAttribute("statement", {
+ LetStatement(_a, target, _b, value, _c) {
+ if (target.term.termType == "variable") {
+ return {
+ statementType: "letStatement",
+ name: {
+ value: (target.term as Variable).name,
+ span: (target.term as Variable).span,
+ },
+ value: value.expression,
+ span: span(this.source),
+ };
+ } else {
+ return {
+ statementType: "letStatement",
+ name: (target.term as ArrayAccess).name,
+ arrayIndex: (target.term as ArrayAccess).index,
+ value: value.expression,
+ span: span(this.source),
+ };
+ }
+ },
+
+ IfStatement(_a, _b, condition, _c, _d, body, _e, elseBlock) {
+ return {
+ statementType: "ifStatement",
+ condition: condition.expression,
+ body: statements(body),
+ else: elseBlock.child(0)?.else ?? [],
+ };
+ },
+
+ WhileStatement(_a, _b, condition, _c, _d, body, _e) {
+ return {
+ statementType: "whileStatement",
+ condition: condition.expression,
+ body: statements(body),
+ };
+ },
+
+ DoStatement(_a, call, _b) {
+ return { statementType: "doStatement", call: call.term as SubroutineCall };
+ },
+
+ EmptyReturn(_a, _b) {
+ return {
+ statementType: "returnStatement",
+ span: span(this.source),
+ };
+ },
+
+ ReturnValue(_a, value, _b) {
+ return {
+ statementType: "returnStatement",
+ value: value.expression,
+ span: span(this.source),
+ };
+ },
+});
+
+jackSemantics.addAttribute("else", {
+ ElseBlock(_a, _b, body, _c) {
+ return statements(body);
+ },
+});
+
+jackSemantics.addAttribute("term", {
+ integerConstant(node) {
+ return {
+ termType: "numericLiteral",
+ value: Number(node.sourceString),
+ };
+ },
+
+ stringConstant(_a, _b, _c) {
+ return { termType: "stringLiteral", value: this.sourceString.slice(1, -1) };
+ },
+
+ keywordConstant(_) {
+ return {
+ termType: "keywordLiteral",
+ value: this.sourceString as KeywordConstant,
+ };
+ },
+
+ SubroutineCall(name, _a, expressions, _b) {
+ return {
+ termType: "subroutineCall",
+ name: { value: name.sourceString, span: span(name.source) },
+ parameters: expressions.expressionList,
+ span: span(this.source),
+ };
+ },
+
+ ArrayAccess(start, index, _) {
+ const name = start.child(0);
+ return {
+ termType: "arrayAccess",
+ name: { value: name.sourceString, span: span(name.source) },
+ index: index.expression,
+ span: span(this.source),
+ };
+ },
+
+ jackIdentifier(first, rest) {
+ return {
+ termType: "variable",
+ name: `${first.sourceString}${rest.sourceString}`,
+ span: span(this.source),
+ };
+ },
+
+ GroupedExpression(_a, expression, _b) {
+ return {
+ termType: "groupedExpression",
+ expression: expression.expression,
+ };
+ },
+
+ UnaryExpression(op, term) {
+ return {
+ termType: "unaryExpression",
+ op: op.sourceString as UnaryOp,
+ term: term.term,
+ };
+ },
+});
+
+jackSemantics.addAttribute("expressionList", {
+ ExpressionList(node) {
+ return node.child(0)?.expressions ?? [];
+ },
+});
+
+jackSemantics.addAttribute("expressions", {
+ Expressions(first, rest) {
+ return [
+ first.expression,
+ ...rest.children.map((n) => n.child(1).expression),
+ ];
+ },
+});
+
+jackSemantics.addAttribute("expression", {
+ Expression(first, rest) {
+ return {
+ nodeType: "expression",
+ term: first.term,
+ rest: rest.children.map((n) => n.expressionPart),
+ };
+ },
+});
+
+jackSemantics.addAttribute("expressionPart", {
+ ExpressionPart(op, term) {
+ return {
+ op: op.sourceString as Op,
+ term: term.term,
+ };
+ },
+});
+
+export const JACK = {
+ parser: grammar,
+ grammar: jackGrammar,
+ semantics: jackSemantics,
+ parse: makeParser(grammar, jackSemantics, (n) => n.class),
+};
diff --git a/src/lib/software/vendor/nand2tetris/languages/vm.ts b/src/lib/software/vendor/nand2tetris/languages/vm.ts
new file mode 100644
index 0000000..24447d8
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/languages/vm.ts
@@ -0,0 +1,260 @@
+/** Reads tst files to apply and perform test runs. */
+
+import { grammar as ohmGrammar } from "ohm-js";
+import { baseSemantics, grammars, makeParser, type Span, span } from "./base.js";
+
+import vmGrammar from "./grammars/vm.ohm.js";
+export const grammar = ohmGrammar(vmGrammar, grammars);
+export const vmSemantics = grammar.extendSemantics(baseSemantics);
+
+export interface Vm {
+ instructions: VmInstruction[];
+}
+
+export type Segment =
+ | "argument"
+ | "local"
+ | "static"
+ | "constant"
+ | "this"
+ | "that"
+ | "pointer"
+ | "temp";
+
+export type VmInstruction =
+ | StackInstruction
+ | OpInstruction
+ | FunctionInstruction
+ | CallInstruction
+ | ReturnInstruction
+ | GotoInstruction
+ | LabelInstruction;
+
+export interface StackInstruction {
+ op: "push" | "pop";
+ segment: Segment;
+ offset: number;
+ span?: Span;
+}
+export interface OpInstruction {
+ op: "add" | "sub" | "neg" | "lt" | "gt" | "eq" | "and" | "or" | "not";
+ span?: Span;
+}
+export interface FunctionInstruction {
+ op: "function";
+ name: string;
+ nVars: number;
+ span?: Span;
+}
+export interface CallInstruction {
+ op: "call";
+ name: string;
+ nArgs: number;
+ span?: Span;
+}
+export interface ReturnInstruction {
+ op: "return";
+ span?: Span;
+}
+export interface LabelInstruction {
+ op: "label";
+ label: string;
+ span?: Span;
+}
+export interface GotoInstruction {
+ op: "goto" | "if-goto";
+ label: string;
+ span?: Span;
+}
+
+vmSemantics.addAttribute<
+ | "push"
+ | "pop"
+ | "function"
+ | "call"
+ | "return"
+ | "goto"
+ | "if-goto"
+ | "label"
+ | "add"
+ | "sub"
+ | "neg"
+ | "lt"
+ | "gt"
+ | "eq"
+ | "and"
+ | "or"
+ | "not"
+>("op", {
+ push(_a, _b) {
+ return "push";
+ },
+ pop(_a, _b) {
+ return "pop";
+ },
+ function(_a, _b) {
+ return "function";
+ },
+ call(_a, _b) {
+ return "call";
+ },
+ return(_a) {
+ return "return";
+ },
+ goto(_a, _b) {
+ return "goto";
+ },
+ ifGoto(_a, _b) {
+ return "if-goto";
+ },
+ label(_a, _b) {
+ return "label";
+ },
+ Add(_) {
+ return "add";
+ },
+ Sub(_) {
+ return "sub";
+ },
+ Neg(_) {
+ return "neg";
+ },
+ Eq(_) {
+ return "eq";
+ },
+ Lt(_) {
+ return "lt";
+ },
+ Gt(_) {
+ return "gt";
+ },
+ And(_) {
+ return "and";
+ },
+ Or(_) {
+ return "or";
+ },
+ Not(_) {
+ return "not";
+ },
+});
+
+vmSemantics.addAttribute<
+ | "argument"
+ | "local"
+ | "static"
+ | "constant"
+ | "this"
+ | "that"
+ | "pointer"
+ | "temp"
+>("segment", {
+ argument(_a, _b) {
+ return "argument";
+ },
+ local(_a, _b) {
+ return "local";
+ },
+ static(_a, _b) {
+ return "static";
+ },
+ constant(_a, _b) {
+ return "constant";
+ },
+ this(_a, _b) {
+ return "this";
+ },
+ that(_a, _b) {
+ return "that";
+ },
+ pointer(_a, _b) {
+ return "pointer";
+ },
+ temp(_a, _b) {
+ return "temp";
+ },
+});
+
+vmSemantics.addAttribute("instruction", {
+ StackInstruction({ op }, { segment }, value) {
+ return {
+ op: op as "push" | "pop",
+ segment,
+ offset: Number(value.sourceString),
+ span: span(this.source),
+ };
+ },
+ OpInstruction({ op }) {
+ return {
+ op: op as
+ | "add"
+ | "sub"
+ | "neg"
+ | "lt"
+ | "gt"
+ | "eq"
+ | "and"
+ | "or"
+ | "not",
+ span: span(this.source),
+ };
+ },
+ FunctionInstruction(_, { name }, nVars) {
+ return {
+ op: "function",
+ name,
+ nVars: Number(nVars.sourceString),
+ span: span(this.source),
+ };
+ },
+ CallInstruction(_, { name }, nArgs) {
+ return {
+ op: "call",
+ name,
+ nArgs: Number(nArgs.sourceString),
+ span: span(this.source),
+ };
+ },
+ ReturnInstruction(_) {
+ return { op: "return", span: span(this.source) };
+ },
+ // LabelInstruction = Label Name
+ LabelInstruction(_, { name: label }) {
+ return { op: "label", label, span: span(this.source) };
+ },
+ // GotoInstruction = (Goto | IfGoto) Name
+ GotoInstruction({ op }, { name: label }) {
+ return {
+ op: op as "goto" | "if-goto",
+ label,
+ span: span(this.source),
+ };
+ },
+ VmInstructionLine(inst, _) {
+ return inst.instruction;
+ },
+});
+
+vmSemantics.addAttribute("vm", {
+ Vm(_, lines, last) {
+ const instructions = lines.children.map((node) => node.instruction) ?? [];
+ return {
+ instructions: last.child(0)
+ ? [...instructions, last.child(0).instruction]
+ : instructions,
+ };
+ },
+});
+
+vmSemantics.addAttribute("root", {
+ Root({ vm }) {
+ return vm;
+ },
+});
+
+export const VM = {
+ grammar: vmGrammar,
+ semantics: vmSemantics,
+ parser: grammar,
+ parse: makeParser(grammar, vmSemantics),
+};
diff --git a/src/lib/software/vendor/nand2tetris/loader.ts b/src/lib/software/vendor/nand2tetris/loader.ts
new file mode 100644
index 0000000..9ba3efc
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/loader.ts
@@ -0,0 +1,30 @@
+import { unwrap } from "@davidsouther/jiffies/result.ts";
+import { ASM } from "./languages/asm.js";
+import { int2, parseTwosInt } from "./util/twos.js";
+
+export async function loadAsm(source: string): Promise {
+ const asm = unwrap(ASM.parse(source));
+ ASM.passes.fillLabel(asm);
+ return ASM.passes.emit(asm);
+}
+
+export async function loadHack(source: string): Promise {
+ return source
+ .split("\n")
+ .filter((line) => line.trim() !== "")
+ .map(int2);
+}
+
+export function loadHackSync(source: string): number[] {
+ return source
+ .split("\n")
+ .filter((line) => line.trim() !== "")
+ .map(int2);
+}
+
+export async function loadBlob(bytes: string): Promise {
+ return bytes
+ .split("\n")
+ .filter((line) => line.trim() !== "")
+ .map(parseTwosInt);
+}
diff --git a/src/lib/software/vendor/nand2tetris/util/asm.ts b/src/lib/software/vendor/nand2tetris/util/asm.ts
new file mode 100644
index 0000000..96bdd54
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/util/asm.ts
@@ -0,0 +1,116 @@
+import {
+ ASSIGN,
+ type ASSIGN_OP,
+ COMMANDS,
+ type COMMANDS_ASM,
+ type COMMANDS_OP,
+ isAssignAsm,
+ isCommandAsm,
+ isJumpAsm,
+ JUMP,
+ type JUMP_OP,
+} from "../cpu/alu.js";
+
+export type CommandOps = keyof typeof COMMANDS.op;
+export type JumpOps = keyof typeof JUMP.op;
+export type StoreOps = keyof typeof ASSIGN.op;
+
+export function asm(op: number): string {
+ if (op & 0x8000) {
+ return cInstruction(op);
+ }
+ return aInstruction(op);
+}
+
+function cInstruction(op: number): string {
+ op = op & 0xffff; // Clear high order bits
+ const mop = (op & 0x1000) >> 12;
+ const cop: CommandOps = ((op & 0b0000111111000000) >> 6) as CommandOps;
+ const sop: StoreOps = ((op & 0b0000000000111000) >> 3) as StoreOps;
+ const jop: JumpOps = (op & 0b0000000000000111) as JumpOps;
+
+ if (COMMANDS.op[cop] === undefined) {
+ // Invalid commend
+ return "#ERR";
+ }
+
+ let command = COMMANDS.op[cop];
+ if (mop) {
+ command = command.replace(/A/g, "M") as COMMANDS_ASM;
+ }
+
+ const store = ASSIGN.op[sop];
+ const jump = JUMP.op[jop];
+
+ let instruction: string = command;
+ if (store) {
+ instruction = `${store}=${instruction}`;
+ }
+ if (jump) {
+ instruction = `${instruction};${jump}`;
+ }
+
+ return instruction;
+}
+
+function aInstruction(op: number): string {
+ return "@" + (op & 0x7fff).toString(10);
+}
+
+export function op(asm: string): number {
+ if (asm[0] === "@") {
+ return aop(asm);
+ } else {
+ return cop(asm);
+ }
+}
+
+function aop(asm: string): number {
+ return parseInt(asm.substring(1), 10);
+}
+
+function cop(asm: string): number {
+ const firstPass = asm.match(
+ /(?:(?.+)=)?(.+)(?:;(?.+))?/,
+ );
+ const { assignExists, jumpExists } = firstPass?.groups ?? {};
+
+ const parts = asm.match(
+ /(?:(?[AMD]{1,3})=)?(?[-+!01ADM&|]{1,3})(?:;(?JGT|JLT|JGE|JLE|JEQ|JMP))?/,
+ );
+ let { assign, jump } = parts?.groups ?? {};
+ const { operation } = parts?.groups ?? {};
+
+ assign = assign ?? (assignExists ? undefined : "");
+ jump = jump ?? (jumpExists ? undefined : "");
+ if (
+ parts?.[0] != asm || // match is not exhaustive
+ !isAssignAsm(assign) ||
+ !isJumpAsm(jump) ||
+ !isCommandAsm(operation)
+ ) {
+ // TODO: This should return Result<> instead of throw
+ throw new Error("Invalid c instruction");
+ }
+
+ const mode = operation.includes("M");
+ const aop = ASSIGN.asm[assign];
+ const jop = JUMP.asm[jump];
+ const cop = COMMANDS.getOp(operation);
+
+ return makeC(mode, cop, aop, jop);
+}
+
+export function makeC(
+ isM: boolean,
+ op: COMMANDS_OP,
+ assign: ASSIGN_OP,
+ jmp: JUMP_OP,
+): number {
+ const C = 0xe000;
+ const A = isM ? 0x1000 : 0;
+ const O = op << 6;
+ const D = assign << 3;
+ const J = jmp;
+ return C + A + O + D + J;
+}
diff --git a/src/lib/software/vendor/nand2tetris/util/twos.ts b/src/lib/software/vendor/nand2tetris/util/twos.ts
new file mode 100644
index 0000000..bdd0d65
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/util/twos.ts
@@ -0,0 +1,129 @@
+const Hex = [
+ "0",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+];
+
+export function chars(i: number): string {
+ return Hex[i] ?? "X";
+}
+
+export function bits(i: number): string {
+ switch (i) {
+ case 0x0:
+ return "0000";
+ case 0x1:
+ return "0001";
+ case 0x2:
+ return "0010";
+ case 0x3:
+ return "0011";
+ case 0x4:
+ return "0100";
+ case 0x5:
+ return "0101";
+ case 0x6:
+ return "0110";
+ case 0x7:
+ return "0111";
+ case 0x8:
+ return "1000";
+ case 0x9:
+ return "1001";
+ case 0xa:
+ return "1010";
+ case 0xb:
+ return "1011";
+ case 0xc:
+ return "1100";
+ case 0xd:
+ return "1101";
+ case 0xe:
+ return "1110";
+ case 0xf:
+ return "1111";
+ default:
+ return "erro";
+ }
+}
+
+export function int(n: string, radix: number): number {
+ const i = parseInt(n.replace(/[^\d a-f A-F +-.]/g, ""), radix);
+ return i & 0xffff;
+}
+
+export function int16(i: string): number {
+ return int(i, 16);
+}
+
+export function int10(i: string): number {
+ return int(i, 10);
+}
+
+export function int2(i: string): number {
+ return int(i.replaceAll(" ", ""), 2);
+}
+
+export function parseTwosInt(i: string): number {
+ if (i.toUpperCase().includes("X")) {
+ return int16(i);
+ }
+ return int10(i);
+}
+
+export function hex(i: number): string {
+ const hu = chars((i & 0xf000) >> 12);
+ const hl = chars((i & 0x0f00) >> 8);
+ const lu = chars((i & 0x00f0) >> 4);
+ const ll = chars(i & 0x000f);
+
+ return `0x${hu}${hl}${lu}${ll}`;
+}
+
+export function bin(i: number, precision = 16): string {
+ const hu = bits((i & 0xf000) >> 12);
+ const hl = bits((i & 0x0f00) >> 8);
+ const lu = bits((i & 0x00f0) >> 4);
+ const ll = bits(i & 0x000f);
+
+ // return `${hu} ${hl} ${lu} ${ll}`;
+ return `${hu}${hl}${lu}${ll}`.substring(16 - precision); // Match the book's formatting
+}
+
+export function dec(i: number): string {
+ i = i & 0xffff;
+ if (i === 0x8000) {
+ return "-32768";
+ }
+ if (i & 0x8000) {
+ i = (~i + 1) & 0x7fff;
+ return `-${i}`;
+ }
+ return `${i}`;
+}
+
+export function unsigned(i: number): string {
+ i = i & 0xffff;
+ return `${i}`;
+}
+
+export function nand16(a: number, b: number): number {
+ a = a & 0xffff;
+ b = b & 0xffff;
+ let c = ~(a & b);
+ c = c & 0xffff;
+ return c;
+}
diff --git a/src/lib/software/vendor/nand2tetris/vm/builtins.ts b/src/lib/software/vendor/nand2tetris/vm/builtins.ts
new file mode 100644
index 0000000..88b2ba4
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/vm/builtins.ts
@@ -0,0 +1,506 @@
+import {
+ type ReturnType,
+ type Subroutine,
+ type SubroutineType,
+ type Type,
+} from "../languages/jack.js";
+import { VmMemory } from "./memory.js";
+import { ERRNO } from "./os/errors.js";
+import { OS } from "./os/os.js";
+import { BACKSPACE, DOUBLE_QUOTES, NEW_LINE } from "./os/string.js";
+
+export type VmBuiltinFunction = (memory: VmMemory, os: OS) => number;
+
+export interface VmBuiltin {
+ func: VmBuiltinFunction;
+ type: SubroutineType;
+ args: Type[];
+ returnType: ReturnType;
+}
+
+function getArgs(memory: VmMemory, n: number) {
+ const args = [];
+ for (let i = 0; i < n; i++) {
+ args.push(memory.get(memory.SP - n + i));
+ }
+ return args;
+}
+
+export function overridesOsCorrectly(cls: string, subroutine: Subroutine) {
+ const builtin = VM_BUILTINS[`${cls}.${subroutine.name.value}`];
+
+ return (
+ builtin &&
+ builtin.args.length == subroutine.parameters.length &&
+ builtin.args.every(
+ (arg, index) => arg == subroutine.parameters[index].type.value,
+ ) &&
+ builtin.returnType == subroutine.returnType.value
+ );
+}
+
+export function makeInterface(name: string, builtin: VmBuiltin) {
+ return `${builtin.returnType} ${name}(${builtin.args.join(",")}`;
+}
+
+export const VM_BUILTINS: Record = {
+ "Math.init": {
+ func: (_, __) => 0,
+ args: [],
+ returnType: "void",
+ type: "function",
+ },
+ "Math.multiply": {
+ func: (memory, _) => {
+ const [a, b] = getArgs(memory, 2);
+ return (a * b) & 0xffff;
+ },
+ args: ["int", "int"],
+ returnType: "int",
+ type: "function",
+ },
+ "Math.divide": {
+ func: (memory, os) => {
+ const [a, b] = getArgs(memory, 2);
+ if (b == 0) {
+ os.sys.error(ERRNO.DIVIDE_BY_ZERO);
+ return 0;
+ }
+ // Round toward zero, as the book's algorithm does: it divides |x| by |y|
+ // and then applies the sign.
+ return Math.trunc(a / b) & 0xffff;
+ },
+ args: ["int", "int"],
+ returnType: "int",
+ type: "function",
+ },
+ "Math.min": {
+ func: (memory, _) => {
+ const [a, b] = getArgs(memory, 2);
+ return Math.min(a, b) & 0xffff;
+ },
+ args: ["int", "int"],
+ returnType: "int",
+ type: "function",
+ },
+ "Math.max": {
+ func: (memory, _) => {
+ const [a, b] = getArgs(memory, 2);
+ return Math.max(a, b) & 0xffff;
+ },
+ args: ["int", "int"],
+ returnType: "int",
+ type: "function",
+ },
+ "Math.sqrt": {
+ func: (memory, os) => {
+ const [x] = getArgs(memory, 1);
+ if (x < 0) {
+ os.sys.error(ERRNO.SQRT_NEG);
+ return 0;
+ }
+ return Math.floor(Math.sqrt(x)) & 0xffff;
+ },
+ args: ["int"],
+ returnType: "int",
+ type: "function",
+ },
+ "Math.abs": {
+ func: (memory, _) => {
+ const [x] = getArgs(memory, 1);
+ return Math.abs(x) & 0xffff;
+ },
+ args: ["int"],
+ returnType: "int",
+ type: "function",
+ },
+ "Screen.init": {
+ func: (_, __) => 0,
+ args: [],
+ returnType: "void",
+ type: "function",
+ },
+ "Screen.clearScreen": {
+ func: (_, os) => {
+ os.screen.clear();
+ return 0;
+ },
+ args: [],
+ returnType: "void",
+ type: "function",
+ },
+ "Screen.setColor": {
+ func: (memory, os) => {
+ const [color] = getArgs(memory, 1);
+ os.screen.color = color !== 0;
+ return 0;
+ },
+ args: ["boolean"],
+ returnType: "void",
+ type: "function",
+ },
+ "Screen.drawPixel": {
+ func: (memory, os) => {
+ const [x, y] = getArgs(memory, 2);
+ os.screen.drawPixel(x, y);
+ return 0;
+ },
+ args: ["int", "int"],
+ returnType: "void",
+ type: "function",
+ },
+ "Screen.drawLine": {
+ func: (memory, os) => {
+ const [x1, y1, x2, y2] = getArgs(memory, 4);
+ os.screen.drawLine(x1, y1, x2, y2);
+ return 0;
+ },
+ args: ["int", "int", "int", "int"],
+ returnType: "void",
+ type: "function",
+ },
+ "Screen.drawRectangle": {
+ func: (memory, os) => {
+ const [x1, y1, x2, y2] = getArgs(memory, 4);
+ os.screen.drawRect(x1, y1, x2, y2);
+ return 0;
+ },
+ args: ["int", "int", "int", "int"],
+ returnType: "void",
+ type: "function",
+ },
+ "Screen.drawCircle": {
+ func: (memory, os) => {
+ const [x, y, r] = getArgs(memory, 3);
+ os.screen.drawCircle(x, y, r);
+ return 0;
+ },
+ args: ["int", "int", "int"],
+ returnType: "void",
+ type: "function",
+ },
+ "Memory.init": {
+ func: (_, __) => 0,
+ args: [],
+ returnType: "void",
+ type: "function",
+ },
+ "Memory.peek": {
+ func: (memory, _) => {
+ const [address] = getArgs(memory, 1);
+ return memory.get(address);
+ },
+ args: ["int"],
+ returnType: "int",
+ type: "function",
+ },
+ "Memory.poke": {
+ func: (memory, _) => {
+ const [address, value] = getArgs(memory, 2);
+ memory.set(address, value);
+ return 0;
+ },
+ args: ["int", "int"],
+ returnType: "void",
+ type: "function",
+ },
+ "Memory.alloc": {
+ func: (memory, os) => {
+ const [size] = getArgs(memory, 1);
+ return os.memory.alloc(size);
+ },
+ args: ["int"],
+ returnType: "Array",
+ type: "function",
+ },
+ "Memory.deAlloc": {
+ func: (memory, os) => {
+ const [address] = getArgs(memory, 1);
+ os.memory.deAlloc(address);
+ return 0;
+ },
+ args: ["Array"],
+ returnType: "void",
+ type: "function",
+ },
+ "Array.init": {
+ func: (_, __) => 0,
+ args: [],
+ returnType: "void",
+ type: "function",
+ },
+ "Array.new": {
+ func: (memory, os) => {
+ const [size] = getArgs(memory, 1);
+ if (size <= 0) {
+ os.sys.error(ERRNO.ARRAY_SIZE_NOT_POSITIVE);
+ return 0;
+ }
+ return os.memory.alloc(size);
+ },
+ args: ["int"],
+ returnType: "Array",
+ type: "constructor",
+ },
+ "Array.dispose": {
+ func: (memory, os) => {
+ const [pointer] = getArgs(memory, 1);
+ os.memory.deAlloc(pointer);
+ return 0;
+ },
+ args: [],
+ returnType: "void",
+ type: "method",
+ },
+ "String.init": {
+ func: (_, __) => 0,
+ args: [],
+ returnType: "void",
+ type: "function",
+ },
+ "String.new": {
+ func: (memory, os) => {
+ const [length] = getArgs(memory, 1);
+ return os.string.new(length);
+ },
+ args: ["int"],
+ returnType: "String",
+ type: "constructor",
+ },
+ "String.dispose": {
+ func: (memory, os) => {
+ const [pointer] = getArgs(memory, 1);
+ os.string.dispose(pointer);
+ return 0;
+ },
+ args: [],
+ returnType: "void",
+ type: "method",
+ },
+ "String.length": {
+ func: (memory, os) => {
+ const [pointer] = getArgs(memory, 1);
+ return os.string.length(pointer);
+ },
+ args: [],
+ returnType: "int",
+ type: "method",
+ },
+ "String.charAt": {
+ func: (memory, os) => {
+ const [pointer, index] = getArgs(memory, 2);
+ return os.string.charAt(pointer, index);
+ },
+ args: ["int"],
+ returnType: "char",
+ type: "method",
+ },
+ "String.setCharAt": {
+ func: (memory, os) => {
+ const [pointer, index, value] = getArgs(memory, 3);
+ os.string.setCharAt(pointer, index, value);
+ return 0;
+ },
+ args: ["int", "char"],
+ returnType: "void",
+ type: "method",
+ },
+ "String.appendChar": {
+ func: (memory, os) => {
+ const [pointer, value] = getArgs(memory, 2);
+ return os.string.appendChar(pointer, value);
+ },
+ args: ["char"],
+ returnType: "String",
+ type: "method",
+ },
+ "String.eraseLastChar": {
+ func: (memory, os) => {
+ const [pointer] = getArgs(memory, 1);
+ os.string.eraseLastChar(pointer);
+ return 0;
+ },
+ args: [],
+ returnType: "void",
+ type: "method",
+ },
+ "String.intValue": {
+ func: (memory, os) => {
+ const [pointer] = getArgs(memory, 1);
+ return os.string.intValue(pointer);
+ },
+ args: [],
+ returnType: "int",
+ type: "method",
+ },
+ "String.setInt": {
+ func: (memory, os) => {
+ const [pointer, value] = getArgs(memory, 2);
+ os.string.setInt(pointer, value);
+ return 0;
+ },
+ args: ["int"],
+ returnType: "void",
+ type: "method",
+ },
+ "String.backSpace": {
+ func: (_, __) => {
+ return BACKSPACE;
+ },
+ args: [],
+ returnType: "char",
+ type: "function",
+ },
+ "String.doubleQuote": {
+ func: (_, __) => {
+ return DOUBLE_QUOTES;
+ },
+ args: [],
+ returnType: "char",
+ type: "function",
+ },
+ "String.newLine": {
+ func: (_, __) => {
+ return NEW_LINE;
+ },
+ args: [],
+ returnType: "char",
+ type: "function",
+ },
+ "Output.init": {
+ func: (_, __) => 0,
+ args: [],
+ returnType: "void",
+ type: "function",
+ },
+ "Output.moveCursor": {
+ func: (memory, os) => {
+ const [i, j] = getArgs(memory, 2);
+ os.output.moveCursor(i, j);
+ return 0;
+ },
+ args: ["int", "int"],
+ returnType: "void",
+ type: "function",
+ },
+ "Output.printChar": {
+ func: (memory, os) => {
+ const [code] = getArgs(memory, 1);
+ os.output.printChar(code);
+ return 0;
+ },
+ args: ["char"],
+ returnType: "void",
+ type: "function",
+ },
+ "Output.printString": {
+ func: (memory, os) => {
+ const [pointer] = getArgs(memory, 1);
+ os.output.printString(pointer);
+ return 0;
+ },
+ args: ["String"],
+ returnType: "void",
+ type: "function",
+ },
+ "Output.printInt": {
+ func: (memory, os) => {
+ const [value] = getArgs(memory, 1);
+ os.output.printInt(value);
+ return 0;
+ },
+ args: ["int"],
+ returnType: "void",
+ type: "function",
+ },
+ "Output.println": {
+ func: (_, os) => {
+ os.output.println();
+ return 0;
+ },
+ args: [],
+ returnType: "void",
+ type: "function",
+ },
+ "Output.backSpace": {
+ func: (_, os) => {
+ os.output.backspace();
+ return 0;
+ },
+ args: [],
+ returnType: "void",
+ type: "function",
+ },
+ "Keyboard.init": {
+ func: (_, __) => 0,
+ args: [],
+ returnType: "void",
+ type: "function",
+ },
+ "Keyboard.keyPressed": {
+ func: (_, os) => {
+ return os.keyboard.keyPressed();
+ },
+ args: [],
+ returnType: "char",
+ type: "function",
+ },
+ "Keyboard.readChar": {
+ func: (_, os) => {
+ os.keyboard.readChar();
+ return 0;
+ },
+ args: [],
+ returnType: "char",
+ type: "function",
+ },
+ "Keyboard.readLine": {
+ func: (memory, os) => {
+ const [message] = getArgs(memory, 1);
+ os.keyboard.readLine(message);
+ return 0;
+ },
+ args: ["String"],
+ returnType: "String",
+ type: "function",
+ },
+ "Keyboard.readInt": {
+ func: (memory, os) => {
+ const [message] = getArgs(memory, 1);
+ os.keyboard.readInt(message);
+ return 0;
+ },
+ args: ["String"],
+ returnType: "int",
+ type: "function",
+ },
+ "Sys.halt": {
+ func: (_, os) => {
+ os.sys.halt();
+ return 0;
+ },
+ args: [],
+ returnType: "void",
+ type: "function",
+ },
+ "Sys.error": {
+ func: (memory, os) => {
+ const [code] = getArgs(memory, 1);
+ os.sys.error(code);
+ return 0;
+ },
+ args: ["int"],
+ returnType: "void",
+ type: "function",
+ },
+ "Sys.wait": {
+ func: (memory, os) => {
+ const [ms] = getArgs(memory, 1);
+ os.sys.wait(ms);
+ return 0;
+ },
+ args: ["int"],
+ returnType: "void",
+ type: "function",
+ },
+};
diff --git a/src/lib/software/vendor/nand2tetris/vm/memory.ts b/src/lib/software/vendor/nand2tetris/vm/memory.ts
new file mode 100644
index 0000000..8022ef9
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/vm/memory.ts
@@ -0,0 +1,258 @@
+import { Err, isErr, Ok, type Result } from "@davidsouther/jiffies/result.ts";
+import { RAM } from "../cpu/memory.js";
+import { type Segment } from "../languages/vm.js";
+import { type VmFrame } from "./vm.js";
+
+export const SP = 0;
+export const LCL = 1;
+export const ARG = 2;
+export const THIS = 3;
+export const THAT = 4;
+export const TEMP = 5;
+export const STATIC = 16;
+
+export class VmMemory extends RAM {
+ strict = true;
+ get SP(): number {
+ return this.get(SP);
+ }
+ set SP(value: number) {
+ this.set(SP, value);
+ }
+ get LCL(): number {
+ return this.get(LCL);
+ }
+ set LCL(value: number) {
+ this.set(LCL, value);
+ }
+ get ARG(): number {
+ return this.get(ARG);
+ }
+ set ARG(value: number) {
+ this.set(ARG, value);
+ }
+ get THIS(): number {
+ return this.get(THIS);
+ }
+ set THIS(value: number) {
+ this.set(THIS, value);
+ }
+ get THAT(): number {
+ return this.get(THAT);
+ }
+ set THAT(value: number) {
+ this.set(THAT, value);
+ }
+
+ get statics() {
+ const statics = [];
+ for (let i = 16; i < 256; i++) {
+ statics.push(this.get(i));
+ }
+ return statics;
+ }
+
+ constructor() {
+ super();
+ this.set(SP, 256);
+ }
+
+ baseSegment(segment: Segment, offset: number): Result {
+ if (this.strict && (offset < 0 || offset > 32767))
+ return Err(
+ new Error(
+ `Illegal offset value ${offset} (must be between 0 and 32767)`,
+ ),
+ );
+ switch (segment) {
+ case "argument":
+ return Ok(this.ARG + offset);
+ case "constant":
+ return Ok(offset);
+ case "local":
+ return Ok(this.LCL + offset);
+ case "pointer":
+ if (this.strict && offset > 1)
+ throw new Error(
+ `pointer out of bounds access (pointer can be 0 for this, 1 for that, but got ${offset}`,
+ );
+ return Ok(offset === 0 ? THIS : THAT);
+ case "static":
+ if (this.strict && offset > 255 - 16)
+ return Err(new Error(`Cannot access statics beyond 239: ${offset}`));
+ return Ok(16 + offset);
+ case "temp":
+ if (this.strict && offset > 7)
+ return Err(
+ new Error(
+ `Temp out of bounds access (temp can be 0 to 7, but got ${offset}`,
+ ),
+ );
+ return Ok(5 + offset);
+ case "that":
+ return Ok(this.THAT + offset);
+ case "this":
+ return Ok(this.THIS + offset);
+ }
+ }
+
+ getSegment(segment: Segment, offset: number): number {
+ if (segment === "constant") {
+ if (this.strict && (offset < 0 || offset > 32767))
+ throw new Error(
+ `Illegal offset value ${offset} (must be between 0 and 32767)`,
+ );
+ return offset;
+ }
+ const base = this.baseSegment(segment, offset);
+ if (isErr(base)) {
+ throw Err(base);
+ }
+ return this.get(Ok(base));
+ }
+ setSegment(segment: Segment, offset: number, value: number) {
+ const base = this.baseSegment(segment, offset);
+ if (isErr(base)) {
+ throw Err(base);
+ }
+ this.set(Ok(base), value);
+ }
+
+ argument(offset: number): number {
+ return this.getSegment("argument", offset);
+ }
+ local(offset: number): number {
+ return this.getSegment("local", offset);
+ }
+ static(offset: number): number {
+ return this.getSegment("static", offset);
+ }
+ constant(offset: number): number {
+ return this.getSegment("constant", offset);
+ }
+ this(offset: number): number {
+ return this.getSegment("this", offset);
+ }
+ that(offset: number): number {
+ return this.getSegment("that", offset);
+ }
+ pointer(offset: number): number {
+ return this.getSegment("pointer", offset);
+ }
+ temp(offset: number): number {
+ return this.getSegment("temp", offset);
+ }
+
+ push(value: number) {
+ const sp = this.SP;
+ this.set(sp, value);
+ this.set(0, sp + 1);
+ }
+ pop(): number {
+ if (this.strict && this.SP === 256)
+ throw new Error(`Cannot pop the stack below 256 in strict mode`);
+ this.set(0, this.SP - 1);
+ const value = this.get(this.SP);
+ return value;
+ }
+ // Stack frame, from figure 8.3, is:
+ // [ARG] Arg0 Arg1... RET LCL ARG THIS THAT [LCL] Local0 Local1... [SP]
+ pushFrame(ret: number, nArgs: number, nLocals: number): number {
+ const base = this.SP;
+ const arg = base - nArgs;
+ this.set(base, ret);
+ this.set(base + 1, this.LCL);
+ this.set(base + 2, this.ARG);
+ this.set(base + 3, this.THIS);
+ this.set(base + 4, this.THAT);
+
+ this.set(ARG, arg);
+ this.set(LCL, base + 5);
+
+ const sp = base + 5;
+ // Technically this happens in the function, but the VM will handle it for free
+ for (let i = 0; i < nLocals; i++) {
+ this.set(sp + i, 0);
+ }
+ this.set(SP, sp + nLocals);
+ return base;
+ }
+
+ popFrame(): number {
+ const frame = this.LCL;
+ const ret = this.get(frame - 5);
+ const value = this.pop();
+ this.set(this.ARG, value);
+ this.set(SP, this.ARG + 1);
+ this.set(THAT, this.get(frame - 1));
+ this.set(THIS, this.get(frame - 2));
+ this.set(ARG, this.get(frame - 3));
+ this.set(LCL, this.get(frame - 4));
+ return ret;
+ }
+
+ getFrame(
+ base: number, // The address of the frame, the RET address
+ argN: number, // The number of arguments to this frame
+ localN: number, // The number of locals in this frame
+ thisN: number, // The number of items in `this`
+ thatN: number, // the number of items in `that`
+ nextFrame: number,
+ ): VmFrame {
+ const arg = base - argN;
+ const lcl = base + 5;
+ const stk = lcl + localN;
+ const stackN = nextFrame - stk;
+ const args = [...this.map((_, v) => v, arg, arg + argN)];
+ const locals = [...this.map((_, v) => v, lcl, lcl + localN)];
+ const stack = [...this.map((_, v) => v, stk, stk + stackN)];
+ const this_ = [...this.map((_, v) => v, this.THIS, this.THIS + thisN)];
+ const that = [...this.map((_, v) => v, this.THAT, this.THAT + thatN)];
+ return {
+ args: { base: arg, count: argN, values: args },
+ locals: { base: lcl, count: localN, values: locals },
+ stack: { base: stk, count: stackN, values: stack },
+ this: { base: stk, count: thisN, values: this_ },
+ that: { base: stk, count: thatN, values: that },
+ frame: {
+ RET: this.get(base),
+ LCL: this.LCL,
+ ARG: this.ARG,
+ THIS: this.THIS,
+ THAT: this.THAT,
+ },
+ };
+ }
+
+ getVmState(staticN = 240) {
+ const temps = [...this.map((_, v) => v, 5, 13)];
+ const internal = [...this.map((_, v) => v, 13, 16)];
+ const statics = [...this.map((_, v) => v, 16, 16 + staticN)];
+ return {
+ ["0: SP"]: this.SP,
+ ["1: LCL"]: this.LCL,
+ ["2: ARG"]: this.ARG,
+ ["3: THIS"]: this.THIS,
+ ["4: THAT"]: this.THAT,
+ temps,
+ internal,
+ static: statics,
+ };
+ }
+
+ binOp(fn: (a: number, b: number) => number) {
+ const a = this.get(this.SP - 2);
+ const b = this.get(this.SP - 1);
+ const v = fn(a, b) & 0xffff;
+ this.set(this.SP - 2, v);
+ this.set(SP, this.SP - 1);
+ }
+ unOp(fn: (a: number) => number) {
+ const a = this.get(this.SP - 1);
+ const v = fn(a) & 0xffff;
+ this.set(this.SP - 1, v);
+ }
+ comp(fn: (a: number, b: number) => boolean) {
+ this.binOp((a, b) => (fn(a, b) ? -1 : 0));
+ }
+}
diff --git a/src/lib/software/vendor/nand2tetris/vm/os/errors.ts b/src/lib/software/vendor/nand2tetris/vm/os/errors.ts
new file mode 100644
index 0000000..9f2aec7
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/vm/os/errors.ts
@@ -0,0 +1,24 @@
+export enum ERRNO {
+ SYS_WAIT_DURATION_NOT_POSITIVE = 1,
+ ARRAY_SIZE_NOT_POSITIVE = 2,
+ DIVIDE_BY_ZERO = 3,
+ SQRT_NEG = 4,
+ ALLOC_SIZE_NOT_POSITIVE = 5,
+ HEAP_OVERFLOW = 6,
+ ILLEGAL_PIXEL_COORD = 7,
+ ILLEGAL_LINE_COORD = 8,
+ ILLEGAL_RECT_COORD = 9,
+ ILLEGAL_CENTER_COORD = 12,
+ ILLEGAL_RADIUS = 13,
+ STRING_LENGTH_NEG = 14,
+ GET_CHAR_INDEX_OUT_OF_BOUNDS = 15,
+ SET_CHAR_INDEX_OUT_OF_BOUNDS = 16,
+ STRING_FULL = 17,
+ STRING_EMPTY = 18,
+ STRING_INSUFFICIENT_CAPACITY = 19,
+ ILLEGAL_CURSOR_LOCATION = 20,
+}
+
+export function isSysError(errno: number): errno is ERRNO {
+ return Object.values(ERRNO).includes(errno as ERRNO);
+}
diff --git a/src/lib/software/vendor/nand2tetris/vm/os/font.ts b/src/lib/software/vendor/nand2tetris/vm/os/font.ts
new file mode 100644
index 0000000..d50cf52
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/vm/os/font.ts
@@ -0,0 +1,1251 @@
+export const CHARACTER_NUM = 126;
+export const FONT = createFont();
+
+/* Character bitmaps are 8x11 boolean pixel values. See Fig 12.9. */
+type Bitmap = boolean[][];
+
+function createBitmap(rows: string[]): Bitmap {
+ return rows.map((row) => row.split("").map((c) => c == "█"));
+}
+
+export function createFont(): Bitmap[] {
+ const font: Bitmap[] = new Array(CHARACTER_NUM);
+
+ font[32] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ]); //
+ font[33] = createBitmap([
+ " ██ ",
+ " ████ ",
+ " ████ ",
+ " ████ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ ]); // !
+ font[34] = createBitmap([
+ " ██ ██ ",
+ " ██ ██ ",
+ " █ █ ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ]); // "
+ font[35] = createBitmap([
+ " ",
+ " █ █ ",
+ " █ █ ",
+ "██████ ",
+ " █ █ ",
+ " █ █ ",
+ "██████ ",
+ " █ █ ",
+ " █ █ ",
+ " ",
+ " ",
+ ]); // #
+ font[36] = createBitmap([
+ " ██ ",
+ " ████ ",
+ "██ ██ ",
+ "██ ",
+ " ████ ",
+ " ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ ]); // $
+ font[37] = createBitmap([
+ " ",
+ " ",
+ "██ █ ",
+ "██ ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "██ ██ ",
+ "█ ██ ",
+ " ",
+ " ",
+ ]); // %
+ font[38] = createBitmap([
+ " ██ ",
+ " ████ ",
+ " ████ ",
+ " ██ ",
+ " ██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ██ ██ ",
+ " ",
+ " ",
+ ]); // &
+ font[39] = createBitmap([
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ]); // '
+ font[40] = createBitmap([
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ ]); // (
+ font[41] = createBitmap([
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ ]); // )
+ font[42] = createBitmap([
+ " ",
+ " ",
+ " ",
+ "██ ██ ",
+ " ████ ",
+ "██████ ",
+ " ████ ",
+ "██ ██ ",
+ " ",
+ " ",
+ " ",
+ ]); // *
+ font[43] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ██ ",
+ " ██ ",
+ "██████ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ " ",
+ ]); // +
+ font[44] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ ]); // ,
+ font[45] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ "██████ ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ]); // -
+ font[46] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ ]); // .
+ font[47] = createBitmap([
+ " ",
+ " ",
+ " █ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "██ ",
+ "█ ",
+ " ",
+ " ",
+ ]); // /
+ font[48] = createBitmap([
+ " ██ ",
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ██ ",
+ " ",
+ " ",
+ ]); // 0
+ font[49] = createBitmap([
+ " ██ ",
+ " ███ ",
+ "████ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "██████ ",
+ " ",
+ " ",
+ ]); // 1
+ font[50] = createBitmap([
+ " ████ ",
+ "██ ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "██ ",
+ "██ ██ ",
+ "██████ ",
+ " ",
+ " ",
+ ]); // 2
+ font[51] = createBitmap([
+ " ████ ",
+ "██ ██ ",
+ " ██ ",
+ " ██ ",
+ " ███ ",
+ " ██ ",
+ " ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // 3
+ font[52] = createBitmap([
+ " █ ",
+ " ██ ",
+ " ███ ",
+ " █ ██ ",
+ "█ ██ ",
+ "██████ ",
+ " ██ ",
+ " ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // 4
+ font[53] = createBitmap([
+ "██████ ",
+ "██ ",
+ "██ ",
+ "█████ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // 5
+ font[54] = createBitmap([
+ " ███ ",
+ " ██ ",
+ "██ ",
+ "██ ",
+ "█████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // 6
+ font[55] = createBitmap([
+ "██████ ",
+ "█ ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ ]); // 7
+ font[56] = createBitmap([
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // 8
+ font[57] = createBitmap([
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " █████ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ███ ",
+ " ",
+ " ",
+ ]); // 9
+ font[58] = createBitmap([
+ " ",
+ " ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ " ",
+ ]); // :
+ font[59] = createBitmap([
+ " ",
+ " ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ ]); // ;
+ font[60] = createBitmap([
+ " ",
+ " ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ ]); // <
+ font[61] = createBitmap([
+ " ",
+ " ",
+ " ",
+ "██████ ",
+ " ",
+ " ",
+ "██████ ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ]); // =
+ font[62] = createBitmap([
+ " ",
+ " ",
+ "██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "██ ",
+ " ",
+ " ",
+ ]); // >
+ font[64] = createBitmap([
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ███ ",
+ "██ ███ ",
+ "██ ███ ",
+ "██ ██ ",
+ "██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // @
+ font[63] = createBitmap([
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ ]); // ?
+ font[65] = createBitmap([
+ " ██ ",
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ",
+ " ",
+ ]); // A
+ font[66] = createBitmap([
+ "█████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "█████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "█████ ",
+ " ",
+ " ",
+ ]); // B
+ font[67] = createBitmap([
+ " ███ ",
+ " ██ ██ ",
+ "██ █ ",
+ "██ ",
+ "██ ",
+ "██ ",
+ "██ █ ",
+ " ██ ██ ",
+ " ███ ",
+ " ",
+ " ",
+ ]); // C
+ font[68] = createBitmap([
+ "████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "████ ",
+ " ",
+ " ",
+ ]); // D
+ font[69] = createBitmap([
+ "██████ ",
+ "██ ██ ",
+ "██ █ ",
+ "██ █ ",
+ "████ ",
+ "██ █ ",
+ "██ █ ",
+ "██ ██ ",
+ "██████ ",
+ " ",
+ " ",
+ ]); // E
+ font[70] = createBitmap([
+ "██████ ",
+ "██ ██ ",
+ "██ █ ",
+ "██ █ ",
+ "████ ",
+ "██ █ ",
+ "██ ",
+ "██ ",
+ "██ ",
+ " ",
+ " ",
+ ]); // F
+ font[71] = createBitmap([
+ " ███ ",
+ " ██ ██ ",
+ "██ █ ",
+ "██ ",
+ "██ ███ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ██ ██ ",
+ " ██ █ ",
+ " ",
+ " ",
+ ]); // G
+ font[72] = createBitmap([
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ",
+ " ",
+ ]); // H
+ font[73] = createBitmap([
+ " ████ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // I
+ font[74] = createBitmap([
+ " ████ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ███ ",
+ " ",
+ " ",
+ ]); // J
+ font[75] = createBitmap([
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ",
+ " ",
+ ]); // K
+ font[76] = createBitmap([
+ "██ ",
+ "██ ",
+ "██ ",
+ "██ ",
+ "██ ",
+ "██ ",
+ "██ █ ",
+ "██ ██ ",
+ "██████ ",
+ " ",
+ " ",
+ ]); // L
+ font[77] = createBitmap([
+ "█ █ ",
+ "██ ██ ",
+ "██████ ",
+ "██████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ",
+ " ",
+ ]); // M
+ font[78] = createBitmap([
+ "██ ██ ",
+ "██ ██ ",
+ "███ ██ ",
+ "███ ██ ",
+ "██████ ",
+ "██ ███ ",
+ "██ ███ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ",
+ " ",
+ ]); // N
+ font[79] = createBitmap([
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // O
+ font[80] = createBitmap([
+ "█████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "█████ ",
+ "██ ",
+ "██ ",
+ "██ ",
+ "██ ",
+ " ",
+ " ",
+ ]); // P
+ font[81] = createBitmap([
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██████ ",
+ "██ ███ ",
+ " ████ ",
+ " ██ ",
+ " ",
+ ]); // Q
+ font[82] = createBitmap([
+ "█████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "█████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ",
+ " ",
+ ]); // R
+ font[83] = createBitmap([
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ██ ",
+ " ███ ",
+ " ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // S
+ font[84] = createBitmap([
+ "██████ ",
+ "██████ ",
+ "█ ██ █ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // T
+ font[85] = createBitmap([
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // U
+ font[86] = createBitmap([
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ████ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ ]); // V
+ font[87] = createBitmap([
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██████ ",
+ "██████ ",
+ "██████ ",
+ " █ █ ",
+ " ",
+ " ",
+ ]); // W
+ font[88] = createBitmap([
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ████ ",
+ " ██ ",
+ " ████ ",
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ",
+ " ",
+ ]); // X
+ font[89] = createBitmap([
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // Y
+ font[90] = createBitmap([
+ "██████ ",
+ "██ ██ ",
+ "█ ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "██ █ ",
+ "██ ██ ",
+ "██████ ",
+ " ",
+ " ",
+ ]); // Z
+ font[91] = createBitmap([
+ " ████ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // [
+ font[92] = createBitmap([
+ " ",
+ " ",
+ "█ ",
+ "██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " █ ",
+ " ",
+ " ",
+ ]); // \
+ font[93] = createBitmap([
+ " ████ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // ]
+ font[94] = createBitmap([
+ " █ ",
+ " ███ ",
+ " ██ ██ ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ]); // ^
+ font[95] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ "██████ ",
+ " ",
+ ]); // _
+ font[96] = createBitmap([
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ]); // `
+ font[97] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ███ ",
+ " ██ ",
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ██ ██ ",
+ " ",
+ " ",
+ ]); // a
+ font[98] = createBitmap([
+ "██ ",
+ "██ ",
+ "██ ",
+ "████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // b
+ font[99] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ████ ",
+ "██ ██ ",
+ "██ ",
+ "██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // c
+ font[100] = createBitmap([
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ████ ",
+ " ██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // d
+ font[101] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ████ ",
+ "██ ██ ",
+ "██████ ",
+ "██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // e
+ font[102] = createBitmap([
+ " ███ ",
+ " ██ ██ ",
+ " ██ █ ",
+ " ██ ",
+ "████ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "████ ",
+ " ",
+ " ",
+ ]); // f
+ font[103] = createBitmap([
+ " ",
+ " ",
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " █████ ",
+ " ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ ]); // g
+ font[104] = createBitmap([
+ "██ ",
+ "██ ",
+ "██ ",
+ "██ ██ ",
+ "███ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ",
+ " ",
+ ]); // h
+ font[105] = createBitmap([
+ " ██ ",
+ " ██ ",
+ " ",
+ " ███ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // i
+ font[106] = createBitmap([
+ " ██ ",
+ " ██ ",
+ " ",
+ " ███ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ ]); // j
+ font[107] = createBitmap([
+ "██ ",
+ "██ ",
+ "██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "████ ",
+ "████ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ",
+ " ",
+ ]); // k
+ font[108] = createBitmap([
+ " ███ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // l
+ font[109] = createBitmap([
+ " ",
+ " ",
+ " ",
+ "█ ███ ",
+ "██████ ",
+ "██ █ █ ",
+ "██ █ █ ",
+ "██ █ █ ",
+ "██ █ █ ",
+ " ",
+ " ",
+ ]); // m
+ font[110] = createBitmap([
+ " ",
+ " ",
+ " ",
+ "█ ███ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ",
+ " ",
+ ]); // n
+ font[111] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // o
+ font[112] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "█████ ",
+ "██ ",
+ "██ ",
+ " ",
+ ]); // p
+ font[113] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ████ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " █████ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ ]); // q
+ font[114] = createBitmap([
+ " ",
+ " ",
+ " ",
+ "█ ███ ",
+ "███ ██ ",
+ "██ ██ ",
+ "██ ",
+ "██ ",
+ "███ ",
+ " ",
+ " ",
+ ]); // r
+ font[115] = createBitmap([
+ " ",
+ " ",
+ " ",
+ " ████ ",
+ "██ ██ ",
+ " ██ ",
+ " ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ",
+ " ",
+ ]); // s
+ font[116] = createBitmap([
+ " █ ",
+ " ██ ",
+ " ██ ",
+ "████ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ██ ",
+ " ███ ",
+ " ",
+ " ",
+ ]); // t
+ font[117] = createBitmap([
+ " ",
+ " ",
+ " ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ██ ██ ",
+ " ",
+ " ",
+ ]); // u
+ font[118] = createBitmap([
+ " ",
+ " ",
+ " ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " ████ ",
+ " ██ ",
+ " ",
+ " ",
+ ]); // v
+ font[119] = createBitmap([
+ " ",
+ " ",
+ " ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ "██████ ",
+ "██████ ",
+ " █ █ ",
+ " ",
+ " ",
+ ]); // w
+ font[120] = createBitmap([
+ " ",
+ " ",
+ " ",
+ "██ ██ ",
+ " ████ ",
+ " ██ ",
+ " ██ ",
+ " ████ ",
+ "██ ██ ",
+ " ",
+ " ",
+ ]); // x
+ font[121] = createBitmap([
+ " ",
+ " ",
+ " ",
+ "██ ██ ",
+ "██ ██ ",
+ "██ ██ ",
+ " █████ ",
+ " ██ ",
+ " ██ ",
+ "████ ",
+ " ",
+ ]); // y
+ font[122] = createBitmap([
+ " ",
+ " ",
+ " ",
+ "██████ ",
+ "██ ██ ",
+ " ██ ",
+ " ██ ",
+ "██ ██ ",
+ "██████ ",
+ " ",
+ " ",
+ ]); // z
+ font[123] = createBitmap([
+ " ███ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "███ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ███ ",
+ " ",
+ " ",
+ ]); // {
+ font[124] = createBitmap([
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ",
+ " ",
+ ]); // |
+ font[125] = createBitmap([
+ "███ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ " ███ ",
+ " ██ ",
+ " ██ ",
+ " ██ ",
+ "███ ",
+ " ",
+ " ",
+ ]); // }
+ font[126] = createBitmap([
+ " ██ █ ",
+ "█ ██ █ ",
+ "█ ██ ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ]); // ~
+
+ return font;
+}
diff --git a/src/lib/software/vendor/nand2tetris/vm/os/keyboard.ts b/src/lib/software/vendor/nand2tetris/vm/os/keyboard.ts
new file mode 100644
index 0000000..76fcb90
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/vm/os/keyboard.ts
@@ -0,0 +1,151 @@
+import { KEYBOARD_OFFSET } from "../../cpu/memory.js";
+import { VmMemory } from "../memory.js";
+import { OS } from "./os.js";
+import { BACKSPACE, NEW_LINE } from "./string.js";
+
+export class KeyboardLib {
+ private memory: VmMemory;
+ private os: OS;
+ private animationFrameId: number | undefined = undefined;
+ private cancel = false;
+
+ constructor(memory: VmMemory, os: OS) {
+ this.memory = memory;
+ this.os = os;
+ }
+
+ keyPressed() {
+ return this.memory.get(KEYBOARD_OFFSET);
+ }
+
+ private readCharLoop(resolve: (value: number) => void) {
+ let pressed = false;
+ let c = 0;
+
+ const loop = () => {
+ if (this.cancel) {
+ return;
+ }
+
+ let exit = false;
+
+ if (!this.os.paused) {
+ if (!pressed && this.keyPressed() !== 0) {
+ pressed = true;
+ c = this.keyPressed();
+ }
+ if (pressed && this.keyPressed() === 0) {
+ exit = true;
+ resolve(c);
+ }
+ }
+
+ if (!exit) {
+ this.animationFrameId = requestAnimationFrame(loop);
+ }
+ };
+
+ loop();
+ }
+
+ readChar() {
+ this.os.sys.block();
+ this.os.output.drawCursor();
+
+ new Promise((resolve) => {
+ this.readCharLoop(resolve);
+ }).then((c) => {
+ this.os.output.printChar(c);
+ this.os.sys.release(c);
+ });
+ }
+
+ private readLineLoop(resolve: (value: number) => void) {
+ const str = this.os.string.new(100);
+ if (this.os.sys.halted) {
+ resolve(0);
+ }
+ let pressed = false;
+ let c = 0;
+
+ const loop = () => {
+ if (this.cancel) {
+ return;
+ }
+
+ let exit = false;
+
+ if (!this.os.paused) {
+ if (!pressed && this.keyPressed() != 0) {
+ pressed = true;
+ c = this.keyPressed();
+ }
+ if (pressed && this.keyPressed() == 0) {
+ pressed = false;
+ // key was released
+ if (c == BACKSPACE) {
+ if (this.os.string.length(str) > 0) {
+ this.os.output.backspace();
+ }
+ this.os.string.eraseLastChar(str);
+ } else if (c == NEW_LINE) {
+ resolve(str);
+ exit = true;
+ } else {
+ this.os.string.appendChar(str, c);
+ if (this.os.sys.halted) {
+ resolve(0);
+ }
+ this.os.output.printChar(c);
+ this.os.output.drawCursor();
+ }
+ }
+ }
+
+ if (!exit) {
+ this.animationFrameId = requestAnimationFrame(loop);
+ }
+ };
+
+ loop();
+ }
+
+ readLine(messagePointer: number) {
+ this.os.sys.block();
+ this.os.output.printString(messagePointer);
+ this.os.output.drawCursor();
+
+ new Promise((resolve) => {
+ this.readLineLoop(resolve);
+ }).then((str) => {
+ if (!this.os.sys.halted) {
+ this.os.output.clearChar();
+ this.os.output.println();
+ }
+ this.os.sys.release(str);
+ });
+ }
+
+ readInt(messagePointer: number) {
+ this.os.sys.block();
+ this.os.output.printString(messagePointer);
+ this.os.output.drawCursor();
+
+ new Promise((resolve) => {
+ this.readLineLoop(resolve);
+ }).then((str) => {
+ if (!this.os.sys.halted) {
+ this.os.output.clearChar();
+ this.os.output.println();
+ }
+ this.os.sys.release(this.os.string.intValue(str));
+ });
+ }
+
+ dispose() {
+ this.cancel = true;
+ if (this.animationFrameId) {
+ cancelAnimationFrame(this.animationFrameId);
+ }
+ }
+}
diff --git a/src/lib/software/vendor/nand2tetris/vm/os/memory.ts b/src/lib/software/vendor/nand2tetris/vm/os/memory.ts
new file mode 100644
index 0000000..ff2f80c
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/vm/os/memory.ts
@@ -0,0 +1,62 @@
+import { VmMemory } from "../memory.js";
+import { ERRNO } from "./errors.js";
+import { OS } from "./os.js";
+
+const HEAP_BASE = 2048;
+const HEAP_SIZE = 14334;
+
+export class MemoryLib {
+ private memory: VmMemory;
+ private os: OS;
+ private freeListPtr: number;
+
+ public constructor(memory: VmMemory, os: OS) {
+ this.memory = memory;
+ this.os = os;
+ this.freeListPtr = HEAP_BASE;
+ this.memory.set(HEAP_BASE, 0);
+ this.memory.set(HEAP_BASE + 1, HEAP_SIZE);
+ }
+
+ alloc(size: number): number {
+ if (size <= 0) {
+ this.os.sys.error(ERRNO.ARRAY_SIZE_NOT_POSITIVE);
+ return 0;
+ }
+
+ let prevPtr = 0;
+ let blockPtr = this.freeListPtr;
+ while (blockPtr !== 0) {
+ const nextFreeList = this.memory.get(blockPtr);
+ const blockSize = this.memory.get(blockPtr + 1);
+ if (blockSize >= size + 2) {
+ this.memory.set(blockPtr + 1, size);
+
+ const newBlockPtr = blockPtr + 2 + size;
+ const newBlockSize = blockSize - size - 2;
+ this.memory.set(newBlockPtr, nextFreeList);
+ this.memory.set(newBlockPtr + 1, newBlockSize);
+
+ // Unlink the allocated block by pointing the predecessor (or the
+ // free list head) at the new remainder block.
+ if (prevPtr === 0) {
+ this.freeListPtr = newBlockPtr;
+ } else {
+ this.memory.set(prevPtr, newBlockPtr);
+ }
+ return blockPtr + 2;
+ }
+ prevPtr = blockPtr;
+ blockPtr = nextFreeList;
+ }
+
+ this.os.sys.error(ERRNO.HEAP_OVERFLOW);
+ return 0;
+ }
+
+ deAlloc(address: number) {
+ const deallocBlockPtr = address - 2;
+ this.memory.set(deallocBlockPtr, this.freeListPtr);
+ this.freeListPtr = deallocBlockPtr;
+ }
+}
diff --git a/src/lib/software/vendor/nand2tetris/vm/os/os.ts b/src/lib/software/vendor/nand2tetris/vm/os/os.ts
new file mode 100644
index 0000000..e6ebaa8
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/vm/os/os.ts
@@ -0,0 +1,34 @@
+import { VmMemory } from "../memory.js";
+import { KeyboardLib } from "./keyboard.js";
+import { MemoryLib } from "./memory.js";
+import { OutputLib } from "./output.js";
+import { ScreenLib } from "./screen.js";
+import { StringLib } from "./string.js";
+import { SysLib } from "./sys.js";
+
+export class OS {
+ private vmMemory: VmMemory;
+ screen: ScreenLib;
+ memory: MemoryLib;
+ string: StringLib;
+ output: OutputLib;
+ keyboard: KeyboardLib;
+ sys: SysLib;
+
+ paused = false;
+
+ constructor(memory: VmMemory) {
+ this.vmMemory = memory;
+ this.screen = new ScreenLib(this.vmMemory, this);
+ this.memory = new MemoryLib(this.vmMemory, this);
+ this.string = new StringLib(this.vmMemory, this);
+ this.output = new OutputLib(this);
+ this.keyboard = new KeyboardLib(this.vmMemory, this);
+ this.sys = new SysLib(this);
+ }
+
+ dispose() {
+ this.keyboard.dispose();
+ this.sys.dispose();
+ }
+}
diff --git a/src/lib/software/vendor/nand2tetris/vm/os/output.ts b/src/lib/software/vendor/nand2tetris/vm/os/output.ts
new file mode 100644
index 0000000..61174a1
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/vm/os/output.ts
@@ -0,0 +1,119 @@
+import { ERRNO } from "./errors.js";
+import { FONT } from "./font.js";
+import { OS } from "./os.js";
+import { BLACK, type Color, WHITE } from "./screen.js";
+import { intToCharArray } from "./string.js";
+
+const MAX_WIDTH = 64;
+const MAX_HEIGHT = 22;
+
+export class OutputLib {
+ private os: OS;
+
+ private col = 0;
+ private row = 0;
+ private lastColor = false;
+
+ constructor(os: OS) {
+ this.os = os;
+ }
+
+ private setColor(color: Color) {
+ this.lastColor = this.os.screen.color;
+ this.os.screen.color = color;
+ }
+
+ private restoreColor() {
+ this.os.screen.color = this.lastColor;
+ }
+
+ clearChar() {
+ this.setColor(WHITE);
+ this.os.screen.drawRect(
+ this.col * 8,
+ this.row * 11,
+ (this.col + 1) * 8,
+ (this.row + 1) * 11,
+ );
+ this.restoreColor();
+ }
+
+ moveCursor(i: number, j: number) {
+ if (i < 0 || i > MAX_HEIGHT || j < 0 || j > MAX_WIDTH) {
+ this.os.sys.error(ERRNO.ILLEGAL_CURSOR_LOCATION);
+ return;
+ }
+ this.row = i;
+ this.col = j;
+ this.drawCursor();
+ }
+
+ println() {
+ this.row = this.row == MAX_HEIGHT ? 0 : this.row + 1;
+ this.col = 0;
+ }
+
+ drawCursor() {
+ this.clearChar();
+ this.setColor(BLACK);
+ this.os.screen.drawRect(
+ this.col * 8 + 2,
+ this.row * 11 + 2,
+ (this.col + 1) * 8 - 2,
+ (this.row + 1) * 11 - 2,
+ );
+ this.restoreColor();
+ }
+
+ printChar(code: number) {
+ const bitmap = FONT[code];
+ if (bitmap) {
+ this.clearChar();
+ this.setColor(BLACK);
+ for (let row = 0; row < bitmap.length; row++) {
+ for (let col = 0; col < bitmap[row].length; col++) {
+ if (bitmap[row][col]) {
+ this.os.screen.drawPixel(this.col * 8 + col, this.row * 11 + row);
+ }
+ }
+ }
+ this.restoreColor();
+ }
+
+ this.col += 1;
+ if (this.col == MAX_WIDTH) {
+ this.println();
+ }
+ }
+
+ printString(pointer: number) {
+ for (let i = 0; i < this.os.string.length(pointer); i++) {
+ this.printChar(this.os.string.charAt(pointer, i));
+ }
+ }
+
+ printJsString(str: string) {
+ for (const char of str) {
+ this.printChar(char.charCodeAt(0));
+ }
+ }
+
+ printInt(value: number) {
+ for (const c of intToCharArray(value)) {
+ this.printChar(c);
+ }
+ }
+
+ backspace() {
+ this.clearChar();
+ this.col -= 1;
+ if (this.col < 0) {
+ this.col = 0;
+ this.row -= 1;
+ if (this.row < 0) {
+ this.row = 0;
+ }
+ }
+ this.drawCursor();
+ }
+}
diff --git a/src/lib/software/vendor/nand2tetris/vm/os/screen.ts b/src/lib/software/vendor/nand2tetris/vm/os/screen.ts
new file mode 100644
index 0000000..5e3a21e
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/vm/os/screen.ts
@@ -0,0 +1,127 @@
+import { SCREEN_COLS, SCREEN_ROWS, SCREEN_SIZE } from "../../cpu/memory.js";
+import { VmMemory } from "../memory.js";
+import { ERRNO } from "./errors.js";
+import { OS } from "./os.js";
+
+const BLANK_SCREEN = new Array(SCREEN_SIZE).fill(0);
+const MAX_R = 181;
+
+export type Color = boolean;
+export const BLACK: Color = true;
+export const WHITE: Color = false;
+
+export class ScreenLib {
+ private memory: VmMemory;
+ private os: OS;
+
+ color: Color = BLACK;
+
+ constructor(memory: VmMemory, os: OS) {
+ this.memory = memory;
+ this.os = os;
+ }
+
+ clear() {
+ this.memory.screen.loadBytes(BLANK_SCREEN);
+ }
+
+ private outOfBounds(col: number, row: number) {
+ return col < 0 || col >= SCREEN_COLS * 16 || row < 0 || row >= SCREEN_ROWS;
+ }
+
+ drawPixel(col: number, row: number) {
+ if (this.outOfBounds(col, row)) {
+ this.os.sys.error(ERRNO.ILLEGAL_PIXEL_COORD);
+ return;
+ }
+ const address = row * 32 + Math.floor(col / 16);
+ let value = this.memory.screen.get(address);
+ const rem = col % 16;
+ if (this.color) {
+ value |= 1 << rem;
+ } else {
+ value &= ~(1 << rem);
+ }
+ this.memory.screen.set(address, value);
+ }
+
+ drawLine(x1: number, y1: number, x2: number, y2: number) {
+ if (this.outOfBounds(x1, y1) || this.outOfBounds(x2, y2)) {
+ this.os.sys.error(ERRNO.ILLEGAL_LINE_COORD);
+ return;
+ }
+ if (x1 == x2) {
+ this.drawVerticalLine(x1, y1, y2);
+ } else if (y1 == y2) {
+ this.drawHorizontalLine(y1, x1, x2);
+ } else {
+ this.drawGeneralLine(x1, y1, x2, y2);
+ }
+ }
+
+ private drawHorizontalLine(y: number, x1: number, x2: number) {
+ for (let x = Math.min(x1, x2); x <= Math.max(x1, x2); x++) {
+ this.drawPixel(x, y);
+ }
+ }
+
+ private drawVerticalLine(x: number, y1: number, y2: number) {
+ for (let y = Math.min(y1, y2); y <= Math.max(y1, y2); y++) {
+ this.drawPixel(x, y);
+ }
+ }
+
+ private drawGeneralLine(x1: number, y1: number, x2: number, y2: number) {
+ const dx = Math.abs(x2 - x1);
+ const dy = Math.abs(y2 - y1);
+
+ let a = 0;
+ let b = 0;
+ let diff = 0;
+
+ const sx = x1 < x2 ? 1 : -1;
+ const sy = y1 < y2 ? 1 : -1;
+
+ while (a <= dx && b <= dy) {
+ this.drawPixel(x1 + sx * a, y1 + sy * b);
+ if (diff < 0) {
+ a = a + 1;
+ diff = diff + dy;
+ } else {
+ b = b + 1;
+ diff = diff - dx;
+ }
+ }
+ }
+
+ drawRect(x1: number, y1: number, x2: number, y2: number) {
+ if (this.outOfBounds(x1, y1) || this.outOfBounds(x2, y2)) {
+ this.os.sys.error(ERRNO.ILLEGAL_RECT_COORD);
+ return;
+ }
+ for (let x = x1; x <= x2; x++) {
+ for (let y = y1; y <= y2; y++) {
+ this.drawPixel(x, y);
+ }
+ }
+ }
+
+ drawCircle(x: number, y: number, r: number) {
+ if (this.outOfBounds(x, y)) {
+ this.os.sys.error(ERRNO.ILLEGAL_CENTER_COORD);
+ return;
+ }
+ if (r > MAX_R) {
+ this.os.sys.error(ERRNO.ILLEGAL_RADIUS);
+ return;
+ }
+ for (let dy = -r; dy <= r; dy++) {
+ this.drawLine(
+ x - Math.floor(Math.sqrt(r * r - dy * dy)),
+ y + dy,
+ x + Math.floor(Math.sqrt(r * r - dy * dy)),
+ y + dy,
+ );
+ }
+ }
+}
diff --git a/src/lib/software/vendor/nand2tetris/vm/os/string.ts b/src/lib/software/vendor/nand2tetris/vm/os/string.ts
new file mode 100644
index 0000000..b05d25f
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/vm/os/string.ts
@@ -0,0 +1,137 @@
+import { VmMemory } from "../memory.js";
+import { ERRNO } from "./errors.js";
+import { OS } from "./os.js";
+
+export const NEW_LINE = 128;
+export const BACKSPACE = 129;
+export const DOUBLE_QUOTES = 34;
+
+function isDigit(char: number) {
+ return char >= 48 && char <= 57;
+}
+
+function toInt(char: number) {
+ return char - 48;
+}
+
+export function intToCharArray(value: number) {
+ return value
+ .toString()
+ .split("")
+ .map((c) => c.charCodeAt(0));
+}
+
+export class StringLib {
+ private memory: VmMemory;
+ private os: OS;
+
+ constructor(memory: VmMemory, os: OS) {
+ this.memory = memory;
+ this.os = os;
+ }
+
+ new(size: number) {
+ if (size < 0) {
+ this.os.sys.error(ERRNO.STRING_LENGTH_NEG);
+ }
+ const pointer = this.os.memory.alloc(size + 3); // +3 to save length, maxLength, charArray Ptr
+ if (this.os.sys.halted) {
+ // alloc returned with an error
+ return 0;
+ }
+
+ this.memory.set(pointer, size); // set maxLength = size
+ this.memory.set(pointer + 1, 0); // set length = 0
+ this.memory.set(pointer + 2, this.os.memory.alloc(size)); // set charArrayPtr.
+ return pointer;
+ }
+
+ dispose(pointer: number) {
+ this.os.memory.deAlloc(pointer);
+ }
+
+ private maxLength(pointer: number) {
+ return this.memory.get(pointer);
+ }
+
+ length(pointer: number) {
+ return this.memory.get(pointer + 1);
+ }
+
+ private setLength(pointer: number, length: number) {
+ this.memory.set(pointer + 1, length);
+ }
+
+ private charArrayPointer(pointer: number) {
+ return this.memory.get(pointer + 2);
+ }
+
+ charAt(pointer: number, index: number) {
+ if (index < 0 || index >= this.length(pointer)) {
+ this.os.sys.error(ERRNO.GET_CHAR_INDEX_OUT_OF_BOUNDS);
+ return 0;
+ }
+ return this.memory.get(this.charArrayPointer(pointer) + index);
+ }
+
+ setCharAt(pointer: number, index: number, value: number) {
+ if (index < 0 || index >= this.length(pointer)) {
+ this.os.sys.error(ERRNO.SET_CHAR_INDEX_OUT_OF_BOUNDS);
+ return;
+ }
+ this.memory.set(this.charArrayPointer(pointer) + index, value);
+ }
+
+ // This returns the string pointer to allow compilation of string literals as described in the book,
+ // i.e. to a series of instructions of the form:
+ // call string.new 1
+ // repeat:
+ // push constant
+ // call String.appendChar 2
+ appendChar(pointer: number, value: number) {
+ const length = this.length(pointer);
+ if (length == this.maxLength(pointer)) {
+ this.os.sys.error(ERRNO.STRING_FULL);
+ return 0;
+ }
+ this.setLength(pointer, length + 1);
+ this.setCharAt(pointer, length, value);
+ return pointer;
+ }
+
+ eraseLastChar(pointer: number) {
+ const length = this.length(pointer);
+ if (length == 0) {
+ this.os.sys.error(ERRNO.STRING_EMPTY);
+ return;
+ }
+ this.setLength(pointer, length - 1);
+ }
+
+ intValue(pointer: number) {
+ const digits = [];
+ const neg = this.charAt(pointer, 0) == 45; // minus sign
+ const start = neg ? 1 : 0;
+ for (let i = start; i < this.length(pointer); i++) {
+ if (isDigit(this.charAt(pointer, i))) {
+ digits.push(toInt(this.charAt(pointer, i)));
+ } else {
+ break;
+ }
+ }
+ const value = digits.reduce((acc, digit) => acc * 10 + digit, 0);
+ return neg ? -value : value;
+ }
+
+ setInt(pointer: number, value: number) {
+ const chars = intToCharArray(value);
+ if (chars.length > this.maxLength(pointer)) {
+ this.os.sys.error(ERRNO.STRING_INSUFFICIENT_CAPACITY);
+ return;
+ }
+ this.setLength(pointer, 0);
+ for (const c of chars) {
+ this.appendChar(pointer, c);
+ }
+ }
+}
diff --git a/src/lib/software/vendor/nand2tetris/vm/os/sys.ts b/src/lib/software/vendor/nand2tetris/vm/os/sys.ts
new file mode 100644
index 0000000..98bb501
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/vm/os/sys.ts
@@ -0,0 +1,85 @@
+import { ERRNO } from "./errors.js";
+import { OS } from "./os.js";
+
+export class SysLib {
+ private os: OS;
+
+ private _blocked = false;
+ private _released = false;
+ private _returnValue = 0;
+ private _halted = false;
+ private _exitCode = 0;
+
+ private cancelWait = false;
+ private waitTimeout: ReturnType | undefined;
+ private animationFrameId: number | undefined;
+
+ constructor(os: OS) {
+ this.os = os;
+ }
+
+ get blocked() {
+ return this._blocked;
+ }
+
+ get released() {
+ return this._released;
+ }
+
+ get halted() {
+ return this._halted;
+ }
+
+ get exitCode() {
+ return this._exitCode;
+ }
+
+ block() {
+ this._blocked = true;
+ }
+
+ release(returnValue?: number) {
+ this._blocked = false;
+ this._returnValue = returnValue ?? 0;
+ this._released = true;
+ }
+
+ readReturnValue() {
+ this._released = false;
+ return this._returnValue;
+ }
+
+ wait(ms: number) {
+ if (ms <= 0) {
+ this.error(ERRNO.SYS_WAIT_DURATION_NOT_POSITIVE);
+ return;
+ }
+
+ this.block();
+
+ this.waitTimeout = setTimeout(() => {
+ this.waitTimeout = undefined;
+ if (!this.cancelWait) this.release();
+ }, ms);
+ }
+
+ halt() {
+ this._halted = true;
+ this._exitCode = 0;
+ }
+
+ error(code: number) {
+ this.os.output.printJsString(`ERR${code}`);
+ this._halted = true;
+ this._exitCode = code;
+ }
+
+ dispose() {
+ this.cancelWait = true;
+ if (this.waitTimeout !== undefined) clearTimeout(this.waitTimeout);
+
+ if (this.animationFrameId) {
+ cancelAnimationFrame(this.animationFrameId);
+ }
+ }
+}
diff --git a/src/lib/software/vendor/nand2tetris/vm/vm.ts b/src/lib/software/vendor/nand2tetris/vm/vm.ts
new file mode 100644
index 0000000..22bfc02
--- /dev/null
+++ b/src/lib/software/vendor/nand2tetris/vm/vm.ts
@@ -0,0 +1,1071 @@
+import {
+ Err,
+ isErr,
+ Ok,
+ type Result,
+ unwrap,
+} from "@davidsouther/jiffies/result.ts";
+import { type MemoryAdapter, RAM } from "../cpu/memory.js";
+import { type CompilationError, createError, type Span } from "../languages/base.js";
+import {
+ type CallInstruction,
+ type FunctionInstruction,
+ type Segment,
+ type StackInstruction,
+ type VmInstruction,
+} from "../languages/vm.js";
+import { VM_BUILTINS } from "./builtins.js";
+import { VmMemory } from "./memory.js";
+import { OS } from "./os/os.js";
+
+interface VmFrameValues {
+ base: number;
+ count: number;
+ values: number[];
+}
+
+export interface VmFrame {
+ fn?: VmFunction;
+ locals: VmFrameValues;
+ args: VmFrameValues;
+ stack: VmFrameValues;
+ this: VmFrameValues;
+ that: VmFrameValues;
+ frame: {
+ RET: number;
+ ARG: number;
+ LCL: number;
+ THIS: number;
+ THAT: number;
+ };
+ usedSegments?: Set;
+}
+
+export type VmFunctions = Record;
+export interface VmFunction {
+ name: string;
+ nVars: number;
+ labels: Record;
+ operations: VmInstruction[];
+ opBase: number;
+}
+
+interface VmFunctionInvocation {
+ function: string;
+ // The current operation offset in the function
+ opPtr: number;
+ // Base address of the frame in memory
+ frameBase: number;
+ // The number of args the function was called with
+ nArgs: number;
+ // Whether the THIS segment was initialized in this invocation
+ thisInitialized: boolean;
+ // Whether the THAT segment was initialized in this invocation
+ thatInitialized: boolean;
+ // The size of the memory block pointed to by the function's THIS (if exists)
+ thisN?: number;
+ // The highest accessed index + 1 of the function's THAT segment
+ thatN?: number;
+}
+
+export const IMPLICIT = "__implicit";
+
+export const SYS_INIT: VmFunction = {
+ name: "Sys.init",
+ labels: {},
+ nVars: 0,
+ opBase: 0,
+ operations: [
+ { op: "function", name: "Sys.init", nVars: 0 },
+ { op: "call", name: "Math.init", nArgs: 0 },
+ { op: "call", name: "String.init", nArgs: 0 },
+ { op: "call", name: "Array.init", nArgs: 0 },
+ { op: "call", name: "Output.init", nArgs: 0 },
+ { op: "call", name: "Screen.init", nArgs: 0 },
+ { op: "call", name: "Keyboard.init", nArgs: 0 },
+ { op: "call", name: "Memory.init", nArgs: 0 },
+ { op: "call", name: "Main.main", nArgs: 0 },
+ ],
+};
+
+const ARRAY_NEW_BRIDGE: VmFunction = {
+ name: "Array.new",
+ labels: {},
+ nVars: 0,
+ opBase: 0,
+ operations: [
+ { op: "function", name: "Array.new", nVars: 0 },
+ { op: "push", segment: "argument", offset: 0 },
+ { op: "call", name: "Memory.alloc", nArgs: 1 },
+ { op: "return" },
+ ],
+};
+
+const ARRAY_DISPOSE_BRIDGE: VmFunction = {
+ name: "Array.dispose",
+ labels: {},
+ nVars: 0,
+ opBase: 0,
+ operations: [
+ { op: "function", name: "Array.dispose", nVars: 0 },
+ { op: "push", segment: "argument", offset: 0 },
+ { op: "call", name: "Memory.deAlloc", nArgs: 1 },
+ { op: "pop", segment: "temp", offset: 0 },
+ { op: "push", segment: "constant", offset: 0 },
+ { op: "return" },
+ ],
+};
+
+// Walks a string by calling String.length / String.charAt so a
+// user-supplied String.jack (with a custom internal layout) is honoured by
+// the builtin Output.printString. local 0 = i, local 1 = length.
+const OUTPUT_PRINT_STRING_BRIDGE: VmFunction = {
+ name: "Output.printString",
+ labels: { LOOP: 6, END: 21 },
+ nVars: 2,
+ opBase: 0,
+ operations: [
+ { op: "function", name: "Output.printString", nVars: 2 },
+ { op: "push", segment: "argument", offset: 0 },
+ { op: "call", name: "String.length", nArgs: 1 },
+ { op: "pop", segment: "local", offset: 1 },
+ { op: "push", segment: "constant", offset: 0 },
+ { op: "pop", segment: "local", offset: 0 },
+ { op: "label", label: "LOOP" },
+ { op: "push", segment: "local", offset: 0 },
+ { op: "push", segment: "local", offset: 1 },
+ { op: "eq" },
+ { op: "if-goto", label: "END" },
+ { op: "push", segment: "argument", offset: 0 },
+ { op: "push", segment: "local", offset: 0 },
+ { op: "call", name: "String.charAt", nArgs: 2 },
+ { op: "call", name: "Output.printChar", nArgs: 1 },
+ { op: "pop", segment: "temp", offset: 0 },
+ { op: "push", segment: "local", offset: 0 },
+ { op: "push", segment: "constant", offset: 1 },
+ { op: "add" },
+ { op: "pop", segment: "local", offset: 0 },
+ { op: "goto", label: "LOOP" },
+ { op: "label", label: "END" },
+ { op: "push", segment: "constant", offset: 0 },
+ { op: "return" },
+ ],
+};
+
+export interface ParsedVmFile {
+ name: string;
+ instructions: VmInstruction[];
+}
+
+interface SegmentStatus {
+ initialized: boolean;
+ n: number;
+}
+
+export class Vm {
+ memory = new VmMemory();
+ private os = new OS(this.memory);
+ // Integration accessors: preserve the reference interpreter's private OS state.
+ get halted(): boolean { return this.os.sys.halted; }
+ get blocked(): boolean { return this.os.sys.blocked; }
+ get exitCode(): number { return this.os.sys.exitCode; }
+ dispose(): void { this.os.dispose(); }
+ functionMap: Record = {};
+ executionStack: VmFunctionInvocation[] = [];
+
+ entry = "";
+
+ segmentInitializations: Record<"local" | "argument", SegmentStatus> = {
+ local: { initialized: false, n: 0 },
+ argument: { initialized: false, n: 0 },
+ };
+
+ functions: VmFunction[] = [];
+ program: VmInstruction[] = [];
+ addedSysInit = false;
+
+ private staticCount = 0;
+ protected statics: Record = {};
+
+ getStaticCount() {
+ return this.staticCount;
+ }
+
+ private returnLine: number | undefined = undefined;
+
+ private registerStatic(fnName: string, offset: number): number {
+ const fileName = fnName.split(".")[0];
+ const statics = this.statics[fileName] ?? [];
+ this.statics[fileName] = statics;
+ const static_ = statics[offset] ?? this.staticCount++;
+ statics[offset] = static_;
+ return static_;
+ }
+
+ private registerStatics() {
+ for (const fn of Object.values(this.functionMap)) {
+ for (const op of fn.operations) {
+ if (
+ (op.op === "push" || op.op === "pop") &&
+ (op as StackInstruction)?.segment === "static"
+ ) {
+ (op as StackInstruction).offset = this.registerStatic(
+ fn.name,
+ (op as StackInstruction).offset,
+ );
+ }
+ }
+ }
+ }
+
+ private static fileBasenameNoExtension(file: string): string {
+ // Files that are part of the web-ide are usually passed with folders but without extensions.
+ // e.g.: /projects/08/FibonacciElement/Sys
+ if (file.includes("/")) {
+ file = file.split("/").pop() ?? "";
+ }
+
+ // Local files on Windows are usually passed with extension.
+ // e.g.: Sys.vm
+ if (file.includes(".")) {
+ file = file.split(".")[0];
+ }
+
+ return file;
+
+ // TODO: Check if this also works for Linux and MacOS
+ }
+
+ private static validateFile(file: ParsedVmFile) {
+ for (const inst of file.instructions) {
+ if (inst.op == "function") {
+ const parts = inst.name.split(".");
+ if (parts.length != 2) {
+ return Err(
+ createError(
+ `Illegal subroutine name ${inst.name} (Expected .)`,
+ inst.span,
+ ),
+ );
+ }
+ if (parts[0] != this.fileBasenameNoExtension(file.name)) {
+ return Err(
+ createError(
+ `File name ${file.name} doesn't match class name ${parts[0]} (at ${inst.name})`,
+ inst.span,
+ ),
+ );
+ }
+ }
+ }
+ return Ok();
+ }
+
+ private static validateFiles(files: ParsedVmFile[]) {
+ const names: Set = new Set();
+
+ for (const file of files) {
+ if (names.has(file.name)) {
+ return Err(createError(`File ${file.name} already exists`));
+ }
+ const result = this.validateFile(file);
+ if (isErr(result)) {
+ return result;
+ }
+ names.add(file.name);
+ }
+ return Ok();
+ }
+
+ private validateStackInstructions() {
+ for (const fn of Object.values(this.functionMap)) {
+ for (const inst of fn.operations) {
+ if (inst.op == "pop" || inst.op == "push") {
+ const base = this.memory.baseSegment(inst.segment, inst.offset);
+ if (isErr(base)) {
+ return Err(createError(Err(base).message, inst.span));
+ }
+ }
+ }
+ }
+ return Ok();
+ }
+
+ private static validateFunctions(
+ instructions: VmInstruction[],
+ ): Result {
+ const functions: Set = new Set();
+ const calls = [];
+
+ for (const inst of instructions) {
+ if (inst.op == "function") {
+ if (inst.nVars < 0 || inst.nVars > 32767) {
+ return Err(
+ createError(
+ `Illegal number of local variables ${inst.nVars} (Expected 0-32767)`,
+ inst.span,
+ ),
+ );
+ }
+ functions.add(inst.name);
+ }
+ if (inst.op == "call") {
+ if (inst.nArgs < 0 || inst.nArgs > 32767) {
+ return Err(
+ createError(
+ `Illegal number of arguments ${inst.nArgs} (Expected 0-32767)`,
+ inst.span,
+ ),
+ );
+ }
+ calls.push(inst as CallInstruction);
+ }
+ }
+
+ for (const call of calls) {
+ if (!functions.has(call.name)) {
+ const builtin = VM_BUILTINS[call.name];
+ if (builtin) {
+ const expectedNArgs =
+ builtin.type == "method"
+ ? builtin.args.length + 1
+ : builtin.args.length;
+ if (expectedNArgs != call.nArgs) {
+ return Err(
+ createError(
+ `OS function ${call.name} expects ${
+ expectedNArgs
+ } arguments, not ${call.nArgs}`,
+ call.span,
+ ),
+ );
+ }
+ } else {
+ return Err(createError(`Undefined function ${call.name}`, call.span));
+ }
+ }
+ }
+
+ return Ok();
+ }
+
+ static buildFromFiles(files: ParsedVmFile[]): Result {
+ if (files.length === 0) {
+ return Err(
+ createError("No .vm files to load. Compile your Jack files first."),
+ );
+ }
+ let result = this.validateFiles(files);
+ if (isErr(result)) {
+ return result;
+ }
+ const instructions = files
+ .map((file) => file.instructions)
+ .reduce((list1, list2) => list1.concat(list2), [] as VmInstruction[]);
+ result = this.validateFunctions(instructions);
+ if (isErr(result)) {
+ return result;
+ }
+ const vm = new Vm();
+ const load = vm.load(instructions);
+ if (isErr(load)) return load;
+ return vm.bootstrap();
+ }
+
+ static build(instructions: VmInstruction[]): Result {
+ const result = this.validateFunctions(instructions);
+ if (isErr(result)) {
+ return result;
+ }
+ const vm = new Vm();
+ const load = vm.load(instructions);
+ if (isErr(load)) return load;
+ return vm.bootstrap();
+ }
+
+ private static buildFunction(
+ instructions: VmInstruction[],
+ i: number,
+ ): Result<[VmFunction, number], CompilationError> {
+ if (instructions[i].op !== "function")
+ throw new Error(
+ "Only call buildFunction at the initial Function instruction",
+ );
+
+ const { name, nVars } = instructions[i] as FunctionInstruction;
+ const fn: VmFunction = {
+ name,
+ nVars,
+ labels: {},
+ operations: [{ op: "function", name, nVars, span: instructions[i].span }],
+ opBase: 0,
+ };
+
+ const declaredLabels: Set = new Set();
+ const usedLabels: Record = {};
+
+ i += 1;
+ instructions: while (i < instructions.length) {
+ switch (instructions[i].op) {
+ case "function":
+ break instructions;
+ case "add":
+ case "sub":
+ case "neg":
+ case "and":
+ case "or":
+ case "not":
+ case "gt":
+ case "lt":
+ case "eq":
+ fn.operations.push({
+ op: instructions[i].op as
+ | "add"
+ | "sub"
+ | "neg"
+ | "lt"
+ | "gt"
+ | "eq"
+ | "and"
+ | "or"
+ | "not",
+ span: instructions[i].span,
+ });
+ break;
+ case "push":
+ case "pop":
+ fn.operations.push({
+ op: instructions[i].op as "push" | "pop",
+ segment: (
+ instructions[i] as {
+ segment:
+ | "argument"
+ | "local"
+ | "static"
+ | "constant"
+ | "this"
+ | "that"
+ | "pointer"
+ | "temp";
+ }
+ ).segment,
+ offset: (instructions[i] as { offset: number }).offset,
+ span: instructions[i].span,
+ });
+ break;
+ case "call":
+ fn.operations.push({
+ op: "call",
+ name: (instructions[i] as { name: string }).name,
+ nArgs: (instructions[i] as { nArgs: number }).nArgs,
+ span: instructions[i].span,
+ });
+ break;
+ case "goto":
+ case "if-goto": {
+ const { label } = instructions[i] as { label: string };
+ usedLabels[label] = instructions[i].span;
+ fn.operations.push({
+ op: instructions[i].op as "goto" | "if-goto",
+ label,
+ span: instructions[i].span,
+ });
+ break;
+ }
+ case "label": {
+ const { label } = instructions[i] as { label: string };
+ declaredLabels.add(label);
+ if (fn.labels[label])
+ return Err(
+ createError(
+ `Cannot redeclare label ${label} in function ${
+ fn.name
+ } (previously at line ${fn.labels[label] + 1})`,
+ instructions[i].span,
+ ),
+ );
+ fn.labels[label] = fn.operations.length;
+ fn.operations.push({
+ op: "label",
+ label,
+ span: instructions[i].span,
+ });
+ break;
+ }
+ case "return": {
+ fn.operations.push({ op: "return", span: instructions[i].span });
+ break;
+ }
+ }
+
+ i += 1;
+ }
+
+ for (const label of Object.keys(usedLabels)) {
+ if (!declaredLabels.has(label)) {
+ return Err(createError(`Undeclared label ${label}`, usedLabels[label]));
+ }
+ }
+
+ return Ok([fn, i]);
+ }
+
+ get RAM(): RAM {
+ return this.memory;
+ }
+
+ get Keyboard(): MemoryAdapter {
+ return this.memory.keyboard;
+ }
+ get Screen(): MemoryAdapter {
+ return this.memory.screen;
+ }
+
+ get invocation(): VmFunctionInvocation {
+ const invocation = this.executionStack.at(-1);
+ if (invocation === undefined) {
+ return {
+ frameBase: 256,
+ function: IMPLICIT,
+ nArgs: 0,
+ opPtr: 0,
+ thisInitialized: false,
+ thatInitialized: false,
+ };
+ }
+ return invocation;
+ }
+
+ get currentFunction() {
+ return this.functionMap[this.invocation.function];
+ }
+
+ get operation() {
+ if (!this.currentFunction) {
+ return undefined;
+ }
+ if (this.invocation.opPtr > this.currentFunction.operations.length)
+ throw new Error(
+ `Current operation step beyond end of function operations (${this.invocation.opPtr} > ${this.currentFunction.operations.length})`,
+ );
+
+ return this.currentFunction.operations[this.invocation.opPtr];
+ }
+
+ load(
+ instructions: VmInstruction[],
+ reset = false,
+ ): Result {
+ if (reset) {
+ this.functionMap = {};
+ this.statics = {};
+ this.staticCount = 0;
+ }
+
+ if (instructions[0]?.op !== "function") {
+ instructions.unshift({ op: "function", name: IMPLICIT, nVars: 0 });
+ }
+
+ let i = 0;
+ while (i < instructions.length) {
+ const buildFn = Vm.buildFunction(instructions, i);
+
+ if (isErr(buildFn)) return buildFn;
+ const [fn, i_] = unwrap(buildFn);
+ if (
+ this.functionMap[fn.name] &&
+ this.memory.strict &&
+ fn.name !== IMPLICIT &&
+ fn.name !== SYS_INIT.name
+ ) {
+ return Err(
+ createError(
+ `VM Already has a function named ${fn.name}`,
+ instructions[0].span,
+ ),
+ );
+ }
+
+ this.functionMap[fn.name] = fn;
+ i = i_;
+ }
+
+ const result = this.validateStackInstructions();
+ if (isErr(result)) {
+ return result;
+ }
+ this.registerStatics();
+
+ if (reset) {
+ this.bootstrap();
+ }
+
+ return Ok(this);
+ }
+
+ bootstrap() {
+ if (!this.functionMap[SYS_INIT.name] && this.functionMap["Main.main"]) {
+ this.functionMap[SYS_INIT.name] = SYS_INIT;
+ this.addedSysInit = true;
+ // TODO should this be an error from the compiler/OS?
+ }
+
+ if (
+ this.functionMap["Memory.alloc"] &&
+ !this.functionMap[ARRAY_NEW_BRIDGE.name]
+ ) {
+ this.functionMap[ARRAY_NEW_BRIDGE.name] = ARRAY_NEW_BRIDGE;
+ }
+ if (
+ this.functionMap["Memory.deAlloc"] &&
+ !this.functionMap[ARRAY_DISPOSE_BRIDGE.name]
+ ) {
+ this.functionMap[ARRAY_DISPOSE_BRIDGE.name] = ARRAY_DISPOSE_BRIDGE;
+ }
+ if (
+ this.functionMap["String.charAt"] &&
+ !this.functionMap[OUTPUT_PRINT_STRING_BRIDGE.name]
+ ) {
+ this.functionMap[OUTPUT_PRINT_STRING_BRIDGE.name] =
+ OUTPUT_PRINT_STRING_BRIDGE;
+ }
+
+ if (this.functionMap[SYS_INIT.name]) {
+ this.entry = SYS_INIT.name;
+ } else if (this.functionMap[IMPLICIT]) {
+ this.entry = IMPLICIT;
+ } else {
+ const fnNames = Object.keys(this.functionMap);
+ if (fnNames.length === 1) {
+ this.entry = fnNames[0];
+ }
+ }
+
+ if (this.functionMap[IMPLICIT] && this.functionMap[SYS_INIT.name]) {
+ return Err(
+ createError("Cannot use both bootstrap and an implicit function"),
+ );
+ }
+
+ if (this.entry === "") {
+ return Err(createError("Could not determine an entry point for VM"));
+ }
+
+ this.functions = Object.values(this.functionMap);
+ this.functions.sort((a, b) => {
+ if (a.name === this.entry) return -1;
+ if (b.name === this.entry) return 1;
+ return 0; // Stable sort otherwise
+ });
+
+ let offset = 0;
+ this.program = this.functions.reduce((prog, fn) => {
+ if (fn.name != SYS_INIT.name) {
+ fn.opBase = offset;
+ }
+ offset += fn.operations.length;
+ return prog.concat(fn.operations);
+ }, [] as VmInstruction[]);
+
+ this.reset();
+
+ return Ok(this);
+ }
+
+ reset() {
+ this.executionStack = [
+ {
+ function: this.entry,
+ opPtr: 1,
+ frameBase: 256,
+ nArgs: 0,
+ thisInitialized: false,
+ thatInitialized: false,
+ },
+ ];
+ this.memory.reset();
+ this.memory.SP = 256;
+ this.segmentInitializations = {
+ local: { initialized: false, n: 0 },
+ argument: { initialized: false, n: 0 },
+ };
+
+ this.os.dispose();
+ this.os = new OS(this.memory);
+ }
+
+ private validateStackOp(op: StackInstruction) {
+ if (this.currentFunction?.name == this.entry) {
+ for (const segment of ["local", "argument"] as const) {
+ if (op.segment == segment) {
+ if (this.segmentInitializations[segment].initialized) {
+ // the size of that segment is always 1
+ this.segmentInitializations[segment].n = Math.max(
+ op.offset + 1,
+ this.segmentInitializations[segment].n,
+ );
+ return;
+ } else {
+ throw new Error(
+ `The ${segment} segment cannot be accessed since it was not initialized`,
+ );
+ }
+ }
+ }
+ if (op.segment == "this" && this.invocation.thisInitialized) {
+ this.invocation.thisN = Math.max(
+ op.offset + 1,
+ this.invocation.thisN ?? 0,
+ );
+ return;
+ }
+ }
+ if (op.segment == "argument" && op.offset >= this.invocation.nArgs) {
+ throw new Error("Argument offset out of bounds");
+ }
+ if (
+ op.segment == "local" &&
+ op.offset >= this.functionMap[this.invocation.function]?.nVars
+ ) {
+ throw new Error("Local offset out of bounds");
+ }
+ if (op.segment == "this" && !this.invocation.thisInitialized) {
+ throw new Error(
+ `The this segment cannot be accessed since it was not initialized`,
+ );
+ }
+ if (op.segment == "that" && !this.invocation.thatInitialized) {
+ throw new Error(
+ `The that segment cannot be accessed since it was not initialized`,
+ );
+ }
+ if (op.segment == "that") {
+ this.invocation.thatN = Math.max(
+ op.offset + 1,
+ this.invocation.thatN ?? 1,
+ );
+ }
+ }
+
+ setPaused(paused = true) {
+ this.os.paused = paused;
+ }
+
+ step(): number | undefined {
+ if (this.os.sys.halted) {
+ return this.os.sys.exitCode;
+ }
+ if (this.os.sys.blocked) {
+ return;
+ }
+ if (this.os.sys.released && this.operation?.op == "call") {
+ const ret = this.os.sys.readReturnValue();
+ const sp = this.memory.SP - this.operation.nArgs;
+ this.memory.set(sp, ret);
+ this.memory.SP = sp + 1;
+ this.invocation.opPtr += 1;
+ return;
+ }
+
+ if (this.operation == undefined) {
+ this.os.sys.halt();
+ return this.step();
+ }
+
+ const operation = this.operation;
+
+ if (operation.op === "label") {
+ this.invocation.opPtr += 1;
+ return this.step();
+ }
+
+ switch (operation.op) {
+ case "push": {
+ this.validateStackOp(operation);
+ const value = this.memory.getSegment(
+ operation.segment,
+ operation.offset,
+ );
+ this.memory.push(value);
+ break;
+ }
+ case "pop": {
+ this.validateStackOp(operation);
+ const value = this.memory.pop();
+ this.memory.setSegment(operation.segment, operation.offset, value);
+
+ // update THIS/THAT segment status
+ if (operation.segment == "pointer") {
+ if (operation.offset == 0) {
+ this.invocation.thisInitialized = true;
+ this.invocation.thisN = this.memory.get(this.memory.THIS - 1);
+ } else if (operation.offset == 1) {
+ this.invocation.thatInitialized = true;
+ this.invocation.thatN = 1;
+ }
+ }
+ break;
+ }
+ case "add": {
+ this.memory.binOp((a, b) => a + b);
+ break;
+ }
+ case "sub": {
+ this.memory.binOp((a, b) => a - b);
+ break;
+ }
+ case "neg": {
+ // neg by flipping the sign bit
+ this.memory.unOp((a) => -a);
+ break;
+ }
+ case "and": {
+ this.memory.binOp((a, b) => a & b);
+ break;
+ }
+ case "or": {
+ this.memory.binOp((a, b) => a | b);
+ break;
+ }
+ case "not": {
+ this.memory.unOp((a) => ~a);
+ break;
+ }
+ case "eq": {
+ this.memory.comp((a, b) => a === b);
+ break;
+ }
+ case "lt": {
+ this.memory.comp((a, b) => a < b);
+ break;
+ }
+ case "gt": {
+ this.memory.comp((a, b) => a > b);
+ break;
+ }
+ case "goto": {
+ this.goto(operation.label);
+ break;
+ }
+ case "if-goto": {
+ const check = this.memory.pop();
+ if (check != 0) {
+ this.goto(operation.label);
+ }
+ break;
+ }
+ case "call": {
+ const fnName = operation.name;
+ if (this.functionMap[fnName]) {
+ const base = this.memory.pushFrame(
+ this.invocation.opPtr,
+ operation.nArgs,
+ this.functionMap[fnName].nVars,
+ );
+ this.executionStack.push({
+ function: fnName,
+ opPtr: 0,
+ nArgs: operation.nArgs,
+ frameBase: base,
+ thisInitialized: false,
+ thatInitialized: false,
+ });
+ } else if (VM_BUILTINS[fnName]) {
+ const ret = VM_BUILTINS[fnName].func(this.memory, this.os);
+ if (this.os.sys.blocked) {
+ return; // we will handle the return when the OS is released
+ }
+ const sp = this.memory.SP - operation.nArgs;
+ this.memory.set(sp, ret);
+ this.memory.SP = sp + 1;
+ }
+ break;
+ }
+ case "return": {
+ const line = this.derivedLine();
+ this.executionStack.pop();
+ const ret = this.memory.popFrame();
+ this.invocation.opPtr = ret;
+ if (this.executionStack.length === 0) {
+ this.returnLine = line;
+ return 0;
+ }
+ break;
+ }
+ }
+ this.invocation.opPtr += 1;
+ return;
+ }
+
+ private goto(label: string) {
+ if (!this.currentFunction) {
+ return;
+ }
+ if (this.currentFunction.labels[label] === undefined)
+ throw new Error(
+ `Attempting GOTO to unknown label ${label} in ${this.currentFunction.name}`,
+ );
+ this.invocation.opPtr = this.currentFunction.labels[label];
+ }
+
+ write(addresses: [number, number][]) {
+ addresses.map(([address, value]) => {
+ this.memory.set(address, value);
+ });
+ }
+
+ read(addresses: number[]): number[] {
+ return addresses.map((address) => this.memory.get(address));
+ }
+
+ vmStack(): VmFrame[] {
+ return this.executionStack.map((invocation, i) => {
+ const next = this.executionStack[i + 1];
+ const end = next ? next.frameBase - next.nArgs : this.memory.get(0);
+ return this.makeFrame(invocation, end);
+ });
+ }
+
+ private getUsedSegments(invocation: VmFunctionInvocation) {
+ const usedSegments = new Set();
+
+ for (const inst of this.functionMap[invocation.function].operations) {
+ if (inst.op === "push" || inst.op == "pop") {
+ usedSegments.add(inst.segment);
+ }
+ }
+
+ return usedSegments;
+ }
+
+ makeFrame(invocation = this.invocation, nextFrame: number): VmFrame {
+ const fn = this.functionMap[invocation.function];
+ if (fn.name === this.entry) {
+ const stackBase = 256 + fn.nVars;
+ const nextFrame = this.executionStack[1];
+ const frameEnd = nextFrame
+ ? nextFrame.frameBase - nextFrame.nArgs
+ : this.memory.get(0);
+ const { ARG, LCL, THAT, THIS } = this.memory;
+ const nArg = this.segmentInitializations["argument"].n;
+ const nLocal = this.segmentInitializations["local"].n;
+ const nThis = this.invocation.thisN ?? 0;
+ const nThat = this.invocation.thatN ?? 1;
+ const stackCount = frameEnd - stackBase;
+ return {
+ fn,
+ args: {
+ base: ARG,
+ count: nArg,
+ values: [...this.memory.map((_, v) => v, ARG, ARG + nArg)],
+ },
+ locals: {
+ base: LCL,
+ count: nLocal,
+ values: [...this.memory.map((_, v) => v, LCL, LCL + nLocal)],
+ },
+ stack: {
+ base: 256,
+ count: Math.max(0, stackCount),
+ values:
+ stackCount > 0
+ ? [...this.memory.map((_, v) => v, stackBase, frameEnd)]
+ : [],
+ },
+ this: {
+ base: THIS,
+ count: nThis,
+ values: [...this.memory.map((_, v) => v, THIS, THIS + nThis)],
+ },
+ that: {
+ base: THAT,
+ count: nThat,
+ values: [...this.memory.map((_, v) => v, THAT, THAT + nThat)],
+ },
+ frame: {
+ ARG,
+ LCL,
+ RET: 0xffff,
+ THAT,
+ THIS,
+ },
+ usedSegments: this.getUsedSegments(invocation),
+ };
+ }
+ const frame = this.memory.getFrame(
+ invocation.frameBase,
+ invocation.nArgs,
+ fn.nVars,
+ this.invocation.thisN ?? 0,
+ this.invocation.thatN ?? 1,
+ nextFrame,
+ );
+ frame.fn = fn;
+ frame.usedSegments = this.getUsedSegments(invocation);
+ return frame;
+ }
+
+ derivedLine(): number {
+ return this.operation?.span?.line ?? this.returnLine ?? 0;
+ }
+
+ writeDebug(): string {
+ const line = this.derivedLine();
+ const from = Math.max(line - 5, 0);
+ const to = Math.min(line + 3, this.program.length);
+ const lines = this.program.slice(from, to);
+ const prog = lines
+ .map((op, i) => `${i === line - from ? "->" : " "} ${writeOp(op)}`)
+ .join("\n");
+ const frame = this.vmStack().at(-1);
+ if (frame) {
+ return prog + "\n\n" + writeFrame(frame);
+ }
+ return prog;
+ }
+}
+
+export function writeFrame(frame: VmFrame): string {
+ return [
+ `Frame: ${frame.fn?.name ?? "Unknown Fn"} ARG:${frame.frame.ARG} LCL:${
+ frame.frame.LCL
+ }`,
+ `Args: ${writeFrameValues(frame.args)}`,
+ `Lcls: ${writeFrameValues(frame.locals)}`,
+ `Stck: ${writeFrameValues(frame.stack)}`,
+ ].join("\n");
+}
+
+function writeFrameValues(fv: VmFrameValues): string {
+ return `[${fv.base};${fv.count}][${fv.values.join(", ")}]`;
+}
+
+function writeOp(op: VmInstruction): string {
+ switch (op.op) {
+ case "add":
+ case "and":
+ case "sub":
+ case "eq":
+ case "gt":
+ case "lt":
+ case "neg":
+ case "not":
+ case "or":
+ case "return":
+ return ` ${op.op}`;
+ case "goto":
+ return ` ${op.op} ${op.label}`;
+ case "if-goto":
+ return ` ${op.op} ${op.label}`;
+ case "label":
+ return `${op.op} ${op.label}`;
+ case "call":
+ return ` ${op.op} ${op.name} ${op.nArgs}`;
+ case "function":
+ return `${op.op} ${op.name} ${op.nVars}`;
+ case "pop":
+ return ` ${op.op} ${op.segment} ${op.offset}`;
+ case "push":
+ return ` ${op.op} ${op.segment} ${op.offset}`;
+ }
+}
diff --git a/src/lib/tools/lab.css b/src/lib/tools/lab.css
new file mode 100644
index 0000000..7c1028e
--- /dev/null
+++ b/src/lib/tools/lab.css
@@ -0,0 +1,327 @@
+.logic-lab {
+ --lab-bg: #0b0d16;
+ --lab-panel: #131725;
+ --lab-border: #41465b;
+ --lab-ink: #f3f3fc;
+ --lab-muted: #b8bbd0;
+ --lab-accent: #c0b5ff;
+ width: min(100%, 1160px);
+ margin: 0 auto;
+ padding: 38px 5% 80px;
+ color: var(--lab-ink);
+ background: var(--lab-bg);
+ box-sizing: border-box;
+}
+.logic-lab *,
+.logic-lab *::before,
+.logic-lab *::after {
+ box-sizing: border-box;
+}
+.logic-lab button,
+.logic-lab input,
+.logic-lab select {
+ font: inherit;
+}
+.logic-lab button,
+.logic-lab select,
+.logic-lab summary {
+ cursor: pointer;
+}
+.logic-lab a {
+ color: var(--lab-accent);
+ text-underline-offset: 5px;
+}
+.logic-lab a:hover {
+ text-decoration: underline;
+}
+.logic-lab p a {
+ text-decoration: underline;
+ text-decoration-thickness: 1px;
+}
+.logic-lab :is(button, input, select, a, summary, pre):focus-visible {
+ outline: 2px solid #d0c7ff !important;
+ outline-offset: 4px;
+}
+.logic-lab .back-link {
+ display: inline-flex;
+ min-height: 40px;
+ align-items: center;
+ gap: 9px;
+ font-size: 13px;
+}
+.logic-lab .tool-heading {
+ margin: 30px 0 36px;
+ max-width: 670px;
+}
+.logic-lab .eyebrow {
+ color: var(--lab-muted);
+ font:
+ 11px/1.5 ui-monospace,
+ monospace;
+ letter-spacing: 0.09em;
+ text-transform: uppercase;
+ margin: 0 0 14px;
+}
+.logic-lab h1 {
+ font-size: clamp(32px, 5vw, 54px);
+ line-height: 1.08;
+ letter-spacing: -0.045em;
+ font-weight: 500;
+ margin: 0;
+}
+.logic-lab .tool-intro {
+ color: var(--lab-muted);
+ font-size: 16px;
+ line-height: 1.7;
+ margin: 20px 0 0;
+}
+.logic-lab h2 {
+ font-size: 18px;
+ font-weight: 500;
+ margin: 0 0 16px;
+}
+.logic-lab h3 {
+ font-size: 15px;
+ font-weight: 600;
+ margin: 20px 0 12px;
+}
+.logic-lab .component-choice {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ border-top: 1px solid var(--lab-border);
+ border-bottom: 1px solid var(--lab-border);
+ padding: 18px 0;
+ margin-bottom: 26px;
+}
+.logic-lab label {
+ display: grid;
+ gap: 9px;
+ color: var(--lab-muted);
+ font-size: 13px;
+}
+.logic-lab select,
+.logic-lab input[type='text'] {
+ min-width: 0;
+ width: 100%;
+ min-height: 44px;
+ padding: 10px 12px;
+ border: 1px solid #62697f;
+ border-radius: 4px;
+ background: #161a29;
+ color: var(--lab-ink);
+}
+.logic-lab input[aria-invalid='true'] {
+ border-color: #f6aaab;
+}
+.logic-lab .component-choice label {
+ width: min(100%, 300px);
+ grid-template-columns: auto 1fr;
+ align-items: center;
+ gap: 16px;
+}
+.logic-lab .small-note {
+ font:
+ 12px/1.6 ui-monospace,
+ monospace;
+ color: var(--lab-muted);
+ margin: 0;
+}
+.logic-lab .lab-grid {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+ gap: 36px;
+ align-items: start;
+}
+.logic-lab .panel {
+ min-width: 0;
+ border: 1px solid var(--lab-border);
+ border-radius: 5px;
+ padding: 24px;
+ background: var(--lab-panel);
+}
+.logic-lab .panel > :last-child {
+ margin-bottom: 0;
+}
+.logic-lab .hint {
+ color: var(--lab-muted);
+ font-size: 13px;
+ line-height: 1.7;
+ margin: 12px 0;
+}
+.logic-lab .signal-button {
+ min-width: 70px;
+ min-height: 48px;
+ padding: 10px 14px;
+ border: 1px solid #7a829b;
+ border-radius: 4px;
+ color: #e4e6f2;
+ background: #171c2b;
+ display: inline-flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ font:
+ 16px ui-monospace,
+ monospace;
+}
+.logic-lab .signal-button[aria-pressed='true'] {
+ color: #fff;
+ border-color: #c2b6ff;
+ background: #4b3faa;
+}
+.logic-lab .signal-button:hover {
+ border-color: #ddd5ff;
+}
+.logic-lab .signal-button strong {
+ font-weight: 500;
+}
+.logic-lab .live-output {
+ width: 58px;
+ height: 58px;
+ display: grid;
+ place-items: center;
+ border: 2px solid #8991ac;
+ border-radius: 50%;
+ background: #111521;
+ color: #e5e7f7;
+ font:
+ 28px ui-monospace,
+ monospace;
+}
+.logic-lab .live-output.high {
+ background: #4b3faa;
+ border-color: #c2b6ff;
+ color: white;
+}
+.logic-lab .formula {
+ font:
+ 15px/1.9 ui-monospace,
+ monospace;
+ color: #e6e1ff;
+ overflow-wrap: anywhere;
+ white-space: pre-wrap;
+ margin: 20px 0 0;
+}
+.logic-lab details {
+ border-top: 1px solid var(--lab-border);
+ margin-top: 26px;
+ padding-top: 18px;
+}
+.logic-lab summary {
+ color: var(--lab-ink);
+ font-size: 15px;
+ min-height: 28px;
+}
+.logic-lab details > p {
+ color: var(--lab-muted);
+ font-size: 14px;
+ line-height: 1.7;
+}
+.logic-lab .error {
+ color: #ffb8b8;
+ font-size: 13px;
+ line-height: 1.5;
+ margin: 9px 0 0;
+}
+.logic-lab .verified {
+ color: #b6e3c8;
+ font-size: 13px;
+ line-height: 1.6;
+}
+.logic-lab .equivalence-result {
+ margin-top: 12px;
+}
+.logic-lab pre {
+ max-width: 100%;
+ overflow: auto;
+ color: #eeeaff;
+ background: #10131f;
+ padding: 20px;
+ border: 1px solid var(--lab-border);
+ border-radius: 4px;
+ font:
+ 13px/1.8 ui-monospace,
+ monospace;
+ tab-size: 4;
+}
+.logic-lab .text-button {
+ color: var(--lab-accent);
+ min-height: 40px;
+ padding: 4px 0;
+ font-size: 13px;
+ text-decoration: underline;
+ text-underline-offset: 5px;
+}
+.logic-lab .more-reading {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px 26px;
+ padding-top: 28px;
+ margin-top: 38px;
+ border-top: 1px solid var(--lab-border);
+ font-size: 13px;
+ line-height: 1.7;
+}
+.logic-lab table {
+ width: 100%;
+ border-collapse: collapse;
+ font:
+ 14px/1.5 ui-monospace,
+ monospace;
+}
+.logic-lab caption {
+ text-align: left;
+ color: var(--lab-muted);
+ font:
+ 12px/1.6 ui-monospace,
+ monospace;
+ margin-bottom: 12px;
+}
+.logic-lab th {
+ color: #c7c9dc;
+ font-weight: 400;
+ font-size: 12px;
+}
+.logic-lab th,
+.logic-lab td {
+ padding: 10px 12px;
+ border-bottom: 1px solid var(--lab-border);
+ text-align: center;
+}
+.logic-lab tbody tr.active-row {
+ background: #25253e;
+}
+.logic-lab .sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+}
+@media (max-width: 720px) {
+ .logic-lab {
+ padding: 24px 6% 56px;
+ }
+ .logic-lab .tool-heading {
+ margin: 20px 0 28px;
+ }
+ .logic-lab .lab-grid {
+ grid-template-columns: 1fr;
+ gap: 26px;
+ }
+ .logic-lab .component-choice {
+ flex-wrap: wrap;
+ }
+ .logic-lab .panel {
+ padding: 20px 16px;
+ }
+ .logic-lab .component-choice label {
+ width: 100%;
+ }
+}
diff --git a/src/lib/tools/logic.test.ts b/src/lib/tools/logic.test.ts
new file mode 100644
index 0000000..c14521b
--- /dev/null
+++ b/src/lib/tools/logic.test.ts
@@ -0,0 +1,179 @@
+import { describe, expect, it } from 'vitest';
+import parseHdl from '#lib/editor/hdl/parse.js';
+import ChipFactory from '#lib/hardware-simulator/chips/ChipFactory.js';
+import {
+ binaryWord,
+ booleanFunctions,
+ busComponents,
+ busInputNames,
+ busSelectorCount,
+ canonicalExpression,
+ constructWithNand,
+ evaluateFunction,
+ evaluateNandConstruction,
+ functionSignature,
+ inputRows,
+ nandHDL,
+ parseWord,
+ simulateBus,
+ toggleFunctionRow,
+} from './logic';
+
+describe('Boolean functions lab', () => {
+ it('gives all sixteen distinct truth tables, in 00, 01, 10, 11 order', () => {
+ expect(booleanFunctions).toHaveLength(16);
+ expect(new Set(booleanFunctions).size).toBe(16);
+ for (let mask = 0; mask < 16; mask++) {
+ expect(inputRows.map(([a, b]) => Number(evaluateFunction(mask, a, b))).join('')).toBe(
+ functionSignature(mask),
+ );
+ for (let row = 0; row < 4; row++) {
+ const changed = toggleFunctionRow(mask, row);
+ inputRows.forEach(([a, b], index) => {
+ expect(evaluateFunction(changed, a, b)).toBe(
+ index === row ? !evaluateFunction(mask, a, b) : evaluateFunction(mask, a, b),
+ );
+ });
+ }
+ }
+ expect(functionSignature(1)).toBe('0001');
+ expect(functionSignature(14)).toBe('1110');
+ });
+
+ it('builds executable NAND-only HDL equivalent to every function on every input', () => {
+ for (let mask = 0; mask < 16; mask++) {
+ const construction = constructWithNand(mask);
+ const parsed = parseHdl(nandHDL(construction));
+ if (!parsed?.[0]) throw new Error('Generated NAND HDL did not contain a chip.');
+ const chip = new ChipFactory().fromAST(parsed[0]);
+ for (const [a, b] of inputRows) {
+ const expected = evaluateFunction(mask, a, b);
+ expect(evaluateNandConstruction(construction, a, b)).toBe(expected);
+ chip.setInput('a', a);
+ chip.setInput('b', b);
+ chip.run();
+ expect(chip.getOutput('out')).toBe(expected);
+ }
+ }
+ });
+
+ it('derives canonical minterms, including the empty and full functions', () => {
+ expect(canonicalExpression(0)).toBe('0');
+ expect(canonicalExpression(1)).toBe('(a AND b)');
+ expect(canonicalExpression(6)).toBe('(NOT a AND b) OR (a AND NOT b)');
+ expect(canonicalExpression(15)).toBe(
+ '(NOT a AND NOT b) OR (NOT a AND b) OR (a AND NOT b) OR (a AND b)',
+ );
+ });
+
+ it('rejects malformed function and circuit inputs', () => {
+ for (const mask of [-1, 16, NaN, 1.5])
+ expect(() => constructWithNand(mask)).toThrow('four binary outputs');
+ expect(() => functionSignature(16)).toThrow('four binary outputs');
+ expect(() => canonicalExpression(-1)).toThrow('four binary outputs');
+ expect(() => toggleFunctionRow(1, 4)).toThrow('Choose a row');
+ expect(() => toggleFunctionRow(1, -1)).toThrow('Choose a row');
+ expect(() => toggleFunctionRow(1, 0.5)).toThrow('Choose a row');
+ expect(() =>
+ evaluateNandConstruction(
+ { gates: [{ id: 'n', a: 'missing', b: 'a' }], output: 'n' },
+ false,
+ false,
+ ),
+ ).toThrow('Unknown NAND input');
+ expect(() =>
+ evaluateNandConstruction(
+ { gates: [{ id: 'n', a: 'a', b: 'missing' }], output: 'n' },
+ false,
+ false,
+ ),
+ ).toThrow('Unknown NAND input');
+ expect(() => evaluateNandConstruction({ gates: [], output: 'missing' }, false, false)).toThrow(
+ 'Unknown NAND output',
+ );
+ });
+});
+
+describe('Buses and routing lab', () => {
+ it('parses unsigned values without silently truncating invalid input', () => {
+ for (const source of ['65535', '0xffff', '0XFFFF', '0b1111111111111111', ' 65535 '])
+ expect(parseWord(source)).toEqual({ value: 65535, error: '' });
+ expect(parseWord('0')).toEqual({ value: 0, error: '' });
+ expect(parseWord('0001')).toEqual({ value: 1, error: '' });
+ expect(parseWord('255', 8).value).toBe(255);
+ for (const source of [
+ '',
+ ' ',
+ '65536',
+ '-1',
+ '1.1',
+ '1e3',
+ '0x',
+ '0b2',
+ '0x10000',
+ '999999999999999999999999',
+ ])
+ expect(parseWord(source).value).toBeNull();
+ expect(parseWord('256', 8).value).toBeNull();
+ expect(parseWord('2', 1).value).toBeNull();
+ expect(binaryWord(1)).toBe('0000000000000001');
+ expect(binaryWord(128, 8)).toBe('10000000');
+ });
+
+ it('applies each bit independently, including the most significant bit', () => {
+ expect(simulateBus('not16', { in: 0 }).out).toBe(65535);
+ expect(simulateBus('not16', { in: 65535 }).out).toBe(0);
+ expect(simulateBus('and16', { a: 0xaaaa, b: 0x5555 }).out).toBe(0);
+ expect(simulateBus('or16', { a: 0xaaaa, b: 0x5555 }).out).toBe(65535);
+ for (let bit = 0; bit < 16; bit++) {
+ const value = 2 ** bit;
+ expect(simulateBus('not16', { in: value }).out).toBe(65535 - value);
+ expect(simulateBus('and16', { a: value, b: 65535 }).out).toBe(value);
+ expect(simulateBus('or16', { a: value, b: 0 }).out).toBe(value);
+ }
+ });
+
+ it('reduces all 256 possible eight-bit inputs to one OR result', () => {
+ for (let value = 0; value < 256; value++)
+ expect(simulateBus('or8way', { in: value }).out).toBe(Number(value > 0));
+ });
+
+ it('routes every selector value to exactly the corresponding word or output', () => {
+ for (const component of ['mux16', 'mux4way16', 'mux8way16'] as const) {
+ const inputs = Object.fromEntries(
+ busInputNames(component).map((name, index) => [name, 2 ** index]),
+ );
+ for (let selector = 0; selector < busSelectorCount(component); selector++)
+ expect(simulateBus(component, inputs, selector).out).toBe(2 ** selector);
+ }
+ for (const component of ['dmux4way', 'dmux8way'] as const) {
+ const count = busSelectorCount(component);
+ for (let selector = 0; selector < count; selector++) {
+ expect(Object.values(simulateBus(component, { in: 0 }, selector))).toEqual(
+ Array(count).fill(0),
+ );
+ expect(Object.values(simulateBus(component, { in: 1 }, selector))).toEqual(
+ Array.from({ length: count }, (_, index) => Number(index === selector)),
+ );
+ }
+ }
+ });
+
+ it('validates all required input words and the full selector range', () => {
+ expect(busComponents.map((component) => component.id)).toHaveLength(9);
+ expect(busSelectorCount('not16')).toBe(0);
+ for (const value of [-1, 65536, 1.5, NaN])
+ expect(() => simulateBus('not16', { in: value })).toThrow('unsigned 16-bit');
+ expect(() => simulateBus('and16', { a: 1 })).toThrow('Input b');
+ expect(() => simulateBus('or8way', { in: 256 })).toThrow('unsigned 8-bit');
+ expect(() => simulateBus('dmux4way', { in: 2 })).toThrow('unsigned 1-bit');
+ for (const selector of [-1, 8, 0.5, NaN])
+ expect(() =>
+ simulateBus(
+ 'mux8way16',
+ Object.fromEntries(busInputNames('mux8way16').map((name) => [name, 0])),
+ selector,
+ ),
+ ).toThrow('Selector');
+ });
+});
diff --git a/src/lib/tools/logic.ts b/src/lib/tools/logic.ts
new file mode 100644
index 0000000..c8de184
--- /dev/null
+++ b/src/lib/tools/logic.ts
@@ -0,0 +1,220 @@
+export const inputRows = [
+ [false, false],
+ [false, true],
+ [true, false],
+ [true, true],
+] as const;
+
+// The four digits are ordered by inputs 00, 01, 10, 11: AND is 0001.
+export const booleanFunctions = [
+ 'Always 0',
+ 'AND',
+ 'a AND NOT b',
+ 'a',
+ 'NOT a AND b',
+ 'b',
+ 'XOR',
+ 'OR',
+ 'NOR',
+ 'Equivalence (XNOR)',
+ 'NOT b',
+ 'b implies a',
+ 'NOT a',
+ 'a implies b',
+ 'NAND',
+ 'Always 1',
+] as const;
+
+function assertFunction(mask: number) {
+ if (!Number.isInteger(mask) || mask < 0 || mask > 15)
+ throw new Error('A two-input function needs four binary outputs.');
+}
+
+export function evaluateFunction(mask: number, a: boolean, b: boolean): boolean {
+ assertFunction(mask);
+ const row = Number(a) * 2 + Number(b);
+ return Boolean((mask >> (3 - row)) & 1);
+}
+
+export function functionSignature(mask: number): string {
+ assertFunction(mask);
+ return mask.toString(2).padStart(4, '0');
+}
+
+export function toggleFunctionRow(mask: number, row: number): number {
+ assertFunction(mask);
+ if (!Number.isInteger(row) || row < 0 || row > 3) throw new Error('Choose a row from 0 to 3.');
+ return mask ^ (1 << (3 - row));
+}
+
+export function canonicalExpression(mask: number): string {
+ assertFunction(mask);
+ const terms = inputRows.flatMap(([a, b]) =>
+ evaluateFunction(mask, a, b) ? [`(${a ? 'a' : 'NOT a'} AND ${b ? 'b' : 'NOT b'})`] : [],
+ );
+ return terms.length ? terms.join(' OR ') : '0';
+}
+
+export interface NandStep {
+ id: string;
+ a: string;
+ b: string;
+}
+
+export interface NandConstruction {
+ gates: NandStep[];
+ output: string;
+}
+
+/** Build the canonical expression using only two-input NANDs, without constants. */
+export function constructWithNand(mask: number): NandConstruction {
+ assertFunction(mask);
+ const gates: NandStep[] = [];
+ const add = (a: string, b: string) => {
+ const id = `n${gates.length + 1}`;
+ gates.push({ id, a, b });
+ return id;
+ };
+ const negations: Record = {};
+ const invert = (input: string) => (negations[input] ??= add(input, input));
+ if (mask === 0) {
+ const one = add('a', invert('a'));
+ return { gates, output: add(one, one) };
+ }
+ const complements = inputRows.flatMap(([a, b]) =>
+ evaluateFunction(mask, a, b) ? [add(a ? 'a' : invert('a'), b ? 'b' : invert('b'))] : [],
+ );
+ let output = invert(complements[0]);
+ for (const complement of complements.slice(1)) output = add(invert(output), complement);
+ return { gates, output };
+}
+
+export function evaluateNandConstruction(
+ construction: NandConstruction,
+ a: boolean,
+ b: boolean,
+): boolean {
+ const signals: Record = { a, b };
+ for (const gate of construction.gates) {
+ if (!(gate.a in signals) || !(gate.b in signals)) throw new Error('Unknown NAND input.');
+ signals[gate.id] = !(signals[gate.a] && signals[gate.b]);
+ }
+ if (!(construction.output in signals)) throw new Error('Unknown NAND output.');
+ return signals[construction.output];
+}
+
+export function nandHDL(construction: NandConstruction): string {
+ const wire = (name: string) => (name === construction.output ? 'out' : name);
+ const statements = construction.gates.map(
+ (gate) => ` Nand(a=${wire(gate.a)}, b=${wire(gate.b)}, out=${wire(gate.id)});`,
+ );
+ return `CHIP Function2 {\n IN a, b;\n OUT out;\n\n PARTS:\n${statements.join('\n')}\n}`;
+}
+
+export type BusComponent =
+ | 'not16'
+ | 'and16'
+ | 'or16'
+ | 'mux16'
+ | 'or8way'
+ | 'mux4way16'
+ | 'mux8way16'
+ | 'dmux4way'
+ | 'dmux8way';
+
+export const busComponents: { id: BusComponent; name: string; description: string }[] = [
+ { id: 'not16', name: 'Not16', description: 'Invert every bit in a 16-bit word.' },
+ { id: 'and16', name: 'And16', description: 'Keep a bit only when both input bits are 1.' },
+ { id: 'or16', name: 'Or16', description: 'Set a bit when either input bit is 1.' },
+ { id: 'mux16', name: 'Mux16', description: 'Choose one of two complete 16-bit words.' },
+ {
+ id: 'or8way',
+ name: 'Or8Way',
+ description: 'Combine eight bits into one answer: is any input 1?',
+ },
+ {
+ id: 'mux4way16',
+ name: 'Mux4Way16',
+ description: 'Route one of four 16-bit words to the output.',
+ },
+ {
+ id: 'mux8way16',
+ name: 'Mux8Way16',
+ description: 'Route one of eight 16-bit words to the output.',
+ },
+ { id: 'dmux4way', name: 'DMux4Way', description: 'Send one signal to one of four destinations.' },
+ {
+ id: 'dmux8way',
+ name: 'DMux8Way',
+ description: 'Send one signal to one of eight destinations.',
+ },
+];
+
+export function parseWord(source: string, width = 16): { value: number | null; error: string } {
+ const text = source.trim();
+ if (!text) return { value: null, error: 'Enter a value.' };
+ if (!/^(?:\d+|0x[\da-f]+|0b[01]+)$/i.test(text))
+ return { value: null, error: 'Use decimal, 0x hex, or 0b binary.' };
+ const value = Number(text);
+ const max = 2 ** width - 1;
+ if (!Number.isSafeInteger(value) || value > max)
+ return { value: null, error: `Use a value from 0 to ${max.toLocaleString('en-US')}.` };
+ return { value, error: '' };
+}
+
+export function binaryWord(value: number, width = 16): string {
+ return value.toString(2).padStart(width, '0');
+}
+
+export function busInputNames(component: BusComponent): string[] {
+ if (component === 'not16' || component === 'or8way' || component.startsWith('dmux'))
+ return ['in'];
+ const count = component === 'mux8way16' ? 8 : component === 'mux4way16' ? 4 : 2;
+ return Array.from({ length: count }, (_, index) => String.fromCharCode(97 + index));
+}
+
+export function busSelectorCount(component: BusComponent): number {
+ if (component === 'mux16') return 2;
+ if (component === 'mux4way16' || component === 'dmux4way') return 4;
+ if (component === 'mux8way16' || component === 'dmux8way') return 8;
+ return 0;
+}
+
+export function simulateBus(
+ component: BusComponent,
+ inputs: Record,
+ selector = 0,
+): Record {
+ const names = busInputNames(component);
+ const width = component === 'or8way' ? 8 : component.startsWith('dmux') ? 1 : 16;
+ for (const name of names) {
+ const value = inputs[name];
+ if (!Number.isInteger(value) || value < 0 || value >= 2 ** width)
+ throw new Error(`Input ${name} must be an unsigned ${width}-bit value.`);
+ }
+ const choices = busSelectorCount(component);
+ if (choices && (!Number.isInteger(selector) || selector < 0 || selector >= choices))
+ throw new Error(`Selector must be between 0 and ${choices - 1}.`);
+ switch (component) {
+ case 'not16':
+ return { out: ~inputs.in & 0xffff };
+ case 'and16':
+ return { out: inputs.a & inputs.b };
+ case 'or16':
+ return { out: inputs.a | inputs.b };
+ case 'or8way':
+ return { out: Number(inputs.in !== 0) };
+ case 'mux16':
+ case 'mux4way16':
+ case 'mux8way16':
+ return { out: inputs[names[selector]] };
+ case 'dmux4way':
+ case 'dmux8way':
+ return Object.fromEntries(
+ Array.from({ length: choices }, (_, index) => [
+ String.fromCharCode(97 + index),
+ index === selector ? inputs.in : 0,
+ ]),
+ );
+ }
+}
diff --git a/src/routes/+error.svelte b/src/routes/+error.svelte
index c1c24c9..23d5bf6 100644
--- a/src/routes/+error.svelte
+++ b/src/routes/+error.svelte
@@ -1,7 +1,13 @@
-
+{page.status} — Chips and Code
+
+ {page.status}
+
+ {page.status === 404 ? 'That page is not here.' : 'Something interrupted the connection.'}
+
+ {page.error?.message ?? 'Try opening the page again.'}
+ Continue learning or open Tools .
+
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index b707672..369500b 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -3,7 +3,8 @@
import { pwaInfo } from 'virtual:pwa-info';
import '#src/app.css';
- import { theme } from '#src/stores.js';
+ import SiteHeader from '#lib/components/SiteHeader.svelte';
+ import SiteFooter from '#lib/components/SiteFooter.svelte';
onMount(async () => {
// @ts-ignore TODO: Any way to do this without polluting the bundle?
@@ -22,23 +23,14 @@
});
}
});
-
- theme.subscribe((name) => {
- if (typeof document === 'undefined') return;
-
- document.documentElement.setAttribute('data-theme', name);
- if (name === 'dark') {
- document.documentElement.classList.add('dark');
- } else {
- document.documentElement.classList.remove('dark');
- }
- });
{#if pwaInfo} {/if}
-
-
+
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index deeefd1..4733164 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -1,115 +1,36 @@
-
- Chips and Code: Learning what our computers are made of
+ Break down the magic of computers — Chips and Code
+
-
-
-
-
-
-
-
-
-
-
- Find out by embarking on the journey of building your own computer from scratch, from
- chips to code. No prerequisites - start for free from the browser.
-
-
-
-
-
-
+
+ goto('/learn')} onwatch={() => (introOpen = true)} />
-
-
+{#if introOpen} (introOpen = false)} />{/if}
diff --git a/src/routes/about/+page.svelte b/src/routes/about/+page.svelte
index 640ecf8..d20b8f5 100644
--- a/src/routes/about/+page.svelte
+++ b/src/routes/about/+page.svelte
@@ -1,147 +1,94 @@
-
- About Chips and Code
+ About — Chips and Code
+
-
-
-
-
- Chips and Code
-
-
- Report Bug / Request Feature
- Discussions
+
+ ABOUT CHIPS AND CODE
+ Understand it by building it.
+
+ Computers become less mysterious when you can change a signal, connect a gate, and see what
+ happens.
+
+
+ From chips to code
+
+ Chips and Code brings hands-on computer construction to the browser. Start with no
+ prerequisites, learn one idea at a time, and use visual circuits or code to explore the same
+ machine.
-
-
-
-
⚒️
-
-
Motivation
-
- This project was started as a reimagined Nand2Tetris
- (not affiliated or endorsed by them). Nand2Tetris is a very popular course that introduces
- a wide range of computer principles by building a virtual computer from the group up. However,
- it is accompanied by an older Java desktop application inaccessible from a large range of
- devices (like tablets, Chromebooks, smartphones... -
- one-fourth of people from developing countries rely on smartphones!). Chips and Code aims to reimplement
- the same functionality using the modern web with improved user experience.
-
-
-
-
-
-
-
🎓
-
-
-
Background
-
- Most of the functionality was built while I was working on my master's thesis at the
- University of Galway . As a
- part of that, I've run a comparative study exploring usability improvements of moving the
- existing learning tool to the web. If you are interested in learning more, visit the links
- below.
-
-
-
Research Behind
-
Code Repository
-
-
-
-
-
-
Credits 🙏
-
-
- None of this would be possible without the open-source community and the help of many
- wonderful people who participated in the research.
-
-
-
-
-
Open source
-
-
- This project relies on a large selection of open-source work. Notably: {oss.join(
- ', ',
- )}. See all
- dependencies .
-
-
-
-
-
Study participants
-
-
- Thank you {studyParticipants.join(', ')}
- for participating in the comparative study and providing me with the feedback. It was a
- blast working with you!
-
-
-
-
-
-
+
+ The learning path runs from signals and gates through arithmetic, memory, machine language,
+ computer architecture, and an assembler. Build and test each layer in the browser. Tools also
+ let you explore virtual machines, compile Jack, and draw graphics.
+
+
+ Start learning or open a tool .
+
+
+
+
+ Your work, on this device
+
+ Learning progress and circuit drafts are kept in your browser. Clearing site data removes
+ those local copies. You can download a simulator experiment to keep its HDL, tests, and
+ expected output.
+
+
+ Simulator experiments can also be saved and shared through a link. Editing a saved experiment
+ uses the anonymous session that created it; another browser can open it and save its own copy.
+ Accounts and cross-device progress sync are not available yet.
+
+
+
+ Sources and credits
+
+ The virtual machine and Jack compiler build on the open-source
+ Nand2Tetris Web IDE by David Souther and its
+ contributors. The adapted runtime retains its license and attribution.
+
+
+ The learning material is adapted from Nand2Tetris by
+ Noam Nisan and Shimon Schocken, under
+ CC BY-NC-SA 3.0 . Chips and
+ Code is an independent project, not affiliated with or endorsed by Nand2Tetris.
+
+
+ The software is MIT licensed . It builds on open-source work including Svelte, Monaco Editor, Nearley, Tailwind, and
+ daisyUI. The repository records the
+ full dependency list .
+
+
+ Thank you to the research participants
+
+ Jan, Matej, Patrik, Pavol, Stefan, Michal, Masa, Michal, Sasa, Jozef, Peter, Matus, Brano,
+ Robert, Lubo, Max, Viktoria, Kyryl, Matus, Lukas, Martina, Karolina, Lubos, Martin, Erik,
+ and Filip.
+
+
+
-
-
diff --git a/src/routes/accessibility-statement/+page.svelte b/src/routes/accessibility-statement/+page.svelte
index 0890040..a7aca67 100644
--- a/src/routes/accessibility-statement/+page.svelte
+++ b/src/routes/accessibility-statement/+page.svelte
@@ -1,99 +1,49 @@
-
-
-
- Accessibility Statement - Chips and Code
-
-
-
-
-
-
- Accessibility
-
-
-
-
Summary
-
- We want as many people as possible to be able to use this website.
- AbilityNet has advice on making
- your device easier to use if you have a disability. Chips and Code strives to meet Web Content
- Accessibility Guidelines (WCAG) 2.1 at Level AA. That being said, implementing for accessibility
- can be hard. If you experience any issues or have any suggestions, please let us know at the
- "Report Bug/Request Feature" link.
-
-
-
Report Bug / Request Feature
-
-
-
-
-
-
Measures to support accessibility
-
You should be able to:
-
-
- change colors, contrast levels and fonts
- zoom in up to 300% without the text spilling off the screen
- navigate most of the website using just a keyboard
- navigate most of the website using speech recognition software
-
- listen to most of the website using a widely used screen reader and the last two
- versions of major browsers.
-
-
-
- We try to make sure the the website is as simple as possible. We try to think about
- accessibility any time we add any new content or feature. We run automated checks on all
- important pages to make sure there are no trivial accessibility issues. We perform
- self-evaluation to assess our compliance.
-
-
-
-
-
-
-
-
Conformance status
-
-
- The Web Content Accessibility Guidelines (WCAG) standard defines requirements to improve accessibility for people with disabilities. It
- defines three levels of conformance: Level A, Level AA, and Level AAA. "Fully conforms"
- means that the content meets all of the WCAG requirements at the specified Level without
- exceptions.
-
-
Chips and Code learning code and tools aim to fully conform to WCAG 2.1 Level AA.
-
-
-
-
Technical specifications
-
We rely on the following technologies for conformance with WCAG 2.1:
-
-
- HTML
- WAI-ARIA
- CSS
- SVG
-
- The following technologies are used to improve accessibility and the user experience for everyone:
-
-
-
-
-
-
-
+Accessibility — Chips and Code
+
+ ACCESSIBILITY
+ A machine{' '} you can explore.
+ Learning should depend on your curiosity, not how you use a screen.
+
+ Navigation and interaction
+
+ The main navigation is always Learn, Tools, and About. A skip link moves past it. Buttons,
+ switches, circuit connections, and tool inputs have keyboard controls and visible focus.
+ Connection menus offer an alternative to selecting pins on a circuit diagram.
+
+
+ Signals show values and labels as well as color. Text uses explicit foreground and background
+ colors. Your operating system’s reduced-motion preference replaces the scrolling computer
+ animation with a static sequence.
+
+
+
+ Reading, code, and media
+
+ Short explanations link to full reading in the same interface. Layouts reflow on narrow
+ screens; code and wide circuit diagrams can scroll inside their own panels. The introduction
+ film has captions and a text transcript.
+
+
+ The Hardware simulator uses Monaco Editor. Its editor help is available from the Help
+ disclosure. Standard text fields in the guided workspace provide another way to write HDL.
+
+
+
+ Checks and feedback
+
+ We use automated accessibility checks alongside keyboard, responsive-layout, and contrast
+ reviews. These checks do not cover every assistive technology or replace feedback from people
+ using the site.
+
+
+ If a control, explanation, or diagram gets in your way, report an accessibility issue . Include the page, what you were trying to do, and your browser or assistive technology if
+ you can.
+
+
+ AbilityNet’s My Computer My Way provides guidance
+ on adapting your device to your needs.
+
+
-
-
diff --git a/src/routes/experiment/+page.svelte b/src/routes/experiment/+page.svelte
new file mode 100644
index 0000000..b31dda8
--- /dev/null
+++ b/src/routes/experiment/+page.svelte
@@ -0,0 +1 @@
+
diff --git a/src/routes/experiment/+page.ts b/src/routes/experiment/+page.ts
new file mode 100644
index 0000000..f932242
--- /dev/null
+++ b/src/routes/experiment/+page.ts
@@ -0,0 +1,2 @@
+import { redirect } from '@sveltejs/kit';
+export const load = () => redirect(308, '/tools');
diff --git a/src/routes/experiment/hardware-ide/+page.svelte b/src/routes/experiment/hardware-ide/+page.svelte
index 839950c..b31dda8 100644
--- a/src/routes/experiment/hardware-ide/+page.svelte
+++ b/src/routes/experiment/hardware-ide/+page.svelte
@@ -1,16 +1 @@
-
-
-
- New Experiment - Hardware IDE - Chips and Code
-
-
-
-
-
- Hardware IDE - New Experiment
-
-
-
+
diff --git a/src/routes/experiment/hardware-ide/+page.ts b/src/routes/experiment/hardware-ide/+page.ts
new file mode 100644
index 0000000..d63114f
--- /dev/null
+++ b/src/routes/experiment/hardware-ide/+page.ts
@@ -0,0 +1,3 @@
+import { redirect } from '@sveltejs/kit';
+import type { PageLoad } from './$types';
+export const load: PageLoad = () => redirect(308, '/tools/hardware-simulator');
diff --git a/src/routes/experiment/hardware-ide/[id]/+page.svelte b/src/routes/experiment/hardware-ide/[id]/+page.svelte
index dce51ed..b31dda8 100644
--- a/src/routes/experiment/hardware-ide/[id]/+page.svelte
+++ b/src/routes/experiment/hardware-ide/[id]/+page.svelte
@@ -1,58 +1 @@
-
-
-
- {#await experiment}
- New Experiment - Hardware IDE - Chips and Code
- {:then experiment}
- {experiment.name} - Hardware IDE - Chips and Code
- {:catch}
- Invalid Experiment - Hardware IDE - Chips and Code
- {/await}
-
-
-
-
-
- {#await experiment}
- New Experiment - Hardware IDE
- {:then experiment}
- {experiment.name} - Hardware IDE
- {:catch}
- Invalid Experiment - Hardware IDE
- {/await}
-
- {#await experiment}
-
- {:then experiment}
-
- {:catch error}
-
- {/await}
-
+
diff --git a/src/routes/experiment/hardware-ide/[id]/+page.ts b/src/routes/experiment/hardware-ide/[id]/+page.ts
index 5e41128..d1583b2 100644
--- a/src/routes/experiment/hardware-ide/[id]/+page.ts
+++ b/src/routes/experiment/hardware-ide/[id]/+page.ts
@@ -1,9 +1,5 @@
+import { redirect } from '@sveltejs/kit';
import type { PageLoad } from './$types';
-
-// We just forward params - any easier way to do it?
-export const load = (async ({ params }) => ({
- id: params.id,
-})) satisfies PageLoad;
-
export const prerender = false;
-export const ssr = false;
+export const load: PageLoad = ({ params, url }) =>
+ redirect(308, `/tools/hardware-simulator/${encodeURIComponent(params.id)}${url.search}`);
diff --git a/src/routes/learn/+page.svelte b/src/routes/learn/+page.svelte
new file mode 100644
index 0000000..a80dcc0
--- /dev/null
+++ b/src/routes/learn/+page.svelte
@@ -0,0 +1,13 @@
+
+
+
+ Learn — Chips and Code
+
+
+
+
diff --git a/src/routes/learn/hardware/[...path]/+page.svelte b/src/routes/learn/hardware/[...path]/+page.svelte
index 7912037..b31dda8 100644
--- a/src/routes/learn/hardware/[...path]/+page.svelte
+++ b/src/routes/learn/hardware/[...path]/+page.svelte
@@ -1,118 +1 @@
-
-
-
- {data.meta.title} - Hardware - Chips and Code
-
-
-
-
-
-
- Hardware
-
-
- {#each menu as item, i}
- {#if !item.disabled}
-
- {item.name}
-
- {:else}
-
- Coming Soon: {item.name}
-
- {/if}
- {/each}
-
-
- Last updated: {updatedHr}
-
- Adapted by
Jan Duras from
-
Nand to Tetris
- by Shimon Schocken and Noam Nisan.
-
CC BY-NC-SA 3.0
-
-
-
-
- {data.meta.title}
-
-
-
-
-
-
-
-
+
diff --git a/src/routes/learn/hardware/[...path]/+page.ts b/src/routes/learn/hardware/[...path]/+page.ts
index f43dfc9..ca8b4bf 100644
--- a/src/routes/learn/hardware/[...path]/+page.ts
+++ b/src/routes/learn/hardware/[...path]/+page.ts
@@ -1,41 +1,5 @@
-import { error } from '@sveltejs/kit';
+import { redirect } from '@sveltejs/kit';
import type { PageLoad } from './$types';
-import type { Content } from '#src/lib/content/types.js';
-import type { Tag } from '@markdoc/markdoc';
-
-const FIRST_CHAPTER = 'boolean-logic';
-const FIRST_SECTION = 'intro';
-
-export const load = (async ({ params }) => {
- const modules = import.meta.glob('../**/*.md');
- let [pathChapter, pathSection] = params.path.split('/');
- pathChapter = pathChapter || FIRST_CHAPTER;
- pathSection = pathSection || FIRST_SECTION;
-
- const chapters = Object.entries(modules).reduce(
- (acc, [path, moduleImport]) => {
- const [, chapter, sectionFile] = path.split('/');
- const section = sectionFile.replace(/\.md$/, '');
-
- if (!(chapter in acc)) acc[chapter] = {};
-
- acc[chapter][section] = moduleImport;
-
- return acc;
- },
- {} as { [chapter: string]: { [section: string]: () => Promise } },
- );
-
- if (!(pathChapter in chapters) || !(pathSection in chapters[pathChapter])) {
- error(404, 'Not found');
- }
-
- const markdownModule = (await chapters[pathChapter][pathSection]()) as { default: Content };
-
- // TODO: We can load all modules upfront and then we can provide the list of pages here as well
-
- return {
- meta: markdownModule.default.meta,
- content: (markdownModule.default.content as Tag).children,
- };
-}) satisfies PageLoad;
+export const prerender = 'auto';
+export const load: PageLoad = ({ params }) =>
+ redirect(308, `/learn/reference/${params.path || 'boolean-logic'}`);
diff --git a/src/routes/learn/hardware/[...path]/Elements.svelte b/src/routes/learn/hardware/[...path]/Elements.svelte
deleted file mode 100644
index 5a88d4e..0000000
--- a/src/routes/learn/hardware/[...path]/Elements.svelte
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-{#each children as node}{#if typeof node !== 'object'}{node}{/if}{#if isTag(node)}{#if node.name in components}{#if node.children?.length} {:else} {/if}{:else if node.children?.length} {:else} {/if}{/if}{/each}
diff --git a/src/routes/learn/hardware/assembler/intro.md b/src/routes/learn/hardware/assembler/intro.md
new file mode 100644
index 0000000..a4ef8ba
--- /dev/null
+++ b/src/routes/learn/hardware/assembler/intro.md
@@ -0,0 +1,115 @@
+---
+title: Turn symbols into instructions
+updated: 2026-11-03
+---
+
+An assembler turns a program's symbolic spelling into the exact 16-bit instructions understood by the computer. It does not execute the program. This is the first translator in the software stack: after building the machine, you build a tool that writes its machine language.
+
+[Build the assembler layer](/learn/path/assembler) or inspect translation and execution side by side in the [computer and assembler tool](/tools/computer).
+
+# The translation contract
+
+The input is a text file such as `Program.asm`. The output, `Program.hack`, is also text: each line contains exactly sixteen characters, each either 0 or 1. Every output line represents one instruction. The first line loads at ROM address 0, the second at address 1, and so on.
+
+Each A-instruction or C-instruction emits one machine word. Comments, blank lines, and label declarations emit none. The binary output must match the language specification and the output of the official assembler for the same valid source.
+
+Assembly is not a high-level expression language. The assembler looks up defined instruction fields; it does not evaluate arbitrary arithmetic expressions, invent new CPU operations, or optimize a program. `@table+3` is not part of the specified language. Address arithmetic belongs in a sequence of machine instructions.
+
+# Parse without losing the source location
+
+Remove the `//` comment portion of each line and ignore insignificant whitespace. Skip empty lines. Keep the original line number alongside each remaining command so an error can point to the code the learner wrote, even though ROM addresses count differently.
+
+| Form | Example | Meaning |
+| --- | --- | --- |
+| A-instruction | `@27` or `@counter` | A literal or symbolic address |
+| C-instruction | `D=M+1;JNE` | Computation with optional destination and jump |
+| Label declaration | `(AGAIN)` | Name the next instruction's ROM address |
+
+For a C-instruction, split the optional `dest=` prefix and optional `;jump` suffix from the required computation. Treat omission as an empty field, not the literal word `null`. The syntax does not contain a trailing semicolon when there is no jump.
+
+Numeric A-instruction literals are nonnegative decimal integers in 0–32767. Assembly mnemonics are uppercase. User symbols are case-sensitive and may contain letters, digits, `_`, `.`, `$`, and `:`, but must not start with a digit. Thus `loop.end` is a possible symbol and `2loop` is not.
+
+# Encode instructions without symbols first
+
+Start with a translator whose input contains only numeric A-instructions and C-instructions. For an A-instruction, convert the value to binary and pad to 15 bits, then prepend 0. Padding is required: the value 3 must not produce a two-character output line.
+
+For a C-instruction, look up the seven computation bits, three destination bits, and three jump bits. Join them after the `111` prefix. The complete [instruction tables](/learn/reference/machine-language#computation-codes) define those mappings.
+
+For example, `D=A` has computation `0110000`, destination `010`, and omitted jump `000`. Its encoded word is:
+
+```text
+111 + 0110000 + 010 + 000 = 1110110000010000
+```
+
+Check fields independently before joining them. Swapping destination and jump bits can still produce sixteen valid binary digits, but the machine will execute a different operation. Reject an unknown mnemonic rather than silently replacing it with zero.
+
+# Three kinds of symbols
+
+All symbolic addresses eventually become integers, but they enter the symbol table in different ways.
+
+| Kind | Examples | How the address is obtained |
+| --- | --- | --- |
+| Predefined | R0–R15, SP, SCREEN, KBD | Fixed by the platform |
+| Label | `(AGAIN)` | Count the real instructions before the declaration |
+| Variable | `@counter` without a matching declaration | Allocate the next available RAM slot, starting at 16 |
+
+Initialize predefined entries before reading the program: R0–R15 map to 0–15; SP=0, LCL=1, ARG=2, THIS=3, THAT=4; SCREEN=16384; KBD=24576. Some names intentionally share an address. The symbol table stores addresses, not current RAM values.
+
+A variable symbol consumes a data-memory slot. A label consumes no instruction-memory slot. Neither operation changes the source program's instructions into RAM initialization commands. When you allocate `counter` to address 16, the generated code still has to put a value into RAM[16] if the program needs one.
+
+# Two passes, one symbol table
+
+Forward references are the reason to separate label discovery from code generation. A program can say `@FINISH` before the declaration `(FINISH)`. If the translator immediately treats every unknown name as a variable, it assigns the wrong kind of address.
+
+**Pass one discovers labels.** Start a ROM counter at zero. Increment it once for each A- or C-instruction. For a label declaration, associate the label with the counter's current value and do not increment. Blank lines and comments do not increment it either. By the end of this pass, every declared label has an address.
+
+**Pass two emits code.** Start the next-variable address at 16. Skip declarations. For each symbolic A-instruction, use the existing table entry if one exists. Otherwise, create one variable entry at the next available address and advance that allocation counter. Translate the resulting numeric address as an ordinary A-instruction. Encode C-instructions with the same field tables as before.
+
+Repeated references to a variable must reuse its first address. Allocate previously unseen variables in order of first appearance during pass two, not alphabetically. Labels and variables use one symbol namespace, even though their addresses usually refer to different memory spaces. Reset the assembler's table and counters for each new source file.
+
+# Walk a small example
+
+This fragment is an address-resolution exercise, not a complete program:
+
+```text
+@later
+0;JMP
+@sample
+M=1
+(later)
+@sample
+D=M
+```
+
+Pass one counts four instructions before `(later)`, so `later` maps to ROM address 4. Pass two encounters `@later` with that address already known. It later assigns `sample` to RAM address 16. Both occurrences of `@sample` become the same A-instruction. The declaration emits no word, leaving six output instructions.
+
+Translation does not execute the jump to decide which lines matter. Even unreachable instructions are translated and count toward later ROM addresses. Control flow is the computer's responsibility after assembly.
+
+# Keep the implementation in small parts
+
+A useful design separates four responsibilities:
+
+1. A parser classifies commands and returns their fields with source locations.
+2. A code mapper converts valid computation, destination, and jump names to bits.
+3. A symbol table records and retrieves numeric addresses.
+4. A driver performs the passes and writes one machine word per emitted instruction.
+
+The official project permits any implementation language. Those responsibilities can be classes or ordinary functions; the behavior matters more than the names. The guided exercises here establish encoding, label counting, variable allocation, and the complete translation procedure. The computer tool provides a working reference for comparing results.
+
+Useful diagnostics identify malformed parentheses, empty fields, unsupported computations, repeated/conflicting label declarations, illegal symbol names, and out-of-range addresses. A 15-bit address cannot hold 32768. A program cannot fit more than 32768 instructions into ROM32K. Avoid allocating ordinary variables into the memory-mapped screen or keyboard area.
+
+# Project 6: verify the assembler
+
+First test symbol-free source. The official Add program and the `MaxL`, `RectL`, and `PongL` variants let you check instruction parsing and encoding before symbol handling. Then translate their symbolic counterparts and compare the complete binary output against the supplied assembler.
+
+Add exercises basic computation and storage. Max adds branches. Rect exercises screen addressing and loops. Pong is a much larger assembly program produced from a higher-level program, making it useful for checking many symbols and long instruction sequences. Implementing Pong itself is not the assembler assignment.
+
+Compare every output word, not only whether a program appears to run. A wrong instruction can be on a path your manual run never takes. When two outputs differ, map the first differing ROM address back to its original source line, then inspect its fields and symbol resolution.
+
+Also test tiny cases designed to isolate mistakes: consecutive labels, a forward label, a variable referenced more than once, two names with different capitalization, comments after commands, and the boundary literals 0 and 32767. A clean translation of valid code and a useful rejection of invalid code are separate qualities worth checking.
+
+# Sources and the next boundary
+
+This chapter adapts [Nand2Tetris Project 6](https://www.nand2tetris.org/project06) and the public [Assembler chapter](https://www.nand2tetris.org/_files/ugd/44046b_b73759b866b249a0b3a715bf5a18f668.pdf), by Noam Nisan and Shimon Schocken. [Official project files](https://github.com/nand2tetris/projects/tree/main/06) supply the comparison programs. Adapted explanations retain CC BY-NC-SA 3.0; software fixtures retain their own license.
+
+You have connected symbolic instructions to a machine built from logic and state. The next step is a virtual machine, followed by a higher-level language, compiler, and operating-system services. Those are [the next software layers](/learn/reference/meta/what-next), beyond this Project 6 path.
diff --git a/src/routes/learn/hardware/boolean-arithmetic/intro.md b/src/routes/learn/hardware/boolean-arithmetic/intro.md
new file mode 100644
index 0000000..4899338
--- /dev/null
+++ b/src/routes/learn/hardware/boolean-arithmetic/intro.md
@@ -0,0 +1,110 @@
+---
+title: From bits to arithmetic
+updated: 2026-11-03
+---
+
+A bus is a group of signals. Give each bit a place value and that same bus becomes a number. This layer turns the gates you already know into adders, then combines arithmetic and logic in one controllable circuit: the ALU.
+
+[Build the arithmetic layer](/learn/path/arithmetic) or open the [chip builder](/tools/chip-builder).
+
+# Numbers are an interpretation
+
+In an unsigned binary number, bit 0 is worth 1, bit 1 is worth 2, bit 2 is worth 4, and each higher bit doubles the previous weight. The four-bit pattern `1010` represents 8 + 2 = 10. Leading zeroes change the width, not the value.
+
+An n-bit word has 2ⁿ possible patterns. A 16-bit word can therefore represent unsigned values from 0 to 65535. Hexadecimal is a compact spelling of the same bits: each hex digit covers four bits, so `0x00FF` is `0000000011111111`, or 255. A wire does not know which notation the interface uses.
+
+**Width is part of the contract.** If a 16-bit addition produces a seventeenth bit, that bit does not fit in the output. Hack retains the low 16 bits: 65535 + 1 becomes 0. This is arithmetic modulo 65536, not an error in the adder.
+
+# Signed numbers and two's complement
+
+The same 65536 patterns can represent values from −32768 to 32767. In this **two's-complement** interpretation, bit 15 has weight −32768 instead of +32768. The other bits keep their positive weights.
+
+| Bits | Unsigned interpretation | Signed interpretation |
+| --- | --- | --- |
+| `0000000000000000` | 0 | 0 |
+| `0111111111111111` | 32767 | 32767 |
+| `1000000000000000` | 32768 | −32768 |
+| `1111111111111111` | 65535 | −1 |
+
+To negate a word, invert every bit and add one, retaining the original width. That makes subtraction possible with the same adder: x − y = x + (NOT y + 1). There is only one representation of zero. The most negative value is a useful edge case: negating −32768 at 16 bits gives the same pattern because +32768 is outside the signed range.
+
+Addition uses the same bit operations for signed and unsigned words. Interpretation changes whether a result is mathematically in range. For example, 32767 + 1 produces the pattern for −32768. The Hack ALU has no overflow flag. Its negative flag describes the resulting bits; it does not promise that an unbounded signed calculation would have the same sign.
+
+# Add one bit at a time
+
+A **HalfAdder** accepts two bits and produces a two-bit total split into `carry` and `sum`. Read the result as 2 × carry + sum.
+
+| a | b | carry | sum |
+| --- | --- | --- | --- |
+| 0 | 0 | 0 | 0 |
+| 0 | 1 | 0 | 1 |
+| 1 | 0 | 0 | 1 |
+| 1 | 1 | 1 | 0 |
+
+A **FullAdder** adds three bits: `a`, `b`, and an incoming carry `c`. Its total ranges from 0 to 3. The sum output is the low bit; carry is the high bit. All eight input cases matter, including 1 + 1 + 1 = binary 11.
+
+To add whole words, start at bit 0. Pass each position's carry to the next position's incoming carry. The lowest position starts without an incoming carry. The final carry is discarded for `Add16`; it is not an extra output pin. This arrangement is called a ripple-carry adder because a change can propagate through successive positions in physical hardware. The logical simulator checks values, not the actual propagation delay.
+
+# Arithmetic chip contracts
+
+| Chip | Inputs | Outputs | Required behavior |
+| --- | --- | --- | --- |
+| HalfAdder | `a`, `b` | `sum`, `carry` | Encode the sum of two bits |
+| FullAdder | `a`, `b`, `c` | `sum`, `carry` | Encode the sum of three bits |
+| Add16 | `a[16]`, `b[16]` | `out[16]` | Low 16 bits of a + b |
+| Inc16 | `in[16]` | `out[16]` | Low 16 bits of in + 1 |
+| ALU | `x[16]`, `y[16]`, six control bits | `out[16]`, `zr`, `ng` | The controlled operation below |
+
+An incrementer is useful even after an adder exists: the program counter will often need the next instruction address. A named chip gives that recurring operation a clear interface.
+
+# The ALU is a controlled pipeline
+
+The Hack arithmetic logic unit has two word inputs and six one-bit controls. Apply the controls in this order:
+
+1. `zx`: replace x with zero when set.
+2. `nx`: invert the resulting x word when set.
+3. `zy`: replace y with zero when set.
+4. `ny`: invert the resulting y word when set.
+5. `f`: choose addition when 1, or bitwise AND when 0.
+6. `no`: invert the resulting output word when set.
+
+Zeroing happens before inversion. Consequently, zeroing and then inverting an input creates all ones, the signed value −1. The output is always a 16-bit word. After all six controls have taken effect, `zr` is 1 exactly when every output bit is zero; `ng` is the final output's bit 15.
+
+There are 64 control patterns. The following 18 useful functions are the documented repertoire; the pipeline also defines the behavior of the other patterns.
+
+| Result | zx | nx | zy | ny | f | no |
+| --- | --- | --- | --- | --- | --- | --- |
+| 0 | 1 | 0 | 1 | 0 | 1 | 0 |
+| 1 | 1 | 1 | 1 | 1 | 1 | 1 |
+| −1 | 1 | 1 | 1 | 0 | 1 | 0 |
+| x | 0 | 0 | 1 | 1 | 0 | 0 |
+| y | 1 | 1 | 0 | 0 | 0 | 0 |
+| NOT x | 0 | 0 | 1 | 1 | 0 | 1 |
+| NOT y | 1 | 1 | 0 | 0 | 0 | 1 |
+| −x | 0 | 0 | 1 | 1 | 1 | 1 |
+| −y | 1 | 1 | 0 | 0 | 1 | 1 |
+| x + 1 | 0 | 1 | 1 | 1 | 1 | 1 |
+| y + 1 | 1 | 1 | 0 | 1 | 1 | 1 |
+| x − 1 | 0 | 0 | 1 | 1 | 1 | 0 |
+| y − 1 | 1 | 1 | 0 | 0 | 1 | 0 |
+| x + y | 0 | 0 | 0 | 0 | 1 | 0 |
+| x − y | 0 | 1 | 0 | 0 | 1 | 1 |
+| y − x | 0 | 0 | 0 | 1 | 1 | 1 |
+| x AND y | 0 | 0 | 0 | 0 | 0 | 0 |
+| x OR y | 0 | 1 | 0 | 1 | 0 | 1 |
+
+For x = 7 and y = 9, the addition setting produces 16, with both status flags 0. For x = 9 and y = 9, subtraction x − y produces 0 and sets `zr`. Change only one control at a time and follow the intermediate transformations before memorizing any control word.
+
+# Build and verify
+
+Build HalfAdder, FullAdder, Add16, and Inc16 before the ALU. Reuse tested interfaces. For the ALU, first establish the main 16-bit output, then derive the two status outputs from that final word. This keeps data-path errors separate from flag errors.
+
+Small adders allow exhaustive truth-table testing. Larger chips need carefully chosen cases: zero, all ones, a carry crossing several bit positions, the highest bit, opposite signed values, and wraparound. Check both operands independently to catch a pin accidentally wired twice. For the ALU, exercise controls across multiple input pairs; one pair of equal numbers can hide swapped inputs or a wrong subtraction direction.
+
+The official project includes separate ALU tests with and without status outputs. Passing representative tests is evidence of correctness, not exhaustive proof over every possible pair of 16-bit inputs. Investigate the first mismatching case and the earliest stage where its value diverges.
+
+# Sources and next layer
+
+This chapter is an original adaptation of [Nand2Tetris Project 2](https://www.nand2tetris.org/project02) and the public [Boolean Arithmetic chapter](https://www.nand2tetris.org/_files/ugd/44046b_89c60703ebfc4bf39acef13bdc050f5d.pdf), by Noam Nisan and Shimon Schocken. Use the [official project files](https://github.com/nand2tetris/projects/tree/main/02) for the supplied contracts and test cases. Adapted explanatory content retains CC BY-NC-SA 3.0; imported software fixtures retain their own license.
+
+Arithmetic still forgets its result when inputs change. [Add memory](/learn/reference/memory) to let a value survive.
diff --git a/src/routes/learn/hardware/boolean-logic/background.md b/src/routes/learn/hardware/boolean-logic/background.md
index 3af8489..b7417df 100644
--- a/src/routes/learn/hardware/boolean-logic/background.md
+++ b/src/routes/learn/hardware/boolean-logic/background.md
@@ -1,143 +1,226 @@
---
-title: Background
-updated: 2023-06-26
+title: Logic, composition, and HDL
+updated: 2026-11-03
---
-This chapter focuses on the construction of a family of simple chips called _Boolean gates_. Since Boolean gates are physical implementations of _Boolean functions_, we start with a brief treatment of Boolean algebra. We then show how Boolean gates implementing simple Boolean functions can be interconnected to deliver the functionality of more complex chips. We conclude the background section with a description of how hardware design is actually done in practice, using software simulation tools.
+A truth table, a Boolean expression, a gate diagram, and an HDL definition can describe the same behavior. This explanation connects those views, from one signal to a circuit you can test.
-# Boolean Algebra
+# Signals and Boolean operations
-Boolean algebra deals with Boolean (also called binary) values that are typically labeled true/false, 1/0, yes/no, on/off, and so forth. We will use 1 and 0. A Boolean function is a function that operates on binary inputs and returns binary outputs. Since computer hardware is based on the representation and manipulation of binary values, Boolean functions play a central role in the specification, construction, and optimization of hardware architectures. Hence, the ability to formulate and analyze Boolean functions is the first step toward constructing computer architectures.
+A **Boolean value** has two possible states. We write them as 0 and 1; other contexts use false and true. A Boolean function accepts these values and produces one or more Boolean results.
-## Truth Table Representation
+Start with three operations:
-The simplest way to specify a Boolean function is to enumerate all the possible values of the function's input variables, along with the function's output for each set of inputs. This is called the _truth table_ representation of the function, illustrated in Figure 1.1.
+| Operation | Rule |
+| --------- | ------------------------------------------ |
+| NOT a | 1 when a is 0; 0 when a is 1 |
+| a AND b | 1 only when both inputs are 1 |
+| a OR b | 1 when either input, or both inputs, are 1 |
-| x | y | z | $f(x, y, z)$ |
-| :-: | :-: | :-: | :----------: |
-| 0 | 0 | 0 | 0 |
-| 0 | 0 | 1 | 0 |
-| 0 | 1 | 0 | 1 |
-| 0 | 1 | 1 | 0 |
-| 1 | 0 | 0 | 1 |
-| 1 | 0 | 1 | 0 |
-| 1 | 1 | 0 | 1 |
-| 1 | 1 | 1 | 0 |
+OR is inclusive. **XOR**, or exclusive OR, is 1 when the inputs differ. **NAND** means NOT AND: compute AND and invert the result. **NOR** similarly inverts OR.
-_**Figure 1.1** Truth table representation of a Boolean function (example)._
+In algebra, AND is often written as multiplication, OR as a plus sign, and NOT as a bar over a variable. These symbols describe Boolean operations, not ordinary arithmetic: in Boolean algebra, 1 OR 1 is 1.
-The first three columns of Figure 1.1 enumerate all the possible binary values of the function's variables. For each one of the $2^n$ possible tuples $v_1 ... v_n$ (here $n = 3$), the last column gives the value of $f(v_1 ... v_n)$.
+# Truth tables
-## Boolean Expressions
+A truth table records the output for every input combination. With n independent binary inputs there are **2ⁿ rows**. Two inputs give four rows; three give eight.
-In addition to the truth table specification, a Boolean function can also be specified using Boolean operations over its input variables. The basic Boolean operators that are typically used are:
+Consider this rule: “a or b is on, and c is off.”
-- `And` (`x And y` is 1 exactly when both $x$ and $y$ are 1),
-- `Or` (`x Or y` is 1 exactly when either $x$ or $y$ or both are 1),
-- and `Not` (`Not x` is 1 exactly when $x$ is 0).
+```text
+f(a, b, c) = (a OR b) AND NOT c
+```
-We will use a common arithmetic-like notation for these operations: $x \cdot y$ (or $xy$) means `x And y`, $x + y$ means `x Or y`, and $\bar x$ means `Not x`.
+| a | b | c | f |
+| --- | --- | --- | --- |
+| 0 | 0 | 0 | 0 |
+| 0 | 0 | 1 | 0 |
+| 0 | 1 | 0 | 1 |
+| 0 | 1 | 1 | 0 |
+| 1 | 0 | 0 | 1 |
+| 1 | 0 | 1 | 0 |
+| 1 | 1 | 0 | 1 |
+| 1 | 1 | 1 | 0 |
-To illustrate, the function defined in Figure 1.1 is equivalently given by the Boolean expression $f(x, y, z) = (x + y) \cdot \bar z$. For example, let us evaluate this expression on the inputs $x = 0, y = 1, z = 0$ (third row in the table).
-Since $y$ is 1, it follows that $x + y = 1$ and thus $1 \cdot \bar 0 = 1 \cdot 1 = 1$. The complete verification of the equivalence between the expression and the truth table is achieved by evaluating the expression on each of the eight possible input combinations, verifying that it yields the same value listed in the table’s right column.
+For a=0, b=1, c=0, the OR gives 1 and NOT c gives 1. AND combines those into 1. Evaluating all eight rows establishes that the expression and table agree for every possible input in this model.
-## Canonical Representation
+# Canonical representation
-As it turns out, every Boolean function can be expressed using at least one Boolean expression called the _canonical representation_. Starting with the function’s truth table, we focus on all the rows in which the function has value 1. For each such row, we construct a term created by `And`-ing together _literals_ (variables or their negations) that fix the values of all the row’s inputs. For example, let us focus on the third row in Figure 1.1, where the function’s value is 1. Since the variable values in this row are $x = 0$, $y = 1$, $z = 0$, we construct the term $\bar x y \bar z$. Following the same procedure, we construct the terms $x \bar y \bar z$ and $xy \bar z$ for rows 5 and 7. Now, if we `Or`-together all these terms (for all the rows where the function has value 1), we get a Boolean expression that is equivalent to the given truth table. Thus the canonical representation of the Boolean function shown in Figure 1.1 is $f(x, y, z) = \bar x y \bar z + x \bar y \bar z + xy \bar z$. This construction leads to an important conclusion: Every Boolean function, no matter how complex, can be expressed using three Boolean operators only: `And`, `Or`, and `Not`.
+There is a direct recipe for turning any truth table into an expression using AND, OR, and NOT.
-## Two-Input Boolean Functions
+1. Find each row whose output is 1.
+2. Make an AND term that matches that row exactly. Use the variable for a 1 and its NOT for a 0.
+3. OR all those terms together.
-An inspection of Figure 1.1 reveals that the number of Boolean functions that can be defined over $n$ binary variables is ${2^2}^n$. For example, the sixteen Boolean functions spanned by two variables are listed in Figure 1.2. These functions were constructed systematically, by enumerating all the possible 4-wise combinations of binary values in the four right columns. Each function has a conventional name that seeks to describe its underlying operation.
+A variable or its negation is called a **literal**. For the row a=0, b=1, c=0, the matching term is `NOT a AND b AND NOT c`. It is 1 for that row and 0 for every other row.
-| Function | y | z | $f(x, y, z)$ |
-| :------: | :-: | :-: | :----------: |
-| 0 | 0 | 0 | 0 |
-| 0 | 0 | 1 | 0 |
-| 0 | 1 | 0 | 1 |
-| 0 | 1 | 1 | 0 |
-| 1 | 0 | 0 | 1 |
-| 1 | 0 | 1 | 0 |
-| 1 | 1 | 0 | 1 |
-| 1 | 1 | 1 | 0 |
+The example above has three rows with output 1, so its canonical **sum of products** is:
-_**Figure 1.2** All the Boolean functions of two variables_
+```text
+f = (NOT a AND b AND NOT c)
+ OR (a AND NOT b AND NOT c)
+ OR (a AND b AND NOT c)
+```
-Here are some examples: The name of the `Nor` function is shorthand for `Not`-`Or`: Take the `Or` of $x$ and $y$, then negate the result. The `Xor` function -- shorthand for "exclusive `Or`" -- returns 1 when its two variables have opposing truth-values and 0 otherwise. Conversely, the Equivalence function returns 1 when the two variables have identical truth-values. The If-$x$-then-$y$ function (also known as $x \rightarrow y$, or "$x$ Implies $y$") returns 1 when $x$ is 0 or when both $x$ and $y$ are 1. The other functions are self-explanatory.
+“Product” means AND; “sum” means OR. The long expression and `(a OR b) AND NOT c` have identical truth tables. Canonical form guarantees a construction, but it is not usually the shortest construction.
-The `Nand` function (as well as the `Nor` function) has an interesting theoretical
-property: Each one of the operations `And`, `Or`, and `Not` can be constructed from it,
-and it alone (e.g., `x Or y = (x Nand x) Nand (y Nand y)`. And since every Boolean function can be constructed from `And`, `Or`, and `Not` operations using the canonical representation method, it follows that every Boolean function can be constructed from `Nand` operations alone. This result has far-reaching practical implications: Once we have in our disposal a physical device that implements `Nand`, we can use many copies of this device (wired in a certain way) to implement in hardware any Boolean function.
+If there are no rows with output 1, the function is the constant 0. If every row outputs 1, it is the constant 1. Constants can also be constructed, for example `a AND NOT a` and `a OR NOT a`.
-# Gate Logic
+[Change the rows and generate a canonical expression](/tools/boolean-functions).
-A _gate_ is a physical device that implements a Boolean function. If a Boolean function $f$ operates on $n$ variables and returns $m$ binary results (in all our examples so far, $m$ was 1), the gate that implements $f$ will have $n$ _input pins_ and $m$ _output pins_. When we put some values $v_1 ... v_n$ in the gate’s input pins, the gate’s ‘‘logic’’ -- its internal structure -- should compute and output $f(v_1 ... v_n)$. And just like complex Boolean functions can be expressed in terms of simpler functions, complex gates are composed from more elementary gates. The simplest gates of all are made from tiny switching devices, called _transistors_, wired in a certain topology designed to effect the overall gate functionality.
+# All two-input functions
-Although most digital computers today use electricity to represent and transmit
-binary data from one gate to another, any alternative technology permitting switching and conducting capabilities can be employed. Indeed, during the last fifty years, researchers have built many hardware implementations of Boolean functions, including magnetic, optical, biological, hydraulic, and pneumatic mechanisms. Today, most gates are implemented as transistors etched in silicon, packaged as _chips_. In this course we use the words _chip_ and _gate_ interchangeably, tending to use the term _gates_ for simple chips.
+A two-input table has four output positions. Each can independently be 0 or 1, giving **2⁴ = 16 functions**. For a single binary output, n inputs give **2^(2ⁿ)** Boolean functions.
-The availability of alternative switching technology options, on the one hand, and the observation that Boolean algebra can be used to abstract the behavior of _any_ such technology, on the other, is extremely important. Basically, it implies that computer scientists don’t have to worry about physical things like electricity, circuits, switches, relays, and power supply. Instead, computer scientists can be content with the abstract notions of Boolean algebra and gate logic, trusting that someone else (the physicists and electrical engineers—bless their souls) will Figure out how to actually realize them in hardware. Hence, a _primitive gate_ (see Figure 1.3) can be viewed as a black box device that implements an elementary logical operation in one way or another—we don’t care how. A hardware designer starts from such primitive gates and designs more complicated functionality by interconnecting them, leading to the construction of _composite_ gates.
+Here is the complete set. The four output digits correspond to inputs **00, 01, 10, 11**, in that order.
-
-_**Figure 1.3** Standard symbolic notation of some elementary logic gates._
+| Outputs | Function |
+| ------- | ----------------------- |
+| 0000 | Constant 0 |
+| 0001 | a AND b |
+| 0010 | a AND NOT b |
+| 0011 | a |
+| 0100 | NOT a AND b |
+| 0101 | b |
+| 0110 | a XOR b |
+| 0111 | a OR b |
+| 1000 | a NOR b |
+| 1001 | Equivalence: a equals b |
+| 1010 | NOT b |
+| 1011 | b implies a |
+| 1100 | NOT a |
+| 1101 | a implies b |
+| 1110 | a NAND b |
+| 1111 | Constant 1 |
-
-_**Figure 1.4** Composite implementation of a three-way `And` gate. The rectangle on the right defines the conceptual boundaries of the gate interface._
+Logical implication `a implies b` is false only when a is 1 and b is 0. It describes a truth-table relation, not an instruction that causes b to change.
-## Primitive and Composite Gates
+The [Boolean functions tool](/tools/boolean-functions) lets you edit every output row, evaluate inputs, and compare the result with its canonical and NAND constructions.
-Since all logic gates have the same input and output semantics (0’s and 1’s), they can be chained together, creating _composite gates_ of arbitrary complexity. For example, suppose we are asked to implement the 3-way Boolean function And($a$, $b$, $c$). Using Boolean algebra, we can begin by observing that $a \cdot b \cdot c = (a \cdot b) \cdot c$, or, using prefix notation, And($a$, $b$, $c$) = And(And($a$, $b$), $c$). Next, we can use this result to construct the composite gate depicted in Figure 1.4.
+# Universality
-The construction described in Figure 1.4 is a simple example of _gate logic_, also called _logic design_. Simply put, logic design is the art of interconnecting gates in order to implement more complex functionality, leading to the notion of _composite gates_. Since composite gates are themselves realizations of (possibly complex) Boolean functions, their "outside appearance" (e.g., left side of Figure 1.4) looks just like that of primitive gates. At the same time, their internal structure can be rather complex.
+Why choose NAND as the building block? Because NAND alone can implement the three operations used by the canonical recipe.
-We see that any given logic gate can be viewed from two different perspectives: external and internal. The right-hand side of Figure 1.4 gives the gate’s internal architecture, or _implementation_, whereas the left side shows only the gate _interface_, namely, the input and output pins that it exposes to the outside world. The former is relevant only to the gate designer, whereas the latter is the right level of detail for other designers who wish to use the gate as an abstract off-the-shelf component, without paying attention to its internal structure.
+```text
+NOT a = NAND(a, a)
+t = NAND(a, b)
+a AND b = NAND(t, t)
+a OR b = NAND(NAND(a, a), NAND(b, b))
+```
-Let us consider another logic design example—that of a `Xor` gate. As discussed before, Xor($a$, $b$) is 1 exactly when either $a$ is 1 and $b$ is 0, or when $a$ is 0 and $b$ is 1. Said otherwise, Xor($a$, $b$) = Or(And($a$, Not($b$)), And(Not($a$), $b$)). This definition leads to the logic design shown in Figure 1.5.
+Tying both NAND inputs to a gives 1 when a is 0 and 0 when a is 1: NOT. Inverting the result of NAND gives AND. Inverting both inputs and feeding them to NAND gives OR, an application of **De Morgan's law**.
-
-_**Figure 1.5** `Xor` gate, along with a possible implementation._
+Now join the arguments. Every Boolean truth table can be expressed with AND, OR, and NOT. Each of those can be built from NAND. Therefore every Boolean function can be built from NAND alone. This property is called **functional completeness** or universality.
-Note that the gate _interface_ is unique: There is only one way to describe it, and this is normally done using a truth table, a Boolean expression, or some verbal specification.
+NOR is another universal primitive. NAND is a useful starting point, not the only possible starting point. Other libraries use combinations of gates to suit their engineering goals.
-This interface, however, can be realized using many different _implementations_, some of which will be better than others in terms of cost, speed, and simplicity. For example, the `Xor` function can be implemented using four, rather than five, `And`, `Or`, and `Not` gates. Thus, from a functional standpoint, the fundamental requirement of logic design is that _the gate implementation will realize its stated interface, in one way or another_. From an efficiency standpoint, the general rule is to try to _do more with less_, that is, use as few gates as possible.
+This statement concerns combinational behavior: outputs determined by the present inputs. Remembering values over time introduces state and timing, which are separate concepts.
-To sum up, the art of logic design can be described as follows: Given a gate specification (interface), find an efficient way to implement it using other gates that were already implemented. This, in a nutshell, is what we will do in the rest of this chapter
+# Gates and physical signals
-# Actual Hardware Construction
+A **gate** is a device that implements a Boolean function. Its input and output pins are the places where signals enter and leave. A function with n inputs and m outputs has a corresponding interface with n input pins and m output pins.
-Having described the logic of composing complex gates from simpler ones, we are now in a position to discuss how gates are actually built. Let us start with an intentionally naïve example.
+In electronic chips, transistor networks implement switching behavior. Many such devices are fabricated in silicon. Other switching technologies can also implement Boolean logic; the logical rule does not depend on a particular material.
-Suppose we open a chip fabrication shop in our home garage. Our first contract is to build a hundred `Xor` gates. Using the order’s downpayment, we purchase a soldering gun, a roll of copper wire, and three bins labeled "And gates," "Or gates," and "Not gates," each containing many identical copies of these elementary logic gates. Each of these gates is sealed in a plastic casing that exposes some input and output pins, as well as a power supply plug. To get started, we pin Figure 1.5 to our garage wall and proceed to realize it using our hardware. First, we take two `And` gates, two Not gates, and one `Or` gate, and mount them on a board according to the figure’s layout. Next, we connect the chips to one another by running copper wires among them and by soldering the wire ends to the respective input/output pins. Now, if we follow the gate diagram carefully, we will end up having three exposed wire ends. We then solder a pin to each one of these wire ends, seal the entire device (except for the three pins) in a plastic casing, and label it `Xor`. We can repeat this assembly process many times over. At the end of the day, we can store all the chips that we’ve built in a new bin and label it "Xor gates". If we (or other people) are asked to construct some other chips in the future, we’ll be able to use these `Xor` gates as elementary building blocks, just as we used the `And`, `Or`, and `Not` gates before.
+The two logical values abstract physical ranges of a signal. A 0 is not the absence of power to the whole computer. This site's bright wires mean a logical 1; they do not measure electrical current, voltage, delay, or energy.
-As the reader has probably sensed, the garage approach to chip production leaves much to be desired. For starters, there is no guarantee that the given chip diagram is correct. Although we can prove correctness in simple cases like `Xor`, we cannot do so in many realistically complex chips. Thus, we must settle for empirical testing: Build the chip, connect it to a power supply, activate and deactivate the input pins in various configurations, and hope that the chip outputs will agree with its specifications. If the chip fails to deliver the desired outputs, we will have to tinker with its physical structure—a rather messy affair. Further, even if we will come up with the right design, replicating the chip assembly process many times over will be a time-consuming and error-prone affair. There must be a better way!
+Working at this level lets you reason about what a circuit does before dealing with its physical realization. Electrical engineering still matters: it determines whether a real implementation meets its timing, power, reliability, and manufacturing constraints.
-# Hardware Description Language (HDL)
+# Interfaces and composition
-Today, hardware designers no longer build anything with their bare hands. Instead, they plan and optimize the chip architecture on a computer workstation, using structured modeling formalisms like _Hardware Description Language_, or HDL (also known as VHDL, where V stands for _Virtual_). The designer specifies the chip structure by writing an HDL program, which is then subjected to a rigorous battery of tests. These tests are carried out virtually, using computer simulation: A special software tool, called a _hardware simulator_, takes the HDL program as input and builds an image of the modeled chip in memory. Next, the designer can instruct the simulator to test the virtual chip on various sets of inputs, generating simulated chip outputs. The outputs can then be compared to the desired results, as mandated by the client who ordered the chip built.
+A **primitive** is supplied as a working part. A **composite** is built by connecting other parts. From outside, both expose an interface: named pins and promised behavior.
-In addition to testing the chip’s correctness, the hardware designer will typically be interested in a variety of parameters such as speed of computation, energy consumption, and the overall cost implied by the chip design. All these parameters can be simulated and quantified by the hardware simulator, helping the designer optimize the design until the simulated chip delivers desired cost/performance levels.
+For example, a three-input AND can be composed from two two-input AND gates:
-Thus, using HDL, one can completely plan, debug, and optimize the entire chip before a single penny is spent on actual production. When the HDL program is deemed complete, that is, when the performance of the simulated chip satisfies the client who ordered it, the HDL program can become the blueprint from which many copies of the physical chip can be stamped in silicon. This final step in the chip
-life cycle - from an optimized HDL program to mass production - is typically outsourced to companies that specialize in chip fabrication, using one switching technology or another.
+```text
+first = AND(a, b)
+out = AND(first, c)
+```
-## Example: Building a Xor Gate
+The caller only needs the three-input contract. The designer needs to know the two parts and the internal wire joining them. A boundary hides the implementation without changing its behavior.
-As we have seen in Figures 1.2 and 1.5, one way to define _exclusive_ `Or` is Xor($a$, $b$) = Or(And($a$, Not($b$)), And(Not($a$), $b$)). This logic can be expressed either graphically, as a gate diagram, or textually, as an HDL program. The latter program is written in the HDL variant used throughout this course. See Simulator 1.1 for the details.
+A part's output may feed several inputs. This is called **fan-out**. In the logical model it copies a value; it does not divide the value between destinations. Real circuits have electrical fan-out limits that this simulator does not model.
-{% EmbeddedHardwareIDE id="Xor" /%}
-_**Simulator 1.1** `Xor` gate, along with a possible implementation._
+Many implementations can satisfy the same interface. A correct design must match the contract for every relevant input. A compact design may use fewer parts or fewer stages, but those structural measures do not by themselves establish physical speed or energy use.
-## Explanation
+# A worked XOR circuit
-An HDL definition of a chip consists of a _header_ section and a _parts_ section. The header section specifies the chip _interface_, namely the chip name and the names of its input and output pins. The parts section describes the names and topology of all the lower-level parts (other chips) from which this chip is constructed. Each part is represented by a _statement_ that specifies the part name and the way it is connected to other parts in the design. Note that in order to write such statements legibly, the HDL programmer must have a complete documentation of the underlying parts’ _interfaces_. For example, the code in Simulator 1.1 assumes that the input and output pins of the `Not` gate are labeled `in` and `out`, and those of `And` and `Or` are labeled `a`, `b` and `out`. This API-type information is not obvious, and one must have access to it before one can plug the chip parts into the present code.
+XOR is 1 for two situations: a is 1 while b is 0, or a is 0 while b is 1.
-Inter-part connections are described by creating and connecting _internal pins_, as needed. For example, consider the bottom of the gate diagram, where the output of a `Not` gate is piped into the input of a subsequent `And` gate. The HDL code describes this connection by the pair of statements `Not(..., out=nota)` and `And(a=nota, ...)`. The first statement creates an internal pin (outbound wire) named `nota`, feeding out into it. The second statement feeds the value of `nota` into the `a` input of an `And` gate. Note that pins may have an unlimited fan out. For example, in Simulator 1.1, each input is simultaneously fed into two gates. In gate diagrams, multiple connections are described using forks. In HDL, the existence of forks is implied by the code.
+```text
+XOR(a, b) = (a AND NOT b) OR (NOT a AND b)
+```
-## Testing
+The following HDL gives those intermediate signals names:
-Rigorous quality assurance mandates that chips be tested in a specific, replicable, and well-documented fashion. With that in mind, hardware simulators are usually designed to run _test scripts_, written in some scripting language. For example, the test script in the tab "Tests" of Simulator 1.1 is written in the scripting language understood by the embedded hardware simulator.
+```hdl
+CHIP Xor {
+ IN a, b;
+ OUT out;
-Let us give a brief description of the test script from Simulator 1.1. First, the script tells the simulator to get ready to print the values of selected variables. Next, the script lists a series of testing scenarios, designed to simulate the various contingencies under which the `Xor` chip will have to operate in "real-life" situations. In each scenario, the script instructs the simulator to bind the chip inputs to certain data values, compute the resulting output, and record the test results. In the case of simple gates like `Xor`, one can write an exhaustive test script that enumerates all the possible input values of the gate. The resulting output (tab "Output" in Simulator 1.1) can then be viewed as a complete empirical proof that the chip is well designed. The luxury of such certitude is not feasible in more complex chips, as we will see later.
+ PARTS:
+ Not(in=a, out=nota);
+ Not(in=b, out=notb);
+ And(a=a, b=notb, out=w1);
+ And(a=nota, b=b, out=w2);
+ Or(a=w1, b=w2, out=out);
+}
+```
-# Hardware Simulation
+[Open the worked XOR in the hardware simulator](/tools/hardware-simulator/Xor).
-Since HDL is a hardware construction language, the process of writing and debugging HDL programs is quite similar to software development. The main difference is that instead of writing code in a language like Java, we write it in HDL, and instead of using a compiler to translate and test the code, we use a hardware simulator. The hardware simulator is a computer program that knows how to parse and interpret HDL code, turn it into an executable representation, and test it according to the specifications of a given test script. There exist many commercial hardware simulators on the market, and these vary greatly in terms of cost, complexity, and ease of use. This website provides a simple (and free) hardware simulator that is sufficiently powerful to support sophisticated hardware design projects. In particular, the simulator provides all the necessary tools for building, testing, and integrating all the chips presented in the course, leading to the construction of a general-purpose computer.
+This uses five parts from a NOT/AND/OR library. XOR can also be built from four NAND gates. Those counts compare two logical constructions; different primitive libraries have different physical costs.
+
+# Reading HDL
+
+**HDL** means hardware description language. The syntax here describes a network of connected parts. It is not a sequence of commands for the chip to execute.
+
+- `CHIP Xor` names the chip.
+- `IN` and `OUT` declare the external pins.
+- `PARTS:` introduces the internal components.
+- `Not(in=a, out=nota)` connects external input a to a NOT gate, and names its output wire nota.
+- `And(a=nota, b=b, out=w2)` consumes that same wire.
+
+Part pin names belong to the part's interface. `Not` uses `in` and `out`; `And` uses `a`, `b`, and `out`. The names on the other side of `=` identify signals in the containing chip. They do not need to match the part's pin names.
+
+One source can feed several destinations. A signal must have a source; attaching multiple drivers or creating a combinational feedback loop is not a valid circuit in this workbench. The visual and code views describe the same supported graph.
+
+The project's HDL is an educational language. VHDL and Verilog are other hardware description languages with their own syntax and capabilities. Do not treat this syntax as interchangeable with them.
+
+# Testing a construction
+
+A circuit can look plausible and still be wrong. A repeatable test assigns input values, evaluates the circuit, and compares the observed outputs with the contract.
+
+For XOR there are only four input combinations. Its complete expected output is:
+
+| a | b | out |
+| --- | --- | --- |
+| 0 | 0 | 0 |
+| 0 | 1 | 1 |
+| 1 | 0 | 1 |
+| 1 | 1 | 0 |
+
+The guided workbench runs every case automatically. The hardware simulator also accepts a test script. One case looks like this:
+
+```text
+output-list a%B3.1.3 b%B3.1.3 out%B3.1.3;
+
+set a 0,
+set b 1,
+eval,
+output;
+```
+
+`output-list` chooses the displayed pins and their formatting. `set` assigns an input. `eval` evaluates the current circuit. `output` records a row. Repeat the cases and compare the recorded rows against the expected table.
+
+Exhaustive testing of a deterministic, combinational model establishes its truth table. That is stronger than trying a few random inputs, but it does not verify physical fabrication, timing, power behavior, or the correctness of the simulator itself. For large interfaces, the number of cases grows exponentially and different verification techniques are needed.
+
+# From a model to physical hardware
+
+Connecting physical parts first and correcting them afterward would make experimentation slow and replication error-prone. An HDL model makes it easier to inspect, change, and test the design before manufacture.
+
+Professional design flows can analyze timing, area, and power using models appropriate to the intended technology. They can translate a verified description toward a physical implementation. The tools here focus on Boolean behavior; they do not simulate those physical properties or manufacture a chip.
+
+# Try the relationships yourself
+
+Use [Learn](/learn) for guided construction, the [hardware simulator](/tools/hardware-simulator) for HDL and test scripts, and the [Boolean functions tool](/tools/boolean-functions) to connect arbitrary truth tables with expressions. Next, [scale the same rules to buses and selectors](/learn/reference/boolean-logic/project#buses).
diff --git a/src/routes/learn/hardware/boolean-logic/intro.md b/src/routes/learn/hardware/boolean-logic/intro.md
index 046a169..f047c83 100644
--- a/src/routes/learn/hardware/boolean-logic/intro.md
+++ b/src/routes/learn/hardware/boolean-logic/intro.md
@@ -1,14 +1,39 @@
---
-title: Boolean Logic
-updated: 2022-06-26
+title: From signals to logic
+updated: 2026-11-03
---
-> Such simple things, And we make of them something so complex it defeats us, Almost.
+A computer stores and transforms information. At the bottom of that process are signals with two logical states: **0** and **1**. Gates turn those signals into useful rules. Connect the rules and they become the parts of a larger machine.
--- John Ashbery (b. 1927), American poet
+# Start with behavior
-Every digital device — be it a personal computer, a cellular telephone, or a network router — is based on a set of chips designed to store and process information. Although these chips come in different shapes and forms, they are all made from the same building blocks: Elementary _logic gates_. The gates can be physically implemented in many different materials and fabrication technologies, but their logical behavior is consistent across all computers. In this chapter we start out with one primitive logic gate — Nand — and build all the other logic gates from it. The result is a rather standard set of gates, which will be later used to construct our computer’s processing and storage chips. This will be done in chapters 2 and 3, respectively, that are coming soon.
+First, change a single signal and watch its output. Then meet **NOT**, which reverses a signal, and **AND**, which checks whether two inputs are both 1. Those two ideas make **NAND** easier to understand: it is the opposite of AND.
-All the hardware chapters in the course, beginning with this one, have the same structure. Each chapter focuses on a well-defined task, designed to construct or integrate a certain family of chips. The prerequisite knowledge needed to approach this task is provided in a brief Background section. The next section provides a complete Specification of the chips abstractions, namely, the various services that they should deliver, one way or another. Having presented the _what_, a subsequent Implementation section proposes guidelines and hints about _how_ the chips can be actually implemented. A Perspective section rounds up the chapter with concluding comments about important topics that were left out from the discussion. Each chapter ends with a technical Project section. This section gives step-by-step instructions for actually building the chips using the integrated hardware simulator.
+The guided path introduces each control when it becomes useful. You can [start learning](/learn), or use these explanations whenever you want the reasoning behind a step.
-This being the first hardware chapter in the course, the Background section is somewhat lengthy, featuring a special section on _hardware description and simulation tools_.
+# Why build from one gate?
+
+NAND is a supplied building block in this project. Copies of it can form NOT, AND, and OR. Those operations can express every Boolean function, so a single kind of primitive is enough to build any combinational logic circuit. [See why this works](/learn/reference/boolean-logic/background#universality).
+
+That does not mean one gate is a whole computer. A computer also needs state, timing, arithmetic, instructions, and software. Building the logic foundation makes those later ideas less mysterious.
+
+# How the material fits together
+
+- **Explore:** understand signals, NOT, AND, and NAND by changing inputs.
+- **Build:** construct NOT, AND, OR, XOR, Mux, and DMux. Check every input combination.
+- **Explain:** connect truth tables, Boolean expressions, gate diagrams, and HDL.
+- **Scale:** use the Boolean functions and bus tools to explore canonical expressions, multi-bit operations, and multi-way routing.
+
+A chip's **interface** tells you what it promises. Its **implementation** is the network that fulfils that promise. There can be several correct implementations; start with correctness, then compare their structure.
+
+# Read or experiment
+
+[Logic, composition, and HDL](/learn/reference/boolean-logic/background) develops the theory, including a worked XOR implementation and test script.
+
+[Gate contracts and larger buses](/learn/reference/boolean-logic/project) collects the construction goals and explains how the same logic scales to several bits and several routes.
+
+The [hardware simulator](/tools/hardware-simulator) runs the project's supported HDL and test scripts. The [Boolean functions tool](/tools/boolean-functions) and [buses and routing tool](/tools/buses) make the remaining logic concepts directly explorable.
+
+# What is available now
+
+The first guided constructions cover single-bit combinational logic. [Continue the learning path](/learn/path) through multi-bit construction, arithmetic, clocked storage, machine language, computer architecture, and the assembler. The [chip builder](/tools/chip-builder) supports multi-bit and clocked HDL experiments. Higher-level software follows in the later Nand2Tetris projects and remains outside this release's guided path.
diff --git a/src/routes/learn/hardware/boolean-logic/project.md b/src/routes/learn/hardware/boolean-logic/project.md
index 688f28e..b1f9696 100644
--- a/src/routes/learn/hardware/boolean-logic/project.md
+++ b/src/routes/learn/hardware/boolean-logic/project.md
@@ -1,237 +1,187 @@
---
-title: Project
-updated: 2023-09-06
+title: Gate contracts and larger buses
+updated: 2026-11-03
---
-# Description
+Build one reliable part, then use its behavior to understand the next. This chapter collects the single-bit construction contracts and the larger bus and routing operations described in the original material.
-We now turn to outlining the first stage of this bottom-up hardware construction project, one gate at a time.
-This project specifies a typical set of gates, each designed to carry out a common Boolean operation.
-These gates will be used in the chapters that follow to construct the full architecture of a typical modern computer.
+# The construction loop
-# Objective
+1. Read the input, output, and behavior contract.
+2. Connect permitted parts in Visual mode, or describe the same circuit in HDL.
+3. Change inputs and inspect the result.
+4. Test every input combination.
+5. Repair any failing case, then continue.
-Implement all the logic gates presented in the chapter. The only building
-blocks that you can use are primitive `Nand` gates and the composite gates that you
-will gradually build on top of them.
-You know your implementation is correct if all Tests pass.
+The guided path introduces each tool gradually. [Continue learning](/learn). For independent experiments, open the [hardware simulator](/tools/hardware-simulator).
-All the gates can be built and simulated here, using the embedded hardware simulator.
-Our implementation guidelines are intentionally partial, since we want you to discover the actual gate architectures yourself.
-We reiterate that each gate can be implemented in more than one way; the simpler the implementation, the better.
+The introductory workbench supplies primitive equivalents of previously introduced gates as permitted components; it does not automatically package those first visual constructions into a library. In the later [chip builder](/tools/chip-builder), add explicit HDL dependencies to compose and test your own chip definitions.
-# The Nand Gate
+# The supplied NAND primitive
-Similar to the role of axioms in mathematics, primitive gates provide a set of elementary building blocks from which everything else can be built.
-Operationally, primitive gates have an "off-the-shelf" implementation that is supplied externally.
-Thus, they can be used in the construction of other gates and chips without worrying about their internal design.
-In the computer architecture that we are now beginning to build, we have chosen to base all the hardware on one primitive gate only: `Nand`.
-This gate is considered primitive and thus there is no need to implement it.
+NAND gives the opposite of AND. It is 0 only when both inputs are 1.
-The `Nand` gate is designed to compute the following Boolean function:
+| a | b | out |
+| --- | --- | --- |
+| 0 | 0 | 1 |
+| 0 | 1 | 1 |
+| 1 | 0 | 1 |
+| 1 | 1 | 0 |
-| a | b | Nand($a$, $b$) |
-| :-: | :-: | :------------: |
-| 0 | 0 | 1 |
-| 0 | 1 | 1 |
-| 1 | 0 | 1 |
-| 1 | 1 | 0 |
+You explore its behavior, then use it as a supplied part. You do not have to construct it. The earlier NOT and AND demonstrations explain what the operations mean; the construction exercises ask you to realize them from the chosen primitive. [Why NAND is enough](/learn/reference/boolean-logic/background#universality).
-{% EmbeddedHardwareIDE id="BuiltinNand" /%}
-_**Simulator 1.2** `Nand` gate using the built-in implementation._
+[Inspect supplied NAND](/tools/hardware-simulator/BuiltinNand).
-# Basic Logic Gates
+# Single-bit gates
-Some of the logic gates presented here are typically referred to as "elementary" or
-"basic". At the same time, every one of them can be composed from `Nand` gates
-alone. Therefore, they need not be viewed as primitive.
+## NOT: invert a signal
-## Not
+The output is the opposite of the input. A NOT gate is also called an **inverter**.
-The single-input `Not` gate, also known as "converter", converts its input from
-0 to 1 and vice versa.
-The implementation of a unary `Not` gate from a binary `Nand` gate is simple.
+| in | out |
+| --- | --- |
+| 0 | 1 |
+| 1 | 0 |
-{% EmbeddedHardwareIDE id="ExerciseNot" celebrate="true" /%}
-_**Simulator 1.3** `Not` gate with missing implementation._
+Hint: consider what a NAND does when both of its inputs receive the same signal.
-## And
+[Open the NOT exercise](/tools/hardware-simulator/ExerciseNot).
-The `And` function returns 1 when both its inputs are 1, and 0 otherwise.
-Once again, the gate implementation is simple.
+## AND: require both inputs
-{% EmbeddedHardwareIDE id="ExerciseAnd" celebrate="true" /%}
-_**Simulator 1.4** `And` gate with missing implementation._
+The output is 1 only when both inputs are 1. NAND already gives the opposite answer; use a gate you understand to reverse it.
-## Or
+## OR: accept either input
-The `Or` function returns 1 when at least one of its inputs is 1, and 0 otherwise.
-This function can be defined in terms of some of the Boolean functions implemented previously, using some simple Boolean manipulations.
-Thus, the respective gate can be built using previously built gates.
+The output is 1 when at least one input is 1. Both inputs may be 1. Try rewriting the condition as “it is not the case that both inputs are 0.”
-{% EmbeddedHardwareIDE id="ExerciseOr" celebrate="true" /%}
-_**Simulator 1.5** `Or` gate with missing implementation._
+## XOR: detect a difference
-## Xor
+The output is 1 when exactly one input is 1. It is 0 when they match. Describe the two situations that should produce a 1, then combine them.
-The `Xor` function, also known as "exclusive or", returns 1 when its two inputs
-have opposing values, and 0 otherwise.
-Likewise, this gate can be built using previously built gates.
+| a | b | AND | OR | XOR |
+| --- | --- | --- | --- | --- |
+| 0 | 0 | 0 | 0 | 0 |
+| 0 | 1 | 0 | 1 | 1 |
+| 1 | 0 | 0 | 1 | 1 |
+| 1 | 1 | 1 | 1 | 0 |
-{% EmbeddedHardwareIDE id="ExerciseXor" celebrate="true" /%}
-_**Simulator 1.6** `Xor` gate with missing implementation._
+Open an exercise: [AND](/tools/hardware-simulator/ExerciseAnd), [OR](/tools/hardware-simulator/ExerciseOr), or [XOR](/tools/hardware-simulator/ExerciseXor). Each has four exhaustive input cases.
-## Multiplexor
+# Selecting and routing
-A multiplexor (Figure 1.6) is a three-input gate that uses one of the inputs, called "selection bit", to select and output one of the other two inputs, called "data bits".
-Thus, a better name for this device might have been _selector_.
-The name _multiplexor_ was adopted from communications systems, where similar devices are used to serialize (multiplex) several input signals over a single output wire.
-As usual, this gate can be built using previously built gates.
+## Mux: choose one input
-{% LayoutRow .gap-4 %}
-{% LayoutCol .flex-1 %}
-| a | b | sel | out |
-| :-: | :-: | :-: | :-: |
-| 0 | 0 | 0 | 0 |
-| 0 | 1 | 0 | 0 |
-| 1 | 0 | 0 | 1 |
-| 1 | 1 | 0 | 1 |
-| 0 | 0 | 1 | 0 |
-| 0 | 1 | 1 | 1 |
-| 1 | 0 | 1 | 0 |
-| 1 | 1 | 1 | 1 |
-{% /LayoutCol %}
+A **multiplexor**, or mux, selects one data input and passes it to the output. The selector chooses a route; it is not a power switch.
-{% LayoutCol .flex-1 %}
| sel | out |
-| :-: | :-: |
-| 0 | a |
-| 1 | b |
+| --- | --- |
+| 0 | a |
+| 1 | b |
-
-{% /LayoutCol %}
-{% /LayoutRow %}
-_**Figure 1.6** Multiplexor. The second truth table is an abbreviated version of the first truth table._
+The full contract has three binary inputs and eight cases:
-{% EmbeddedHardwareIDE id="ExerciseMux" celebrate="true" /%}
-_**Simulator 1.7** `Mux` gate with missing implementation._
+| a | b | sel | out |
+| --- | --- | --- | --- |
+| 0 | 0 | 0 | 0 |
+| 0 | 1 | 0 | 0 |
+| 1 | 0 | 0 | 1 |
+| 1 | 1 | 0 | 1 |
+| 0 | 0 | 1 | 0 |
+| 0 | 1 | 1 | 1 |
+| 1 | 0 | 1 | 0 |
+| 1 | 1 | 1 | 1 |
-## Demultiplexor
+A useful expression is `(a AND NOT sel) OR (b AND sel)`. With sel=0, only a can reach the output; with sel=1, only b can.
-A demultiplexor (Figure 1.7) performs the opposite function of a multiplexor: It takes a single input and channels it to one of two possible outputs according to a selector bit that specifies which output to chose.
-You know the drill: This gate can be built using previously built gates.
+[Open the Mux exercise](/tools/hardware-simulator/ExerciseMux).
-{% LayoutRow .gap-4 %}
-{% LayoutCol .flex-1 %}
-| sel | a | b |
-| :-: | :-: | :-: |
-| 0 | in | 0 |
-| 1 | 0 | in |
-{% /LayoutCol %}
+## DMux: choose one output
-{% LayoutCol .flex-1 %}
-
-{% /LayoutCol %}
-{% /LayoutRow %}
-_**Figure 1.7** Demultiplexor._
+A **demultiplexor**, or demux, takes one data input and sends it to a selected output. Every other output is 0.
-{% EmbeddedHardwareIDE id="ExerciseDMux" celebrate="true" /%}
-_**Simulator 1.8** `DMux` gate with missing implementation._
+| in | sel | a | b |
+| --- | --- | --- | --- |
+| 0 | 0 | 0 | 0 |
+| 0 | 1 | 0 | 0 |
+| 1 | 0 | 1 | 0 |
+| 1 | 1 | 0 | 1 |
-# Multi-Bit Versions of Basic Gates
+Equivalently, `a = in AND NOT sel` and `b = in AND sel`. Check both outputs in every case. Routing an input of 0 still produces 0 at the chosen output; the selection does not create a 1.
-Computer hardware is typically designed to operate on multi-bit arrays called "buses".
-For example, a basic requirement of a 32-bit computer is to be able to compute (bit-wise) an And function on two given 32-bit buses.
-To implement this operation, we can build an array of 32 binary And gates, each operating separately on a pair of bits.
-In order to enclose all this logic in one package, we can encapsulate the gates array in a single chip interface consisting of two 32-bit input buses and one 32-bit output bus.
+[Open the DMux exercise](/tools/hardware-simulator/ExerciseDMux).
-This section describes a typical set of such multi-bit logic gates, as needed for the construction of a typical 16-bit computer.
-We note in passing that the architecture of $n$-bit logic gates is basically the same irrespective of $n$’s value.
+# Buses
-When referring to individual bits in a bus, it is common to use an array syntax.
-For example, to refer to individual bits in a 16-bit bus named $data$, we use the notation `data[0]`, `data[1]`,..., `data[15]`.
+A **bus** groups several signals into one interface. A 16-bit bus has sixteen bits, named `data[0]` through `data[15]`. When a bus represents an unsigned binary number, bit 0 is the least significant bit and bit 15 is the most significant.
-## Multi-Bit Not
+A word's width and the number of inputs are different things. A two-input, 16-bit AND has two buses, each containing sixteen bits. It applies sixteen independent AND operations.
-An $n$-bit `Not` gate applies the Boolean operation `Not` to every one of the bits in its $n$-bit input bus.
+| Operation | Contract for each bit i |
+| --------- | -------------------------------------- |
+| Not16 | out[i] = NOT in[i] |
+| And16 | out[i] = a[i] AND b[i] |
+| Or16 | out[i] = a[i] OR b[i] |
+| Mux16 | out[i] = a[i] if sel=0; otherwise b[i] |
-## Multi-Bit And
+The selector of Mux16 is **one bit**. It selects an entire word; it does not need one selector per data bit.
-An $n$-bit `And` gate applies the Boolean operation `And` to every one of the $n$ bit-pairs arrayed in its two $n$-bit input buses.
+For a four-bit illustration, NOT of `0011` is `1100`. The same construction works at 8, 16, or 32 bits: repeat the one-bit operation in parallel. Bitwise AND and OR are not arithmetic addition.
-## Multi-Bit Or
+[Explore 16-bit gates in the buses and routing tool](/tools/buses).
-An $n$-bit `Or` gate applies the Boolean operation `Or` to every one of the $n$ bit-pairs arrayed in its two $n$-bit input buses.
+These operations are executable behavioral models in the buses tool. To construct and validate your own multi-bit HDL, [continue with the bus challenges](/learn/path/buses) or use the [chip builder](/tools/chip-builder). Exploring a supplied model and verifying your own construction are separate steps.
-## Multi-Bit Multiplexor
+# Multi-way operations
-An $n$-bit multiplexor is exactly the same as the binary multiplexor described in Figure 1.6, except that the two inputs are each $n$-bit wide; the selector is a single bit.
+A multi-way gate combines or selects among more than two inputs. “Multi-way” describes the number of alternatives; “multi-bit” describes the width of each alternative.
-# Multi-Way Versions of Basic Gates
+## OR across a word
-Many 2-way logic gates that accept two inputs have natural generalization to multiway variants that accept an arbitrary number of inputs.
-This section describes a set of multi-way gates that will be used subsequently in various chips in our computer architecture.
-Similar generalizations can be developed for other architectures, as needed.
+**Or8Way** reduces eight input bits to one output. The result is 1 if any input is 1, and 0 only if all eight inputs are 0. This differs from Or16, which combines two words and produces a word.
-## Multi-Way Or
+It can be composed as a chain or a tree of two-input OR gates. Both give the same Boolean answer; a balanced tree uses fewer successive gate stages than a long chain.
-An $n$-way `Or` gate outputs 1 when at least one of its $n$ bit inputs is 1, and 0 otherwise.
+## Multi-way multiplexors
-## Multi-Way/Multi-Bit Multiplexor
+A 4-way, 16-bit mux chooses one of four words. Its selector has two bits:
-An $m$-way $n$-bit multiplexor selects one of $m$ $n$-bit input buses and outputs it to a single $n$-bit output bus. The selection is specified by a set of $k$ control bits, where $k = log_2m$. Figure 1.8 depicts a typical example.
+| sel[1] | sel[0] | Selected word |
+| ------ | ------ | ------------- |
+| 0 | 0 | a |
+| 0 | 1 | b |
+| 1 | 0 | c |
+| 1 | 1 | d |
-The computer platform that we develop in this course requires two variations of this chip: A 4-way 16-bit multiplexor and an 8-way 16-bit multiplexor.
+An 8-way, 16-bit mux chooses among eight words and needs three selector bits. For a power-of-two number of alternatives m, the number of selector bits is `log₂(m)`.
-{% LayoutRow .gap-4 %}
-{% LayoutCol .flex-1 %}
-| sel[1] | sel[0] | out |
-| :----: | :----: | :-: |
-| 0 | 0 | a |
-| 0 | 1 | b |
-| 1 | 0 | c |
-| 1 | 1 | d |
-{% /LayoutCol %}
+A 4-way mux can be built from three 2-way muxes: select between a and b, select between c and d, then select between those two intermediate results. Extending the selection tree gives an 8-way mux.
-{% LayoutCol .flex-1 %}
-
-{% /LayoutCol %}
-{% /LayoutRow %}
-_**Figure 1.8** 4-way multiplexor. The width of the input and output buses may vary._
+## Multi-way demultiplexors
-## Multi-Way/Multi-Bit Demultiplexor
+A 4-way, 1-bit demux sends its input to a, b, c, or d according to a two-bit selector. An 8-way version uses three selector bits and eight outputs.
-An $m$-way $n$-bit demultiplexor (Figure 1.9) channels a single $n$-bit input into one of $m$ possible $n$-bit outputs. The selection is specified by a set of $k$ control bits, where $k = log_2m$.
+| sel | a | b | c | d |
+| --- | --- | --- | --- | --- |
+| 00 | in | 0 | 0 | 0 |
+| 01 | 0 | in | 0 | 0 |
+| 10 | 0 | 0 | in | 0 |
+| 11 | 0 | 0 | 0 | in |
-The specific computer platform that we will build requires two variations of this chip: A 4-way 1-bit demultiplexor and an 8-way 1-bit multiplexor, as follows.
+A demux tree repeatedly splits one route into two. The same routing idea can carry a bus, but the original 4-way and 8-way construction contracts here carry a **single bit**.
-{% LayoutRow .gap-4 %}
-{% LayoutCol .flex-1 %}
-| sel[1] | sel[0] | a | b | c | d |
-| :----: | :----: | :-: | :-: | :-: | :-: |
-| 0 | 0 | in | 0 | 0 | 0 |
-| 0 | 1 | 0 | in | 0 | 0 |
-| 1 | 0 | 0 | 0 | in | 0 |
-| 1 | 1 | 0 | 0 | 0 | in |
-{% /LayoutCol %}
+[Try Or8Way, 4-way and 8-way muxes, and demuxes](/tools/buses). Change the selector and check that only the chosen data reaches the output. For demuxes, also inspect every inactive output.
-{% LayoutCol .flex-1 %}
-
-{% /LayoutCol %}
-{% /LayoutRow %}
-_**Figure 1.9** 4-way demultiplexor._
+# Correctness, then efficiency
-# Perspective
+There is usually more than one correct circuit. Begin by satisfying the interface for all inputs. Then compare designs by their number of parts, repeated subexpressions, fan-out, and depth of dependent gates.
-This chapter described the first steps taken in an applied digital design project. In the next chapter we will build more complicated functionality using the gates built here.
+These comparisons can reveal opportunities to simplify a logical network. They are not a physical timing or power measurement. Real optimization also depends on transistor technology, wire lengths and capacitance, layout, manufacturing cost, and other electrical constraints.
-Although we have chosen to use Nand as our basic building block, other approaches are possible.
-For example, one can build a complete computer platform using `Nor` gates alone, or, alternatively, a combination of `And`, `Or`, and `Not` gates.
-These constructive approaches to logic design are theoretically equivalent, just as all theorems in geometry can be founded on different sets of axioms as alternative points of departure.
-The theory and practice of such constructions are covered in standard textbooks about digital design or logic design.
+NAND is not the only valid foundation. NOR alone is universal, and a library containing AND, OR, and NOT is also complete. Choosing a different primitive changes how you express a design, not the Boolean behavior you are trying to implement.
-Throughout the chapter, we paid no attention to efficiency considerations such as the number of elementary gates used in constructing a composite gate or the number of wire crossovers implied by the design.
-Such considerations are critically important in practice, and a great deal of computer science and electrical engineering expertise focuses on optimizing them.
-Another issue we did not address at all is the physical implementation of gates and chips using the laws of physics, for example, the role of transistors embedded in silicon.
-There are of course several such implementation options, each having its own characteristics (speed, power requirements, production cost, etc.).
-Any nontrivial coverage of these issues requires some background in electronics and physics.
+# After the logic layer
+
+You now have the vocabulary for signals, logic operations, composition, and routing. [Continue constructing multi-bit chips](/learn/path/buses), then [turn those gates into arithmetic](/learn/reference/boolean-arithmetic). Memory adds state; architecture connects calculation, storage, and control. The guided path continues through a working computer and its assembler.
+
+[See the available next steps](/learn/reference/meta/what-next).
diff --git a/src/routes/learn/hardware/computer-architecture/intro.md b/src/routes/learn/hardware/computer-architecture/intro.md
new file mode 100644
index 0000000..0753dec
--- /dev/null
+++ b/src/routes/learn/hardware/computer-architecture/intro.md
@@ -0,0 +1,89 @@
+---
+title: Put the computer together
+updated: 2026-11-03
+---
+
+The computer joins three capabilities: an ALU transforms values, memory keeps them, and instructions choose what happens next. You have already met each interface. This layer connects them into a machine that runs a program.
+
+[Build the computer layer](/learn/path/architecture), use the [chip builder](/tools/chip-builder), or trace instructions in the [computer tool](/tools/computer).
+
+# A stored program
+
+A stored-program machine keeps instructions in memory instead of fixing one sequence permanently into its wiring. Loading a different instruction sequence gives the same hardware a different job.
+
+Hack is deliberately small: 16-bit instructions and data words, a 15-bit instruction address, two main CPU registers, and a memory-mapped screen and keyboard. Its instruction memory and data memory are separate. This arrangement is often called Harvard-style; a classic unified-memory von Neumann machine shares an address space for instructions and data. Both illustrate the stored-program idea.
+
+Do not equate our step-by-step view with a modern processor's implementation. Real processors may overlap instructions, predict branches, cache memory, and have many more registers. Here the simpler machine makes the boundary between the instruction contract and its circuitry visible.
+
+# Three construction contracts
+
+| Chip | Inputs | Outputs | Responsibility |
+| --- | --- | --- | --- |
+| Memory | `in[16]`, `load`, `address[15]` | `out[16]` | Decode the data address and route reads and writes |
+| CPU | `inM[16]`, `instruction[16]`, `reset` | `outM[16]`, `writeM`, `addressM[15]`, `pc[15]` | Execute one instruction's data and control decisions |
+| Computer | `reset` | No external data output pins | Connect CPU, instruction ROM, and Memory |
+
+Computer's observable behavior appears in its state and devices rather than an `out` pin. Loading a program into its instruction ROM and inspecting the screen or RAM are simulator facilities.
+
+# The memory map
+
+Memory exposes one interface over several different devices:
+
+| Address range | Device | Read | Write |
+| --- | --- | --- | --- |
+| 0–16383 | RAM16K | Selected 16-bit RAM word | Store on a clock update when load is 1 |
+| 16384–24575 | Screen | Selected screen word | Store on a clock update when load is 1 |
+| 24576 | Keyboard | Current key code, or zero | No program write |
+| 24577–32767 | Unmapped | Outside the specified valid map | Outside the specified valid map |
+
+Decode the address before routing `load`. The keyboard must never be treated as writable RAM. Reading selects the appropriate device output using the same map. The Screen needs a 13-bit offset; RAM16K needs a 14-bit offset. Check the boundaries 16383/16384 and 24575/24576 carefully.
+
+The project supplies Screen and Keyboard as primitives. You are responsible for their integration, not for modeling a display panel or the electronics of a keyboard. Unmapped addresses are not extra usable RAM; avoid depending on a simulator's incidental result there.
+
+# The CPU data path
+
+The **D register** supplies one ALU operand. The other operand is selected between the **A register** and `inM`, according to the instruction's `a` bit. The ALU's six control bits come from the C-instruction's computation field.
+
+The A register has two sources. An A-instruction loads the literal encoded in the instruction. A C-instruction whose destination includes A loads the ALU result. D loads only when a C-instruction's destination includes D. Both registers otherwise hold their values.
+
+`addressM` is the low 15 bits of the current A register. `outM` carries the combinational ALU result. `writeM` is true only for a C-instruction whose destination includes M. An arbitrary `outM` value when `writeM=0` does not cause a memory write.
+
+Control bits must be gated by instruction type. Bits in an A-instruction are a literal, not destination or jump fields. Accidentally decoding them as C-instruction controls can make loading an address overwrite D, RAM, or the PC.
+
+# The CPU control path
+
+The PC chooses the next ROM instruction. In ordinary execution it increments. For a taken C-instruction jump it loads A's address. With `reset=1`, it restarts at zero at the next clock update.
+
+The jump condition is derived from the final ALU result. Zero means `zr=1`; negative means `ng=1`; positive means both are 0. Combine those conditions with the three jump bits. An A-instruction never jumps, even when its low three literal bits resemble a jump code.
+
+The PC's reset input takes priority over loading a jump target. CPU reset restarts instruction selection; it is not a command to clear RAM, erase the screen, or reset all CPU registers. A tool's separate “reset machine” or “clear memory” control may offer a broader fresh-start operation, but that is not the hardware reset pin's contract.
+
+# One cycle, one shared old state
+
+Think of an instruction as two stages: calculate from the old state, then commit the next state together. All writes in that instruction use the same pre-update registers.
+
+If A is 40 and D is 7, `AM=D` stores 7 into A and into RAM[40]. It does not write RAM[7]. If an instruction both writes A and jumps, the jump target is the old A address. The newly written A is visible to the next instruction.
+
+This rule also explains why combinational outputs can be inspected before the clock moves while stored register values change only at the update. Mixing these stages creates bugs that may survive simple programs but fail instructions with multiple destinations.
+
+# Connect the complete machine
+
+ROM32K accepts the CPU's `pc` output and supplies `instruction`. Data Memory accepts `addressM`, `outM`, and `writeM`, and returns the selected word as `inM`. The CPU's reset input is Computer's reset input. A common clock coordinates state updates.
+
+Instruction ROM holds up to 32768 words and is loaded externally. It is separate from the writable data memory; writing data address 0 does not replace instruction 0. The CPU repeatedly reads the current instruction, computes its effects, and selects the next instruction address. Fetch, decode, and execute are useful explanatory phases, not additional user controls the program must call.
+
+# Build and verify
+
+Construct and test Memory independently. Then test CPU with supplied instruction words and `inM` values so that errors in the memory wiring cannot hide CPU errors. Finally connect Computer and run complete programs.
+
+The official project provides CPU tests both with internal-register inspection and with externally observable outputs. A design need not expose every internal wire to satisfy the external CPU contract. For whole-computer tests, the supplied Add, Max, and Rect programs check arithmetic/storage, branching, and screen output respectively.
+
+Use several kinds of evidence: a correct final RAM value, correct PC changes, writes at the correct addresses, and preserved state where no write should happen. Test an A-instruction with low bits that would be dangerous if misdecoded. Test both taken and untaken jumps, the zero condition, negative ALU results, simultaneous destinations, and reset while a jump is requested.
+
+If a known-good program fails only on your constructed computer, trace the earliest incorrect hardware signal. An emulator with built-in CPU behavior is a useful reference, but running a program there does not by itself validate your HDL CPU.
+
+# Sources and next layer
+
+This chapter adapts [Nand2Tetris Project 5](https://www.nand2tetris.org/project05) and the public [Computer Architecture chapter](https://www.nand2tetris.org/_files/ugd/44046b_552ed0898d5d491aabafd8a768a87c6f.pdf), by Noam Nisan and Shimon Schocken. The [official project files](https://github.com/nand2tetris/projects/tree/main/05) provide Memory, CPU, and Computer contracts and tests. Adapted explanatory content retains CC BY-NC-SA 3.0; software fixtures retain their own license.
+
+The hardware now has an instruction language. [Build the assembler](/learn/reference/assembler) that translates its symbolic spelling into the machine words it consumes.
diff --git a/src/routes/learn/hardware/machine-language/intro.md b/src/routes/learn/hardware/machine-language/intro.md
new file mode 100644
index 0000000..969a089
--- /dev/null
+++ b/src/routes/learn/hardware/machine-language/intro.md
@@ -0,0 +1,128 @@
+---
+title: Tell the machine what to do
+updated: 2026-11-03
+---
+
+The same hardware can perform different jobs because instructions are data too: bit patterns stored in instruction memory. This layer introduces the Hack instruction set and uses it to control arithmetic, memory, the screen, and the keyboard.
+
+[Write machine-language programs](/learn/path/machine-language) or open the [computer and assembler](/tools/computer).
+
+# The programmer's view
+
+Hack works with 16-bit words. Its instruction memory and data memory have separate address spaces. Instruction address 20 and data address 20 name different locations.
+
+| Name | Meaning |
+| --- | --- |
+| A | A 16-bit register holding a value or an address |
+| D | A 16-bit register used for data and calculations |
+| M | The data-memory word at the address in A; not a third CPU register |
+| PC | The address of the instruction to execute next |
+
+Only the low 15 bits of A address memory. The A register's full 16-bit value can also participate in arithmetic. The program counter normally advances by one after an instruction, or changes to A's address when a jump is taken.
+
+Data memory contains ordinary RAM and memory-mapped devices. Instruction memory contains the program's machine words. Loading a new program into the tool is an external operation; it is not a Hack instruction.
+
+# The Hack instruction set
+
+There are two instruction forms. An **A-instruction** sets A to a nonnegative 15-bit value. A **C-instruction** tells the ALU what to compute, where to store the result, and whether to jump.
+
+In assembly, `@12` means A = 12. Its machine word is a leading 0 followed by the 15-bit binary representation of 12. A literal following `@` must be in 0–32767. There is no `@-1`; a negative value is formed with a computation.
+
+A C-instruction has the shape `dest=comp;jump`. The destination and its `=` can be omitted. The jump and its `;` can be omitted. The computation is required.
+
+| Assembly | Effect |
+| --- | --- |
+| `D=A` | Copy A's value into D |
+| `D=M` | Read the memory word addressed by A into D |
+| `M=D` | Store D in the memory word addressed by A |
+| `D=D+1` | Increment D with 16-bit wraparound |
+| `D;JGT` | Jump to A's address if D is strictly positive |
+| `0;JMP` | Jump to A's address unconditionally |
+
+The distinction between `D=A` and `D=M` is central: the first uses the address itself as data; the second follows the address to memory.
+
+These small operations express several addressing ideas. An immediate value is written directly in the instruction, as in `@12`. Direct access uses a known address before reading or writing M. Indirect access first obtains an address from stored data, puts that address into A, and then accesses M. An array element is the same idea with an address calculated from a base plus an index. Hack does not need a separate array instruction to support this pattern.
+
+# Computation codes
+
+A C-instruction is encoded as `111accccccdddjjj`. The seven `acccccc` bits select the computation. The `a` bit selects A or M as the ALU's second input; the other six bits control the ALU pipeline from the arithmetic layer.
+
+| comp | acccccc | comp using M | acccccc |
+| --- | --- | --- | --- |
+| `0` | `0101010` | — | — |
+| `1` | `0111111` | — | — |
+| `-1` | `0111010` | — | — |
+| `D` | `0001100` | — | — |
+| `A` | `0110000` | `M` | `1110000` |
+| `!D` | `0001101` | — | — |
+| `!A` | `0110001` | `!M` | `1110001` |
+| `-D` | `0001111` | — | — |
+| `-A` | `0110011` | `-M` | `1110011` |
+| `D+1` | `0011111` | — | — |
+| `A+1` | `0110111` | `M+1` | `1110111` |
+| `D-1` | `0001110` | — | — |
+| `A-1` | `0110010` | `M-1` | `1110010` |
+| `D+A` | `0000010` | `D+M` | `1000010` |
+| `D-A` | `0010011` | `D-M` | `1010011` |
+| `A-D` | `0000111` | `M-D` | `1000111` |
+| `D&A` | `0000000` | `D&M` | `1000000` |
+| `D\|A` | `0010101` | `D\|M` | `1010101` |
+
+Use the specified spellings. An assembler maps instructions, not general algebra: `D+M` is an instruction computation, while an expression such as `D+7` is not. Put a constant into A first, or use a sequence of instructions.
+
+# Destinations and jumps
+
+The destination field contains one bit each for A, D, and M, in that order. `000` stores nowhere; `001` stores in M; `010` stores in D; `100` stores in A. Set multiple bits to write the same result into multiple destinations. `AMD` therefore encodes as `111`. `MD` and `DM` name the same two destinations; the supplied project programs use both orders. Repeat no destination letter.
+
+The jump field tests the **current ALU result**, interpreted as a signed two's-complement value. There is no persistent condition-code register in Hack.
+
+| Jump | Bits | Condition on the result |
+| --- | --- | --- |
+| Omitted | `000` | Never jump |
+| JGT | `001` | Greater than zero |
+| JEQ | `010` | Equal to zero |
+| JGE | `011` | Greater than or equal to zero |
+| JLT | `100` | Less than zero |
+| JNE | `101` | Not equal to zero |
+| JLE | `110` | Less than or equal to zero |
+| JMP | `111` | Always jump |
+
+A subtraction followed by a sign test is useful when its result fits the signed range. It is not a universal signed comparison for arbitrary 16-bit inputs: overflow can reverse the sign. Keep each program's numeric assumptions explicit.
+
+Within a single instruction, memory access and a jump target use the **old A**. If the instruction also writes A, that new value takes effect for subsequent instructions. For example, `AM=D` writes D both into A and into memory at the address A held before the instruction. This is simultaneous clocked behavior, not a sequence of assignments evaluated left to right.
+
+# Symbols and control flow
+
+Assembly lets you give addresses names. `(LOOP)` declares a label for the next instruction; it does not occupy a ROM location. `@LOOP` loads that instruction address into A. A conditional jump can then choose between continuing and returning to the label.
+
+An undeclared symbolic name can identify a RAM variable. The assembler allocates variables from RAM address 16 upward. Symbols are case-sensitive: `count` and `Count` are different. A typo in a label reference may therefore become an unintended variable instead of a syntax error.
+
+Predefined names include `R0`–`R15` for RAM addresses 0–15; `SP`, `LCL`, `ARG`, `THIS`, and `THAT` for addresses 0–4; `SCREEN` for 16384; and `KBD` for 24576. The first five names become useful in the later virtual-machine layer, but their addresses are already part of the assembler's contract.
+
+Hack has no halt instruction. Programs often finish useful work by repeatedly jumping to a terminal label. Stopping the emulator is a tool action, distinct from a machine instruction. Likewise, a bounded run that reaches its step limit has paused; it has not proved that a program terminates.
+
+# Screen and keyboard
+
+The screen is 512 pixels wide and 256 pixels high. Its 8192 words occupy addresses 16384–24575. Each word describes 16 horizontal pixels, with bit 0 representing the leftmost pixel of that word. A set bit is black; a cleared bit is white.
+
+For row r and column c, the screen word address is `16384 + r × 32 + floor(c / 16)`, and the bit index is `c mod 16`. Writing all ones to a screen word makes sixteen pixels black. Writing zero clears those pixels. Check the row boundary: the word after a row's final sixteen pixels starts the next row.
+
+The keyboard register at address 24576 is read-only from the program's perspective. It holds zero when no key is pressed, or the code of the pressed key. Ordinary character keys use their character codes; special keys have defined Hack codes, including 128 for Enter and 130–133 for left, up, right, and down. A program reads the register; it does not receive a function callback or interrupt in this model.
+
+# Project 4: multiplication and screen control
+
+**Mult** computes R0 × R1 and stores the result in R2. The project assumes nonnegative inputs and a result below 32768. Plan a loop invariant: identify what your accumulated result and remaining counter mean after every iteration. Test either input equal to zero, one, several different positive values, and swapped operands. Do not assume an initial output value will already be zero.
+
+**Fill** repeatedly observes the keyboard. Holding any key long enough must eventually make the whole screen black; releasing all keys long enough must eventually make it white. This program runs continuously. Decide how a screen position advances, where the screen ends, and when to re-read the keyboard. The contract permits different drawing orders; it does not require the entire display to change in one machine cycle.
+
+Test Fill both by pressing and releasing keys and by checking screen memory after enough cycles. A single changed pixel is useful evidence during debugging, but it does not satisfy the complete-screen requirement. Ensure the write loop never overruns into KBD or an unmapped address.
+
+# Debug one instruction
+
+Before stepping, identify the current PC, A, D, and memory at A. Predict the computation, destination writes, and next PC. Step once and compare. Follow the first divergence, not just the final incorrect answer. A source line number is not necessarily a ROM address because blank lines, comments, and label declarations emit no instructions.
+
+# Sources and next layer
+
+This chapter adapts [Nand2Tetris Project 4](https://www.nand2tetris.org/project04) and its public [Machine Language chapter](https://www.nand2tetris.org/_files/ugd/44046b_d70026d8c1424487a451eaba3e372132.pdf), by Noam Nisan and Shimon Schocken. [Official project files](https://github.com/nand2tetris/projects/tree/main/04) contain Mult and Fill starter programs and tests. Adapted explanations retain CC BY-NC-SA 3.0; software fixtures retain their own license.
+
+Now that the instruction contract is clear, [construct the computer that executes it](/learn/reference/computer-architecture).
diff --git a/src/routes/learn/hardware/memory/intro.md b/src/routes/learn/hardware/memory/intro.md
new file mode 100644
index 0000000..f8862d8
--- /dev/null
+++ b/src/routes/learn/hardware/memory/intro.md
@@ -0,0 +1,94 @@
+---
+title: Give the machine a memory
+updated: 2026-11-03
+---
+
+A combinational circuit answers a question about its current inputs. A memory circuit can answer a different question: what value was stored earlier? State gives a machine a past, so it can count, follow a sequence, and keep the results of a program.
+
+[Build the memory layer](/learn/path/memory) or experiment with the clock in the [chip builder](/tools/chip-builder).
+
+# Separate now from next
+
+The primitive **DFF**, or data flip-flop, holds one bit. Over a complete clock cycle, the value supplied at its input becomes the next stored output. Between updates, changing the input does not change the stored output.
+
+For this educational model, the clock has two observable phases. **Tick** captures the next state from the current inputs and current stored state. **Tock** commits that captured state. Inspecting the output after tick still shows the old value; after tock it shows the newly committed value. A full cycle performs both phases. This convention is a simulation model, not a transistor-level account of every physical flip-flop.
+
+All stateful parts capture before any of them commit. If one register feeds another, a cycle moves the first register's old value into the second. It does not let a new value race through the whole chain in one cycle. This simultaneous update rule is essential when you connect a CPU's registers.
+
+The DFF is supplied as a primitive. Project 3 asks you to build the memory devices above it, not to construct the DFF itself from combinational gates.
+
+# Hold a bit, or load a bit
+
+A DFF always accepts the next input. A useful **Bit** chip adds a `load` control:
+
+| load | State after a completed cycle |
+| --- | --- |
+| 0 | Keep the previously stored bit |
+| 1 | Store `in` |
+
+The choice is between the incoming value and the old stored value. A feedback path through a state element is meaningful: it connects one time step to the next. A combinational loop with no storage is different; it may have no stable or unique value and is not a valid substitute for memory.
+
+A **Register** applies the same load decision to sixteen stored bits together. There is one shared `load`, not a separate instruction for each bit. Its interface is `in[16], load → out[16]`.
+
+# Address a word
+
+RAM is a collection of registers with an address. If a RAM has 8 words, a 3-bit address selects one of them. Each word still holds 16 bits: **address width and word width are different quantities**.
+
+Reading is combinational in this model: changing the address changes which stored word appears at `out`. Writing is clocked. With `load=1`, a completed cycle stores `in` at the selected address. With `load=0`, all words keep their values.
+
+A correct write changes only the selected word. A correct read does not modify memory. When testing, write distinct values into several addresses, revisit them in a different order, and confirm that the others survived.
+
+# Memory chip contracts
+
+| Chip | Word width | Words | Address width | Inputs in addition to address | Output |
+| --- | --- | --- | --- | --- | --- |
+| Bit | 1 | 1 | None | `in`, `load` | `out` |
+| Register | 16 | 1 | None | `in[16]`, `load` | `out[16]` |
+| RAM8 | 16 | 8 | 3 | `in[16]`, `load` | `out[16]` |
+| RAM64 | 16 | 64 | 6 | `in[16]`, `load` | `out[16]` |
+| RAM512 | 16 | 512 | 9 | `in[16]`, `load` | `out[16]` |
+| RAM4K | 16 | 4096 | 12 | `in[16]`, `load` | `out[16]` |
+| RAM16K | 16 | 16384 | 14 | `in[16]`, `load` | `out[16]` |
+
+Here K means 1024 words. RAM16K contains 16384 × 16 stored bits. It does not mean sixteen thousand one-bit locations.
+
+# Grow memory through hierarchy
+
+Larger RAMs combine smaller banks. Split an address into two pieces: high bits choose a bank, and low bits choose a word inside that bank. Route the write-enable signal to exactly one bank; select the corresponding bank's output for reads.
+
+For example, a six-bit address for RAM64 can select one of eight RAM8 banks using three bits, then one of eight words in that bank using the remaining three bits. The bank choice must agree for both reading and writing. Reversing the address groups may pass tests at address zero and still scramble most locations.
+
+Use a hierarchy to reason about the design, but do not mistake the logical picture for a requirement to allocate an enormous object graph in a simulator. A built-in memory chip with the same contract can represent a verified lower layer efficiently. When testing your own RAM64, however, the top-level chip under test must be your implementation, not a built-in substitute bearing the same name.
+
+# The program counter
+
+A **PC** is a 16-bit register that can hold, load, increment, or reset. Its input pins are `in[16]`, `load`, `inc`, and `reset`; its output is `out[16]`. Resolve competing controls in this strict order:
+
+| Highest active control | Next value |
+| --- | --- |
+| reset | 0 |
+| load | `in` |
+| inc | old `out` + 1, retaining 16 bits |
+| None | old `out` |
+
+Reset overrides load; load overrides increment. These are clocked state updates. Setting reset does not make the stored output change before the update. Incrementing 65535 wraps to zero. Later, the CPU uses the low 15 bits as the instruction-memory address.
+
+The PC gives control flow a simple physical meaning. Most instructions increment it. A taken jump loads a different address. Restarting a program resets it to zero.
+
+# A useful clock experiment
+
+Load the value 6 into a Register with `load=1`. Before a cycle its output is still the old value. Tick, inspect, then tock: the output becomes 6. Set `load=0`, change the input to 11, and complete another cycle. The output must remain 6. Finally, enable load and cycle again; it becomes 11.
+
+Repeat the same experiment with RAM, adding an address. Then test two addresses whose low bits match but high bits differ. This catches mistakes in bank selection that nearby addresses may not reveal.
+
+# Build and verify
+
+Construct Bit, Register, the RAM hierarchy, and PC. Test hold behavior as carefully as loading. Check first and last addresses, bank boundaries, several consecutive writes, and reads before and after each clock phase. PC tests must include simultaneous controls to establish precedence, not just one active control at a time.
+
+The official scripts interleave input changes, `tick`, `tock`, and recorded outputs. In the [chip builder](/tools/chip-builder), compile your design and open **Test scripts** to run a TST script with optional CMP expected output. Read the timing of each expected row before interpreting a failure: a value correct one half-cycle too early is still incorrect. Simulator initialization or a tool's “clear state” action is separate from a chip's specified input pins.
+
+# Sources and next layer
+
+This chapter adapts [Nand2Tetris Project 3](https://www.nand2tetris.org/project03) and the public [Memory chapter](https://www.nand2tetris.org/_files/ugd/44046b_1801b5682e4d4a67bd05e14235665d8b.pdf), by Noam Nisan and Shimon Schocken. [Official project files](https://github.com/nand2tetris/projects/tree/main/03) include clocked tests for every required construction. Explanatory adaptations retain CC BY-NC-SA 3.0; project software retains its own license.
+
+Now the machine can calculate and remember. [Machine language](/learn/reference/machine-language) specifies the instructions that will control those capabilities.
diff --git a/src/routes/learn/hardware/meta/what-next.md b/src/routes/learn/hardware/meta/what-next.md
index 4e8e83c..f8c5fa6 100644
--- a/src/routes/learn/hardware/meta/what-next.md
+++ b/src/routes/learn/hardware/meta/what-next.md
@@ -1,17 +1,37 @@
---
-title: What Next?
-updated: 2023-09-06
+title: Beyond the assembler
+updated: 2026-11-03
---
-Congratulations on making your way through the first chapter!
+The path now connects signals to an assembler: gates combine into arithmetic, clocked storage keeps state, a CPU follows instructions, and a translator turns symbolic programs into machine words.
-Unfortunately, this project is a free initiative and still very much a work in progress. More content should come soon! Until then, you can continue learning by following the existing content this project is based on.
+# Finish the hardware and assembler path
-Before you go, please consider:
+[Open the learning path](/learn/path) to continue through multi-bit logic, arithmetic, memory, machine language, computer architecture, and assembly translation. Each layer has a full explanation in this reference.
-- Giving us [feedback](https://github.com/durasj/chipsandcode/discussion) or [report a bug / request a feature](https://github.com/durasj/chipsandcode/issues).
-- Helping us by [contributing learning content or code](https://github.com/durasj/chipsandcode).
+Use the [chip builder](/tools/chip-builder) for multi-bit and clocked HDL experiments, including TST scripts and CMP comparisons. Use the [computer and assembler](/tools/computer) for instruction translation, execution, RAM, screen, and keyboard inspection. The [Boolean functions](/tools/boolean-functions) and [buses and routing](/tools/buses) tools let you explore behavior before constructing an implementation.
-# Continue Learning
+Keep the distinction between a working reference model and your own construction. Running a program on a built-in CPU demonstrates the program's behavior. Validating your HDL CPU requires running that construction against its contract. Similarly, translating a program with the supplied assembler is different from implementing and testing your own translator.
-This project was started as a reimagined [Nand2Tetris](https://nand2tetris.org/) (not affiliated or endorsed by them). You can continue on your journey by using their content. Unfortunately, it's not quite as convenient as you have to get a Java desktop application, but you will be hopefully fine. You just completed the first week of the content, so you have a solid head start. Let's hope we'll see you back soon!
+# The next software layers
+
+Nand2Tetris continues beyond Project 6:
+
+| Projects | Layer | What it adds |
+| --- | --- | --- |
+| 7–8 | Virtual machine | Stack arithmetic, memory segments, branches, function calls, and returns |
+| 9 | High-level programming | Programs written in Jack rather than assembly |
+| 10–11 | Compiler | Parsing Jack and generating executable VM code |
+| 12 | Operating-system services | Memory allocation, arithmetic helpers, strings, screen output, and keyboard input |
+
+The guided lessons stop at Project 6. You can already explore the later layers with the [VM emulator](/tools/vm), [Jack compiler](/tools/compiler), and [bitmap editor](/tools/bitmap). Compile Jack into VM code, open it in the emulator, or draw a sprite and inspect the code that puts it on screen. Follow the [official course](https://www.nand2tetris.org/course) for Projects 7–12 and their construction assignments.
+
+# Take your work further
+
+Use the [official project files](https://github.com/nand2tetris/projects) and [online tools](https://www.nand2tetris.org/software) to compare your work with the course's contracts. The official tests make projects portable; a visual success in one interface is not a replacement for checking the required behavior.
+
+Chips and Code is independent and is not affiliated with or endorsed by Nand2Tetris. The curriculum draws on work by Noam Nisan and Shimon Schocken. Adapted explanations retain [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/); imported software assets retain their source licenses. The authors ask learners not to publish completed exercise solutions, preserving the construction challenge for others.
+
+# Help improve this project
+
+[Report a problem](https://github.com/durasj/chipsandcode/issues), [join the discussion](https://github.com/durasj/chipsandcode/discussions), or [contribute](https://github.com/durasj/chipsandcode). Include the smallest example that shows the problem and the behavior you expected. For a learning issue, describe the first concept or control that became unclear.
diff --git a/src/routes/learn/path/+page.svelte b/src/routes/learn/path/+page.svelte
new file mode 100644
index 0000000..0e87541
--- /dev/null
+++ b/src/routes/learn/path/+page.svelte
@@ -0,0 +1,5 @@
+
+
+
diff --git a/src/routes/learn/path/[chapter]/+page.svelte b/src/routes/learn/path/[chapter]/+page.svelte
new file mode 100644
index 0000000..5f00ccb
--- /dev/null
+++ b/src/routes/learn/path/[chapter]/+page.svelte
@@ -0,0 +1,12 @@
+
+
+{#if chapter}{#key chapter.id} {/key}{:else}
+ Chapter not found
+ Return to the computer path
+ {/if}
diff --git a/src/routes/learn/reference/[...path]/+page.svelte b/src/routes/learn/reference/[...path]/+page.svelte
new file mode 100644
index 0000000..c7c8d8e
--- /dev/null
+++ b/src/routes/learn/reference/[...path]/+page.svelte
@@ -0,0 +1,382 @@
+
+
+
+ {data.title} — Chips and Code
+
+
+
+
+
+
+
+
+ In this explanation
+
+ {#each data.headings as heading (heading.id)}
+ {heading.title}
+ {/each}
+
+
+
+
+
+
+
+
+
+
+ Adapted from the Chips and Code learning material by Jan Duras, based on
+ Nand2Tetris by Noam Nisan and Shimon Schocken.
+ Learning content:
+ CC BY-NC-SA 3.0 . Chips and Code
+ is not affiliated with or endorsed by Nand2Tetris.
+
+
+
+
diff --git a/src/routes/learn/reference/[...path]/+page.ts b/src/routes/learn/reference/[...path]/+page.ts
new file mode 100644
index 0000000..d0a20d1
--- /dev/null
+++ b/src/routes/learn/reference/[...path]/+page.ts
@@ -0,0 +1,70 @@
+import { error } from '@sveltejs/kit';
+import type { RenderableTreeNode, Tag } from '@markdoc/markdoc';
+import type { Content } from '#lib/content/types.js';
+import { referencePages } from '#lib/learning/reference.js';
+import type { PageLoad } from './$types';
+
+export const prerender = 'auto';
+
+const modules = import.meta.glob('../../hardware/**/*.md');
+
+function isTag(node: RenderableTreeNode): node is Tag {
+ return (
+ !!node &&
+ typeof node === 'object' &&
+ !Array.isArray(node) &&
+ typeof node.name === 'string' &&
+ Array.isArray(node.children) &&
+ !!node.attributes &&
+ typeof node.attributes === 'object'
+ );
+}
+
+function textOf(node: RenderableTreeNode): string {
+ if (Array.isArray(node)) return node.map(textOf).join('');
+ if (isTag(node)) return node.children.map(textOf).join('');
+ return typeof node === 'string' || typeof node === 'number' ? String(node) : '';
+}
+
+export const load = (async ({ params }) => {
+ const requested = (params.path || 'boolean-logic').replace(/\/$/, '');
+ const pageIndex = referencePages.findIndex(
+ (page) => page.path === requested || page.source === requested,
+ );
+ if (pageIndex < 0) error(404, 'This explanation was not found.');
+ const current = referencePages[pageIndex];
+ const importer = modules[`../../hardware/${current.source}.md`];
+ if (!importer) error(404, 'This explanation was not found.');
+ const module = (await importer()) as { default: Content };
+ const headings: { id: string; title: string }[] = [];
+ const usedIds = new Map();
+
+ function withAnchors(node: RenderableTreeNode): RenderableTreeNode {
+ if (Array.isArray(node)) return node.map(withAnchors) as unknown as RenderableTreeNode;
+ if (!isTag(node)) return node;
+ const children = node.children.map(withAnchors);
+ if (node.name === 'h2' || node.name === 'h3') {
+ const title = textOf(node);
+ const slug = title
+ .toLowerCase()
+ .replace(/[^a-z0-9]+/g, '-')
+ .replace(/^-|-$/g, '');
+ const occurrence = usedIds.get(slug) ?? 0;
+ usedIds.set(slug, occurrence + 1);
+ const id = occurrence ? `${slug}-${occurrence + 1}` : slug;
+ if (node.name === 'h2') headings.push({ id, title });
+ return { ...node, attributes: { ...node.attributes, id }, children } as Tag;
+ }
+ return { ...node, children } as Tag;
+ }
+
+ const content = withAnchors(module.default.content) as Tag;
+ return {
+ title: current.title,
+ current,
+ headings,
+ content: content.children,
+ previous: referencePages[pageIndex - 1] ?? null,
+ next: referencePages[pageIndex + 1] ?? null,
+ };
+}) satisfies PageLoad;
diff --git a/src/routes/signin/+page.svelte b/src/routes/signin/+page.svelte
index 112984f..b31dda8 100644
--- a/src/routes/signin/+page.svelte
+++ b/src/routes/signin/+page.svelte
@@ -1,22 +1 @@
-
-
-
- Chips and Code: Sign In
-
-
-
-
-
-
- Hi, Anonym 👋
-
- Currently, all session are anonymous. You are able to edit your content from the same device.
- Content opened on other devices by you or others is read-only. The ability to sign in will come
- soon. Stay tuned!
-
-
-
-
+
diff --git a/src/routes/signin/+page.ts b/src/routes/signin/+page.ts
new file mode 100644
index 0000000..3acf864
--- /dev/null
+++ b/src/routes/signin/+page.ts
@@ -0,0 +1,2 @@
+import { redirect } from '@sveltejs/kit';
+export const load = () => redirect(308, '/about#device-storage');
diff --git a/src/routes/tools/+page.svelte b/src/routes/tools/+page.svelte
new file mode 100644
index 0000000..93683d6
--- /dev/null
+++ b/src/routes/tools/+page.svelte
@@ -0,0 +1,245 @@
+
+
+
+ Tools — Chips and Code
+
+
+
+
+
+
+
+ Start with the basics in Learn . Each tool is here when you need
+ it.
+
+
+
+
diff --git a/src/routes/tools/bitmap/+page.svelte b/src/routes/tools/bitmap/+page.svelte
new file mode 100644
index 0000000..97b9ea8
--- /dev/null
+++ b/src/routes/tools/bitmap/+page.svelte
@@ -0,0 +1,360 @@
+
+
+Bitmap editor · Tools · Chips and Code
+
+ ← Tools
+
+
+ {
+ pixels = pixels.map(() => false);
+ save();
+ }}>Clear {
+ pixels = pixels.map((value) => !value);
+ save();
+ }}>Invert Pixel sizeSmall Medium Large
+
+
+ {#if error}{error}
{/if}{#if notice}
+ {notice}
+
{/if}
+
+
+
+
diff --git a/src/routes/tools/boolean-functions/+page.svelte b/src/routes/tools/boolean-functions/+page.svelte
new file mode 100644
index 0000000..0399d2a
--- /dev/null
+++ b/src/routes/tools/boolean-functions/+page.svelte
@@ -0,0 +1,260 @@
+
+
+
+ Boolean functions · Tools · Chips and Code
+
+
+
+
+ ← Tools
+
+
+
+
Function
+ choose(Number(event.currentTarget.value))}
+ >
+ {#each booleanFunctions as name, index}{name} {/each}
+
+
+
{functionSignature(mask)} · {booleanFunctions[mask]}
+
+
+
+
+ Define the output
+
+ All four input combinations. Select an output to change it.
+ a b out
+
+ {#each inputRows as [x, y], index}
+
+ {Number(x)} {Number(y)}
+ choose(toggleFunctionRow(mask, index))}
+ >{Number(evaluateFunction(mask, x, y))}
+
+ {/each}
+
+
+ Four independent 0-or-1 answers give 2⁴ = 16 possible functions.
+
+
+
+
+ Try its inputs
+
+
+ (a = !a)}>a {' '}{Number(a)}
+ (b = !b)}>b {' '}{Number(b)}
+
+
+
+ out {Number(output)}
+
+
+ The highlighted table row is the input you are testing.
+
+
+ The same function, as an expression
+
+ Take each row whose output is 1. AND its input values together, then OR those terms.
+
+ f = {expression}
+
+
+
+
+
+ NAND construction
+
+ NOT, AND, and OR can each be built from NAND. Applying those transformations to this
+ expression gives the construction below. It is systematic, not necessarily the smallest
+ circuit.
+
+
+ {verified ? '4 of 4 input combinations match.' : 'Construction mismatch.'}
+ {construction.gates.length} NAND gates.
+
+ Copy HDL
+ {copyState}
+
+
+ {source}
+
+ This is real single-bit HDL. Paste it into the hardware simulator to inspect or test it there.
+
+
+
+
+ Compare functions
+ Two functions are equivalent only if every input combination produces the same output.
+ Compare with
+
+ {#each booleanFunctions as name, index}{name} {/each}
+
+
+
+ {#if differences.length === 0}Equivalent: all 4 input combinations match.
+ {:else}{differences.length} of 4 input combinations differ: {differences
+ .map(([x, y]) => `a=${Number(x)}, b=${Number(y)}`)
+ .join('; ')}.{/if}
+
+
+
+
+
+
+
diff --git a/src/routes/tools/buses/+page.svelte b/src/routes/tools/buses/+page.svelte
new file mode 100644
index 0000000..f9039b1
--- /dev/null
+++ b/src/routes/tools/buses/+page.svelte
@@ -0,0 +1,490 @@
+
+
+
+ Buses and routing · Tools · Chips and Code
+
+
+
+
+ ← Tools
+
+
+
+
Component
+ chooseComponent(event.currentTarget.value as BusComponent)}
+ >
+ {#each busComponents as entry}{entry.name} {/each}
+
+
+
+ {isDemux ? '1-bit routing' : component === 'or8way' ? '8 inputs → 1 output' : '16-bit words'}
+
+
+ {info.description}
+
+
+
+
+
+
+
{isDemux ? 'Output paths' : 'Output'}
+ {info.name}
+
+ {#if outputs}
+ {#if isDemux}
+
+ Only output {selectedName} receives the input. All other outputs are 0.
+ Output Path Value
+ {#each Object.entries(outputs) as [name, value]}
+ {name} {name === selectedName ? 'selected' : '—'} {value}
+ {/each}
+
+
+ Input {Number(signal)} → output {selectedName}: {outputs[selectedName]}
+
+ {:else}
+ {outputs.out}
+ {#if outputWidth === 16}
+ 0x{outputs.out.toString(16).toUpperCase().padStart(4, '0')}
+
{/if}
+
+ {#each binaryWord(outputs.out, outputWidth).split('') as bit, index}{outputWidth - 1 - index} {bit} {/each}
+
+ {#if isMux}
+ Input {selectedName} → out. Every bit travels together.
+
+ {:else if component === 'or8way'}
+ {outputs.out ? 'At least one input bit is 1.' : 'All eight input bits are 0.'}
+
+ {:else}
+ The same {component === 'not16' ? 'NOT' : component === 'and16' ? 'AND' : 'OR'} operation
+ at each of 16 positions.
+
{/if}
+ {/if}
+ {:else}
+
+
—
+
Enter valid inputs to see the output.
+
+ {/if}
+
+ {#if isMux}
+
+ Available input words
+ Input Decimal Path
+ {#each names as name, index}{name} {parsed[name].value ?? 'invalid'} {selector === index ? '→ out' : '—'} {/each}
+
+ {/if}
+
+
+
+
+ How this component is built
+ {#if component === 'not16' || component === 'and16' || component === 'or16'}
+
+ Place 16 copies of a single-bit {component === 'not16'
+ ? 'NOT'
+ : component === 'and16'
+ ? 'AND'
+ : 'OR'} gate side by side. Each copy handles one bit position. There is no carry between positions:
+ this is bitwise logic, not arithmetic.
+
+ {:else if component === 'or8way'}
+
+ Combine pairs with OR, then combine their results until one bit remains. A tree of seven
+ two-input OR gates can combine eight inputs.
+
+ {:else if isMux}
+
+ A Mux16 uses 16 single-bit Mux gates controlled by the same selector. Larger multiplexors
+ form a tree: {component === 'mux8way16'
+ ? 'seven Mux16 chips select among eight input words'
+ : component === 'mux4way16'
+ ? 'three Mux16 chips select among four input words'
+ : 'one selector chooses the entire a or b word'}. The selector is an unsigned binary
+ index: zero selects a.
+
+ {:else}
+
+ Route the signal through a tree of single-bit DMux gates. A {choices}-way demultiplexor
+ needs {choices - 1} two-way DMux gates. The selected path receives the input; every other output
+ stays at 0, even when the selected input is 1.
+
+ {/if}
+
+ These models let you explore the bus contracts directly. Build these contracts in HDL in the chip workshop , or follow the guided construction path .
+
+
+
+
+
+
+
diff --git a/src/routes/tools/chip-builder/+page.svelte b/src/routes/tools/chip-builder/+page.svelte
new file mode 100644
index 0000000..a8a86ae
--- /dev/null
+++ b/src/routes/tools/chip-builder/+page.svelte
@@ -0,0 +1,464 @@
+
+
+Chip builder · Tools · Chips and Code
+
+ ← Tools
+
+
+ ViewSplit Visual Code Compile {phase === 'low' ? 'Tick' : 'Tock'} Reset
+
+ {#if error}{error}
{/if}
+ {status}
+
+ {#if mode !== 'visual'}
+ Circuit definition
+ Chip HDL
+
+ Bus bit 0 is the least significant bit. Connect slices with in[0..7].
+
+
+ Inspect a supplied component
+
+ Each probe wraps one supplied component. Replace its parts to build your own design.
+
+
+ loadExample('inverter')}>16-bit inverter loadExample('arithmetic')}>ALU loadExample('register')}>Register loadExample('computer')}>Computer
+
+
+
+ Your chip dependencies{dependencies.length ? ` · ${dependencies.length}` : ''}
+
+ Give each custom chip its own HDL definition. Its name can then be used as a part above.
+
+ {#each dependencies as dependency, index (dependency.id)}
+ Custom chip {index + 1} removeDependency(dependency.id)}
+ >Remove custom chip {index + 1}
+
{/each}
+ Add custom chip
+
+ {/if}
+ {#if mode !== 'code'}
+ Live signals
+ {#if circuit}
+
+ Clock {phase} {cycles} manual cycles
+
+ {#if Object.keys(inputWidths).length}Inputs
+ {#each Object.entries(inputWidths) as [name, width] (name)}
+ Input {name} {
+ inputValues[name] = event.currentTarget.value;
+ evaluate();
+ }}
+ aria-label={`Input ${name}`}
+ aria-describedby={`pin-width-${name}`}
+ />
+ {width} {width === 1 ? 'bit' : 'bits'}
+
{/each}{:else}This circuit has no external inputs.
{/if}
+ Outputs
+ {#if Object.keys(outputWidths).length}
+ {#each Object.entries(outputWidths) as [name, width] (name)}
+
{name} · {width} {width === 1 ? 'bit' : 'bits'}
+ {outputs[name] ?? '—'}
+ {#if outputs[name] !== undefined}{outputs[name].toString(2).padStart(width, '0')} {/if}
+ {/each}
+ {:else}
+ This circuit has no external output pins. Use a CPU or Memory probe to expose internal
+ behavior, or run a complete program in the computer tool .
+
{/if}
+
+ Combinational outputs follow input changes. Stored values become visible at tock.
+
+ {:else}Compile your circuit to reveal its pins.
{/if}
+ {/if}
+
+ {#key circuit} {
+ if (circuit) {
+ outputs = { ...circuit.outputs };
+ phase = circuit.phase === 'tick' ? 'high' : 'low';
+ if (inspectingMemory) inspectMemory();
+ }
+ }}
+ />{/key}
+
+ ROM and keyboard
+
+ For circuits containing ROM32K, Keyboard, or Computer. These controls supply the program and
+ keyboard memory value.
+
+
+ Program formatHack assembly Binary .hack Load ROM
+
+ ROM program
+
+ Keyboard code Set keyboard
+
+ {#if peripheralError}{peripheralError}
{/if}
+ Inspect your computer's memory
+
+ Read the memory inside your compiled circuit. Once selected, this word updates as you advance
+ its clock.
+
+
+ Memory address {
+ inspectingMemory = false;
+ memoryValue = null;
+ }}
+ /> Inspect memory
+
+
+ Memory word: {memoryValue ?? '—'}
+
+ {#if memoryError}{memoryError}
{/if}
+
+ {#if notice}{notice}
{/if}
+
+
+
+
diff --git a/src/routes/tools/compiler/+page.svelte b/src/routes/tools/compiler/+page.svelte
new file mode 100644
index 0000000..b3716d3
--- /dev/null
+++ b/src/routes/tools/compiler/+page.svelte
@@ -0,0 +1,153 @@
+
+
+Jack compiler · Tools · Chips and Code
+
+ ← Tools
+
+
+ ViewSource & output Source Output Compile Jack Open in VM emulator
+
+ {status}
+ {#if diagnostics.length}
+
Compilation errors
+
+ {#each diagnostics as issue, index (index)}
+ {issue.file}{issue.line ? `:${issue.line}:${issue.column}` : ''} — {issue.message}
+ {/each}
+
+
{/if}
+
+ {#if mode !== 'output'}
{/if}{#if mode !== 'source'}
+
+ VM output file{#each Object.keys(output) as name (name)}{name} {/each}
+
+ Generated VM Download selected .vm file
+
+ The compiler handles classes, methods, constructors, arrays, strings, expressions, and
+ control flow. Runtime services are supplied by the VM emulator.
+
+ {/if}
+
+ {#if notice}{notice}
{/if}
+
+
diff --git a/src/routes/tools/computer/+page.svelte b/src/routes/tools/computer/+page.svelte
new file mode 100644
index 0000000..f0c040c
--- /dev/null
+++ b/src/routes/tools/computer/+page.svelte
@@ -0,0 +1,448 @@
+
+
+Computer & assembler · Tools · Chips and Code
+
+ ← Tools
+
+
+ ViewSplit Visual Code
+ Assemble & load
+ Step
+ {#if running}Pause {:else}Run {/if}
+ Reset
+
+ {#if error}{error}
{/if}
+ {message}
+
+ {#if mode !== 'visual'}
+
+
Program
+ Source formatHack assembly Binary .hack
+
+ Program source
+
+ Assembly symbols are case-sensitive. Machine words have exactly 16 binary digits.
+
+
+ Small examples
+
+ These demonstrations write a value or a screen word. Your course projects build larger
+ programs.
+
+
+ loadDemo('value')}>Write a value loadDemo('pixels')}>Light 16 pixels
+
+
+ {#if words.length}
+ Machine code · {words.length} instructions
+
+ The highlighted address is next. Source line numbers refer to your assembly text.
+
+
+
+ Download .hack
+ {/if}
+ {#if Object.keys(symbols).length}
+ Symbol table
+
+ Labels resolve to ROM addresses. Variables start at RAM address 16.
+ {/if}
+ {/if}
+ {#if mode !== 'code'}
{/if}
+
+ {#if notice}{notice}
{/if}
+
+
diff --git a/src/routes/tools/hardware-simulator/+page.svelte b/src/routes/tools/hardware-simulator/+page.svelte
new file mode 100644
index 0000000..aa1ba18
--- /dev/null
+++ b/src/routes/tools/hardware-simulator/+page.svelte
@@ -0,0 +1,54 @@
+
+
+Hardware simulator — Chips and Code
+
+
+
+
+
+
diff --git a/src/routes/tools/hardware-simulator/[id]/+page.svelte b/src/routes/tools/hardware-simulator/[id]/+page.svelte
new file mode 100644
index 0000000..6e3cc28
--- /dev/null
+++ b/src/routes/tools/hardware-simulator/[id]/+page.svelte
@@ -0,0 +1,91 @@
+
+
+Hardware simulator — Chips and Code
+
+
+ {#key data.id}
+ {#await experiment}
+ Loading experiment…
+ {:then loaded}
+
+ {:catch cause}
+
+
This experiment could not be opened.
+
{cause instanceof Error ? cause.message : 'The link may be unavailable.'}
+
Start a new experiment →
+
+ {/await}
+ {/key}
+
+
+
diff --git a/src/routes/tools/hardware-simulator/[id]/+page.ts b/src/routes/tools/hardware-simulator/[id]/+page.ts
new file mode 100644
index 0000000..4d14c33
--- /dev/null
+++ b/src/routes/tools/hardware-simulator/[id]/+page.ts
@@ -0,0 +1,4 @@
+import type { PageLoad } from './$types';
+export const load = (async ({ params }) => ({ id: params.id })) satisfies PageLoad;
+export const prerender = false;
+export const ssr = false;
diff --git a/src/routes/tools/vm/+page.svelte b/src/routes/tools/vm/+page.svelte
new file mode 100644
index 0000000..64fa75d
--- /dev/null
+++ b/src/routes/tools/vm/+page.svelte
@@ -0,0 +1,357 @@
+
+
+VM emulator · Tools · Chips and Code
+
+ ← Tools
+
+
+ ViewSplit Visual Code Load program Step {#if running} {
+ pause();
+ status = 'Paused.';
+ }}>Pause {:else}Run {/if}Reset
+
+ {#if error}{error}
{/if}
+ {status}
+
+ {#if mode !== 'visual'}
+
+
+ Supports arithmetic, memory segments, branching, functions, calls, and return. Native Jack
+ OS services are available.
+
+ {/if}
+ {#if mode !== 'code'}
+ Stack
+
+ {current ? `${current.file}:${current.line} · ${current.command}` : 'No next command.'}
+
+ {cycles} commands executed. The most recent stack value is last.
+
+ {#if stack.length}{#each stack.slice(-16) as word, index (index)}
+ {segments.SP - Math.min(16, stack.length) + index} {word}
+
{/each}{:else}
The stack is empty.
{/if}
+
+
+
+ Keyboard
+
+
+ Segments and calls
+
+ {#each Object.entries(segments) as [name, value] (name)}
+
{name}
+ {value}
+ {/each}
+
+ Call stack
+ {#if calls.length}
+ {#each calls as call, index (index)}{call} {/each}
+ {:else}No active function calls.
{/if}
+
+
+ Inspect memory
+
+ Memory address (memoryValue = null)}
+ /> Read memory
+
+
+ Value: {memoryValue ?? '—'}
+
+ Use an address from 0 to 24576.
+
+ {/if}
+
+ {#if notice}{notice}
{/if}
+
+
+
+
diff --git a/src/stores.ts b/src/stores.ts
index 8bb4e46..31b872f 100644
--- a/src/stores.ts
+++ b/src/stores.ts
@@ -1,12 +1,5 @@
import { writable } from 'svelte/store';
-let defaultTheme: 'dark' | 'light' = 'light';
-if (typeof window !== 'undefined') {
- defaultTheme = window.localStorage?.getItem('theme') as 'dark' | 'light';
- // We should not dynamically adapt the theme once explicit choice is made
- if (!defaultTheme) {
- const prefersDark = window.matchMedia?.('(prefers-color-scheme: dark)').matches;
- defaultTheme = prefersDark ? 'dark' : 'light';
- }
-}
-export const theme = writable<'light' | 'dark'>(defaultTheme);
+// One coherent canvas for learning, tools, and reading. Individual narrative
+// sections may use a light surface with their own explicit high-contrast ink.
+export const theme = writable<'light' | 'dark'>('dark');
diff --git a/static/media/computer-intro-poster.jpg b/static/media/computer-intro-poster.jpg
new file mode 100644
index 0000000..2f2cc8f
Binary files /dev/null and b/static/media/computer-intro-poster.jpg differ
diff --git a/static/media/computer-intro-timing.json b/static/media/computer-intro-timing.json
new file mode 100644
index 0000000..2e00391
--- /dev/null
+++ b/static/media/computer-intro-timing.json
@@ -0,0 +1,67 @@
+{
+ "title": "Chips and Code \u2014 from signal to software",
+ "duration": 48.0,
+ "fps": 30,
+ "width": 1280,
+ "height": 720,
+ "audio_status": "silent-master-awaiting-narration",
+ "voice_direction": "Natural, clear English. Calm, precise, curious. About 110 words per minute. No theatrical emphasis. Leave breathing room between layers.",
+ "segments": [
+ {
+ "start": 0.0,
+ "end": 4.8,
+ "layer": "signals",
+ "title": "Two states.",
+ "narration": "Every computer begins with two states. Zero and one."
+ },
+ {
+ "start": 4.8,
+ "end": 12.2,
+ "layer": "logic",
+ "title": "Signals become logic.",
+ "narration": "Connect those signals through logic gates, and simple rules become useful behavior."
+ },
+ {
+ "start": 12.2,
+ "end": 20.2,
+ "layer": "arithmetic",
+ "title": "Logic becomes arithmetic.",
+ "narration": "Combine gates into arithmetic. Bits become numbers, and circuits add, compare, and calculate."
+ },
+ {
+ "start": 20.2,
+ "end": 28.2,
+ "layer": "memory",
+ "title": "A value can stay.",
+ "narration": "Add memory, and the machine can keep its state. A value survives beyond a single moment."
+ },
+ {
+ "start": 28.2,
+ "end": 36.2,
+ "layer": "architecture",
+ "title": "A computer takes shape.",
+ "narration": "Bring calculation, memory, and control together. Instructions now move through a complete computer."
+ },
+ {
+ "start": 36.2,
+ "end": 43.4,
+ "layer": "software",
+ "title": "Signals become software.",
+ "narration": "Software builds on all of it. Every line of code connects back to the machine beneath."
+ },
+ {
+ "start": 43.4,
+ "end": 48.0,
+ "layer": "closing",
+ "title": "Chips and Code",
+ "narration": "Start with logic. Build from the ground up."
+ }
+ ],
+ "visual_accuracy": {
+ "logic": "All four NAND input cases; out = NOT(a AND b).",
+ "arithmetic": "Four-bit addition:0011 +0001 =0100.",
+ "memory": "Eight-bit register loads10110100 on a rising edge, then holds it.",
+ "architecture": "Conceptual fetch/decode/execute/write-back: D=D+A with D=3,A=1 produces D=4.",
+ "software": "Conceptual high-level add(3,1) returns4; this software layer is a roadmap, not a current programming exercise."
+ }
+}
diff --git a/static/media/computer-intro-transcript.txt b/static/media/computer-intro-transcript.txt
new file mode 100644
index 0000000..5d7fb60
--- /dev/null
+++ b/static/media/computer-intro-transcript.txt
@@ -0,0 +1,15 @@
+Chips and Code — from signal to software
+
+Every computer begins with two states. Zero and one.
+
+Connect those signals through logic gates, and simple rules become useful behavior.
+
+Combine gates into arithmetic. Bits become numbers, and circuits add, compare, and calculate.
+
+Add memory, and the machine can keep its state. A value survives beyond a single moment.
+
+Bring calculation, memory, and control together. Instructions now move through a complete computer.
+
+Software builds on all of it. Every line of code connects back to the machine beneath.
+
+Start with logic. Build from the ground up.
diff --git a/static/media/computer-intro.mp4 b/static/media/computer-intro.mp4
new file mode 100644
index 0000000..f04466f
Binary files /dev/null and b/static/media/computer-intro.mp4 differ
diff --git a/static/media/computer-intro.vtt b/static/media/computer-intro.vtt
new file mode 100644
index 0000000..5c03c5b
--- /dev/null
+++ b/static/media/computer-intro.vtt
@@ -0,0 +1,30 @@
+WEBVTT
+
+1
+00:00:00.150 --> 00:00:04.700 line:88% position:50% size:85% align:center
+Every computer begins with two states. Zero and one.
+
+2
+00:00:04.950 --> 00:00:12.100 line:88% position:50% size:85% align:center
+Connect those signals through logic gates, and simple rules become useful behavior.
+
+3
+00:00:12.350 --> 00:00:20.100 line:88% position:50% size:85% align:center
+Combine gates into arithmetic. Bits become numbers, and circuits add, compare, and calculate.
+
+4
+00:00:20.350 --> 00:00:28.100 line:88% position:50% size:85% align:center
+Add memory, and the machine can keep its state. A value survives beyond a single moment.
+
+5
+00:00:28.350 --> 00:00:36.100 line:88% position:50% size:85% align:center
+Bring calculation, memory, and control together. Instructions now move through a complete computer.
+
+6
+00:00:36.350 --> 00:00:43.300 line:88% position:50% size:85% align:center
+Software builds on all of it. Every line of code connects back to the machine beneath.
+
+7
+00:00:43.550 --> 00:00:47.900 line:88% position:50% size:85% align:center
+Start with logic. Build from the ground up.
+
diff --git a/vite.config.js b/vite.config.js
index 256e893..0bb1daf 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -24,10 +24,15 @@ const config = defineConfig(() => {
contentPlugin(),
withPwa(
{
- adapter: adapter({ runtime: 'nodejs24.x' }),
+ adapter: adapter({ runtime: 'nodejs26.x' }),
preprocess: vitePreprocess({ script: true }),
prerender: {
- entries: ['*', '/learn/hardware/boolean-logic'],
+ entries: [
+ '*',
+ '/learn/reference',
+ '/learn/reference/boolean-logic',
+ '/learn/hardware/boolean-logic',
+ ],
},
serviceWorker: { register: false },
},
@@ -79,7 +84,12 @@ const config = defineConfig(() => {
coverage: {
provider: 'v8',
include: ['src/lib/**/*.ts'],
- exclude: ['src/lib/**/*.d.ts', 'src/lib/**/testing/**', 'src/lib/editor/index.ts'],
+ exclude: [
+ 'src/lib/**/*.d.ts',
+ 'src/lib/**/testing/**',
+ 'src/lib/editor/index.ts',
+ 'src/lib/software/vendor/**',
+ ],
thresholds: { lines: 90, functions: 90, branches: 90, statements: 90 },
},
},