diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index c93e6ac..421cac0 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -48,7 +48,7 @@ jobs: start: npm run preview -- --host 127.0.0.1 wait-on: http://127.0.0.1:4173 - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 - if: failure() + if: always() with: name: cypress-screenshots path: | diff --git a/.nvmrc b/.nvmrc index a45fd52..6f4247a 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -24 +26 diff --git a/README.md b/README.md index c6486f5..06b51a5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@

Chips and Code

- Wondering how computers work? Find out by embarking on the journey of building your own computer from scratch, from chips to code. No prerequisites and for free from the browser. + Wondering how computers work? Build your own computer from scratch, from chips to code. Free in your browser, with no prerequisites.
Visit »

@@ -20,9 +20,26 @@ ## Features - +### Break down the magic of computers + +The homepage is a native-scroll visual journey: a complete computer separates into its screen, board, memory, and processor, then the view moves inside the chip to binary signals. Mobile and reduced-motion layouts show the same sequence without requiring animation. The original chip/code mark and indigo branding remain. + +One shared navigation—**Learn, Tools, About**—covers the entire site. Old simulator and reading URLs redirect to the new interface, preserving saved experiment IDs and bookmarks. No legacy course or IDE chrome is exposed. + +**Learn** starts with one signal, introduces NOT and AND through observation, then explains NAND and why it is a useful primitive. Six construction exercises follow: NOT, AND, OR, XOR, Mux, and DMux. Visual, Code, and Split share the actual HDL parser and simulator. Wiring guidance, exhaustive tests, recoverable drafts, and optional theory support the same progression. Progress and learning drafts remain on the current device. + +Short reference entries link to complete, corrected explanations in the same visual style. All existing Boolean logic material is covered: functions and canonical expressions, gate composition, HDL and testing, 16-bit buses, multi-way routing, and design tradeoffs. Sources and CC BY-NC-SA attribution remain visible. + +**Tools** contains three working workspaces: + +- **Hardware simulator:** Monaco HDL and test editing, signal inspection, expected/actual output, examples, local drafts, saved experiment links, and ZIP export. +- **Boolean functions:** all sixteen two-input functions, editable truth tables, canonical expressions, equivalence checks, and NAND-only HDL. Every generated function is tested through the existing parser and simulator. +- **Buses & routing:** Not16, And16, Or16, Mux16, Or8Way, Mux4Way16, Mux8Way16, DMux4Way, and DMux8Way, with validated inputs, selectors, and live outputs. These are dedicated logic models; the general HDL simulator does not yet support bus construction. + +The existing material ends at Boolean logic. Arithmetic, clocked memory, processors, assembly, and higher-level software remain future layers. A separate optional 48-second introductory film has captions and a transcript; its current master is silent. See [intro production](docs/intro-production.md). + +See the [interaction design](docs/computer-layers-design.md), [art direction](docs/art-direction.md), and [content audit](docs/content-audit.md) for behavior, source coverage, and boundaries. -Currently contains and fully supports the first week of Nand2Tetris. Can work offline and supports installation as a PWA. No cloud dependency for the basic functionality. @@ -64,14 +81,14 @@ Major features, ordered by priority: ## Developing -Use Node.js 24 (`nvm use`) and install the locked dependencies: +Use Node.js 26 (`nvm use`) and install the locked dependencies: ```bash npm ci npm run dev ``` -The app uses Svelte 5, SvelteKit 3, Vite 8, and TypeScript 6 (the current version supported by SvelteKit and svelte-check). The editor uses Monaco 0.57. UI menus and tabs use Bits UI. Tailwind 3 and daisyUI 3 retain the existing presentation during this infrastructure migration; redesigning the styling system is a separate step. +The app uses Svelte 5, SvelteKit 3, Vite 8, and TypeScript 6 (the current version supported by SvelteKit and svelte-check). The editor uses Monaco 0.57. UI menus and tabs use Bits UI. Tailwind 3 and daisyUI 3 support the existing course and IDE pages. The shared shell, narrative landing, learning workspace, full reading, and tools use explicit high-contrast component styles with the original indigo brand. Lessons, built-in examples, the simulator, local drafts and ZIP downloads work without a database. Saved experiments use the same-origin SvelteKit `/api/experiments` routes and require `DATABASE_URL` from a Neon Postgres database. Copy `.env.template` to `.env.local` and set the URL locally when working on persistence. Never commit credentials or migration exports. @@ -85,9 +102,9 @@ npm run preview -- --host 127.0.0.1 npm run test:cy ``` -The production build generates `.vercel/output` using `@sveltejs/adapter-vercel`; it does not need database credentials. Lessons and the new-experiment page are prerendered. Shared experiment pages load on the client, and the API runs on Node.js 24 functions. The PWA precaches application assets and lessons; private API responses are never cached. +The production build generates `.vercel/output` using `@sveltejs/adapter-vercel`; it does not need database credentials. Lessons and the new-experiment page are prerendered. Shared experiment pages load on the client, and the API runs on Node.js 26 functions. The PWA precaches application assets and lessons; private API responses are never cached. -Unit tests live next to the source and include parser fixtures, simulator behavior, ownership checks, origin checks and migration validation. Cypress retains the existing accessibility and visual-regression checks. CI uses Node.js 24 and `npm ci` and runs typing, coverage, builds and Cypress on pull requests. +Unit tests live next to the source and include parser fixtures, simulator behavior, ownership checks, origin checks and migration validation. Cypress retains the existing accessibility and visual-regression checks. CI uses Node.js 26 and `npm ci` and runs typing, coverage, builds and Cypress on pull requests. ## Deployment and data migration diff --git a/cypress/e2e/about.cy.ts b/cypress/e2e/about.cy.ts index e072f9c..2d92608 100644 --- a/cypress/e2e/about.cy.ts +++ b/cypress/e2e/about.cy.ts @@ -1,68 +1,54 @@ +import { checkAccessibility, expectMainNavigation, expectNoPageOverflow } from '../support/checks'; + describe('About', () => { - it('Can be navigated to from menu', () => { + it('Uses the shared navigation and preserves project background and attribution', () => { cy.visit('/'); + cy.findByRole('navigation', { name: 'Main navigation' }) + .findByRole('link', { name: 'About' }) + .click(); + cy.location('pathname').should('eq', '/about'); + expectMainNavigation(); + cy.findByRole('heading', { level: 1, name: 'Understand it by building it.' }).should( + 'be.visible', + ); + cy.findByRole('link', { name: 'University of Galway' }).should( + 'have.attr', + 'href', + 'https://www.universityofgalway.ie', + ); + cy.findByRole('link', { name: 'Read the research' }).should( + 'have.attr', + 'href', + 'https://thesis.chipsandcode.com', + ); + cy.findByRole('link', { name: 'Nand2Tetris' }).should( + 'have.attr', + 'href', + 'https://www.nand2tetris.org', + ); + cy.findByRole('link', { name: 'CC BY-NC-SA 3.0' }).should( + 'have.attr', + 'href', + 'https://creativecommons.org/licenses/by-nc-sa/3.0/', + ); + cy.contains('not affiliated with or endorsed by Nand2Tetris'); + cy.findByRole('link', { name: 'report a bug or request a feature' }).should( + 'have.attr', + 'href', + 'https://github.com/durasj/chipsandcode/issues', + ); + cy.contains('summary', 'Thank you to the research participants').click(); + cy.contains('Viktoria, Kyryl, Matus'); cy.injectAxe(); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1500); - - cy.contains('nav a', 'About').click(); - - cy.contains('Chips and Code'); - - cy.matchImage(); - - cy.scrollTo('bottom'); - cy.matchImage(); - - // ... and screenshots cause the app to reload which may take some time - cy.wait(500); - - cy.checkA11y(); + checkAccessibility(); + cy.screenshot('about-unified', { capture: 'fullPage' }); }); - it('Contains all important information and links', () => { + it('Reflows the project explanation at a narrow width', () => { + cy.viewport(320, 760); cy.visit('/about'); - - cy.contains('h1', 'Chips and Code'); - - cy.contains('a', 'Report Bug / Request Feature') - .invoke('attr', 'href') - .should('equal', 'https://github.com/durasj/chipsandcode/issues'); - - cy.contains('a', 'Discussions') - .invoke('attr', 'href') - .should('equal', 'https://github.com/durasj/chipsandcode/discussions'); - - cy.contains('reimagined'); - cy.contains('a', 'Nand2Tetris') - .invoke('attr', 'href') - .should('equal', 'https://nand2tetris.org'); - - cy.contains('not affiliated or endorsed by them'); - - cy.contains(`master's thesis at the`); - cy.contains('a', 'University of Galway') - .invoke('attr', 'href') - .should('equal', 'https://www.universityofgalway.ie'); - - cy.contains('a', 'Research Behind') - .invoke('attr', 'href') - .should('equal', 'https://thesis.chipsandcode.com'); - - cy.contains('a', 'Code Repository') - .invoke('attr', 'href') - .should('equal', 'https://github.com/durasj/chipsandcode'); - - cy.contains('Credits'); - cy.contains('Open source'); - cy.contains( - 'Nand2Tetris content licensed under the CC BY-NC-SA 3.0, Svelte framework, Tailwind and DaisyUI styling libraries, Nearley parser toolkit, and Monaco Editor, all licensed under the MIT license', - ); - - cy.contains('participants'); - cy.contains( - 'Thank you 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, Filip', - ); + expectNoPageOverflow(); + cy.injectAxe(); + checkAccessibility(); }); }); diff --git a/cypress/e2e/accessibility.cy.ts b/cypress/e2e/accessibility.cy.ts index 5f6740e..509416d 100644 --- a/cypress/e2e/accessibility.cy.ts +++ b/cypress/e2e/accessibility.cy.ts @@ -1,47 +1,26 @@ -describe('Accessibility Statement', () => { - it('Can be navigated to via Footer and contains everything important', () => { - cy.visit('/'); - - cy.contains('a', 'Accessibility Statement').click(); +import { checkAccessibility, expectMainNavigation } from '../support/checks'; - cy.contains('h1', 'Accessibility'); +describe('Accessibility statement', () => { + it('Explains the available controls and feedback path in the shared interface', () => { + cy.visit('/'); + cy.get('footer').findByRole('link', { name: 'Accessibility' }).click(); cy.location('pathname').should('eq', '/accessibility-statement'); - - // Unfortunately, images take a bit to load - cy.wait(1000); - cy.matchImage(); - // ... and screenshots cause the app to reload which may take some time - cy.wait(500); - - cy.injectAxe(); - cy.checkA11y(); - - cy.contains('h2', 'Summary'); - - cy.contains('a', 'AbilityNet') - .invoke('attr', 'href') - .should('equal', 'https://mcmw.abilitynet.org.uk/'); - - cy.contains( - 'Chips and Code strives to meet Web Content Accessibility Guidelines (WCAG) 2.1 at Level AA', + expectMainNavigation(); + cy.findByRole('heading', { level: 1, name: 'A machine you can explore.' }).should('be.visible'); + cy.findByRole('heading', { name: 'Navigation and interaction' }).should('be.visible'); + cy.findByRole('heading', { name: 'Reading, code, and media' }).should('exist'); + cy.findByRole('heading', { name: 'Checks and feedback' }).should('exist'); + cy.findByRole('link', { name: 'report an accessibility issue' }).should( + 'have.attr', + 'href', + 'https://github.com/durasj/chipsandcode/issues', ); - - cy.contains( - 'If you experience any issues or have any suggestions, please let us know at the "Report Bug/Request Feature" link.', + cy.findByRole('link', { name: /AbilityNet/ }).should( + 'have.attr', + 'href', + 'https://mcmw.abilitynet.org.uk/', ); - - cy.contains('a', 'Report Bug / Request Feature') - .invoke('attr', 'href') - .should('equal', 'https://github.com/durasj/chipsandcode/issues'); - - cy.contains('h2', 'Measures to support accessibility'); - - cy.contains('h2', 'Conformance status'); - - cy.contains('a', 'WCAG') - .invoke('attr', 'href') - .should('equal', 'https://www.w3.org/WAI/standards-guidelines/wcag/'); - - cy.contains('h2', 'Technical specifications'); + cy.injectAxe(); + checkAccessibility(); }); }); diff --git a/cypress/e2e/experiment.cy.ts b/cypress/e2e/experiment.cy.ts index 992d30b..2fae0aa 100644 --- a/cypress/e2e/experiment.cy.ts +++ b/cypress/e2e/experiment.cy.ts @@ -1,218 +1,202 @@ -describe('Experiment - Hardware IDE', () => { - beforeEach(() => { - const experiment = { - id: 'abc123', - name: 'FooBar CHIP', - code: '// Empty code', - tests: '// Empty TST', - compare: 'Expected output', - type: 'HARDWARE', - visibility: 'PUBLIC', - }; +import { checkAccessibility, expectMainNavigation, expectNoPageOverflow } from '../support/checks'; + +const simulatorPath = '/tools/hardware-simulator'; + +function waitForEditor() { + cy.get('.hardware-workspace', { timeout: 20000 }).should('have.attr', 'data-ready', 'true'); + cy.get('.monaco-editor').filter(':visible').first().should('be.visible'); +} + +function typeInEditor(text: string, expectedOutput = false) { + // Monaco's keyboard input is its native textarea, positioned at the caret. + // Focusing that input exercises normal keyboard editing without a forced click + // on an invisible caret or a click on the outer accessibility container. + cy.get( + expectedOutput + ? '.modified-in-monaco-diff-editor textarea.inputarea' + : '.editor-mount .monaco-editor textarea.inputarea', + ) + .should('have.length', 1) + .focus() + .should('be.focused') + .type(text, { delay: 0 }); + if (!text.includes('{')) { + cy.get('.editor-mount .view-lines').should(($lines) => { + expect($lines.text().replace(/\s+/g, ' '), 'typed source appears in the editor').to.contain( + text, + ); + }); + } +} - cy.intercept('GET', '*/experiments/Xor', { - fixture: 'experiment.json', - }).as('getExperiment'); +function visitSimulator(id = '') { + cy.visit(`${simulatorPath}${id ? `/${id}` : ''}`); + waitForEditor(); +} - cy.intercept('DELETE', '*/experiments/Xor', { - fixture: 'experiment.json', +describe('Hardware simulator tool', () => { + beforeEach(() => { + cy.fixture('experiment.json').then(({ experiment }) => { + cy.intercept('GET', '**/api/experiments/saved-example', { + body: { experiment: { ...experiment, id: 'saved-example' } }, + }).as('getExperiment'); + }); + cy.intercept('DELETE', '**/api/experiments/saved-example', { + body: { experiment: { id: 'saved-example' } }, }).as('deleteExperiment'); - - cy.intercept('GET', '*/experiments', { - body: { experiments: [] }, - }).as('listExperiments'); - - cy.intercept('POST', '*/experiments', { - body: { - experiment, - }, + cy.intercept('GET', '**/api/experiments', { body: { experiments: [] } }).as('listExperiments'); + cy.intercept('POST', '**/api/experiments', (request) => { + request.reply({ + experiment: { ...request.body, id: 'abc123', created: '2026-11-03T00:00:00Z' }, + }); }).as('postExperiment'); }); - it('Can be navigated to from menu', () => { + it('Lives under Tools with the same primary navigation and accessible workspace', () => { cy.visit('/'); - cy.injectAxe(); - cy.configureAxe({ - rules: [ - // Minor Monaco issue this project has no control over - { id: 'landmark-unique', enabled: false }, - ], - }); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1500); - - cy.contains('nav button', 'Experiment').click(); - - cy.contains('nav a', 'Hardware IDE').click(); - + cy.findByRole('navigation', { name: 'Main navigation' }) + .findByRole('link', { name: 'Tools' }) + .click(); + cy.location('pathname').should('eq', '/tools'); + cy.findByRole('link', { name: /Hardware simulator/ }).click(); + cy.location('pathname').should('eq', simulatorPath); + waitForEditor(); + expectMainNavigation(); cy.findByLabelText('Experiment name').should('have.value', 'Untitled Experiment'); - - cy.matchImage(); - // ... and screenshots cause the app to reload which may take some time - cy.wait(500); - - cy.checkA11y(); - }); - - it('Loads example Xor', () => { - cy.visit('/experiment/hardware-ide'); cy.injectAxe(); - cy.configureAxe({ - rules: [ - // Minor Monaco issue this project has no control over - { id: 'landmark-unique', enabled: false }, - // These are all within Monaco that has opt-in high contrast theme that we're bundling - // TODO: How to narrow this down? - { id: 'color-contrast', enabled: false }, - ], - }); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1500); - - cy.findByLabelText('Experiment name').should('have.value', 'Untitled Experiment'); + checkAccessibility(); + cy.screenshot('hardware-simulator-empty', { capture: 'viewport' }); + }); + it('Loads XOR through the simulator and preserves its real computed outputs', () => { + visitSimulator(); cy.contains('a', 'Xor Gate').click(); - - cy.location('pathname').should('eq', '/experiment/hardware-ide/Xor'); - + cy.location('pathname').should('eq', `${simulatorPath}/Xor`); cy.findByLabelText('Experiment name').should('have.value', 'Xor Gate'); - cy.contains('CHIP Xor'); - - cy.matchImage(); - // ... and screenshots cause the app to reload which may take some time - cy.wait(500); - - cy.checkA11y(); - }); - - it('Reacts to changes to input pins', () => { - cy.visit('/experiment/hardware-ide/Xor'); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1000); - cy.findByLabelText('Value for a').clear().type('1').blur(); cy.contains('tr', 'out').contains('td', '1'); - cy.findByLabelText('Value for b').clear().type('1').blur(); cy.contains('tr', 'out').contains('td', '0'); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('hardware-simulator-xor', { capture: 'viewport' }); }); - it('Reacts to changes in HDL', () => { + it('Redirects legacy experiment links into Tools, including saved IDs', () => { cy.visit('/experiment/hardware-ide/Xor'); + cy.location('pathname').should('eq', `${simulatorPath}/Xor`); + waitForEditor(); + cy.findByLabelText('Experiment name').should('have.value', 'Xor Gate'); + expectMainNavigation(); + cy.visit('/experiment/hardware-ide/saved-example'); + cy.location('pathname').should('eq', `${simulatorPath}/saved-example`); + cy.wait('@getExperiment'); + cy.findByLabelText('Experiment name').should('have.value', 'Xor Gate'); + }); - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1000); - - // Add input pin - cy.get('.monaco-editor textarea:first') - .click({ force: true }) - .focused() - .type('{moveToStart}') - .type('{downArrow}{downArrow}{downArrow}{downArrow}{downArrow}{downArrow}{downArrow}') - .type('{end}{leftArrow}, c'); - cy.findByLabelText('Value for c'); - - // Cause error - cy.get('.monaco-editor textarea:first') - .click({ force: true }) - .focused() - // Anchor to the document end rather than the cursor position left by a mouse click. - .type('{moveToEnd}{upArrow}{upArrow}') - .type('{end}{leftArrow}{leftArrow}{backspace}{backspace}{backspace}nota'); + it('Updates inputs from HDL and clears stale verification when the design becomes invalid', () => { + visitSimulator('Xor'); + cy.contains('[role="tab"]', 'Tests').contains('4 / 4'); + typeInEditor( + '{ctrl+home}{downArrow}{downArrow}{downArrow}{downArrow}{downArrow}{downArrow}{downArrow}{end}{leftArrow}, c', + ); + cy.findByLabelText('Value for c').should('be.visible'); + typeInEditor( + '{ctrl+end}{upArrow}{upArrow}{end}{leftArrow}{leftArrow}{backspace}{backspace}{backspace}nota', + ); + cy.get('.editor-mount') + .invoke('text') + .should('match', /Or\(a=w1,\s*b=w2,\s*out=nota\);/); cy.contains('[role="alert"]', 'contains a loop'); - cy.contains('[role="tab"]', 'Tests').contains('2 / 4'); + cy.contains('[role="tab"]', 'Tests').should('not.contain', '/'); + cy.get('.signal-panel').should(($panel) => { + expect( + [...$panel[0].querySelectorAll('.pin-value')].filter((node) => + /^[01]$/.test(node.textContent?.trim() || ''), + ), + 'invalid circuits expose no stale bit values', + ).to.have.length(0); + }); }); - it('Reacts to changes in Tests', () => { - cy.visit('/experiment/hardware-ide/Xor'); + it('Keeps an intentionally emptied local draft across reloads', () => { + visitSimulator('Xor'); + typeInEditor('{ctrl+a}{backspace}'); + cy.contains('[role="tab"]', 'Tests').should('not.contain', '/'); + cy.reload(); + waitForEditor(); + cy.get('.editor-mount') + .invoke('text') + .should('not.match', /CHIP\s+Xor/); + cy.contains('[role="tab"]', 'Tests').should('not.contain', '/'); + typeInEditor('// A local draft'); + cy.reload(); + waitForEditor(); + cy.get('.editor-mount') + .invoke('text') + .should('match', /A\s+local\s+draft/); + }); - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1000); + it('Explains an invalid input without presenting a stale output', () => { + visitSimulator('Xor'); + cy.findByLabelText('Value for a').clear().type('2').blur(); + cy.contains('[role="alert"]', 'Input a must be 0 or 1.').should('be.visible'); + cy.contains('tr', 'out').contains('td', '—'); + cy.findByLabelText('Value for a').clear().type('1').blur(); + cy.contains('[role="alert"]', 'Input a must be 0 or 1.').should('not.exist'); + cy.contains('tr', 'out').contains('td', '1'); + }); - // Change test case + it('Re-evaluates changed test scripts and removes the result when tests are cleared', () => { + visitSimulator('Xor'); cy.contains('[role="tab"]', 'Tests').contains('4 / 4').click(); - cy.get('.monaco-editor textarea:first') - .click({ force: true }) - .focused() - .type('{moveToStart}') - .type('{downArrow}{downArrow}') - .type('{shift}{end}{backspace}'); + typeInEditor('{ctrl+home}{downArrow}{downArrow}{shift}{end}{backspace}'); + // Deliberately change the first input combination. Omitting `set a 0` + // alone does not change its initial zero value and must still pass. + typeInEditor('set a 1,'); cy.contains('[role="tab"]', 'Tests').contains('3 / 4'); - - // Remove all test cases - cy.get('.monaco-editor textarea:first') - .click({ force: true }) - .focused() - .type('{selectAll}{backspace}'); - cy.contains('[role="tab"]', 'Tests'); + typeInEditor('{ctrl+a}{backspace}'); + cy.contains('[role="tab"]', 'Tests').should('not.contain', '/'); }); - it('Reacts to changes in Output', () => { - cy.visit('/experiment/hardware-ide/Xor'); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1000); - - // Change expected output + it('Re-evaluates edited expected output', () => { + visitSimulator('Xor'); cy.contains('[role="tab"]', 'Tests').contains('4 / 4'); cy.contains('[role="tab"]', 'Output').click(); - cy.get('.monaco-editor textarea:last') - .click({ force: true }) - .focused() - .type('{moveToStart}') - .type('{downArrow}{end}') - .type('{leftArrow}{leftArrow}{leftArrow}{leftArrow}{backspace}1'); + typeInEditor( + '{ctrl+home}{downArrow}{end}{leftArrow}{leftArrow}{leftArrow}{leftArrow}{backspace}1', + true, + ); cy.contains('[role="tab"]', 'Tests').contains('3 / 4'); }); - it('Works in dark mode', () => { - cy.visit('/experiment/hardware-ide/Xor'); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1000); - - cy.contains('Color theme switch').click(); - - cy.findByLabelText('Experiment name').should('have.value', 'Xor Gate'); - - // Wait for animation - cy.wait(2000); - - cy.matchImage(); + it('Keeps the tool usable on a narrow screen with the same dark theme', () => { + cy.viewport(320, 760); + visitSimulator('Xor'); + expectMainNavigation(); + expectNoPageOverflow(); + cy.findByLabelText('Value for a').clear().type('1').blur(); + cy.contains('tr', 'out').contains('td', '1'); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('hardware-simulator-mobile', { capture: 'fullPage' }); }); - it('Allows opening, saving, and sharing a new experiment', () => { - cy.visit('/experiment/hardware-ide/Xor'); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1000); - - cy.findByLabelText('Experiment name').should('have.value', 'Xor Gate'); - - cy.findByLabelText('Open/New').click(); - - cy.contains('button', 'Open new').click(); - + it('Opens, saves and shares a new experiment using canonical URLs', () => { + visitSimulator('Xor'); + cy.findByRole('button', { name: 'File' }).click(); + cy.findByRole('menuitem', { name: 'Open new' }).click(); cy.findByLabelText('Experiment name').should('have.value', 'Untitled Experiment'); - - cy.location('pathname').should('eq', '/experiment/hardware-ide'); - - cy.get('.monaco-editor textarea:first').click({ force: true }).focused().type('// Empty code'); - + cy.location('pathname').should('eq', simulatorPath); + waitForEditor(); + typeInEditor('// Empty code'); cy.contains('[role="tab"]', 'Tests').click(); - cy.get('.monaco-editor textarea:first').click({ force: true }).focused().type('// Empty TST'); - + typeInEditor('// Empty TST'); cy.contains('[role="tab"]', 'Output').click(); - cy.get('.monaco-editor textarea:last').click({ force: true }).focused().type('Expected output'); - + typeInEditor('Expected output', true); cy.findByLabelText('Experiment name').clear().type('FooBar CHIP'); - - cy.contains('Save').click(); - + cy.contains('button', 'Save').click(); cy.wait('@postExperiment').its('request.body').should('deep.equal', { name: 'FooBar CHIP', code: '// Empty code', @@ -221,34 +205,80 @@ describe('Experiment - Hardware IDE', () => { type: 'HARDWARE', visibility: 'PUBLIC', }); - - cy.location('pathname').should('eq', '/experiment/hardware-ide/abc123'); - + cy.location('pathname').should('eq', `${simulatorPath}/abc123`); cy.findByLabelText('Experiment name').should('have.value', 'FooBar CHIP'); - cy.findByLabelText('Share').click(); - - cy.findByLabelText('Experiment URL') - .invoke('val') - .should('contains', '/experiment/hardware-ide/abc123'); + cy.findByLabelText('Experiment URL').invoke('val').should('contain', `${simulatorPath}/abc123`); + cy.get('body').type('{esc}'); + cy.findByRole('button', { name: 'File' }).click(); + cy.findByRole('menuitem', { name: 'Open new' }).click(); + cy.location('pathname').should('eq', simulatorPath); + waitForEditor(); + cy.findByLabelText('Experiment name').should('have.value', 'Untitled Experiment'); + cy.get('.editor-mount') + .invoke('text') + .should('not.match', /Empty\s+code/); + cy.contains('[role="tab"]', 'Tests').click(); + cy.get('.editor-mount') + .invoke('text') + .should('not.match', /Empty\s+TST/); }); - it('Allows deleting existing experiment', () => { - cy.visit('/experiment/hardware-ide/Xor'); + it('Keeps edits made during an in-flight save as a newer local draft', () => { + let releaseSave: (() => void) | undefined; + cy.intercept('POST', '**/api/experiments', (request) => { + const snapshot = { ...request.body }; + return new Cypress.Promise((resolve) => { + releaseSave = () => { + request.reply({ + body: { experiment: { ...snapshot, id: 'abc123', created: '2026-11-03T00:00:00Z' } }, + }); + resolve(); + }; + }); + }).as('delayedSave'); + visitSimulator(); + typeInEditor('// First revision'); + cy.findByLabelText('Experiment name').clear().type('First revision').blur(); + cy.contains('button', 'Save').click(); + cy.wrap(null).should(() => expect(releaseSave).to.be.a('function')); + cy.findByRole('button', { name: 'Saving…' }).should('be.disabled'); + typeInEditor('{ctrl+end} plus an unsaved edit'); + cy.findByLabelText('Experiment name').clear().type('Second revision').blur(); + cy.then(() => releaseSave?.()); + cy.wait('@delayedSave').its('request.body').should('include', { + name: 'First revision', + code: '// First revision', + }); + cy.location('pathname').should('eq', `${simulatorPath}/abc123`); + cy.findByLabelText('Experiment name').should('have.value', 'Second revision'); + cy.get('.editor-mount') + .invoke('text') + .should('match', /plus\s+an\s+unsaved\s+edit/); + cy.get('.editor-status').should('contain', 'Local draft'); + cy.findByLabelText('Share').should('be.disabled'); + cy.findByRole('button', { name: 'Save' }).should('not.be.disabled'); + }); - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1000); + it('Saves a bundled template as a copy without updating or deleting the template', () => { + visitSimulator('Xor'); + cy.findByLabelText('More actions').click(); + cy.findByRole('menuitem', { name: 'Delete' }).should('not.exist'); + cy.get('body').type('{esc}'); + cy.findByLabelText('Experiment name').clear().type('My XOR'); + cy.contains('button', 'Save').click(); + cy.wait('@postExperiment').its('request.body').should('include', { name: 'My XOR' }); + cy.location('pathname').should('eq', `${simulatorPath}/abc123`); + }); + it('Deletes a saved experiment and returns to a fresh simulator', () => { + visitSimulator('saved-example'); + cy.wait('@getExperiment'); cy.findByLabelText('Experiment name').should('have.value', 'Xor Gate'); - cy.findByLabelText('More actions').click(); - cy.contains('button', 'Delete').click(); - cy.wait('@deleteExperiment'); - - cy.location('pathname').should('eq', '/experiment/hardware-ide'); - + cy.location('pathname').should('eq', simulatorPath); cy.findByLabelText('Experiment name').should('have.value', 'Untitled Experiment'); }); }); diff --git a/cypress/e2e/game.cy.ts b/cypress/e2e/game.cy.ts new file mode 100644 index 0000000..b7ea820 --- /dev/null +++ b/cypress/e2e/game.cy.ts @@ -0,0 +1,323 @@ +import { checkAccessibility, expectNoPageOverflow, exploreNotAnd } from '../support/checks'; + +const inverterHDL = `CHIP Not { + IN in; + OUT out; + PARTS: + Nand(a=in, b=in, out=out); +}`; + +function visitGame(progress: string[] = ['nand']) { + cy.visit('/learn', { + onBeforeLoad(window) { + window.localStorage.clear(); + if (progress.length) { + window.localStorage.setItem('chipsandcode.progress.v1', JSON.stringify(progress)); + } + }, + }); + cy.get('.computer-game').should('have.attr', 'data-ready', 'true'); +} + +function openNotWorkbench() { + cy.findByRole('heading', { name: 'Invert a signal' }).should('be.visible'); +} + +function chooseView(view: 'Visual' | 'Split' | 'Code') { + cy.findByRole('combobox', { name: 'Editor view' }) + .select(view.toLowerCase()) + .should('have.value', view.toLowerCase()); +} + +function openConnections() { + cy.contains('summary', 'Connections').then(($summary) => { + if (!$summary.parent('details').prop('open')) cy.wrap($summary).click(); + }); +} + +function writeHDL(source: string) { + cy.findByLabelText('HDL source').clear().type(source, { + parseSpecialCharSequences: false, + delay: 0, + }); +} + +function buildInverter() { + cy.findByRole('button', { name: /^Nand\b/ }).click(); + openConnections(); + cy.findByLabelText('Part 1 Nand input a').select('in'); + cy.findByLabelText('Part 1 Nand input b').select('in'); + cy.findByLabelText('Chip output out').select('g1'); +} + +function openReference() { + cy.findByRole('button', { name: 'Reference' }).click(); + cy.findByRole('heading', { level: 1, name: 'Reference' }).should('have.focus'); +} + +describe('Chips and Code workbench', () => { + beforeEach(() => visitGame()); + + it('Explores signal, NOT and AND before NAND, then builds the first circuit in order', () => { + visitGame([]); + cy.findByRole('heading', { name: 'A computer starts with a signal.' }).should('be.visible'); + cy.findByRole('button', { name: 'Continue' }).should('not.exist'); + cy.findByRole('switch', { name: 'Signal' }) + .should('have.attr', 'aria-checked', 'false') + .click() + .should('have.attr', 'aria-checked', 'true'); + cy.findByRole('img', { name: 'Output 1' }).should('be.visible'); + openReference(); + openReference(); + cy.findByRole('button', { name: 'Back' }).click(); + cy.findByRole('switch', { name: 'Signal' }).should('have.attr', 'aria-checked', 'true'); + cy.findByRole('button', { name: 'Continue' }).should('not.exist'); + cy.findByRole('switch', { name: 'Signal' }) + .click() + .should('have.attr', 'aria-checked', 'false'); + cy.findByRole('img', { name: 'Output 0' }).should('be.visible'); + cy.findByRole('button', { name: 'Continue' }).click(); + exploreNotAnd(); + cy.findByLabelText('HDL source').should('not.exist'); + cy.findByLabelText('Editor view').should('not.exist'); + cy.screenshot('nand-guided-experiment', { capture: 'viewport' }); + + // Wrong answers neither advance the experiment nor unlock the next circuit. + cy.findByRole('button', { name: 'Output 0' }).click(); + cy.contains('The output is 1. Follow the line on the right and try again.'); + cy.findByRole('button', { name: 'Continue' }).should('not.exist'); + cy.findByRole('button', { name: 'Output 1' }).click(); + cy.findByRole('button', { name: 'Next combination' }).click(); + cy.findByRole('button', { name: 'Output 1' }).should('be.disabled'); + cy.findByRole('button', { name: 'Input b 0' }).click(); + cy.findByRole('button', { name: 'Output 1' }).click(); + cy.findByRole('button', { name: 'Next combination' }).click(); + cy.findByRole('button', { name: 'Input a 0' }).click(); + cy.findByRole('button', { name: 'Output 0' }).click(); + cy.findByRole('button', { name: 'Next combination' }).click(); + cy.findByRole('button', { name: 'Input b 1' }).click(); + cy.findByRole('button', { name: 'Output 1' }).click(); + cy.contains('NAND outputs 0 only when both inputs are 1.'); + cy.findByRole('heading', { name: 'Why build from NAND?' }).should('be.visible'); + cy.contains('summary', 'Go deeper: why NAND is universal').click(); + cy.contains('summary', 'See its code').parent('details').should('not.have.attr', 'open'); + cy.injectAxe(); + checkAccessibility(); + cy.findByRole('link', { name: /Read the full explanation/ }).click(); + cy.location('pathname').should('eq', '/learn/reference/boolean-logic/background'); + cy.location('hash').should('eq', '#universality'); + cy.window().then((window) => { + expect( + JSON.parse(window.localStorage.getItem('chipsandcode.progress.v1') || '[]'), + ).not.to.include('nand'); + }); + cy.findByRole('navigation', { name: 'Main navigation' }) + .findByRole('link', { name: 'Learn' }) + .click(); + cy.get('.computer-game').should('have.attr', 'data-ready', 'true'); + cy.findByRole('heading', { name: 'Why build from NAND?' }).should('be.visible'); + cy.findByRole('button', { name: 'Continue' }).click(); + cy.window() + .its('sessionStorage') + .invoke('getItem', 'chipsandcode.nand-observation.v1') + .should('eq', null); + cy.findByRole('heading', { name: 'NAND, explored.' }).should('be.visible'); + cy.window() + .its('localStorage') + .invoke('getItem', 'chipsandcode.progress.v1') + .should('eq', '["nand"]'); + cy.window() + .its('localStorage') + .invoke('getItem', 'chipsandcode.signal-intro.v1') + .should('eq', 'complete'); + cy.findByRole('button', { name: 'Continue' }).click(); + cy.findByRole('heading', { name: 'Invert a signal' }).should('be.visible'); + cy.findByRole('combobox', { name: 'Editor view' }).should('have.value', 'visual'); + cy.findByLabelText('HDL source').should('not.exist'); + cy.contains('summary', 'Connections').parent('details').should('not.have.attr', 'open'); + cy.contains('summary', 'Signal history').parent('details').should('not.have.attr', 'open'); + cy.findByRole('button', { name: 'Test circuit' }).should('not.exist'); + cy.screenshot('first-circuit-minimal', { capture: 'viewport' }); + buildInverter(); + cy.findByRole('button', { name: 'Test circuit' }).click(); + cy.findByRole('button', { name: 'Continue' }).should('have.focus'); + openReference(); + cy.findByRole('button', { name: 'Back' }).click(); + cy.findByRole('button', { name: 'Continue' }).should('be.visible'); + cy.contains('2 of 2 combinations work.'); + cy.findByRole('button', { name: 'Test circuit' }).should('not.exist'); + cy.contains('summary', 'Test results').parent('details').should('not.have.attr', 'open'); + cy.contains('summary', 'Test results').click(); + cy.contains('2 of 2 combinations work.').should('be.visible'); + cy.findByRole('button', { name: 'Continue' }).click(); + cy.findByRole('heading', { name: 'NOT works.' }).should('be.visible'); + cy.reload(); + cy.get('.computer-game').should('have.attr', 'data-ready', 'true'); + cy.findByRole('button', { name: 'Your chips' }).click(); + cy.findByRole('button', { name: /^Reopen Not/ }).should('be.visible'); + cy.findByRole('button', { name: /^Reopen And/ }).should('not.exist'); + cy.injectAxe(); + checkAccessibility(); + cy.findByRole('button', { name: 'Continue learning' }).click(); + cy.findByRole('heading', { name: 'Combine conditions' }).should('be.visible'); + }); + + it('Invalidates a passed test after a connection changes and restores the edited draft', () => { + openNotWorkbench(); + buildInverter(); + cy.findByRole('button', { name: 'Test circuit' }).click(); + cy.contains('2 of 2 combinations work.'); + cy.findByRole('button', { name: 'Continue' }).should('be.visible'); + + // A direct wire is a valid circuit, but it is not an inverter. + cy.findByLabelText('Chip output out').select('in'); + cy.contains('2 of 2 combinations work.').should('not.exist'); + cy.findByRole('button', { name: 'Continue' }).should('not.exist'); + cy.reload(); + openNotWorkbench(); + openConnections(); + cy.findByLabelText('Part 1 Nand input a').should('have.value', 'in'); + cy.findByLabelText('Part 1 Nand input b').should('have.value', 'in'); + cy.findByRole('button', { name: 'Continue' }).should('not.exist'); + cy.findByRole('button', { name: 'Test circuit' }).click(); + cy.contains('0 of 2 combinations work.'); + cy.findAllByRole('button', { name: /Inspect case \d, needs work/ }).should('have.length', 2); + cy.findByLabelText('Chip output out').should('have.value', 'in').select('g1'); + cy.contains('0 of 2 combinations work.').should('not.exist'); + cy.findByRole('button', { name: 'Test circuit' }).click(); + cy.contains('2 of 2 combinations work.'); + cy.findByRole('button', { name: 'Continue' }).should('be.visible'); + }); + + it('Wires directly on the board and can undo clearing the saved circuit', () => { + openNotWorkbench(); + cy.findByRole('button', { name: /^Nand\b/ }).click(); + cy.findByRole('button', { name: 'Select source input in' }).click(); + cy.findByRole('button', { name: 'Connect to part 1 Nand input a' }).click(); + cy.findByRole('button', { name: 'Connect to part 1 Nand input b' }).click(); + cy.findByRole('button', { name: 'Select source part 1 Nand output' }).click(); + cy.findByRole('button', { name: 'Connect chip output out' }).click(); + cy.findByRole('button', { name: 'Test circuit' }).click(); + cy.contains('2 of 2 combinations work.'); + openConnections(); + cy.findByRole('button', { name: 'Clear circuit' }).click(); + cy.findByLabelText('Part 1 Nand input a').should('not.exist'); + cy.findByRole('button', { name: 'Undo clear' }).click(); + cy.findByLabelText('Part 1 Nand input a').should('have.value', 'in'); + cy.findByLabelText('Chip output out').should('have.value', 'g1'); + cy.findByRole('button', { name: 'Test circuit' }).click(); + cy.contains('2 of 2 combinations work.'); + cy.reload(); + openNotWorkbench(); + openConnections(); + cy.findByLabelText('Chip output out').should('have.value', 'g1'); + }); + + it('Explains an unwired extra part and recovers when it is removed', () => { + openNotWorkbench(); + cy.findByRole('button', { name: /^Nand\b/ }).click(); + cy.findByRole('button', { name: /^Nand\b/ }).click(); + cy.findByRole('button', { name: 'Select source input in' }).click(); + cy.findByRole('button', { name: 'Connect to part 1 Nand input a' }).click(); + cy.findByRole('button', { name: 'Connect to part 1 Nand input b' }).click(); + cy.findByRole('button', { name: 'Select source part 1 Nand output' }).click(); + cy.findByRole('button', { name: 'Connect chip output out' }).click(); + cy.contains( + 'Part 2 (Nand) still needs input a. Connect it, or remove that part in Connections.', + ).should('be.visible'); + cy.findByRole('button', { name: 'Test circuit' }).should('not.exist'); + cy.findByRole('button', { name: 'Continue' }).should('not.exist'); + openConnections(); + cy.findByRole('button', { name: 'Remove part 2, Nand' }).click(); + cy.findByLabelText('Part 2 Nand input a').should('not.exist'); + cy.findByRole('button', { name: 'Test circuit' }).click(); + cy.contains('2 of 2 combinations work.'); + cy.findByRole('button', { name: 'Continue' }).should('be.visible'); + }); + + it('Solves in code and keeps visual and HDL representations synchronized', () => { + openNotWorkbench(); + cy.findByRole('combobox', { name: 'Editor view' }).should('have.value', 'visual'); + cy.findByRole('button', { name: 'Test circuit' }).should('not.exist'); + chooseView('Code'); + cy.get('.visual-workspace').should('not.exist'); + writeHDL(inverterHDL); + cy.findByRole('alert').should('not.exist'); + cy.findByRole('button', { name: 'Test circuit' }).click(); + cy.contains('2 of 2 combinations work.'); + chooseView('Split'); + cy.findByLabelText('HDL source').should('have.value', inverterHDL); + openConnections(); + cy.findByLabelText('Part 1 Nand input a').should('have.value', 'in'); + cy.findByLabelText('Part 1 Nand input b').should('have.value', 'in'); + cy.findByLabelText('Chip output out').should('have.value', 'g1'); + cy.findByRole('region', { name: 'HDL code editor' }).then(($code) => { + cy.get('.visual-workspace').then(($visual) => { + expect( + $code[0].getBoundingClientRect().left, + 'HDL is beside the visual circuit on desktop', + ).to.be.at.least($visual[0].getBoundingClientRect().right - 1); + }); + }); + cy.findByLabelText('Chip output out').select('in'); + cy.contains('2 of 2 combinations work.').should('not.exist'); + cy.findByLabelText('HDL source').invoke('val').should('include', 'gamebufferout'); + cy.findByRole('button', { name: 'Test circuit' }).click(); + cy.contains('0 of 2 combinations work.'); + cy.findByLabelText('Chip output out').select('g1'); + cy.findByLabelText('HDL source').invoke('val').should('not.include', 'gamebufferout'); + cy.findByRole('button', { name: 'Test circuit' }).click(); + cy.contains('2 of 2 combinations work.'); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('computer-workbench-split', { capture: 'fullPage' }); + }); + + it('Preserves invalid HDL across views and reloads while blocking stale verification', () => { + openNotWorkbench(); + chooseView('Code'); + writeHDL(inverterHDL); + cy.findByRole('button', { name: 'Test circuit' }).click(); + cy.contains('2 of 2 combinations work.'); + const invalidHDL = inverterHDL.replace('b=in', 'b=missing'); + writeHDL(invalidHDL); + cy.contains('HDL could not be applied.'); + cy.contains('Signal missing has no driver.'); + cy.findByRole('button', { name: 'Test circuit' }).should('be.disabled'); + cy.findByRole('button', { name: 'Continue' }).should('not.exist'); + cy.contains('2 of 2 combinations work.').should('not.exist'); + chooseView('Visual'); + cy.findByRole('button', { name: 'Test circuit' }).should('be.disabled'); + chooseView('Split'); + cy.findByLabelText('HDL source').should('have.value', invalidHDL); + cy.reload(); + openNotWorkbench(); + cy.findByLabelText('HDL source').should('have.value', invalidHDL); + cy.findByRole('button', { name: 'Test circuit' }).should('be.disabled'); + cy.findByRole('button', { name: 'Continue' }).should('not.exist'); + writeHDL(inverterHDL); + cy.findByRole('alert').should('not.exist'); + cy.findByRole('button', { name: 'Test circuit' }).should('not.be.disabled').click(); + cy.contains('2 of 2 combinations work.'); + }); + + [320, 1280].forEach((width) => { + it(`Keeps every editor view within a ${width}px viewport`, () => { + cy.viewport(width, 900); + expectNoPageOverflow(); + openNotWorkbench(); + expectNoPageOverflow(); + buildInverter(); + expectNoPageOverflow(); + chooseView('Code'); + expectNoPageOverflow(); + cy.findByLabelText('HDL source').invoke('val').should('include', 'Nand(a=in, b=in'); + chooseView('Split'); + expectNoPageOverflow(); + cy.findByRole('button', { name: 'Test circuit' }).click(); + cy.contains('2 of 2 combinations work.'); + expectNoPageOverflow(); + if (width === 320) cy.screenshot('computer-workbench-mobile', { capture: 'fullPage' }); + }); + }); +}); diff --git a/cypress/e2e/home.cy.ts b/cypress/e2e/home.cy.ts index 650cf13..cc55663 100644 --- a/cypress/e2e/home.cy.ts +++ b/cypress/e2e/home.cy.ts @@ -1,21 +1,187 @@ -describe('Home', () => { - it('Contains welcome message and link to content', () => { - cy.visit('/'); - cy.injectAxe(); +import { + checkAccessibility, + expectMainNavigation, + expectNoPageOverflow, + exploreNotAnd, +} from '../support/checks'; + +function visitLanding(reducedMotion = false) { + cy.visit('/', { + onBeforeLoad(window) { + window.localStorage.clear(); + const originalMatchMedia = window.matchMedia.bind(window); + window.matchMedia = (query: string) => { + const result = originalMatchMedia(query); + if (query === '(prefers-reduced-motion: reduce)') { + Object.defineProperty(result, 'matches', { value: reducedMotion }); + } + return result; + }; + }, + }); + cy.get('.landing-page').should('have.attr', 'data-ready', 'true'); +} + +const phases = ['computer', 'components', 'chip', 'signals']; - cy.contains('Wondering how computers work?'); - cy.contains('Find out by embarking on the journey of building your own computer'); +function scrollToPhase(phase: string, fraction = 0.5) { + cy.get(`#journey-${phase}`).then(($section) => { + cy.window().then((window) => { + const box = $section[0].getBoundingClientRect(); + window.scrollTo({ + top: window.scrollY + box.top + box.height * fraction - window.innerHeight / 2, + behavior: 'instant', + }); + }); + }); +} + +describe('Computer journey landing', () => { + it('Offers one clear start with Learn, Tools and About navigation', () => { + visitLanding(); + expectMainNavigation(); + cy.findByRole('heading', { level: 1, name: 'Break down the magic of computers.' }).should( + 'be.visible', + ); + cy.get('.opening') + .findByRole('button', { name: 'Start learning' }) + .then(($button) => { + expect( + $button[0].getBoundingClientRect().bottom, + 'learning starts without scrolling', + ).to.be.at.most(720); + }); + cy.window().then((window) => { + const visibleControls = [ + ...window.document.querySelectorAll( + 'a, button, summary, input, select, [role="switch"]', + ), + ].filter((element) => { + const bounds = element.getBoundingClientRect(); + return ( + Cypress.dom.isVisible(element) && + bounds.width > 0 && + bounds.height > 0 && + bounds.top >= 0 && + bounds.bottom <= window.innerHeight + ); + }); + expect( + visibleControls.map((element) => element.textContent?.trim()), + 'only the brand, three main links, and start action occupy the opening', + ).to.have.length.at.most(5); + }); + cy.findByRole('navigation', { name: 'Workspace menu' }).should('not.exist'); + cy.findByRole('button', { name: /Play layer journey|Pause layer journey/ }).should('not.exist'); + cy.screenshot('computer-home-desktop', { capture: 'viewport' }); + cy.injectAxe(); + checkAccessibility(); + cy.get('.opening').findByRole('button', { name: 'Start learning' }).click(); + cy.location('pathname').should('eq', '/learn'); + cy.findByRole('heading', { name: 'A computer starts with a signal.' }).should('be.visible'); + cy.findByLabelText('HDL source').should('not.exist'); + cy.findByLabelText('Editor view').should('not.exist'); + }); - // Unfortunately, images take a bit to load - cy.wait(1000); - cy.matchImage(); - // ... and screenshots cause the app to reload which may take some time - cy.wait(500); + it('Disassembles the computer and zooms to signals through native scrolling', () => { + visitLanding(); + cy.injectAxe(); + phases.forEach((phase) => { + scrollToPhase(phase); + cy.get('.computer-stage').should('have.attr', 'data-phase', phase); + cy.get(`#journey-${phase}`) + .findByRole('heading', { level: phase === 'computer' ? 1 : 2 }) + .should('be.visible'); + checkAccessibility(); + cy.screenshot(`computer-journey-${phase}`, { capture: 'viewport' }); + }); + cy.get('.computer-stage') + .invoke('attr', 'data-progress') + .then((progress) => { + expect(Number(progress), 'scene reaches the chip-level signal view').to.be.greaterThan(2.5); + }); + // Intermediate scroll positions must remain readable too, not only settled phases. + ['computer', 'components', 'chip'].forEach((phase) => { + scrollToPhase(phase, 0.95); + checkAccessibility(); + }); + cy.get('.journey-start').scrollIntoView(); + checkAccessibility(); + cy.get('.journey-start').findByRole('button', { name: 'Start learning' }).click(); + cy.location('pathname').should('eq', '/learn'); + cy.findByRole('heading', { name: 'A computer starts with a signal.' }).should('be.visible'); + }); - cy.checkA11y(); + it('Provides readable stills for every phase with reduced motion', () => { + visitLanding(true); + cy.get('.computer-journey').should('have.class', 'reduced-motion'); + phases.forEach((phase) => { + cy.get(`#journey-${phase}`).within(() => { + cy.findByRole('heading', { level: phase === 'computer' ? 1 : 2 }).should('be.visible'); + cy.findByRole('img').should('be.visible'); + }); + }); + cy.screenshot('computer-journey-reduced-motion', { capture: 'fullPage' }); + cy.injectAxe(); + checkAccessibility(); + }); - cy.contains('Start Learning').click(); + it('Introduces signals, NOT and AND before NAND on a narrow screen', () => { + cy.viewport(320, 760); + visitLanding(true); + expectMainNavigation(); + expectNoPageOverflow(); + cy.screenshot('computer-home-mobile', { capture: 'fullPage' }); + cy.get('.opening').findByRole('button', { name: 'Start learning' }).click(); + cy.findByRole('heading', { name: 'A computer starts with a signal.' }).should('be.visible'); + cy.screenshot('first-signal-mobile', { capture: 'viewport' }); + cy.injectAxe(); + checkAccessibility(); + cy.findByRole('switch', { name: 'Signal' }).click(); + cy.findByRole('switch', { name: 'Signal' }).click(); + cy.findByRole('button', { name: 'Continue' }).click(); + exploreNotAnd(); + expectNoPageOverflow(); + cy.screenshot('nand-after-foundations-mobile', { capture: 'viewport' }); + checkAccessibility(); + }); - cy.location('pathname').should('eq', '/learn/hardware/boolean-logic'); + it('Plays the optional captioned introduction and restores focus when closed', () => { + visitLanding(true); + cy.findByRole('button', { name: 'Watch the introduction' }).click(); + cy.findByRole('dialog', { name: 'From signals to software' }).should('be.visible'); + cy.get('video').should('have.attr', 'controls'); + cy.get('video source').should('have.attr', 'src', '/media/computer-intro.mp4'); + cy.get('video track[kind="captions"]').should('have.attr', 'default'); + cy.findByRole('link', { name: /Read transcript/ }).should( + 'have.attr', + 'href', + '/media/computer-intro-transcript.txt', + ); + cy.get('video', { timeout: 30000 }).should(($video) => { + const video = $video[0]; + expect(video.error, 'the browser can decode the film').to.equal(null); + expect(video.readyState, 'a decoded video frame is available').to.be.at.least(2); + expect(video.videoWidth).to.equal(1280); + expect(video.videoHeight).to.equal(720); + expect(video.duration).to.be.closeTo(48, 0.2); + }); + cy.get('video').then(($video) => { + const video = $video[0]; + video.pause(); + video.currentTime = 0; + video.muted = true; + return video.play(); + }); + cy.get('video', { timeout: 10000 }).should(($video) => { + expect($video[0].currentTime, 'decoded video playback advances').to.be.greaterThan(0.25); + }); + cy.get('video track[kind="captions"]').should(($track) => { + expect($track[0].readyState, 'captions load').to.equal(2); + expect($track[0].track.cues?.length).to.be.greaterThan(0); + }); + cy.findByRole('button', { name: 'Close introduction' }).click(); + cy.findByRole('dialog').should('not.exist'); + cy.findByRole('button', { name: 'Watch the introduction' }).should('have.focus'); }); }); diff --git a/cypress/e2e/learn.cy.ts b/cypress/e2e/learn.cy.ts index 4876a2a..b1c6b41 100644 --- a/cypress/e2e/learn.cy.ts +++ b/cypress/e2e/learn.cy.ts @@ -1,129 +1,156 @@ -describe('Learn', () => { - it('Can be navigated to from menu', () => { - cy.visit('/'); - cy.injectAxe(); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1500); - - cy.contains('nav button', 'Learn').click(); - - cy.contains('nav a', 'Chip Hardware').click(); - - cy.contains('Boolean Logic'); - - cy.matchImage(); - // ... and screenshots cause the app to reload which may take some time - cy.wait(500); - - cy.checkA11y(); +import { checkAccessibility, expectMainNavigation, expectNoPageOverflow } from '../support/checks'; + +const pages = [ + ['boolean-logic', 'From signals to logic'], + ['boolean-logic/background', 'Logic, composition, and HDL'], + ['boolean-logic/project', 'Gate contracts and larger buses'], + ['meta/what-next', 'Beyond the logic layer'], +]; + +function visitFreshLearning() { + cy.visit('/learn', { + onBeforeLoad(window) { + window.localStorage.clear(); + window.sessionStorage.clear(); + }, }); - - it('Can be navigated using side menu', () => { - cy.visit('/learn/hardware/boolean-logic'); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1000); - - cy.contains('h1', 'Boolean Logic'); - - cy.contains('nav a', 'Background').click(); - - cy.location('pathname').should('eq', '/learn/hardware/boolean-logic/background'); - - cy.contains('h1', 'Background'); - }); - - it('Contains Boolean Logic text with a "next" button', () => { - cy.visit('/learn/hardware/boolean-logic'); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1000); - - cy.contains('h1', 'Boolean Logic'); - - cy.contains('blockquote', 'so complex it defeats us, Almost'); - - cy.contains('p', 'Every digital device'); - - cy.contains('p', 'section on hardware description and simulation tools'); - - cy.contains('a', '1.1 Background').click(); - - cy.location('pathname').should('eq', '/learn/hardware/boolean-logic/background'); - - cy.contains('h1', 'Background'); + cy.get('.computer-game').should('have.attr', 'data-ready', 'true'); +} + +describe('Unified learning and full explanations', () => { + it('Starts Learn at the foundation and opens optional reference in the same interface', () => { + cy.visit('/', { + onBeforeLoad(window) { + window.localStorage.clear(); + }, + }); + cy.findByRole('navigation', { name: 'Main navigation' }) + .findByRole('link', { name: 'Learn' }) + .click(); + cy.location('pathname').should('eq', '/learn'); + cy.findByRole('heading', { name: 'A computer starts with a signal.' }).should('be.visible'); + cy.findByRole('button', { name: 'Reference' }).click(); + cy.findByRole('heading', { level: 1, name: 'Reference' }).should('have.focus'); + cy.findByRole('button', { name: 'NOT' }).should('have.attr', 'aria-pressed', 'true'); + cy.findByRole('link', { name: 'Read the full explanation' }).click(); + cy.location('pathname').should('eq', '/learn/reference/boolean-logic/background'); + cy.findByRole('heading', { level: 1, name: 'Logic, composition, and HDL' }).should( + 'be.visible', + ); + expectMainNavigation(); + cy.findByRole('link', { name: 'Color theme switch' }).should('not.exist'); }); - it('Contains Hardware Background text with a "prev" button', () => { - cy.visit('/learn/hardware/boolean-logic/background'); + it('Keeps every reference chapter accessible with contextual deeper reading', () => { + visitFreshLearning(); + cy.findByRole('button', { name: 'Reference' }).click(); cy.injectAxe(); - cy.configureAxe({ - rules: [ - // MathML is accessible but aXe doesn't properly detect that - { id: 'empty-table-header', enabled: false }, - // Minor Monaco issue this project has no control over - { id: 'landmark-unique', enabled: false }, - // These are all within Monaco that has opt-in high contrast theme that we're bundling - // TODO: How to narrow this down? - { id: 'color-contrast', enabled: false }, - ], + const chapters = [ + ['Signals & gates', 'Signals and gates'], + ['Expressions', 'Boolean expressions'], + ['HDL & composition', 'Interfaces and implementation'], + ['Buses & selectors', 'Buses and selectors'], + ['Read more', 'Source material'], + ]; + chapters.forEach(([button, heading]) => { + cy.findByRole('navigation', { name: 'Reference chapters' }) + .findByRole('button', { name: new RegExp(button) }) + .click(); + cy.findByRole('heading', { name: heading }).should('be.visible'); + checkAccessibility(); }); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1000); - - cy.contains('h1', 'Background'); - - cy.matchImage(); - // ... and screenshots cause the app to reload which may take some time - cy.wait(500); - - cy.checkA11y(); - - cy.contains('p', 'construction of a family of simple chips called Boolean gates'); - - cy.contains('math', '2^n'); - - cy.contains('math', 'f(x, y, z)'); - - cy.findByAltText('Standard symbolic notation of some elementary logic gates.'); - - cy.contains('code', 'Not(..., out=nota)'); - - cy.contains('1 Boolean Logic').click(); - - cy.location('pathname').should('eq', '/learn/hardware/boolean-logic'); - - cy.contains('h1', 'Boolean Logic'); + cy.findByRole('button', { name: 'Back' }).click(); + cy.findByRole('heading', { name: 'A computer starts with a signal.' }).should('be.visible'); }); - it('Works in dark mode', () => { - cy.visit('/learn/hardware/boolean-logic/background'); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1000); - - cy.contains('Color theme switch').click(); - - cy.contains('h1', 'Background'); - - // Wait for animation - cy.wait(2000); - - cy.matchImage(); + it('Redirects every legacy article into the adapted, consistently styled reading', () => { + pages.forEach(([path, title]) => { + cy.visit(`/learn/hardware/${path}`); + cy.location('pathname').should('eq', `/learn/reference/${path}`); + cy.findByRole('heading', { level: 1, name: title }).should('be.visible'); + expectMainNavigation(); + cy.get('main') + .find('a[href^="/experiment/"], a[href^="/learn/hardware/"]') + .should('not.exist'); + cy.get('.monaco-editor').should('not.exist'); + cy.injectAxe(); + checkAccessibility(); + }); }); - it('Has working embedded Hardware IDE with Xor', () => { - cy.visit('/learn/hardware/boolean-logic/background'); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1000); - - cy.findByLabelText('Experiment name').should('have.value', 'Xor Gate'); + it('Covers complete theory and moves through the full explanations without old course chrome', () => { + cy.visit('/learn/reference/boolean-logic'); + cy.findByRole('navigation', { name: 'Continue reading' }) + .findByRole('link', { name: /Next/ }) + .click(); + cy.location('pathname').should('eq', '/learn/reference/boolean-logic/background'); + [ + 'Signals and Boolean operations', + 'Truth tables', + 'Canonical representation', + 'All two-input functions', + 'Universality', + 'Interfaces and composition', + 'A worked XOR circuit', + 'Reading HDL', + 'Testing a construction', + ].forEach((name) => { + cy.findByRole('heading', { name }).should('exist'); + }); + cy.get('#all-two-input-functions') + .nextAll('.reference-table') + .first() + .find('tbody tr') + .should('have.length', 16); + cy.contains('summary', 'In this explanation').click(); + cy.findByRole('navigation', { name: 'On this page' }) + .findByRole('link', { name: 'Universality' }) + .click(); + cy.location('hash').should('eq', '#universality'); + cy.get('#universality').should('be.visible'); + cy.findByRole('navigation', { name: 'Continue reading' }) + .findByRole('link', { name: /Next/ }) + .click(); + cy.location('pathname').should('eq', '/learn/reference/boolean-logic/project'); + cy.findByRole('heading', { name: 'Buses' }).should('exist'); + cy.findByRole('heading', { name: 'Multi-way operations' }).should('exist'); + cy.findByRole('heading', { name: 'Correctness, then efficiency' }).should('exist'); + cy.contains('summary', 'Full explanations').click(); + cy.findByRole('navigation', { name: 'Full explanations' }) + .findByRole('link', { name: 'Overview' }) + .click(); + cy.location('pathname').should('eq', '/learn/reference/boolean-logic'); + }); + it('Links full reading to the working simulator and additional tools', () => { + cy.visit('/learn/reference/boolean-logic/background'); + cy.findByRole('link', { name: 'Open the worked XOR in the hardware simulator' }).click(); + cy.location('pathname').should('eq', '/tools/hardware-simulator/Xor'); + cy.get('.hardware-workspace', { timeout: 20000 }).should('have.attr', 'data-ready', 'true'); cy.findByLabelText('Value for a').clear().type('1').blur(); - cy.contains('tr', 'out').contains('td', '1'); + cy.visit('/learn/reference/meta/what-next'); + cy.findByRole('link', { name: 'Explore all sixteen two-input functions' }).should( + 'have.attr', + 'href', + '/tools/boolean-functions', + ); + cy.findByRole('link', { name: 'Work with buses and routing' }).click(); + cy.location('pathname').should('eq', '/tools/buses'); + cy.findByTestId('bus-output').should('have.text', '65295'); + }); + + it('Keeps complete explanations readable on a narrow screen with keyboard-scrollable tables', () => { + cy.viewport(320, 760); + cy.visit('/learn/reference/boolean-logic/background'); + expectNoPageOverflow(); + cy.get('.reference-table') + .first() + .should('have.attr', 'tabindex', '0') + .focus() + .should('have.focus'); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('full-explanation-mobile', { capture: 'fullPage' }); }); }); diff --git a/cypress/e2e/part-one.cy.ts b/cypress/e2e/part-one.cy.ts new file mode 100644 index 0000000..cbbdd2f --- /dev/null +++ b/cypress/e2e/part-one.cy.ts @@ -0,0 +1,517 @@ +import { checkAccessibility, expectMainNavigation, expectNoPageOverflow } from '../support/checks'; + +function visitComputer() { + cy.visit('/tools/computer'); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); +} + +function writeProgram(source: string) { + cy.findByRole('textbox', { name: 'Program source' }) + .clear() + .type(source, { parseSpecialCharSequences: false, delay: 0 }); + cy.findByRole('button', { name: 'Assemble & load' }).click(); +} + +function step(count = 1) { + for (let index = 0; index < count; index += 1) { + cy.findByRole('button', { name: 'Step' }).click(); + } +} + +describe('From gates to an assembler', () => { + it('Earns progress from a working construction and resumes with the next additive step', () => { + cy.visit('/learn/path/buses'); + cy.get('.course-page') + .should('have.attr', 'data-ready', 'true') + .and('have.attr', 'data-task', 'not16'); + expectMainNavigation(); + cy.findByRole('button', { name: /^Continue/ }).should('not.exist'); + cy.findByRole('button', { name: 'Check my work' }).click(); + cy.findByRole('status').should('contain', 'Keep building.'); + cy.window().then((window) => { + expect( + JSON.parse(window.localStorage.getItem('chipsandcode.part-one.progress.v1') || '[]'), + ).to.deep.equal([]); + }); + cy.findByRole('combobox', { name: 'Construction view' }).select('code'); + const source = `CHIP Not16 { IN in[16]; OUT out[16]; PARTS: +${Array.from({ length: 16 }, (_, bit) => `Not(in=in[${bit}], out=out[${bit}]);`).join('\n')} +}`; + cy.findByRole('textbox', { name: 'HDL source' }) + .clear() + .type(source, { parseSpecialCharSequences: false, delay: 0 }); + cy.findByRole('button', { name: 'Check my work' }).click(); + cy.findByRole('status').should('contain', 'It works.'); + cy.window().then((window) => { + expect( + JSON.parse(window.localStorage.getItem('chipsandcode.part-one.progress.v1') || '[]'), + ).to.deep.equal(['buses/not16']); + expect(window.localStorage.getItem('chipsandcode.part-one.draft.buses/not16')).to.equal( + source, + ); + }); + cy.injectAxe(); + checkAccessibility(); + cy.findByRole('button', { name: /^Continue/ }).click(); + cy.get('.course-page').should('have.attr', 'data-task', 'and16'); + cy.findByRole('heading', { name: 'Combine two words' }).should('have.focus'); + cy.reload(); + cy.get('.course-page') + .should('have.attr', 'data-ready', 'true') + .and('have.attr', 'data-task', 'and16'); + cy.findByRole('button', { name: /^Continue/ }).should('not.exist'); + cy.findByRole('link', { name: /Computer path/ }).click(); + cy.findByRole('link', { name: /Work with words/ }).should('contain', '1 / 9'); + }); + + it('Keeps visual and code construction synchronized and accessible on a small screen', () => { + cy.viewport(320, 760); + cy.visit('/learn/path/buses'); + cy.get('.course-page').should('have.attr', 'data-ready', 'true'); + cy.findByRole('textbox', { name: 'HDL source' }).should('not.exist'); + cy.findByRole('combobox', { name: 'Part to add' }).select('Not'); + cy.findByRole('button', { name: 'Add part' }).click(); + cy.findByRole('textbox', { name: 'Part 1 pin in input' }).type('in[0]', { + parseSpecialCharSequences: false, + }); + cy.findByRole('textbox', { name: 'Part 1 pin out output' }).type('out[0]', { + parseSpecialCharSequences: false, + }); + cy.injectAxe(); + checkAccessibility(); + expectNoPageOverflow(); + cy.findByRole('combobox', { name: 'Construction view' }).select('split'); + cy.findByRole('textbox', { name: 'HDL source' }).should( + 'contain.value', + 'Not(in=in[0], out=out[0]);', + ); + expectNoPageOverflow(); + checkAccessibility(); + cy.screenshot('course-mobile-construction', { capture: 'fullPage' }); + cy.reload(); + cy.get('.course-page').should('have.attr', 'data-ready', 'true'); + cy.findByRole('textbox', { name: 'Part 1 pin in input' }).should('have.value', 'in[0]'); + cy.findByRole('textbox', { name: 'Part 1 pin out output' }).should('have.value', 'out[0]'); + }); + + it('Stops a learner assembler that loops forever and lets them repair it', () => { + cy.visit('/learn/path/assembler'); + cy.get('.course-page').should('have.attr', 'data-ready', 'true'); + cy.contains('summary', 'Steps in this layer').click(); + cy.findByRole('button', { name: 'Build your assembler' }).click(); + cy.findByRole('textbox', { name: 'Assembler source' }) + .clear() + .type('function assemble(source) { while (true) {} }', { parseSpecialCharSequences: false }); + cy.findByRole('button', { name: 'Check my work' }).click(); + cy.findByRole('status', { timeout: 10000 }).should('contain', '4 seconds'); + cy.findByRole('button', { name: 'Check my work' }).should('be.enabled'); + cy.get('iframe[title="Isolated assembler verification"]').should('not.exist'); + cy.findByRole('textbox', { name: 'Assembler source' }) + .clear() + .type('function assemble(source) { return ""; }', { parseSpecialCharSequences: false }); + cy.findByRole('button', { name: 'Check my work' }).click(); + cy.findByRole('status') + .should('contain', 'Translation 1 differs') + .and('not.contain', '4 seconds'); + cy.findByRole('button', { name: 'Check my work' }).should('be.enabled'); + cy.get('iframe[title="Isolated assembler verification"]').should('not.exist'); + }); + + it('Assembles source and traces real register and memory changes', () => { + visitComputer(); + expectMainNavigation(); + cy.findByTestId('register-pc').should('have.text', '0'); + step(); + cy.findByTestId('register-a').should('have.text', '7'); + cy.findByTestId('register-d').should('have.text', '0'); + step(); + cy.findByTestId('register-d').should('have.text', '7'); + step(2); + cy.findByTestId('memory-0').should('have.text', '7'); + cy.findByTestId('register-pc').should('have.text', '4'); + cy.contains('summary', 'Last instruction').click(); + cy.contains('Memory[0] ← 7').should('be.visible'); + cy.findByRole('button', { name: 'Run' }).should('be.disabled'); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('computer-instruction-trace', { capture: 'fullPage' }); + }); + + it('Resolves forward labels and variable symbols, then runs binary input', () => { + visitComputer(); + writeProgram('@NEXT\n0;JMP\n@99\n(NEXT)\n@value\nM=1'); + cy.contains('summary', 'Symbol table').click(); + cy.findByRole('region', { name: 'Assembler symbols' }).within(() => { + cy.contains('tr', 'NEXT').should('contain', '3'); + cy.contains('tr', 'value').should('contain', '16'); + }); + step(2); + cy.findByTestId('register-pc').should('have.text', '3'); + step(2); + cy.findByRole('textbox', { name: 'Memory start address' }).clear().type('16'); + cy.findByTestId('memory-16').should('have.text', '1'); + cy.findByRole('combobox', { name: 'Source format' }).select('binary'); + // @7, D=A, @0, M=D: a supplied machine program independent of this assembler. + writeProgram('0000000000000111\n1110110000010000\n0000000000000000\n1110001100001000'); + cy.findByRole('button', { name: 'Run' }).click(); + cy.findByRole('textbox', { name: 'Memory start address' }).clear().type('0'); + cy.findByTestId('memory-0').should('have.text', '7'); + cy.contains('summary', 'Machine code').click(); + cy.findByRole('region', { name: 'Machine instructions' }).should('contain', '1110110000010000'); + }); + + it('Rejects invalid source without keeping an executable stale program and preserves the draft', () => { + visitComputer(); + writeProgram('@32768\nD=A'); + cy.findByRole('alert').should('be.visible'); + cy.findByRole('button', { name: 'Step' }).should('be.disabled'); + cy.findByRole('button', { name: 'Run' }).should('be.disabled'); + cy.contains('summary', 'Machine code').should('not.exist'); + cy.reload(); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + cy.findByRole('textbox', { name: 'Program source' }).should('have.value', '@32768\nD=A'); + cy.findByRole('alert').should('be.visible'); + cy.findByRole('combobox', { name: 'Source format' }).select('binary'); + writeProgram('101'); + cy.findByRole('alert').should('be.visible'); + cy.findByRole('button', { name: 'Run' }).should('be.disabled'); + cy.findByRole('combobox', { name: 'Source format' }).select('assembly'); + writeProgram('@9\nD=A\n@0\nM=D'); + cy.findByRole('button', { name: 'Run' }).click(); + cy.findByTestId('memory-0').should('have.text', '9'); + cy.findByRole('alert').should('not.exist'); + }); + + it('Connects screen and keyboard devices to their memory-mapped addresses', () => { + visitComputer(); + cy.contains('summary', 'Small examples').click(); + cy.findByRole('button', { name: 'Light 16 pixels' }).click(); + cy.findByRole('button', { name: 'Run' }).click(); + cy.findByRole('textbox', { name: 'Memory start address' }).clear().type('16384'); + cy.findByTestId('memory-16384').should('have.text', '65535'); + cy.get('.hack-screen canvas').should(($canvas) => { + const context = $canvas[0].getContext('2d'); + expect(context, 'screen renderer').not.to.equal(null); + expect(context!.getImageData(0, 0, 1, 1).data[0], 'first pixel is lit').to.be.lessThan(128); + expect(context!.getImageData(15, 0, 1, 1).data[0], 'sixteenth pixel is lit').to.be.lessThan( + 128, + ); + expect( + context!.getImageData(16, 0, 1, 1).data[0], + 'next word remains clear', + ).to.be.greaterThan(128); + }); + cy.findByRole('textbox', { name: 'Memory start address' }).clear().type('24576'); + cy.findByTestId('memory-24576').should('have.text', '0'); + cy.findByRole('textbox', { name: 'Keyboard input' }) + .focus() + .trigger('keydown', { key: 'ArrowLeft', code: 'ArrowLeft' }); + cy.findByTestId('memory-24576').should('have.text', '130'); + cy.findByRole('textbox', { name: 'Keyboard input' }).trigger('keyup', { key: 'ArrowLeft' }); + cy.findByTestId('memory-24576').should('have.text', '0'); + cy.findByRole('textbox', { name: 'Keyboard input' }).trigger('keydown', { + key: 'F12', + code: 'F12', + }); + cy.findByTestId('memory-24576').should('have.text', '152'); + cy.findByRole('textbox', { name: 'Keyboard input' }).blur(); + cy.findByTestId('memory-24576').should('have.text', '0'); + }); + + it('Compiles multi-bit HDL and removes stale output after an invalid input or definition', () => { + cy.visit('/tools/chip-builder'); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + expectMainNavigation(); + cy.findByTestId('chip-output-out').should('have.text', '65535'); + cy.findByRole('textbox', { name: 'Input in' }).clear().type('0x00ff'); + cy.findByTestId('chip-output-out').should('have.text', '65280'); + cy.findByRole('textbox', { name: 'Input in' }).clear().type('65536'); + cy.findByRole('alert').should('contain', '65535'); + cy.findByTestId('chip-output-out').should('have.text', '—'); + cy.findByRole('textbox', { name: 'Chip HDL' }) + .clear() + .type('CHIP Invalid {', { parseSpecialCharSequences: false }); + cy.findByRole('button', { name: 'Compile' }).click(); + cy.findByRole('alert').should('be.visible'); + cy.findByTestId('chip-output-out').should('not.exist'); + cy.findByRole('button', { name: 'Tick' }).should('be.disabled'); + }); + + it('Separates captured next state from committed register state across tick and tock', () => { + cy.visit('/tools/chip-builder'); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + cy.contains('summary', 'Inspect a supplied component').click(); + cy.findByRole('button', { name: 'Register' }).click(); + cy.findByRole('textbox', { name: 'Input in' }).clear().type('7'); + cy.findByRole('textbox', { name: 'Input load' }).clear().type('1'); + cy.findByTestId('chip-output-out').should('have.text', '0'); + cy.findByRole('button', { name: 'Tick' }).click(); + cy.findByTestId('chip-output-out').should('have.text', '0'); + cy.findByRole('button', { name: 'Tock' }).click(); + cy.findByTestId('chip-output-out').should('have.text', '7'); + cy.findByRole('textbox', { name: 'Input load' }).clear().type('0'); + cy.findByRole('textbox', { name: 'Input in' }).clear().type('12'); + cy.findByRole('button', { name: 'Tick' }).click(); + cy.findByRole('button', { name: 'Tock' }).click(); + cy.findByTestId('chip-output-out').should('have.text', '7'); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('clocked-chip-builder', { capture: 'fullPage' }); + cy.reload(); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + cy.findByRole('textbox', { name: 'Chip HDL' }).should('contain.value', 'Register(in=in'); + cy.findByRole('textbox', { name: 'Input load' }).should('exist'); + }); + + it('Runs clocked TST scripts and reports real comparison failures', () => { + cy.visit('/tools/chip-builder'); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + cy.contains('summary', 'Inspect a supplied component').click(); + cy.findByRole('button', { name: 'Register' }).click(); + cy.contains('summary', 'Test scripts').click(); + const script = + 'output-list in%D1.6.1 load%B1.1.1 out%D1.6.1;\nset in 7, set load 1, eval, output;\ntick, output;\ntock, output;\nset in 9, set load 0, tick, tock, output;'; + const expected = + '| in | load | out |\n| 7 | 1 | 0 |\n| 7 | 1 | 0 |\n| 7 | 1 | 7 |\n| 9 | 0 | 7 |'; + cy.findByRole('textbox', { name: 'TST script' }) + .clear() + .type(script, { parseSpecialCharSequences: false, delay: 0 }); + cy.findByRole('textbox', { name: 'Expected output' }).type(expected, { delay: 0 }); + cy.findByRole('button', { name: 'Run tests' }).click(); + cy.contains('[role="status"]', '4 passed, 0 failed').should('be.visible'); + cy.findByTestId('chip-output-out').should('have.text', '7'); + cy.findByRole('textbox', { name: 'Actual test output' }).should('contain.value', 'out'); + cy.findByRole('textbox', { name: 'Expected output' }) + .clear() + .type(expected.replace('| 7 | 1 | 0 |', '| 7 | 1 | 99 |'), { delay: 0 }); + cy.findByRole('button', { name: 'Run tests' }).click(); + cy.contains('[role="status"]', '3 passed, 1 failed').should('be.visible'); + cy.injectAxe(); + checkAccessibility(); + }); + + it('Runs a ROM program through the clocked computer inside a compiled HDL circuit', () => { + cy.visit('/tools/chip-builder'); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + cy.contains('summary', 'Inspect a supplied component').click(); + cy.findByRole('button', { name: 'Computer' }).click(); + cy.contains('summary', 'ROM and keyboard').click(); + cy.findByRole('button', { name: 'Load ROM' }).click(); + cy.findByRole('button', { name: 'Inspect memory' }).click(); + cy.findByTestId('chip-memory-word').should('have.text', '0'); + for (let cycle = 0; cycle < 4; cycle += 1) { + cy.findByRole('button', { name: 'Tick' }).click(); + cy.findByTestId('chip-memory-word').should('have.text', '0'); + cy.findByRole('button', { name: 'Tock' }).click(); + } + cy.findByTestId('chip-memory-word').should('have.text', '7'); + cy.findByRole('button', { name: 'Reset' }).click(); + cy.findByTestId('chip-memory-word').should('have.text', '0'); + }); + + it('Keeps the multi-bit builder keyboard accessible on a narrow screen', () => { + cy.viewport(320, 760); + cy.visit('/tools/chip-builder'); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + expectNoPageOverflow(); + cy.injectAxe(); + checkAccessibility(); + cy.findByRole('combobox', { name: 'View' }).select('visual'); + cy.findByRole('textbox', { name: 'Chip HDL' }).should('not.exist'); + cy.findByRole('textbox', { name: 'Input in' }).clear().type('65535'); + cy.findByTestId('chip-output-out').should('have.text', '0'); + expectNoPageOverflow(); + checkAccessibility(); + cy.screenshot('chip-builder-mobile', { capture: 'fullPage' }); + }); + + it('Keeps the computer workspace usable at 320 pixels in every view', () => { + cy.viewport(320, 760); + visitComputer(); + expectNoPageOverflow(); + cy.injectAxe(); + checkAccessibility(); + cy.findByRole('combobox', { name: 'View' }).select('visual'); + cy.findByRole('textbox', { name: 'Program source' }).should('not.exist'); + cy.findByRole('heading', { name: 'Machine state' }).should('be.visible'); + expectNoPageOverflow(); + cy.findByRole('combobox', { name: 'View' }).select('code'); + cy.findByRole('textbox', { name: 'Program source' }).should('be.visible'); + cy.findByRole('heading', { name: 'Machine state' }).should('not.exist'); + cy.contains('summary', 'Machine code').click(); + cy.findByRole('region', { name: 'Machine instructions' }).focus().should('be.focused'); + expectNoPageOverflow(); + checkAccessibility(); + cy.screenshot('computer-mobile-code', { capture: 'fullPage' }); + }); +}); + +describe('The complete tool suite', () => { + it('Executes VM stack commands and clears a stale machine when source becomes invalid', () => { + cy.viewport(320, 760); + cy.visit('/tools/vm'); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + expectMainNavigation(); + cy.findByTestId('vm-current').should('contain', 'push constant 7'); + cy.findByRole('button', { name: 'Step' }).click(); + cy.findByTestId('vm-stack').find('strong').should('have.length', 1).and('have.text', '7'); + cy.findByRole('button', { name: 'Step' }).click(); + cy.findByTestId('vm-stack') + .find('strong') + .should('have.length', 2) + .last() + .should('have.text', '8'); + cy.findByRole('button', { name: 'Run' }).click(); + cy.findByTestId('vm-stack').find('strong').should('have.length', 1).and('have.text', '15'); + cy.findByRole('button', { name: 'Run' }).should('be.disabled'); + expectNoPageOverflow(); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('vm-mobile-stack', { capture: 'fullPage' }); + cy.findByRole('textbox', { name: 'Source code' }).clear().type('push imaginary 7'); + cy.findByRole('button', { name: 'Step' }).should('be.disabled'); + cy.findByTestId('vm-stack').should('contain', 'The stack is empty.'); + cy.findByRole('button', { name: 'Load program' }).click(); + cy.findByRole('alert').should('be.visible'); + cy.findByRole('button', { name: 'Run' }).should('be.disabled'); + cy.findByRole('textbox', { name: 'Source code' }) + .clear() + .type('push constant 7\npush constant 8\nadd\npop temp 0', { delay: 0 }); + cy.findByRole('button', { name: 'Load program' }).click(); + cy.findByRole('button', { name: 'Run' }).click(); + cy.contains('summary', 'Inspect memory').click(); + cy.findByRole('textbox', { name: 'Memory address' }).clear().type('5'); + cy.findByRole('button', { name: 'Read memory' }).click(); + cy.findByTestId('vm-memory').should('have.text', '15'); + cy.findByRole('alert').should('not.exist'); + cy.findByRole('button', { name: 'Reset' }).click(); + cy.findByTestId('vm-memory').should('have.text', '0'); + }); + + it('Compiles multiple Jack classes and runs their transferred VM code', () => { + cy.viewport(320, 760); + cy.visit('/tools/compiler'); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + expectMainNavigation(); + cy.findByRole('button', { name: 'Compile Jack' }).click(); + cy.findByRole('textbox', { name: 'Generated VM' }).should( + 'contain.value', + 'function Main.main', + ); + cy.findByRole('textbox', { name: 'Source code' }) + .clear() + .type('class Main {', { parseSpecialCharSequences: false }); + cy.findByRole('textbox', { name: 'Generated VM' }).should('have.value', ''); + cy.findByRole('button', { name: 'Open in VM emulator' }).should('be.disabled'); + cy.findByRole('button', { name: 'Compile Jack' }).click(); + cy.findByRole('alert').should('contain', 'Main.jack'); + cy.findByRole('textbox', { name: 'Source code' }) + .clear() + .type( + 'class Main { function void main() { do Memory.poke(100, Helper.twice(21)); return; } }', + { parseSpecialCharSequences: false, delay: 0 }, + ); + cy.contains('summary', 'Project files').click(); + cy.findByRole('textbox', { name: 'New file name' }).type('Helper.jack'); + cy.findByRole('button', { name: 'Add file' }).click(); + cy.findByRole('textbox', { name: 'Source code' }).type( + 'class Helper { function int twice(int value) { return value + value; } }', + { parseSpecialCharSequences: false, delay: 0 }, + ); + cy.findByRole('button', { name: 'Compile Jack' }).click(); + cy.findByRole('combobox', { name: 'VM output file' }).select('Main.vm'); + cy.findByRole('textbox', { name: 'Generated VM' }).should( + 'contain.value', + 'call Helper.twice 1', + ); + cy.findByRole('alert').should('not.exist'); + expectNoPageOverflow(); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('compiler-mobile-project', { capture: 'fullPage' }); + cy.findByRole('button', { name: 'Open in VM emulator' }).click(); + cy.location('pathname').should('eq', '/tools/vm'); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + cy.findByRole('combobox', { name: 'Source file' }).select('Main.vm'); + cy.findByRole('textbox', { name: 'Source code' }).should( + 'contain.value', + 'call Helper.twice 1', + ); + cy.reload(); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + cy.findByRole('combobox', { name: 'Source file' }).select('Main.vm'); + cy.findByRole('textbox', { name: 'Source code' }).should( + 'contain.value', + 'call Helper.twice 1', + ); + cy.findByRole('combobox', { name: 'Source file' }).find('option').should('have.length', 2); + cy.findByRole('button', { name: 'Run' }).click(); + cy.findByRole('status', { timeout: 10000 }).should('contain', 'Program finished.'); + cy.contains('summary', 'Inspect memory').click(); + cy.findByRole('textbox', { name: 'Memory address' }).clear().type('100'); + cy.findByRole('button', { name: 'Read memory' }).click(); + cy.findByTestId('vm-memory').should('have.text', '42'); + }); + + it('Edits accessible bitmap pixels and executes the generated drawing code', () => { + cy.viewport(320, 760); + cy.visit('/tools/bitmap'); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + expectMainNavigation(); + cy.findByRole('button', { name: 'Pixel 0, 0 off' }).focus().type(' '); + cy.findByRole('button', { name: 'Pixel 0, 0 on' }).should('have.attr', 'aria-pressed', 'true'); + cy.findByRole('textbox', { name: 'Generated bitmap code' }).should( + 'contain.value', + 'Memory.poke(16384, 1)', + ); + cy.findByRole('button', { name: 'Pixel 0, 0 on' }).type(' '); + cy.findByRole('button', { name: 'Pixel 15, 0 off' }).focus().type(' '); + cy.findByRole('textbox', { name: 'Generated bitmap code' }).should( + 'contain.value', + 'Memory.poke(16384, ~32767)', + ); + cy.findByRole('button', { name: 'Pixel 0, 1 off' }).focus().type(' '); + cy.findByRole('combobox', { name: 'Export' }).select('words'); + cy.findByRole('textbox', { name: 'Generated bitmap code' }) + .should('contain.value', '16384: 32768') + .and('contain.value', '16416: 1'); + cy.contains('summary', 'Screen position').click(); + cy.findByRole('textbox', { name: 'X' }).clear().type('512'); + cy.findByRole('alert').should('be.visible'); + cy.findByRole('textbox', { name: 'Generated bitmap code' }).should('have.value', ''); + cy.findByRole('button', { name: 'Download code' }).should('be.disabled'); + cy.findByRole('textbox', { name: 'X' }).clear().type('0'); + cy.findByRole('alert').should('not.exist'); + expectNoPageOverflow(); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('bitmap-mobile-drawing', { capture: 'fullPage' }); + cy.reload(); + cy.get('.machine-lab').should('have.attr', 'data-ready', 'true'); + cy.findByRole('button', { name: 'Pixel 15, 0 on' }).should('have.attr', 'aria-pressed', 'true'); + cy.findByRole('button', { name: 'Pixel 0, 1 on' }).should('have.attr', 'aria-pressed', 'true'); + cy.findByRole('combobox', { name: 'Export' }).select('assembly'); + cy.findByRole('textbox', { name: 'Generated bitmap code' }) + .invoke('val') + .then((source) => { + visitComputer(); + writeProgram(String(source)); + cy.findByRole('button', { name: 'Run' }).click(); + cy.findByRole('textbox', { name: 'Memory start address' }).clear().type('16384'); + cy.findByTestId('memory-16384').should('have.text', '32768'); + cy.findByRole('textbox', { name: 'Memory start address' }).clear().type('16416'); + cy.findByTestId('memory-16416').should('have.text', '1'); + cy.get('.hack-screen canvas').should(($canvas) => { + const context = $canvas[0].getContext('2d'); + expect(context!.getImageData(0, 0, 1, 1).data[0], 'bit 0 is clear').to.be.greaterThan( + 128, + ); + expect(context!.getImageData(15, 0, 1, 1).data[0], 'bit 15 is lit').to.be.lessThan(128); + expect( + context!.getImageData(0, 1, 1, 1).data[0], + 'next screen row is lit', + ).to.be.lessThan(128); + }); + }); + }); +}); diff --git a/cypress/e2e/profile.cy.ts b/cypress/e2e/profile.cy.ts index d479c59..55832c8 100644 --- a/cypress/e2e/profile.cy.ts +++ b/cypress/e2e/profile.cy.ts @@ -1,24 +1,16 @@ -describe('Profile', () => { - it('Can be navigated to using icon', () => { - cy.visit('/'); - cy.injectAxe(); - - // TODO: Find a way to suppress dynamic ESM loading for Cypress tests - cy.wait(1500); - - cy.findByLabelText('User account').click(); - - cy.contains('Hi, Anonym'); +import { checkAccessibility, expectMainNavigation } from '../support/checks'; - cy.contains('anonymous'); - cy.contains('from the same device'); - cy.contains('is read-only'); - - cy.matchImage(); - - // ... and screenshots cause the app to reload which may take some time - cy.wait(500); - - cy.checkA11y(); +describe('Device storage and legacy account route', () => { + it('Redirects the old sign-in page to an honest account explanation on About', () => { + cy.visit('/signin'); + cy.location('pathname').should('eq', '/about'); + cy.location('hash').should('eq', '#device-storage'); + expectMainNavigation(); + cy.findByRole('heading', { name: 'Your work, on this device' }).should('be.visible'); + cy.contains('Learning progress and circuit drafts are kept in your browser.'); + cy.contains('Accounts and cross-device progress sync are not available yet.'); + cy.findByText('Hi, Anonym').should('not.exist'); + cy.injectAxe(); + checkAccessibility(); }); }); diff --git a/cypress/e2e/tools.cy.ts b/cypress/e2e/tools.cy.ts new file mode 100644 index 0000000..1c2ce5c --- /dev/null +++ b/cypress/e2e/tools.cy.ts @@ -0,0 +1,131 @@ +import { checkAccessibility, expectMainNavigation, expectNoPageOverflow } from '../support/checks'; + +function visitLab(tool: 'boolean-functions' | 'buses') { + cy.visit(`/tools/${tool}`); + cy.get('.logic-lab').should('have.attr', 'data-ready', 'true'); +} + +function chooseComponent(value: string) { + cy.findByRole('combobox', { name: 'Component' }).select(value).should('have.value', value); +} + +function setWord(name: string, value: string) { + cy.findByRole('textbox', { name }).clear().type(value); +} + +describe('Logic tools', () => { + it('Connects edited truth tables, canonical form, NAND construction, and equivalence', () => { + visitLab('boolean-functions'); + expectMainNavigation(); + cy.findByRole('heading', { level: 1, name: 'Boolean functions' }).should('be.visible'); + cy.findByRole('combobox', { name: 'Function' }).should('have.value', '6'); + cy.findByTestId('function-output').should('have.text', '0'); + cy.findByRole('button', { name: 'Input a 0' }).click(); + cy.findByRole('button', { name: 'Input a 1' }).should('have.attr', 'aria-pressed', 'true'); + cy.findByTestId('function-output').should('have.text', '1'); + cy.findByRole('button', { name: 'Input b 0' }).click(); + cy.findByTestId('function-output').should('have.text', '0'); + cy.findByRole('combobox', { name: 'Function' }).select('1'); + cy.findByTestId('canonical-expression').should('have.text', 'f = (a AND b)'); + cy.findByTestId('function-output').should('have.text', '1'); + cy.findByRole('button', { name: 'Output for a 0 b 0: 0' }).click(); + cy.findByRole('button', { name: 'Output for a 0 b 0: 1' }).should( + 'have.attr', + 'aria-pressed', + 'true', + ); + cy.findByRole('combobox', { name: 'Function' }).should('have.value', '9'); + cy.findByTestId('canonical-expression').should('contain', '(NOT a AND NOT b) OR (a AND b)'); + cy.contains('summary', 'NAND construction').click(); + cy.findByTestId('nand-verification').should('contain', '4 of 4 input combinations match.'); + cy.findByLabelText('Equivalent NAND HDL').should('contain', 'CHIP Function2'); + cy.contains('summary', 'Compare functions').click(); + cy.findByRole('combobox', { name: 'Compare with' }).select('6'); + cy.findByTestId('equivalence-result').should('contain', '4 of 4 input combinations differ'); + cy.findByRole('combobox', { name: 'Compare with' }).select('9'); + cy.findByTestId('equivalence-result').should( + 'contain', + 'Equivalent: all 4 input combinations match.', + ); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('boolean-functions-lab', { capture: 'fullPage' }); + }); + + it('Computes bus operations, exposes bit order, and rejects out-of-range words', () => { + visitLab('buses'); + expectMainNavigation(); + cy.findByRole('heading', { level: 1, name: 'Buses and routing' }).should('be.visible'); + cy.findByTestId('bus-output').should('have.text', '65295'); + setWord('Input in', '0'); + cy.findByTestId('bus-output').should('have.text', '65535'); + cy.contains('summary', 'Inspect individual bits').click(); + cy.findByRole('button', { name: 'Input in bit 15: 0' }).click(); + cy.findByTestId('bus-output').should('have.text', '32767'); + setWord('Input in', '65536'); + cy.findByRole('alert').should('be.visible'); + cy.findByTestId('bus-output') + .should('contain', 'Enter valid inputs') + .and('not.contain', '32767'); + setWord('Input in', '0'); + chooseComponent('and16'); + setWord('Input a', '0xAAAA'); + setWord('Input b', '0x5555'); + cy.findByTestId('bus-output').should('have.text', '0'); + chooseComponent('or16'); + cy.findByTestId('bus-output').should('have.text', '65535'); + chooseComponent('or8way'); + setWord('Input in', '0b00000000'); + cy.findByTestId('bus-output').should('have.text', '0'); + setWord('Input in', '0b10000000'); + cy.findByTestId('bus-output').should('have.text', '1'); + cy.injectAxe(); + checkAccessibility(); + }); + + it('Routes whole words and single signals using the selected path only', () => { + visitLab('buses'); + chooseComponent('mux4way16'); + cy.findByRole('combobox', { name: 'Selector' }).select('2'); + cy.findByTestId('bus-output').should('have.text', '13107'); + cy.findByRole('combobox', { name: 'Input to edit' }).select('c'); + setWord('Input c', '42'); + cy.findByTestId('bus-output').should('have.text', '42'); + chooseComponent('mux8way16'); + cy.findByRole('combobox', { name: 'Selector' }).select('7'); + cy.findByTestId('bus-output').should('have.text', '65535'); + chooseComponent('dmux8way'); + cy.findByRole('combobox', { name: 'Selector' }).select('7'); + cy.findByTestId('bus-output-h').should('have.text', '1'); + ['a', 'b', 'c', 'd', 'e', 'f', 'g'].forEach((pin) => { + cy.findByTestId(`bus-output-${pin}`).should('have.text', '0'); + }); + cy.findByRole('button', { name: 'Input in 1' }).click(); + cy.findByTestId('bus-output-h').should('have.text', '0'); + cy.contains('summary', 'How this component is built').click(); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('bus-routing-lab', { capture: 'fullPage' }); + }); + + it('Keeps both new labs readable and operable at 320 pixels', () => { + cy.viewport(320, 760); + visitLab('boolean-functions'); + expectNoPageOverflow(); + cy.findByRole('combobox', { name: 'Function' }).select('15'); + cy.contains('summary', 'NAND construction').click(); + expectNoPageOverflow(); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('boolean-functions-mobile', { capture: 'fullPage' }); + visitLab('buses'); + chooseComponent('mux8way16'); + cy.contains('summary', 'Inspect individual bits').click(); + cy.findByRole('button', { name: 'Input a bit 0: 0' }).click(); + cy.findByTestId('bus-output').should('have.text', '241'); + expectNoPageOverflow(); + cy.injectAxe(); + checkAccessibility(); + cy.screenshot('buses-mobile', { capture: 'fullPage' }); + }); +}); diff --git a/cypress/support/checks.ts b/cypress/support/checks.ts new file mode 100644 index 0000000..49df956 --- /dev/null +++ b/cypress/support/checks.ts @@ -0,0 +1,63 @@ +export function checkAccessibility() { + cy.checkA11y(undefined, undefined, (violations) => { + if (violations.length) { + throw new Error( + violations + .map( + (violation) => + `${violation.id}:\n${violation.nodes + .map((node) => `${JSON.stringify(node.target)}\n${node.failureSummary}`) + .join('\n')}`, + ) + .join('\n\n'), + ); + } + }); +} + +export function expectNoPageOverflow() { + cy.document().should((document) => { + expect( + Math.max(document.documentElement.scrollWidth, document.body.scrollWidth), + 'page content fits the viewport', + ).to.be.at.most(document.documentElement.clientWidth + 1); + }); +} + +export function expectMainNavigation() { + cy.findAllByRole('navigation', { name: 'Main navigation' }).should('have.length', 1); + cy.findByRole('navigation', { name: 'Main navigation' }).within(() => { + cy.findAllByRole('link').should('have.length', 3); + cy.findByRole('link', { name: 'Learn' }).should('have.attr', 'href', '/learn'); + cy.findByRole('link', { name: 'Tools' }).should('have.attr', 'href', '/tools'); + cy.findByRole('link', { name: 'About' }).should('have.attr', 'href', '/about'); + }); + cy.findByText('Color theme switch').should('not.exist'); +} + +export function exploreNotAnd() { + cy.get('.signal-intro').should('have.attr', 'data-foundation', 'not'); + cy.findByRole('heading', { name: 'First, flip a signal.' }).should('be.visible'); + cy.findByRole('button', { name: 'Continue' }).should('not.exist'); + cy.findByRole('switch', { name: 'NOT input' }) + .should('have.attr', 'aria-checked', 'false') + .click() + .should('have.attr', 'aria-checked', 'true'); + cy.findByRole('img', { name: 'Output 0' }).should('be.visible'); + cy.findByRole('switch', { name: 'NOT input' }).click(); + cy.findByRole('img', { name: 'Output 1' }).should('be.visible'); + cy.findByRole('button', { name: 'Continue' }).click(); + + cy.get('.signal-intro').should('have.attr', 'data-foundation', 'and'); + cy.findByRole('heading', { name: 'Now, combine two signals.' }).should('be.visible'); + cy.findByRole('button', { name: 'Continue' }).should('not.exist'); + cy.findByRole('switch', { name: 'AND input a' }).click(); + cy.findByRole('img', { name: 'Output 0' }).should('be.visible'); + cy.findByRole('switch', { name: 'AND input b' }).click(); + cy.findByRole('img', { name: 'Output 1' }).should('be.visible'); + cy.findByRole('switch', { name: 'AND input a' }).click(); + cy.findByRole('img', { name: 'Output 0' }).should('be.visible'); + cy.findByRole('switch', { name: 'AND input b' }).click(); + cy.findByRole('button', { name: 'Continue' }).click(); + cy.findByRole('heading', { name: 'AND, with its answer flipped.' }).should('be.visible'); +} diff --git a/docs/art-direction.md b/docs/art-direction.md new file mode 100644 index 0000000..c2241d2 --- /dev/null +++ b/docs/art-direction.md @@ -0,0 +1,41 @@ +# Chips and Code: visual direction + +## Identity and composition + +Keep the original chip/code mark and indigo `#4f46e5`. Use a mature, precise visual language: technical illustration, clear typography, responsive signals, and restrained depth. Avoid fictional geography, currency, mascots, ornamental counters, and gamification unrelated to constructing a computer. + +The landing opens “Break down the magic of computers” with “By building your own.” A recognizable computer is the main visual. Native scrolling separates its actual components, then the view moves into the processor and resolves into signals. This is one connected visual transformation, not a succession of unrelated cards. The pale conclusion points from signals back toward software. + +One learning action is repeated at the end. Learn, Tools, About stay visible as the main navigation. The optional film is a secondary text link. No chapter tabs, autoplay timeline, or playback dashboard appears in the landing. + +## Palette + +| Role | Typical color | +| --- | --- | +| Shared canvas | `#080b13` | +| Working panel | `#131725` | +| Primary ink | `#f4f3ff` | +| Secondary ink | `#b8bfd1` | +| Original brand | `#4f46e5` | +| Bright signal/link | `#c0b7ff` | +| Inactive functional wire | `#747d99` | +| Pale narrative surface | `#f1eff8` | +| Ink on pale surface | `#161327` | + +These are explicit foreground/background pairs. Do not let a browser theme preference change only one side of a pair. Keep ordinary text at least 4.5:1 and meaningful non-text states/controls at least 3:1 against their surroundings. Dividers and decorative traces may be subtler, but an inactive signal must still be visible. Focus rings must work on their surrounding surface; a light CTA needs a dark external ring. + +## Typography and interaction + +Use a clean sans-serif for navigation, explanations, and body copy. Monospace belongs to values, signals, code, and compact technical labels. Large headlines are sparse; reading paragraphs use comfortable line lengths and line spacing. Avoid decorative jargon and tiny labels used to fit redundant content. + +Learning adds one idea at a time: signal, NOT, AND, NAND, then construction. Keep the current instruction close to its diagram. Show advanced controls and longer theory when requested. Visual and HDL remain equal authoring views through one compact selector, with a useful desktop Split layout and readable single views on mobile. + +Tools have the same canvas, type, boundaries, and focus behavior as Learn. The simulator can expose editing and debugging detail because that is its task; its default screen should still emphasize code and signal behavior. Full reading uses the same visual style and contextual tool links, not legacy course chrome. + +## Motion, access, and small screens + +Scroll owns the landing animation. Do not hijack scrolling or add continuous decorative movement. Mobile and reduced-motion views show a static sequence with the same explanations. Values and names accompany state colors. Meaningful diagrams have textual equivalents. + +Native controls provide switches, selectors, disclosures, and video playback. Keep a visible focus indicator and a stable progression after each action. Layouts fit 320px; code and broad circuit surfaces may scroll within their own boundaries. No page-level horizontal overflow should be required. + +See [interaction design](computer-layers-design.md) and [film production](intro-production.md). diff --git a/docs/computer-layers-design.md b/docs/computer-layers-design.md new file mode 100644 index 0000000..dfeb20c --- /dev/null +++ b/docs/computer-layers-design.md @@ -0,0 +1,64 @@ +# Chips and Code: one interface, from signals up + +## The experience + +The original chip/code mark and indigo identity remain. A computer is the subject of the experience, not a fictional map. The landing begins “Break down the magic of computers. By building your own.” Native scrolling separates a recognizable laptop into physical components, moves into its processor, and reveals binary signals. The closing section connects those signals back to gates, circuits, computers, and code. + +The animation is continuous and scroll-driven. It adds no timeline controls or autoplay loop. Mobile and reduced-motion views use the same visual phases as static illustrations. Deep surfaces use explicit light text; the pale conclusion uses explicit dark text and a dark focus ring. Meaningful signal strokes and control boundaries must remain legible, including inactive states. + +## Navigation and routing + +Every page shares **Learn, Tools, About**, the original brand mark, and a small footer. There is no parallel legacy interface, theme menu, or account dropdown. + +| Destination | Behavior | +| -------------------------------- | ---------------------------------------------------------- | +| `/` | Computer disassembly story and one primary learning action | +| `/learn` | Starts or resumes the guided learning sequence | +| `/learn/reference/...` | Complete corrected explanations in the same design | +| `/tools` | Hardware simulator, Boolean functions, buses and routing | +| `/tools/hardware-simulator[/id]` | Free-form HDL simulation and saved/example experiments | +| `/tools/boolean-functions` | Truth tables, canonical expressions, equivalence, NAND HDL | +| `/tools/buses` | Multi-bit gates and multi-way routing | +| `/about` | Purpose, research, credits, and device storage explanation | + +Existing `/experiment/hardware-ide[/id]` and `/learn/hardware/...` URLs redirect to their canonical counterparts. Experiment IDs, API paths, and ownership checks remain unchanged. `/signin` redirects to the explanation of anonymous sessions on About; there is no unsupported sign-in flow. + +## Foundational learning + +A new learner first operates one binary signal. A supplied NOT gate shows the opposite output, then a supplied AND gate demonstrates the two-input condition. NAND follows as AND with an inverted result. The learner observes each input combination before continuing. + +The NAND conclusion explains why this primitive matters. Tying its inputs creates NOT; combining NANDs creates AND and OR; those operations can express arbitrary Boolean functions. Deeper theory is optional. Opening the full explanation after completing observations preserves the observation state without awarding construction credit. + +Six construction exercises follow in dependency order: NOT, AND, OR, XOR, Mux, DMux. Instructions follow the actual first circuit: add a gate, select a source, connect both inputs, connect the output, test. Additional incomplete parts are identified explicitly rather than leaving the learner with a hidden test action. + +A circuit passes only when every truth-table case matches, including both DMux outputs. A passing test becomes one Continue action. Invalid or edited code invalidates the prior result. Saved progress resumes at the earliest unfinished exercise, while verified chips can be reopened. + +## Visual and code + +Visual, Code, and Split are representations of one circuit, not separate simulators. The guided workspace uses the existing HDL parser and circuit runtime, with a deliberately bounded scalar, feed-forward model. Valid supported HDL updates the graph; visual edits update the HDL. Invalid source remains editable across views and reloads, and blocks stale verification. + +Connections, hints, signal history, and detailed test results open on request. Direct pin wiring and labeled connection menus both work with the keyboard. Opening the short reference keeps the current learning component mounted, so inputs, drafts, and results survive the detour. + +Progress and drafts are local to the current browser. The simulator has its existing server-backed anonymous experiment sharing; this is separate from learning-progress synchronization. + +## Complete existing material + +The source contains one Boolean logic chapter. Its introduction, background, project, and next-steps text are adapted into complete reading with source corrections and attribution. The short reference links to the relevant full sections. Buses and multi-way selectors now have executable models in Tools rather than being described only as future work. + +The Boolean-function lab covers all sixteen two-input functions, editable truth tables, canonical sums of products, equivalence checks, and real NAND-only HDL. Each generated function is exercised through the existing parser and simulator for all four input cases in unit tests. + +The bus lab implements Not16, And16, Or16, Mux16, Or8Way, Mux4Way16, Mux8Way16, DMux4Way, and DMux8Way. Inputs accept validated decimal, hexadecimal, or binary; each view shows actual computed values and selector behavior. These are dedicated combinational models. They do not add general bus support, clocked state, RAM, CPU, or assembly execution to the HDL engine. + +The Hardware simulator retains Monaco editing, tests, output comparisons, pin inspection, examples, local drafts, shared experiments, and ZIP download within the same design. Invalid HDL clears stale tests and outputs. Saving a bundled example creates a new experiment. Edits made while a save is pending remain visibly unsaved when the earlier response arrives. + +## Accessibility and verification + +Use native controls, visible keyboard focus, values alongside color, explicit readable palettes, and bounded horizontal scrolling for code/diagrams. All public routes share the same navigation. The scroll story has a static equivalent, and the optional film has captions and a transcript. + +Verification covers types, simulator/model tests, builds, existing editing/sharing flows, the novice sequence, reference detours, redirects, mobile layouts, and accessibility checks without global color-contrast exclusions. Automated checks complement visual and keyboard review; they do not certify every assistive-technology combination. + +## Boundaries + +The extended path now covers Projects1–6: multi-bit construction, arithmetic, clocked memory, machine language, architecture, and an assembler. The chip workshop and computer workspace provide the corresponding runtimes. Virtual machines, compilers, and higher-level software remain PartII work. The optional 48-second film introduces that wider journey; its current master is silent. The film is not narrated. + +See [source coverage](content-audit.md), [visual direction](art-direction.md), and [film production](intro-production.md). diff --git a/docs/content-audit.md b/docs/content-audit.md new file mode 100644 index 0000000..8a9be7e --- /dev/null +++ b/docs/content-audit.md @@ -0,0 +1,68 @@ +# Chips and Code: complete source adaptation + +The repository contained one Boolean logic chapter: `intro.md` (14 lines), `background.md` (143), `project.md` (237), and `meta/what-next.md` (17). This audit covers all 411 source lines from the pre-redesign course. Later README chapter names were plans, not additional learning material. + +The four documents now contain corrected full explanations, rendered at `/learn/reference/...` in the same visual system as Learn and Tools. The compact reference links into the relevant full-text section. The former course routes redirect to these pages; they do not expose a second interface. Embedded legacy editors have been replaced by contextual links to the simulator under Tools. + +## Source-to-experience coverage + +| Source material | Adapted explanation | Interaction or tool | +| ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| Introduction: binary building blocks and constructing a computer from gates | `/learn/reference/boolean-logic` | Guided signals → supplied NOT → supplied AND → NAND, then circuit construction | +| Boolean algebra: two values, NOT, AND, OR, XOR, NAND, NOR | `/learn/reference/boolean-logic/background#signals-and-boolean-operations` | Foundational exploration and compact reference gate controls | +| Three-variable truth table and `(a OR b) AND NOT c` | `background#truth-tables` | Compact reference exposes inputs and intermediate values | +| Canonical representation, literals, and sum of products | `background#canonical-representation` | `/tools/boolean-functions` edits table outputs and derives canonical expressions | +| All sixteen two-input functions, equivalence, implication, and function count | `background#all-two-input-functions` | Boolean functions tool evaluates every two-input truth table | +| NAND and NOR universality, NOT/AND/OR constructions | `background#universality` | NAND's optional deeper explanation and Boolean functions tool | +| Physical gates, transistors, silicon, alternate switching technologies, abstraction | `background#gates-and-physical-signals` | Precise distinction between logical signals and electrical quantities | +| Primitive/composite gates, interfaces, internal signals, three-input AND, fan-out | `background#interfaces-and-composition` | Visual/code workbench and compact reference | +| Worked XOR implementation and alternate designs | `background#a-worked-xor-circuit` | `/tools/hardware-simulator/Xor` retains the source example and fixture | +| HDL header, part interfaces, named internal wires, structural interpretation | `background#reading-hdl` | Same simulator and parser, now under Tools | +| Test scripts, expected/actual values, exhaustive testing and its limits | `background#testing-a-construction` | Guided exhaustive tests plus simulator Tests and Output views | +| Why model before fabrication; timing, power, and cost limits | `background#from-a-model-to-physical-hardware` | Explicit simulator boundary; no fabricated physical measurements | +| Project objective and supplied NAND contract | `/learn/reference/boolean-logic/project#the-supplied-nand-primitive` | NAND observation; `/tools/hardware-simulator/BuiltinNand` | +| NOT, AND, OR, XOR contracts and hints | `project#single-bit-gates` | Six guided builds retain existing scalar contracts and exercise IDs | +| Full Mux truth table and selector meaning | `project#selecting-and-routing` | Guided Mux construction and `ExerciseMux` simulator fixture | +| DMux contract and all inactive outputs | `project#dmux-choose-one-output` | Guided DMux construction and `ExerciseDMux` fixture | +| Bus notation, word width, Not16, And16, Or16, Mux16 | `project#buses` | `/tools/buses` evaluates the multi-bit behavior | +| Or8Way versus bitwise OR | `project#multi-way-operations` | Buses and routing tool evaluates reduction | +| 4/8-way 16-bit mux, selector width, composition trees | `project#multi-way-multiplexors` | Buses and routing tool routes actual words | +| 4/8-way 1-bit demux, inactive zero outputs | `project#multi-way-demultiplexors` | Buses and routing tool evaluates every output | +| Alternative primitives and efficiency considerations | `project#correctness-then-efficiency` | Optional comparison after correct constructions; no timing claims | +| What next, contribution links, wider Nand2Tetris curriculum | `/learn/reference/meta/what-next` | Links to available labs, simulator, and official external continuation | + +Paths beginning with `background#` and `project#` are relative to `/learn/reference/boolean-logic/`. + +## Corrections made during adaptation + +- Replaced the incorrectly duplicated three-input table under “Two-Input Boolean Functions” with all sixteen actual two-input functions. Output strings consistently use row order 00, 01, 10, 11. +- Corrected the number of Boolean functions of n inputs to `2^(2^n)`, distinguishing it from the `2^n` input combinations. +- Introduced ordinary NOT and AND behavior before NAND. Explained NAND as NOT-AND and justified its role through functional completeness. +- Used **inverter**, not “converter,” for NOT. +- Explained HDL accurately; removed the incorrect expansion of VHDL as “Virtual.” Distinguished this educational syntax from VHDL and Verilog. +- Corrected the 8-way, 1-bit **demultiplexor** reference that previously said multiplexor. +- Distinguished bitwise operations from arithmetic and multi-bit width from multi-way alternatives. +- Clarified that a selector routes data rather than enabling power; a 0 input remains 0 along the chosen route. +- Separated logical fan-out from real electrical loading and logical circuit depth from physical propagation time. +- Qualified exhaustive testing as a guarantee of the modeled finite truth table, not a proof of physical fabrication, timing, or simulator correctness. +- Replaced unsupported claims that the existing simulator could build the full computer. Later chapters are explicitly still to be authored. +- Removed the claim that six scalar constructions complete the entire original first project, which also includes multi-bit construction work. +- Preserved source attribution and content licensing while removing dated update text, decorative quotations, and the legacy editor embeds. + +## Executable scope and limits + +The guided workbench constructs and verifies NOT, AND, OR, XOR, Mux, and DMux after exploration of supplied primitive behavior. Visual and code views share the same scalar, feed-forward circuit representation, parser, and simulator. All truth-table cases, including both DMux outputs, are checked. + +The hardware simulator remains the existing HDL/test-script environment, integrated under Tools. NAND, NOT, AND, OR, and XOR have real built-in implementations. Mux and DMux construction fixtures use composite networks; their built-in classes remain placeholders. The simulator does not gain support for every placeholder class simply because its interface is redesigned. + +The Boolean functions tool and buses/routing tool are executable behavioral explorations of the previously descriptive material. They extend what a learner can manipulate and inspect. They do not assert that arbitrary multi-bit HDL designs have been compiled or that a player's custom 16-bit gate has passed a construction exercise. + +The factory does not yet register the player's earlier custom implementations as reusable chip packages. The workbench supplies primitive equivalents of permitted previously introduced gates. Both the full text and product avoid claiming a custom reusable library exists. + +This audit describes the original Boolean-logic adaptation. The subsequent Projects1–6 expansion adds arithmetic, sequential state, memory, machine language, CPU construction, and an assembler; see `part-one-content-audit.md` and `part-one-sources.md`. High-level software is the remaining PartII scope. + +## Licensing and continuity + +Software remains MIT licensed. Adapted learning content remains **CC BY-NC-SA 3.0**, credited to the existing Chips and Code material by Jan Duras and its Nand2Tetris source by Noam Nisan and Shimon Schocken. The full-text pages preserve license links and the statement that Chips and Code is not affiliated with or endorsed by Nand2Tetris. + +Existing `/learn/hardware/...` addresses are compatibility redirects into the new reference, and `/experiment/hardware-ide/...` addresses resolve into Tools. Canonical links within the adapted experience use `/learn`, `/learn/reference/...`, and `/tools/...` only. diff --git a/docs/intro-production.md b/docs/intro-production.md new file mode 100644 index 0000000..3bc4bad --- /dev/null +++ b/docs/intro-production.md @@ -0,0 +1,57 @@ +# Computer journey: intro film + +The introduction is a 48-second, 1280 × 720 motion film at 30 fps. It introduces the broader signals-to-software journey. The homepage separately uses a scroll-driven computer disassembly and chip close-up. The original Chips and Code logo is used unchanged. + +## Current media state + +`static/media/computer-intro.mp4` is a **silent visual master**. Captions and a plain-text transcript provide the complete explanation. A natural narration track still needs to be generated or recorded and muxed into the film. The current asset must not be described as narrated or as having a voiceover. + +The connected Runway workspace was checked during this revision. Its Free plan exposes no speech models, so narration generation is blocked by the plan. No generation, credit purchase, or account change was made. + +The film introduces the relationship between computer layers. The site now includes the learning path and tools through Project6 (assembler). The high-level software section of the film remains a conceptual preview of PartII. + +## Assets + +| File | Purpose | +| ------------------------------- | --------------------------------------------------------------------------------- | +| `computer-intro.mp4` | H.264 / yuv420p video with fast-start metadata | +| `computer-intro-poster.jpg` | Original brand and complete abstraction stack | +| `computer-intro.vtt` | Timed English captions, reserving the lower part of the frame | +| `computer-intro-transcript.txt` | Plain-text equivalent of the narration | +| `computer-intro-timing.json` | Authoritative scene timing, narration, palette/example descriptions, audio status | + +The renderer is `scripts/render-computer-intro.py`. It uses Pillow and NumPy for precise vector-like frames, the repository's `sharp` dependency for the original SVG mark, and FFmpeg for encoding. No generated raster imagery or browser automation is involved. + +## Sequence + +| Time | Layer | Motion and technical meaning | +| ----------- | -------------- | ------------------------------------------------------------------------------------------------- | +| 0.0–4.8 s | Signals | A sampled two-level waveform introduces 0 and 1. | +| 4.8–12.2 s | Logic | NAND cycles through all four input cases; live wire values and the truth row agree. | +| 12.2–20.2 s | Arithmetic | A four-bit addition develops from right to left: `0011 + 0001 = 0100`. | +| 20.2–28.2 s | Memory | An eight-bit register loads `10110100` at the rising clock edge, then holds it. | +| 28.2–36.2 s | Architecture | A conceptual fetch/decode/execute/write-back sequence evaluates `D = D + A` with `D=3` and `A=1`. | +| 36.2–43.4 s | Software | `add(3, 1)` returns `4`, presenting the same idea at a higher level. | +| 43.4–48.0 s | Complete stack | The five layers separate into one view, ending with “Start with logic.” | + +Color moves through `#070910`, `#111526`, `#303a57`, `#a6afc7`, and `#f2f1f7`. Indigo remains `#4f46e5`. Signal markers denote Boolean values and conceptual data flow, not electrical measurements or physical propagation speed. + +## Rebuilding + +Run from the repository with Node dependencies installed and Pillow, NumPy, FFmpeg, DejaVu Sans Mono, and Nimbus Sans available: + +```sh +python scripts/render-computer-intro.py +``` + +Review stills are written outside the repository to `../intro-review` by default. To change that location, set `INTRO_REVIEW_DIRECTORY`. Use `--stills-only` to inspect the composition without re-encoding the film. + +To add a finished, authorized voice recording or generated narration: + +```sh +python scripts/render-computer-intro.py --audio /absolute/path/narration.wav +``` + +The narration should follow the exact segment timing in the JSON file. Use a natural, clear English voice, calm and precise, with breathing room between layers. The script is approximately 110 words per minute overall; avoid speeding through the transitions. No imitation of an identifiable person is needed. + +The renderer normalizes the supplied audio to -16 LUFS with a -1.5 dBTP ceiling, pads to the 48-second duration, encodes AAC, and changes the timing JSON's `audio_status` to `narrated`. Captions and transcript must be revised if the spoken script changes. Listen to the finished track and verify scene synchronization before publishing it as a voiced introduction. diff --git a/docs/part-one-content-audit.md b/docs/part-one-content-audit.md new file mode 100644 index 0000000..3470dba --- /dev/null +++ b/docs/part-one-content-audit.md @@ -0,0 +1,40 @@ +# Part I reference coverage + +This revision extends the existing Boolean logic explanations through Nand2Tetris Project 6. The new prose is an original adaptation of the official public chapter PDFs and project contracts, preserving author attribution and the explanatory content's CC BY-NC-SA 3.0 license. Official software fixtures have their own MIT license and retained source headers; the website-content license is not applied indiscriminately to those files. + +Detailed source URLs and specification nuances are recorded in `docs/part-one-sources.md`. Every new article also links its official project page, chapter PDF, and project files. + +## Reference and learning coverage + +| Project | Canonical full explanation | Concepts and construction contracts | Guided chapter | +| ------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | +| 1 | `/learn/reference/boolean-logic/project` | Existing scalar gates plus Not16, And16, Or16, Mux16, Or8Way, Mux4Way16, Mux8Way16, DMux4Way, DMux8Way; bus width versus number of alternatives | `/learn/path/buses` | +| 2 | `/learn/reference/boolean-arithmetic` | Place value; unsigned and signed words; two's complement; carry; wraparound; HalfAdder, FullAdder, Add16, Inc16; six-stage ALU control and all 18 documented functions; final zr/ng flags | `/learn/path/arithmetic` | +| 3 | `/learn/reference/memory` | DFF primitive; current versus next state; tick/tock; simultaneous updates; Bit, Register, all five RAM sizes; bank/address decomposition; clocked writes and combinational reads; PC priority and wrapping | `/learn/path/memory` | +| 4 | `/learn/reference/machine-language` | A/D/M/PC; separate ROM and data space; both instruction formats; every comp and jump code; destination bits; old-A semantics; addressing; labels and variables; memory-mapped screen and keyboard; Mult and Fill contracts/testing | `/learn/path/machine-language` | +| 5 | `/learn/reference/computer-architecture` | Stored programs; Harvard-style memory separation; Memory/CPU/Computer interfaces; complete valid memory map; data path and control path; reset; simultaneous destination writes; ROM integration; isolated CPU and whole-machine verification | `/learn/path/architecture` | +| 6 | `/learn/reference/assembler` | File formats; parsing; source locations; complete instruction encoding; predefined symbols; label versus variable addresses; two passes and forward references; allocation order; module design; diagnostic boundaries; official Add/Max/Rect/Pong comparison strategy | `/learn/path/assembler` | + +`/learn/reference/meta/what-next` distinguishes the guided lesson scope, which ends at Project 6, from the available tools. The VM emulator (`/tools/vm`), Jack compiler (`/tools/compiler`), and bitmap editor (`/tools/bitmap`) support exploration of later software layers; Projects 7–12 are linked to the official course rather than presented as local lessons. + +## Meaning preserved across interfaces + +- The scalar visual workbench remains a separate introductory representation. Its previously supplied primitive equivalents are not described as automatic exports of the learner's own chip definitions. +- The new chip builder supports explicit HDL dependencies and bounded TST script execution with optional CMP comparison. Reading links distinguish exploration of a built-in behavioral model from validation of the learner's construction. +- Clocked examples distinguish observing old state after tick from committing captured state at tock. They do not describe a sequential loop of register writes as simultaneous hardware behavior. +- The CPU reset pin resets the PC, not all RAM. A tool's fresh-machine control is not presented as the same contract. +- A-instructions cannot write D or RAM or take jumps; their literal bits must not be decoded as C-instruction control bits. +- Memory writes and jump targets in a C-instruction use the pre-update A register, including simultaneous A destinations. +- The screen occupies 8192 16-bit words, with bit 0 at the left of each word. KBD is read-only; addresses above it are not usable extra RAM. +- ALU flags describe the wrapped 16-bit result. A sign test on subtraction is not claimed to implement every signed comparison when overflow is possible. +- The assembler's symbol table records addresses, not data values. Labels count emitted ROM instructions, while new variables receive RAM addresses starting at 16. +- Official fixtures use both MD and DM destination ordering; the reference explains equivalent unique destination sets. +- The prose gives contracts, construction reasoning, and small instructional fragments. It does not publish complete Mult, Fill, CPU, or assembler student-assignment source solutions. + +## Integration + +The existing Markdoc loader discovers new source documents via its recursive glob; no loader exception or legacy page was added. `referencePages` supplies continuous previous/next navigation and the existing closed chapter-picker disclosure. The full-text page's metadata and eyebrow now apply to all computer layers rather than only logic. + +The two existing Boolean logic overview/project pages were amended only to remove obsolete statements that arithmetic, memory, CPU, or assembler chapters were unavailable and to link the new continuation. Established explanations and attribution remain. + +Verification of the executable course and engines belongs to their unit and browser suites. This map records curriculum coverage and source fidelity; it is not a claim that prose alone completes the original construction assignments. diff --git a/docs/part-one-sources.md b/docs/part-one-sources.md new file mode 100644 index 0000000..7b04039 --- /dev/null +++ b/docs/part-one-sources.md @@ -0,0 +1,71 @@ +# Part I source map and acceptance checklist + +Reviewed 2026-11-03. This maps the official Nand2Tetris Projects 1–6 to Chips and Code. It is an implementation checklist, not a claim that every item already works. The lesson path stops at the assembler. The tool suite also covers the official web IDE’s VM, Jack compiler, and bitmap utilities; this does not add Part II lessons. + +## Primary sources + +| Project | Official project contract | Public chapter PDF | Official fixture directory | +| ------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------- | +| 1 · Boolean logic | https://www.nand2tetris.org/project01 | [Chapter 1](https://www.nand2tetris.org/_files/ugd/44046b_f2c9e41f0b204a34ab78be0ae4953128.pdf) | `projects/01` | +| 2 · Arithmetic | https://www.nand2tetris.org/project02 | [Chapter 2](https://www.nand2tetris.org/_files/ugd/44046b_89c60703ebfc4bf39acef13bdc050f5d.pdf) | `projects/02` | +| 3 · Memory | https://www.nand2tetris.org/project03 | [Chapter 3](https://www.nand2tetris.org/_files/ugd/44046b_1801b5682e4d4a67bd05e14235665d8b.pdf) | `projects/03/a`, `projects/03/b` | +| 4 · Machine language | https://www.nand2tetris.org/project04 | [Chapter 4](https://www.nand2tetris.org/_files/ugd/44046b_d70026d8c1424487a451eaba3e372132.pdf) | `projects/04/mult`, `projects/04/fill` | +| 5 · Computer architecture | https://www.nand2tetris.org/project05 | [Chapter 5](https://www.nand2tetris.org/_files/ugd/44046b_552ed0898d5d491aabafd8a768a87c6f.pdf) | `projects/05` | +| 6 · Assembler | https://www.nand2tetris.org/project06 | [Chapter 6](https://www.nand2tetris.org/_files/ugd/44046b_b73759b866b249a0b3a715bf5a18f668.pdf) | `projects/06/add`, `max`, `rect`, `pong` | + +Fixture repository: https://github.com/nand2tetris/projects, reviewed commit `5bd2184edfd4945ff8a28eb0b237c12cdbe9e498`. Pin imported fixtures to this revision and retain source headers. Additional primary references: the HDL and test-description guides linked from the current project pages; [Hack chip set](https://drive.google.com/file/d/1IsDnH0t7q_Im491LQ7_5_ajV0CokRbwR/view); [official assembler user guide](https://nand2tetris.github.io/web-ide/user_guide/asm.pdf). + +Research access: the project pages, official fixtures, and all six chapter PDFs were inspected. Chapters 1, 4, and 6 were downloaded directly from the linked official URLs and their text extracted after the browser reader could not follow the file redirects. The source PDFs remain outside the repository; course prose is an original adaptation with source links. + +## Coverage + +| Project | Learning and construction coverage | Verification target | +| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | Supplied NAND; construct Not, And, Or, Xor, Mux, DMux; Not16, And16, Or16, Mux16; Or8Way; Mux4Way16, Mux8Way16, DMux4Way, DMux8Way. Explain bit indices, bus slices, fan-out, selection, and composition. | All 15 construction contracts, corresponding `.tst`/`.cmp` pairs; no credit merely for opening a behavioral demo. | +| 2 | Positional binary, two's complement, carry; HalfAdder, FullAdder, Add16, Inc16; ALU preprocessing, operation, output negation, zero/negative flags. | All supplied comparison files, including the staged ALU-nostat and complete ALU tests; boundary/wraparound cases and every control-bit combination. | +| 3 | Distinguish combinational outputs from stored state; supplied DFF, then Bit, Register, RAM8, RAM64, RAM512, RAM4K, RAM16K, PC. Explain load, addressing, clock phases, and hierarchy. | Official tick/tock observations, hold versus load, separate addresses, and PC control priority. | +| 4 | A/D/M, A- and C-instructions, destinations, signed branches, symbols, loops, screen and keyboard mapping. Author Mult and Fill. | Mult inputs satisfy the official nonnegative/product-bound assumptions; Fill is checked with key press and release, plus automatic fixture scenarios. | +| 5 | Join ALU, registers, control and PC; construct Memory, CPU, Computer using supplied screen, keyboard and ROM devices. Trace instruction and data flow. | Memory and CPU fixtures, including external-observation variants; run ComputerAdd, ComputerMax and ComputerRect programs on the assembled platform. | +| 6 | Parse commands; translate fields; first pass resolves labels, second pass allocates variables and emits words. Explain symbol table and source-to-ROM mapping. | Add, Max/MaxL, Rect/RectL and Pong/PongL agree; output lines are exactly 16 binary digits; inspect translations and execute generated binaries. | + +## Semantics that must remain exact + +- Words are 16 bits. Add16, Inc16, and ALU wrap modulo 65536. Signed interpretation is two's complement, from -32768 to 32767; carry-out and signed overflow are different concepts. Hack ALU has no overflow output. +- Apply ALU controls in order: zero and optionally invert each input, choose bitwise AND or addition, optionally invert the result, then derive `zr` and `ng` from the final 16-bit result. Six controls define 64 combinations, with 18 named functions documented in Chapter 2. +- Clocked chips sample and commit state together. In official `Bit.tst`/`Bit.cmp`, `tick` observations show the previous value; the following `tock` exposes the committed value. A combinational feedback loop remains invalid, while feedback crossing a state element is meaningful. +- RAM reads follow the selected address without a clock. A write captures its address, input and load for the next state transition; changing the address must not move a pending write. PC priority is reset, then load, then increment, then hold. +- `M` denotes the word addressed by A. CPU `outM`/`writeM` are combinational; `addressM` and `pc` reflect clocked state. Consequently, when a C-instruction changes A and also writes M or jumps, the current memory address and jump destination use the old A. This is a consequence of the documented simultaneous register-update model, not a sequential software assignment order. +- CPU reset redirects the next PC to zero; it is not a command to clear all registers and RAM. Chapter 5's PDF has an inverted parenthetical comment on the reset input; the surrounding prose and current `CPU.hdl` specify reset=1 as restart. +- Data RAM occupies 0–16383. Screen words occupy 16384–24575. Keyboard is the read-only word at 24576. Addresses above that are invalid according to `Memory.hdl`; do not invent ordinary RAM there. ROM has 32768 instruction addresses and is separate from data memory. +- Screen geometry is 512×256, with 32 words per row and bit 0 at the left of each 16-pixel word. Keyboard zero means no key; browser keyboard input should map to Hack codes rather than silently using unrelated browser key codes. +- A C-instruction has the layout `111accccccdddjjj`. The book presents canonical destination spellings such as `MD`; official Project 6 fixture programs also use `DM`. Accept unique A/D/M destination letters in either order, mapping them to the same destination bits, while rejecting duplicates and other letters. +- Assembly is case-sensitive. Labels emit no words and denote ROM addresses; variables occupy RAM addresses beginning at 16. A-instruction literals occupy 15 bits. Reject invalid input with line-specific errors and clear stale executable output rather than silently truncating it. + +## Rights and attribution + +The [official website license](https://www.nand2tetris.org/license) states CC BY-NC-SA 3.0 for website educational materials. Adapted chapter explanations must retain attribution to Noam Nisan and Shimon Schocken and the applicable noncommercial/share-alike terms. Public availability alone does not imply unrestricted reuse. + +The reviewed official **projects repository has its own MIT LICENSE**, crediting Schocken/Nisan and upstream tool authors. Retain that file and the individual source notices when importing project fixtures. Do not relabel all software as CC or all book content as MIT. + +The authors request that completed student solutions not be published publicly. Supply specifications, starter files, tests, hints and executable tool infrastructure; do not expose a downloadable answer library as a substitute for completing the projects. This request is distinct from the license terms. Chips and Code remains an independent adaptation, not an official Nand2Tetris product. + +## Official web IDE tool inventory + +The expanded tool scope was checked against the [official web IDE](https://nand2tetris.github.io/web-ide) and its [source repository](https://github.com/nand2tetris/web-ide), pinned at `2070cd89065e49074563b33c7ca066d953aa8a8a`. The six entries are declared in [`web/src/urls.tsx`](https://github.com/nand2tetris/web-ide/blob/2070cd89065e49074563b33c7ca066d953aa8a8a/web/src/urls.tsx). `/util` and `/about` are supporting pages, not additional simulator types. + +| Upstream tool | Chips and Code surface | Required behavior and useful integration check | +| ------------------ | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Hardware Simulator | `/tools/chip-builder` | Compile learner HDL, connect buses and custom chips, evaluate signals, separate tick/tock state, load ROM and inspect mapped memory, and run bounded TST scripts against optional CMP output. A compiled Computer probe must execute a ROM program and change its own RAM. | +| CPU Emulator | `/tools/computer` | Load assembly or binary, step/run/reset, show A/D/PC and memory, screen and keyboard devices. A program must visibly update RAM and obey a jump. | +| Assembler | `/tools/computer` | Translate Hack assembly, expose binary words and source mapping, resolve labels and variables, export `.hack`, report invalid input without keeping stale executable code. This shares a focused workspace with the CPU emulator. | +| VM Emulator | `/tools/vm` | Parse and execute real VM instructions, show stack and segments, support multiple files and function calls, and expose screen/keyboard through the supplied OS services. Validate arithmetic, call/return, and compiler output. | +| Jack Compiler | `/tools/compiler` | Compile Jack source to VM, report syntax/semantic errors, preserve source drafts, and transfer successful output to the VM. Validate an actual compiled program instead of only checking that text was produced. | +| Bitmap Editor | `/tools/bitmap` | Edit pixels and generate usable Hack/Jack drawing code. Bit 0 must remain the leftmost pixel of a word. Export must handle signed 16-bit values, including the `0x8000` case, and use a 32-word screen stride. | + +Upstream implementation references: [`simulator/src/vm`](https://github.com/nand2tetris/web-ide/tree/2070cd89065e49074563b33c7ca066d953aa8a8a/simulator/src/vm), [`simulator/src/jack`](https://github.com/nand2tetris/web-ide/tree/2070cd89065e49074563b33c7ca066d953aa8a8a/simulator/src/jack), [`simulator/src/languages`](https://github.com/nand2tetris/web-ide/tree/2070cd89065e49074563b33c7ca066d953aa8a8a/simulator/src/languages), and [`web/src/utils/bitmapUtils.ts`](https://github.com/nand2tetris/web-ide/blob/2070cd89065e49074563b33c7ca066d953aa8a8a/web/src/utils/bitmapUtils.ts). UI descriptions and route mappings here are an adaptation plan; the acceptance checks must establish which features actually work in this repository. + +### Web IDE software attribution + +The pinned repository’s root [LICENSE](https://github.com/nand2tetris/web-ide/blob/2070cd89065e49074563b33c7ca066d953aa8a8a/LICENSE) is MIT, ©2022 David Souther et al, with acknowledgments of Stefano Volpe’s Nand2Tetris Tools and Aviv Yaish’s NAND IDE. Imported source or a bundled derivative must retain this license and applicable source/dependency notices. The simulator’s package metadata says ISC while the repository supplies the root MIT license; preserve the actual supplied license rather than silently replacing it with a package metadata label. This software notice is separate from the CC BY-NC-SA terms on the educational website. + +The adaptation should preserve correctness and interoperability while keeping the existing site’s minimal visual language. It does not imply exact duplication of every upstream file-management, editor, or test-runner setting. New tool implementations need their own meaningful integration and accessibility checks; a navigation link alone does not count as bringing in a tool. diff --git a/docs/vercel-migration.md b/docs/vercel-migration.md index 8eaff40..47b510d 100644 --- a/docs/vercel-migration.md +++ b/docs/vercel-migration.md @@ -21,7 +21,7 @@ Import `durasj/chipsandcode` into the `durasjs-projects` team. Use these setting | Project name | `chipsandcode` | | Framework | SvelteKit | | Root directory | Repository root | -| Node.js | 24.x | +| Node.js | 26.x | | Install command | `npm ci` | | Build command | `npm run build` | | Output directory | Framework default; leave the override unset | diff --git a/eslint.config.js b/eslint.config.js index 9f74f32..e99ae81 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -13,6 +13,7 @@ export default ts.config( 'build/**', 'coverage/**', 'dev-dist/**', + 'src/lib/software/vendor/**', ], }, js.configs.recommended, diff --git a/package-lock.json b/package-lock.json index 19e95cb..1b36e7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { + "@davidsouther/jiffies": "2026.26.1", "@internationalized/date": "^3.8.1", "@markdoc/markdoc": "^0.3.2", "@neondatabase/serverless": "1.2.0", @@ -23,6 +24,7 @@ "denque": "^2.1.0", "dompurify": "3.4.17", "monaco-editor": "0.57.0", + "ohm-js": "17.5.0", "screenfull": "^6.0.2", "svelte-confetti": "2.3.2", "yaml": "^2.3.1", @@ -42,7 +44,7 @@ "@testing-library/svelte": "5.4.2", "@types/katex": "^0.16.2", "@types/nearley": "^2.11.2", - "@types/node": "^24.0.0", + "@types/node": "^26.6.6", "@vite-pwa/assets-generator": "2.0.0", "@vite-pwa/sveltekit": "2.0.0", "@vitest/browser": "5.1.0", @@ -78,9 +80,15 @@ "yaml": "^2.8.0" }, "engines": { - "node": "24.x" + "node": "26.x" } }, + "node_modules/@acemir/cssom": { + "version": "0.9.32", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.32.tgz", + "integrity": "sha512-OijrAUu7rrJhSIoHNg6LMPS5e344nwUHA+1EFYYjrh64D+GmytUsfBQjci45TjT+rd5Spsp8B5xsZDT+TgyXXQ==", + "license": "MIT" + }, "node_modules/@alloc/quick-lru": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.3.0.tgz", @@ -93,6 +101,75 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.2.tgz", + "integrity": "sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==", + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^3.0.0", + "@csstools/css-color-parser": "^4.0.1", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "lru-cache": "^11.2.5" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", + "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", + "license": "MIT", + "dependencies": { + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.1.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.2.6" + } + }, + "node_modules/@asamuzakjp/dom-selector/node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@asamuzakjp/dom-selector/node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0" + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -1709,6 +1786,116 @@ "dev": true, "license": "MIT" }, + "node_modules/@csstools/color-helpers": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.2.tgz", + "integrity": "sha512-grhRy3OKmniaAEKXMjua5z/EODX0MSqBGjunw8+j/3HQjOnahs2AGhvEOIYVUWcU6ScApbhLhVrQTX8XqrMrow==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.4.3.tgz", + "integrity": "sha512-iex20d8CHVkyvg6B7UKV7uHnI2Bqo9g+EFfT9E0y+GvTvhZ/DwONJ+9aKb1dlqm0ZiGsL5RXjp0fCoJYnkeDjA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.2", + "@csstools/css-tokenizer": "^4.0.2" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.2.7.tgz", + "integrity": "sha512-zgm9yjQz5iJB4VL8RyVwd71TWB8Q89FSxt/NzXoWqPSkEBOVtn9L6vAPtSc9hpKfB0Awo/AL2VKFHjYetBLFHQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.2", + "@csstools/css-calc": "^3.4.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.2", + "@csstools/css-tokenizer": "^4.0.2" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.2.tgz", + "integrity": "sha512-40cSKyMvK+tq4qz6Awrlye2WGuOKt3FwPgtGg6KTfbHOWNw+Rk1rzbAtZnZ6IBhsY491HLRnDXwoyBAijmmILA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.2" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.2.tgz", + "integrity": "sha512-OoKoR0f76dCY666JlcbhmVTs2drYj1GUXZTYTcbUgJjh9Nv41aFfZ21bPQTERm5+L5cBDo466NltB2lplS5GBw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, "node_modules/@cypress/request": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-4.0.1.tgz", @@ -1759,6 +1946,34 @@ "ms": "^2.1.1" } }, + "node_modules/@davidsouther/jiffies": { + "version": "2026.26.1", + "resolved": "https://registry.npmjs.org/@davidsouther/jiffies/-/jiffies-2026.26.1.tgz", + "integrity": "sha512-NAl/sZ3w0ChNQBwUNlwPpd+/t+hX7wA0rrVCAkPa/3kVEBkgehybMOq1Wr6EBnyl2+BsCRYiI/JI/HjaqjRqbw==", + "dependencies": { + "@rollup/plugin-node-resolve": "^16.0.3", + "jsdom": "^27.4.0", + "rollup": "^4.61.1", + "ts-blank-space": "^0.7.0", + "typescript": "^5.9.3" + }, + "engines": { + "node": ">=22.18.0" + } + }, + "node_modules/@davidsouther/jiffies/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/@emnapi/runtime": { "version": "1.11.3", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", @@ -1927,6 +2142,23 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@exodus/bytes": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.16.0.tgz", + "integrity": "sha512-IcpW84uEn3N7ETtNZMlxKhfl6Pec8rUNGOTBtWbK1FKhJxIFAptZyVrvVRVBimAJxJCgc3PxepxkdWWG4DVzfA==", + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, "node_modules/@floating-ui/core": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", @@ -2696,7 +2928,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3094,7 +3325,6 @@ "version": "16.0.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", - "dev": true, "license": "MIT", "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -3174,7 +3404,6 @@ "version": "5.5.1", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.5.1.tgz", "integrity": "sha512-P9ZvnfouRu4MSC+ilERaw6FmZs8zqKhpHxEs4aGDGWQAMzQGXnhvCSvoNwokfNvdt7t3Y5Y4p6gStQgezeIqug==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -3200,7 +3429,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3214,7 +3442,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3228,7 +3455,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3242,7 +3468,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3256,7 +3481,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3270,7 +3494,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3284,7 +3507,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3298,7 +3520,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3312,7 +3533,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3326,7 +3546,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3340,7 +3559,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3354,7 +3572,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3368,7 +3585,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3382,7 +3598,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3396,7 +3611,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3410,7 +3624,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3424,7 +3637,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3438,7 +3650,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3452,7 +3663,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3466,7 +3676,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3480,7 +3689,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3494,7 +3702,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3508,7 +3715,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3522,7 +3728,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3536,7 +3741,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3550,7 +3754,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3928,20 +4131,19 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.19.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.19.2.tgz", - "integrity": "sha512-93d49wCWJkCyN87MxLpNN6KXPCwFw7bVUg79mGUV1OS40JGWwVCr8n61DXCSqz7CV6/VfPkb7xec7uP2M+QHWQ==", + "version": "26.6.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.6.tgz", + "integrity": "sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog==", "devOptional": true, "license": "MIT", "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" + "undici-types": "~8.9.0" } }, "node_modules/@types/resolve": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", - "dev": true, "license": "MIT" }, "node_modules/@types/sinonjs__fake-timers": { @@ -4799,7 +5001,6 @@ "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 14" @@ -5270,6 +5471,15 @@ "tweetnacl": "^0.14.3" } }, + "node_modules/bidi-js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.1.0.tgz", + "integrity": "sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==", + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -6138,6 +6348,73 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/cssstyle": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.7.tgz", + "integrity": "sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==", + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^4.1.1", + "@csstools/css-syntax-patches-for-csstree": "^1.0.21", + "css-tree": "^3.1.0", + "lru-cache": "^11.2.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cssstyle/node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.16.tgz", + "integrity": "sha512-LsDbJPP/B8cPasUJyTA5S99F7C4G93ngW8hUluXz8CFeOaaRnBPtBiIlvgcPYU0HmHNz8CXg+1vwFrIB4F6Dgw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/cssstyle/node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cssstyle/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/cssstyle/node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "license": "CC0-1.0" + }, "node_modules/cypress": { "version": "15.21.1", "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.21.1.tgz", @@ -6240,6 +6517,62 @@ "node": ">=0.10" } }, + "node_modules/data-urls": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.1.tgz", + "integrity": "sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ==", + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^15.1.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/data-urls/node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz", + "integrity": "sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==", + "license": "MIT", + "dependencies": { + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -6315,7 +6648,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -6329,6 +6661,12 @@ } } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "license": "MIT" + }, "node_modules/decode-bmp": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/decode-bmp/-/decode-bmp-0.2.1.tgz", @@ -6369,7 +6707,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7104,7 +7441,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, "license": "MIT" }, "node_modules/esutils": { @@ -7951,6 +8287,31 @@ "dev": true, "license": "MIT" }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/http-signature": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz", @@ -7970,7 +8331,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -8372,7 +8732,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true, "license": "MIT" }, "node_modules/is-negative-zero": { @@ -8434,6 +8793,12 @@ "node": ">=8" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "license": "MIT" + }, "node_modules/is-reference": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", @@ -8732,6 +9097,109 @@ "dev": true, "license": "MIT" }, + "node_modules/jsdom": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.4.0.tgz", + "integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==", + "license": "MIT", + "dependencies": { + "@acemir/cssom": "^0.9.28", + "@asamuzakjp/dom-selector": "^6.7.6", + "@exodus/bytes": "^1.6.0", + "cssstyle": "^5.3.4", + "data-urls": "^6.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "parse5": "^8.0.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.0", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^15.1.0", + "ws": "^8.18.3", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/tldts": { + "version": "7.4.19", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.19.tgz", + "integrity": "sha512-48dH6aSpQnpbzDUc4vIQZ1VjB8tkK+e8c1yx05/SZK+rkssgjEOlxDd/yU8/a4vGYQ9vRgJr9dwMq9TJ0b3X2Q==", + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.19" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/jsdom/node_modules/tldts-core": { + "version": "7.4.20", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.20.tgz", + "integrity": "sha512-C630TWXZCZmLq0F2bW4QqwnaaxCQ/svpAqvJwnC4JvgEM5ohhBnGsEzTLSOXcN+xjz+kEaHS5uoWIw2klnqd0A==", + "license": "MIT" + }, + "node_modules/jsdom/node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz", + "integrity": "sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==", + "license": "MIT", + "dependencies": { + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -9588,7 +10056,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mz": { @@ -9827,6 +10294,15 @@ "node": ">=12.20.0" } }, + "node_modules/ohm-js": { + "version": "17.5.0", + "resolved": "https://registry.npmjs.org/ohm-js/-/ohm-js-17.5.0.tgz", + "integrity": "sha512-l4Sa7026+6jsvYbt0PXKmL+f+ML32fD++IznLgxDhx2t9Cx6NC7zwRqblCujPHGGmkQerHoeBzRutdxaw/S72g==", + "license": "MIT", + "engines": { + "node": ">=0.12.1" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -9956,6 +10432,30 @@ "node": ">=6" } }, + "node_modules/parse5": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.1.0.tgz", + "integrity": "sha512-sq3qBFpee5jeocbFbO48VHlGr8sT7mbXS0vxlKN6sottBtJzrOG3998sr0llSZcQAGgfpdmEYAIZE0P9z0dE8w==", + "license": "MIT", + "dependencies": { + "entities": "^9.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-9.0.0.tgz", + "integrity": "sha512-oJFNDJg3kTPwAD1cNn2+WmUq4wFoo09npc3Ydf1D7ED4smRiWrsKnaLxykrTWgyGEcusc87P5dxlAleol9kpkg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -10927,7 +11427,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -11151,7 +11650,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11299,7 +11797,6 @@ "version": "4.67.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.67.4.tgz", "integrity": "sha512-Lsv3oKcz5jgOQJej/p7nfwbVEdAbDT+z6OPf/SCdI+nF+q2ENp0pTKT35ZwXAmH8g45mfrIiJeEyAqKYSYoL9Q==", - "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.10" @@ -11471,6 +11968,18 @@ "node": ">=11.0.0" } }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/screenfull": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-6.0.2.tgz", @@ -12887,6 +13396,12 @@ "node": ">= 10" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "license": "MIT" + }, "node_modules/systeminformation": { "version": "5.33.19", "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.33.19.tgz", @@ -13294,6 +13809,31 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-blank-space": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/ts-blank-space/-/ts-blank-space-0.7.0.tgz", + "integrity": "sha512-1D9ytD3K9QGGWJWFslEeQFvIwiOlj8rS3s+WA45DAHxqtvnyc+vzg2C8OLjoOyQKMgLrzndEcR5TNWsVC4daLQ==", + "license": "Apache-2.0", + "dependencies": { + "typescript": "5.1.6 - 5.9.x" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/ts-blank-space/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", @@ -13525,9 +14065,9 @@ } }, "node_modules/undici-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", - "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", "devOptional": true, "license": "MIT" }, @@ -13948,6 +14488,18 @@ "node": ">=12.20.0" } }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -13955,6 +14507,15 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -14487,7 +15048,6 @@ "version": "8.22.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.22.1.tgz", "integrity": "sha512-oyL6OPYme/CmiFvNuGzeoxCJ4nOrZE2O1FwM9MWM1AsGri6nLXB2pg+lNA8aLeXMSav0J6eIVS1j6vUPzUtK9g==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -14505,6 +15065,21 @@ } } }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT" + }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", diff --git a/package.json b/package.json index 29f8342..6a70dc6 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "@testing-library/svelte": "5.4.2", "@types/katex": "^0.16.2", "@types/nearley": "^2.11.2", - "@types/node": "^24.0.0", + "@types/node": "^26.6.6", "@vite-pwa/assets-generator": "2.0.0", "@vite-pwa/sveltekit": "2.0.0", "@vitest/browser": "5.1.0", @@ -73,6 +73,7 @@ "yaml": "^2.8.0" }, "dependencies": { + "@davidsouther/jiffies": "2026.26.1", "@internationalized/date": "^3.8.1", "@markdoc/markdoc": "^0.3.2", "@neondatabase/serverless": "1.2.0", @@ -84,12 +85,13 @@ "daisyui": "^3.5.0", "date-fns": "4.4.0", "denque": "^2.1.0", + "dompurify": "3.4.17", "monaco-editor": "0.57.0", + "ohm-js": "17.5.0", "screenfull": "^6.0.2", "svelte-confetti": "2.3.2", "yaml": "^2.3.1", - "zod": "4.6.7", - "dompurify": "3.4.17" + "zod": "4.6.7" }, "overrides": { "unist-util-find": "1.0.2", @@ -99,7 +101,7 @@ }, "type": "module", "engines": { - "node": "24.x" + "node": "26.x" }, "imports": { "#lib/*": "./src/lib/*", diff --git a/scripts/render-computer-intro.py b/scripts/render-computer-intro.py new file mode 100644 index 0000000..a702adc --- /dev/null +++ b/scripts/render-computer-intro.py @@ -0,0 +1,425 @@ +#!/usr/bin/env python3 +"""Render the Chips and Code intro without a browser or external services. + +Requires Pillow, NumPy, ffmpeg and the system DejaVu/Nimbus fonts. The original +SVG mark is rasterized through the repository's sharp dependency. The default +output is a SILENT visual master. --audio adds an already authorized narration +file; this script never synthesizes or imitates a voice. +""" +from __future__ import annotations +import argparse, json, math, os, subprocess, sys +from pathlib import Path +import numpy as np +from PIL import Image, ImageDraw, ImageFont + +ROOT = Path(__file__).resolve().parents[1] +OUT = ROOT / 'static/media' +WIDTH, HEIGHT, SCALE, FPS, DURATION = 1280, 720, 2, 30, 48.0 +ACCENT = (79, 70, 229) +LIGHT_ACCENT = (166, 154, 255) +PALETTE = [(7,9,16), (17,21,38), (48,58,87), (166,175,199), (242,241,247)] +FONT_REG = '/usr/share/fonts/opentype/urw-base35/NimbusSans-Regular.otf' +FONT_BOLD = '/usr/share/fonts/opentype/urw-base35/NimbusSans-Bold.otf' +FONT_MONO = '/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf' +_font_cache = {} + +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.'}, +] +LAYERS = [('00','Signals & logic'),('01','Arithmetic'),('02','Memory'),('03','Architecture'),('04','Software')] + + +def font(size, mono=False, bold=False): + key=(size,mono,bold) + if key not in _font_cache: + _font_cache[key]=ImageFont.truetype(FONT_MONO if mono else FONT_BOLD if bold else FONT_REG, round(size*SCALE)) + return _font_cache[key] + + +def lerp(a,b,t): return a+(b-a)*t + +def clamp(t): return max(0.0,min(1.0,t)) + +def ease(t): + t=clamp(t) + return t*t*(3-2*t) + + +def mix(a,b,t): return tuple(round(lerp(x,y,t)) for x,y in zip(a,b)) + + +def rgba(color, alpha=255): return tuple(color[:3])+(round(alpha),) + + +class Canvas: + def __init__(self, image, origin=(0,0), scale=1): + self.im=image + self.d=ImageDraw.Draw(image) + self.ox,self.oy=origin + self.scale=scale + def pt(self,p): return ((self.ox+p[0]*self.scale)*SCALE,(self.oy+p[1]*self.scale)*SCALE) + def line(self, points, color, width=1): + self.d.line([self.pt(p) for p in points], fill=color, width=max(1,round(width*self.scale*SCALE)), joint='curve') + def box(self,xy,fill=None,outline=None,width=1,radius=0): + coords=(*self.pt(xy[:2]),*self.pt(xy[2:])) + if radius: + self.d.rounded_rectangle(coords,radius=radius*self.scale*SCALE,fill=fill,outline=outline,width=max(1,round(width*SCALE*self.scale))) + else:self.d.rectangle(coords,fill=fill,outline=outline,width=max(1,round(width*SCALE*self.scale))) + def poly(self,points,fill=None,outline=None,width=1): + self.d.polygon([self.pt(p) for p in points],fill=fill) + if outline:self.line(points+[points[0]],outline,width) + def circle(self,p,r,fill=None,outline=None,width=1): + self.box((p[0]-r,p[1]-r,p[0]+r,p[1]+r),fill,outline,width,r) + def text(self,p,text,size,color,mono=False,bold=False,anchor='la'): + self.d.text(self.pt(p),text,font=font(size*self.scale,mono,bold),fill=color,anchor=anchor) + + +def moving_point(points,progress): + lengths=[math.dist(a,b) for a,b in zip(points,points[1:])] + distance=sum(lengths)*(progress%1) + for a,b,length in zip(points,points[1:],lengths): + if distance <= length: + t=distance/length if length else 0 + return (lerp(a[0],b[0],t),lerp(a[1],b[1],t)) + distance-=length + return points[-1] + + +def trace(c,points,color,progress=None,width=1.8,glow=False): + if glow:c.line(points,rgba(color,35),width+6) + c.line(points,rgba(color),width) + if progress is not None: + p=moving_point(points,progress) + c.circle(p,6,rgba(color,35)) + c.circle(p,2.5,rgba(color)) + + +def signal(c,p,value,ink,accent,label=None): + col=accent if value else mix(ink,(128,132,152),.45) + c.circle(p,20,rgba(col,22),rgba(col),1.2) + c.text((p[0],p[1]-1),str(value),19,rgba(ink),True,anchor='mm') + if label:c.text((p[0],p[1]+32),label,11,rgba(ink,180),True,anchor='ma') + + +def nand(c,center,ink,accent,out): + x,y=center + pts=[(x-50,y-50),(x+5,y-50)] + pts += [(x+5+50*math.cos(a),y+50*math.sin(a)) for a in np.linspace(-math.pi/2,math.pi/2,30)] + pts += [(x-50,y+50)] + c.poly(pts,rgba(accent,22),rgba(ink,190),1.5) + c.circle((x+63,y),8,rgba(PALETTE[0]),rgba(accent if out else ink),1.8) + c.text((x-3,y-4),'NAND',20,rgba(ink),True,anchor='mm') + c.text((x-3,y+20),'a · b',10,rgba(ink,160),True,anchor='mm') + + +def backdrop(index): + base=np.array(PALETTE[index],dtype=np.float32) + y,x=np.mgrid[0:HEIGHT*SCALE,0:WIDTH*SCALE] + radial=np.exp(-(((x/(WIDTH*SCALE)-.72)/.53)**2+((y/(HEIGHT*SCALE)-.52)/.66)**2)*3) + # A restrained lens of indigo behind the changing machine. + delta=np.array([7,5,22],dtype=np.float32) if index<3 else np.array([-9,-9,-1],dtype=np.float32) + pixels=np.clip(base+radial[:,:,None]*delta,0,255).astype('uint8') + return Image.fromarray(pixels,'RGB').convert('RGBA') + + +def plate(c,y,ink,accent,p=0,depth=1,light=False): + x=820 + w=520 + h=128 + points=[(x-w/2,y),(x,y-h/2),(x+w/2,y),(x,y+h/2)] + fill=mix(PALETTE[4] if light else PALETTE[1],accent,.13) + c.poly([(a,b+18) for a,b in points],rgba((0,0,0),20)) + c.poly(points,rgba(fill,130),rgba(ink,60),1) + c.line([(x-w/2,y),(x,y+h/2),(x+w/2,y)],rgba(accent,160),1.4) + for i in range(3): + xx=x+40+i*23 + c.line([(xx,y+h/2-10-i*5),(xx+15,y+h/2-15-i*5)],rgba(ink,110),1.4) + + +def draw_signals(c,p,ink,accent): + # One moving observation point, on an exact two-level waveform. + c.text((640,216),'SIGNAL',12,rgba(ink,150),True) + pts=[(600,410),(670,410),(670,320),(770,320),(770,410),(875,410),(875,320),(1020,320),(1020,410),(1140,410)] + c.line([(600,320),(1140,320)],rgba(ink,35)) + c.line([(600,410),(1140,410)],rgba(ink,35)) + trace(c,pts,accent,p*1.4,width=2.3,glow=True) + c.text((565,314),'1',15,rgba(ink,150),True) + c.text((565,403),'0',15,rgba(ink,150),True) + pos=moving_point(pts,p*1.4) + c.line([(pos[0],275),(pos[0],455)],rgba(ink,90),1) + c.text((870,484),'0 → 1 → 0',19,rgba(ink),True,anchor='mm') + + +def draw_logic(c,p,ink,accent): + case=min(3,int(p*4)) + a,b=[(0,0),(0,1),(1,0),(1,1)][case] + out=1-(a&b) + signal(c,(625,305),a,ink,accent,'a') + signal(c,(625,435),b,ink,accent,'b') + trace(c,[(645,305),(725,305),(725,345),(770,345)],accent if a else mix(ink,PALETTE[0],.7),p*4) + trace(c,[(645,435),(725,435),(725,395),(770,395)],accent if b else mix(ink,PALETTE[0],.7),p*4+.3) + nand(c,(820,370),ink,accent,out) + trace(c,[(891,370),(1090,370)],accent if out else mix(ink,PALETTE[0],.7),p*4+.6,2.2,bool(out)) + signal(c,(1110,370),out,ink,accent,'out') + for i,(aa,bb) in enumerate([(0,0),(0,1),(1,0),(1,1)]): + x=700+i*98 + c.box((x,520,x+78,569),rgba(accent,25 if i==case else 8),rgba(accent if i==case else ink,150 if i==case else 35),1,3) + c.text((x+39,544),f'{aa}{bb} → {1-(aa&bb)}',13,rgba(ink,255 if i==case else 110),True,anchor='mm') + + +def draw_arithmetic(c,p,ink,accent): + a=[0,0,1,1]; b=[0,0,0,1]; sums=[0,1,0,0] + reveal=min(4,int(p*6)) + c.text((880,228),'0011 + 0001',26,rgba(ink),True,anchor='mm') + for i in range(4): + x=660+i*128 + active=i>=4-reveal + shade=accent if active else mix(ink,PALETTE[1],.7) + c.text((x-19,287),str(a[i]),16,rgba(ink,230),True,anchor='mm') + c.text((x+19,287),str(b[i]),16,rgba(ink,230),True,anchor='mm') + c.line([(x-19,306),(x-19,335)],rgba(shade),1.5) + c.line([(x+19,306),(x+19,335)],rgba(shade),1.5) + c.box((x-45,335,x+45,405),rgba(accent,22 if active else 5),rgba(shade),1.5,4) + c.text((x,362),'ADD',16,rgba(ink,255 if active else 110),True,anchor='mm') + c.text((x,388),f'bit {3-i}',10,rgba(ink,160),True,anchor='mm') + if i<3: + pts=[(x+128-45,375),(x+45,375)] + trace(c,pts,accent if reveal>3-i else mix(ink,PALETTE[1],.8),p*5) + c.line([(x,405),(x,458)],rgba(shade),1.5) + signal(c,(x,480),sums[i] if active else 0,ink,accent) + c.text((850,560),'0100 = 4',26,rgba(ink,255 if reveal==4 else 80),True,anchor='mm') + c.text((850,599),'Carry flows from right to left.',12,rgba(ink,160),anchor='mm') + + +def draw_memory(c,p,ink,accent): + # The waveform cursor reaches the rising edge after170 of596 path units. + edge=170/596 + loaded=p>=edge + bits='10110100' if loaded else '00000000' + c.text((867,230),'8-BIT REGISTER',14,rgba(ink,180),True,anchor='mm') + c.text((867,275),'IN 10110100',21,rgba(ink),True,anchor='mm') + for i,bit in enumerate(bits): + x=605+i*69 + col=accent if bit=='1' else mix(ink,PALETTE[2],.6) + c.line([(x+25,310),(x+25,340)],rgba(accent if loaded else ink,150),1.3) + c.box((x,340,x+50,412),rgba(accent,36 if bit=='1' else 5),rgba(col),1.4,3) + c.text((x+25,376),bit,29,rgba(ink),True,anchor='mm') + c.text((x+25,431),str(7-i),10,rgba(ink,170),True,anchor='mm') + c.line([(598,462),(1135,462)],rgba(ink,80)) + for i in range(8): + x=630+i*69 + c.line([(x,444),(x,462)],rgba(ink,80)) + clockx=lerp(650,1100,p) + wave=[(620,554),(790,554),(790,511),(925,511),(925,554),(1130,554)] + trace(c,wave,accent,p,1.6) + c.line([(790,490),(790,574)],rgba(ink,80),1) + c.text((598,528),'CLK',11,rgba(ink,180),True,anchor='rm') + c.text((870,605),'HOLD 10110100' if loaded else 'WAITING FOR THE CLOCK',14,rgba(ink),True,anchor='mm') + if edge <= p <= edge+.17: + a=(1-(p-edge)/.17)*150 + c.box((592,329,1155,425),None,rgba(accent,a),2,6) + + +def block(c,box,label,ink,accent,sub=None,active=False): + c.box(box,rgba(accent,28 if active else 9),rgba(accent if active else ink,180 if active else 80),1.5,4) + x=(box[0]+box[2])/2;y=(box[1]+box[3])/2 + c.text((x,y-(10 if sub else 0)),label,17,rgba(ink),True,anchor='mm') + if sub:c.text((x,y+20),sub,12,rgba(ink,185),True,anchor='mm') + + +def draw_architecture(c,p,ink,accent): + stage=0 if p<.26 else 1 if p<.5 else 2 if p<.76 else 3 + c.box((590,300,980,574),rgba((255,255,255),20),rgba(ink,110),1.5,5) + c.text((614,316),'CPU',13,rgba(ink,170),True) + block(c,(1012,221,1182,293),'PROGRAM',ink,accent,'D = D + A',stage==0) + block(c,(612,365,734,431),'CONTROL',ink,accent,None,stage==1) + block(c,(778,365,947,451),'ALU',ink,accent,'3 + 1 = 4',stage==2) + block(c,(674,489,786,550),'A = 1',ink,accent) + block(c,(830,489,947,550),'D = '+('4' if stage==3 else '3'),ink,accent,None,stage==3) + paths=[[(1097,293),(1097,337),(673,337),(673,365)],[(734,398),(778,398)],[(730,489),(730,470),(816,470),(816,451)],[(888,451),(888,489)]] + for i,pts in enumerate(paths):trace(c,pts,accent if i==stage else mix(ink,PALETTE[3],.65),p*4+i/4 if i==stage else None,2 if i==stage else 1.3) + c.text((867,615),['FETCH','DECODE','EXECUTE','WRITE BACK'][stage],14,rgba(ink),True,anchor='mm') + + +def draw_software(c,p,ink,accent): + c.box((571,219,1190,518),rgba((255,255,255),130),rgba(ink,55),1.2,6) + c.line([(571,262),(1190,262)],rgba(ink,40),1) + c.text((597,237),'main.js',12,rgba(ink,160),True) + for i,col in enumerate([accent,mix(accent,(255,255,255),.4),mix(accent,(255,255,255),.7)]):c.circle((1135+i*16,241),3,rgba(col)) + lines=[('function add(a, b) {',accent),(' return a + b;',ink),('}',ink),('',ink),('add(3, 1);',accent)] + for i,(txt,col) in enumerate(lines): + alpha=255 if p>(i*.07) else round(100+155*clamp(p/(i*.07+.01))) + c.text((600,292+i*35),f'{i+1:2}',12,rgba(ink,85),True) + c.text((643,288+i*35),txt,21,rgba(col,alpha),True) + if p>.43: + q=ease((p-.43)/.17) + c.line([(892,518),(892,548)],rgba(accent,q*230),1.8) + c.box((786,548,998,608),rgba(accent,q*20),rgba(accent,q*170),1.3,4) + c.text((892,578),'4',34,rgba(accent,q*255),True,anchor='mm') + + +def draw_stack(c,p,ink,accent): + # Actual abstraction order: hardware at the bottom, software above it. + labels=['Software','Architecture','Memory','Arithmetic','Logic'] + colors=[(242,241,247),(166,175,199),(48,58,87),(17,21,38),(7,9,16)] + reveal=ease(min(1,p*2.3)) + for i in reversed(range(5)): + y=245+i*(56+12*reveal) + cx=855 + pts=[(cx-230,y),(cx,y-61),(cx+230,y),(cx,y+61)] + top=colors[i] + c.poly([(x,yy+14) for x,yy in pts],rgba(mix(top,(0,0,0),.24)),None) + c.poly(pts,rgba(top),rgba(accent,100),1) + c.line([(cx-230,y),(cx,y+61),(cx+230,y)],rgba(accent,170),1.5) + localink=(39,41,68) if i<2 else (179,173,237) + for j in range(4): + x=cx-100+j*43 + c.line([(x,y-12),(x+25,y-20),(x+76,y-5),(x+51,y+3)],rgba(localink,100),1) + c.text((1143,y-2),labels[i],12,rgba(ink,200),anchor='lm') + c.line([(cx+234,y),(1128,y)],rgba(ink,65),1) + + +def add_common(c,t,layer_idx,ink,accent,mark): + # Quiet framing and a truthful abstraction rail, not dashboard decoration. + c.im.alpha_composite(mark,(round(58*SCALE),round(39*SCALE))) + c.text((102,46),'Chips and Code',18,rgba(ink),bold=True) + c.line([(58,96),(1222,96)],rgba(ink,35),1) + c.text((1222,52),'FROM SIGNAL TO SOFTWARE',10,rgba(ink,145),True,anchor='ra') + y=116 + railwidth=1164 + for i,(number,name) in enumerate(LAYERS): + x=58+i*railwidth/5 + active=(i==layer_idx) + c.line([(x,y),(x+railwidth/5-20,y)],rgba(accent if active else ink,200 if active else 40),2 if active else 1) + c.text((x,y+13),number+' '+name,10,rgba(ink,240 if active else 130),True) + + +def get_scene(t): + return next((i for i,s in enumerate(SEGMENTS) if t {timestamp(s["end"]-.1)} line:88% position:50% size:85% align:center\n{s["narration"]}\n\n' for n,s in enumerate(SEGMENTS)) + (OUT/'computer-intro.vtt').write_text(captions) + (OUT/'computer-intro-transcript.txt').write_text('Chips and Code — from signal to software\n\n'+ '\n\n'.join(s['narration'] for s in SEGMENTS)+'\n') + + +def prepare_mark(): + path=OUT/'computer-intro-mark.png' + subprocess.run(['node','-e',"require('sharp')('static/logo.svg').resize(96,96).png().toFile('static/media/computer-intro-mark.png')"],cwd=ROOT,check=True) + image=Image.open(path).convert('RGBA').resize((32*SCALE,32*SCALE),Image.Resampling.LANCZOS) + path.unlink() + return image + + +def frame_at(t,backgrounds,mark): + idx=get_scene(t);segment=SEGMENTS[idx] + p=clamp((t-segment['start'])/(segment['end']-segment['start'])) + current_palette=max(0,min(4,idx-1)) + previous_palette=max(0,min(4,idx-2)) + transition=ease((t-segment['start'])/1.15) if idx else ease(t/.8) + bg=Image.blend(backgrounds[previous_palette],backgrounds[current_palette],transition) if idx else backgrounds[0].copy() + ink=(236,236,247) if current_palette<3 else (27,30,54) + accent=LIGHT_ACCENT if current_palette<3 else ACCENT + if idx and transition<1: + oldink=(236,236,247) if previous_palette<3 else (27,30,54) + oldaccent=LIGHT_ACCENT if previous_palette<3 else ACCENT + previous=render_scene(idx-1,1,t,oldink,oldaccent,mark) + previous.putalpha(previous.getchannel('A').point(lambda a:round(a*(1-transition)))) + bg.alpha_composite(previous) + scene=render_scene(idx,p,t,ink,accent,mark) + if transition<1:scene.putalpha(scene.getchannel('A').point(lambda a:round(a*transition))) + bg.alpha_composite(scene) + # Fade framing only at the film opening; layer controls never jump. + compositeink=mix((236,236,247) if previous_palette<3 else (27,30,54),ink,transition) + compositeaccent=mix(LIGHT_ACCENT if previous_palette<3 else ACCENT,accent,transition) + framing=Image.new('RGBA',bg.size) + add_common(Canvas(framing),t,current_palette,compositeink,compositeaccent,mark) + bg.alpha_composite(framing) + if t<.7: + black=Image.new('RGBA',bg.size,PALETTE[0]+(255,));bg=Image.blend(black,bg,ease(t/.7)) + return bg.convert('RGB').resize((WIDTH,HEIGHT),Image.Resampling.LANCZOS) + + +def main(): + parser=argparse.ArgumentParser() + parser.add_argument('--audio',type=Path,help='Optional finished narration file. It must fit the timed48-second film.') + parser.add_argument('--stills-only',action='store_true') + parser.add_argument('--start',type=float,default=0.0,help='Render a time range for motion review.') + parser.add_argument('--end',type=float,default=DURATION,help='End of an optional review range.') + parser.add_argument('--output',type=Path,default=OUT/'computer-intro.mp4') + args=parser.parse_args() + if not 0 <= args.start < args.end <= DURATION: + parser.error('Require0 <= start < end <=48.') + if args.audio and (args.start != 0 or args.end != DURATION): + parser.error('Audio muxing requires the complete film.') + metadata() + mark=prepare_mark() + backgrounds=[backdrop(i) for i in range(5)] + framesdir=Path(os.environ.get('INTRO_REVIEW_DIRECTORY',str(ROOT.parent/'intro-review'))) + framesdir.mkdir(exist_ok=True) + for second in [2.5,8.3,16.8,25.6,33.5,40.8,46.2]: + frame_at(second,backgrounds,mark).save(framesdir/f'frame-{second:04.1f}.jpg',quality=94) + # Poster shows the complete abstraction stack using the real brand mark. + frame_at(46.2,backgrounds,mark).save(OUT/'computer-intro-poster.jpg',quality=94) + if args.stills_only: + print(f'Review frames: {framesdir}',flush=True);return + master=args.output if not args.audio else args.output.with_name(args.output.stem+'-silent.mp4') + command=['ffmpeg','-hide_banner','-loglevel','warning','-y','-f','rawvideo','-pix_fmt','rgb24','-s',f'{WIDTH}x{HEIGHT}','-r',str(FPS),'-i','-','-an','-c:v','libx264','-preset','medium','-crf','22','-profile:v','high','-level','3.1','-pix_fmt','yuv420p','-movflags','+faststart',str(master)] + process=subprocess.Popen(command,stdin=subprocess.PIPE) + try: + for n in range(round((args.end-args.start)*FPS)): + process.stdin.write(frame_at(args.start+n/FPS,backgrounds,mark).tobytes()) + if n%300==0:print(f'Rendered {args.start+n/FPS:.1f} / {args.end:.1f} seconds',flush=True) + process.stdin.close() + if process.wait()!=0:raise RuntimeError('ffmpeg failed') + except BaseException: + process.kill();raise + if args.audio: + subprocess.run(['ffmpeg','-hide_banner','-loglevel','warning','-y','-i',str(master),'-i',str(args.audio),'-map','0:v:0','-map','1:a:0','-c:v','copy','-c:a','aac','-b:a','160k','-af','loudnorm=I=-16:TP=-1.5:LRA=7,apad','-t',str(DURATION),'-movflags','+faststart',str(args.output)],check=True) + data=json.loads((OUT/'computer-intro-timing.json').read_text());data['audio_status']='narrated';(OUT/'computer-intro-timing.json').write_text(json.dumps(data,indent=2)+'\n') + master.unlink() + print(f'Film: {args.output} ({args.output.stat().st_size/1e6:.2f} MB)',flush=True) + + +if __name__=='__main__':main() diff --git a/src/app.css b/src/app.css index 21f64c0..916b5ba 100644 --- a/src/app.css +++ b/src/app.css @@ -3,46 +3,186 @@ @tailwind components; @tailwind utilities; -*:focus { - @apply !outline-primary; +:root { + color-scheme: dark; + background: #080b13; + color: #f4f3ff; + font-family: + Inter, + ui-sans-serif, + system-ui, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + sans-serif; +} +body { + margin: 0; + min-width: 280px; +} +.app-shell { + min-height: 100svh; + display: flex; + flex-direction: column; + background: #080b13; + color: #f4f3ff; +} +#page-content { + flex: 1; + min-width: 0; +} +#page-content:focus { + outline: none; +} +*:focus-visible { + outline: 2px solid #c5bdff; + outline-offset: 4px; +} +[hidden] { + display: none !important; +} +button, +input, +select, +textarea { + font: inherit; +} +button, +summary, +a { + -webkit-tap-highlight-color: transparent; +} +button:not(:disabled), +summary { + cursor: pointer; +} +button:disabled { + cursor: default; +} +.page-prose { + max-width: 1000px; + margin: auto; + padding: 60px max(24px, 5%) 100px; + color: #e9ecf6; +} +.page-prose .eyebrow { + margin: 0 0 24px; + color: #b8afff; + font: + 12px ui-monospace, + monospace; + letter-spacing: 0.08em; +} +.page-prose h1 { + font-size: clamp(38px, 5vw, 64px); + line-height: 1.06; + font-weight: 500; + letter-spacing: -0.045em; + margin: 0 0 28px; + color: #f6f4ff; +} +.page-prose h2 { + font-size: 25px; + font-weight: 500; + letter-spacing: -0.025em; + margin: 46px 0 16px; + color: #f6f4ff; +} +.page-prose h3 { + font-size: 18px; + font-weight: 600; + margin: 28px 0 12px; +} +.page-prose p, +.page-prose li { + font-size: 16px; + line-height: 1.8; + color: #bac3d8; +} +.page-prose p { + margin: 0 0 18px; +} +.page-prose .lead { + max-width: 650px; + font-size: clamp(18px, 2vw, 21px); + line-height: 1.6; + color: #d0d6e7; +} +.page-prose a { + color: #c0b7ff; + text-decoration: underline; + text-underline-offset: 4px; +} +.page-prose a:hover { + color: #eeeaff; +} +.page-prose ul { + list-style: disc; + padding-left: 23px; +} +.page-prose section { + scroll-margin-top: 30px; +} +.page-prose details { + border-top: 1px solid #414a63; + margin: 28px 0; + padding-top: 18px; +} +.page-prose summary { + min-height: 44px; + color: #e0dfff; +} +@media (max-width: 520px) { + .page-prose { + padding: 36px 20px 70px; + } } /* Overrides for DaisyUI components */ .btn { - @apply font-semibold text-base; + @apply font-semibold text-base; } .btn.btn-link { - @apply no-underline text-base-content no-animation; + @apply no-underline text-base-content no-animation; } -.btn.btn-link.btn-active, .btn.btn-link:hover { - @apply text-primary; +.btn.btn-link.btn-active, +.btn.btn-link:hover { + @apply text-primary; } -[data-theme="dark"] .btn.btn-link.btn-active, [data-theme="dark"] .btn.btn-link:hover { - @apply text-white; +[data-theme='dark'] .btn.btn-link.btn-active, +[data-theme='dark'] .btn.btn-link:hover { + @apply text-white; } .btn.btn-outline { - @apply border-gray-200 shadow-sm; + @apply border-gray-200 shadow-sm; } -.btn.btn-outline:hover, .btn.btn-outline.btn-active { - @apply bg-base-200 text-primary; +.btn.btn-outline:hover, +.btn.btn-outline.btn-active { + @apply bg-base-200 text-primary; } -[data-theme="dark"] .btn.btn-outline { - @apply border-zinc-500 bg-neutral; +[data-theme='dark'] .btn.btn-outline { + @apply border-zinc-500 bg-neutral; } -[data-theme="dark"] .btn.btn-outline:hover, [data-theme="dark"] .btn.btn-outline.btn-active { - @apply bg-base-100 text-white; +[data-theme='dark'] .btn.btn-outline:hover, +[data-theme='dark'] .btn.btn-outline.btn-active { + @apply bg-base-100 text-white; } -.btn.btn-outline.btn-success, .btn.btn-outline.btn-warning, .btn.btn-outline.btn-error { - @apply border-gray-200; +.btn.btn-outline.btn-success, +.btn.btn-outline.btn-warning, +.btn.btn-outline.btn-error { + @apply border-gray-200; } -[data-theme="dark"] .btn.btn-outline.btn-success, [data-theme="dark"] .btn.btn-outline.btn-warning, [data-theme="dark"] .btn.btn-outline.btn-error { - @apply border-zinc-500 bg-neutral; +[data-theme='dark'] .btn.btn-outline.btn-success, +[data-theme='dark'] .btn.btn-outline.btn-warning, +[data-theme='dark'] .btn.btn-outline.btn-error { + @apply border-zinc-500 bg-neutral; } -.menu :where(li:not(.menu-title):not(:empty)) > :where(:not(ul).active), .menu :where(li:not(.menu-title):not(:empty)) > :where(*:not(ul):active) { - @apply bg-base-content/10 text-base-content; +.menu :where(li:not(.menu-title):not(:empty)) > :where(:not(ul).active), +.menu :where(li:not(.menu-title):not(:empty)) > :where(*:not(ul):active) { + @apply bg-base-content/10 text-base-content; } diff --git a/src/app.html b/src/app.html index 0c4bb9a..6075cdc 100644 --- a/src/app.html +++ b/src/app.html @@ -1,5 +1,5 @@ - - + + @@ -7,8 +7,7 @@ - - + Chips and Code - - - %sveltekit.head% diff --git a/src/lib/components/EmbeddedHardwareIDE.svelte b/src/lib/components/EmbeddedHardwareIDE.svelte index e75d164..a031f52 100644 --- a/src/lib/components/EmbeddedHardwareIDE.svelte +++ b/src/lib/components/EmbeddedHardwareIDE.svelte @@ -1,26 +1,60 @@ -
- {#if experiment} - - {:else} - - {/if} -
+{#if experiment} + +{:else}

That circuit example is unavailable.

{/if} + + diff --git a/src/lib/components/Footer.svelte b/src/lib/components/Footer.svelte deleted file mode 100644 index b283c60..0000000 --- a/src/lib/components/Footer.svelte +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/src/lib/components/HardwareIDE.svelte b/src/lib/components/HardwareIDE.svelte index e3b085c..35b4f1a 100644 --- a/src/lib/components/HardwareIDE.svelte +++ b/src/lib/components/HardwareIDE.svelte @@ -1,20 +1,5 @@ { - if (!controls) return; - - if (e.ctrlKey && e.key === 's' && apiEnabled) { - // Don't open default Save dialog - e.preventDefault(); - save(); + on:keydown={(event) => { + if ( + controls && + (event.ctrlKey || event.metaKey) && + event.key.toLowerCase() === 's' && + apiEnabled + ) { + event.preventDefault(); + void save(); } }} /> -
-
- onTabChange({ detail: Number(value) as EditorTab })} - activationMode="manual" - > - - HDL - Tests {#if typeof testStats?.passed === 'number'} -
+
+ + {#if controls} +
+ + File + + Open new - {testStats.passed} / {testStats.total} - {#if celebrateTestsPass && justSucceeded} -
- {/if} -
- {/if} - - Output - - - {#if selectedTab === EditorTab.DIFF} - - {/if} - -
- -
- -
-
- - - {#if controls} -
-
+
Examples
+ {#each examples as example (example.id)} + + {#snippet child({ props })} + {example.name} + {/snippet} + + {/each} {#if apiEnabled} - - {:else} - - Download - {/if} - - - - - - - - {#if apiEnabled} - {#await getUserExperiments()} - - {:then savedExperiments} - - - {#each savedExperiments as saved} - - {#snippet child({ props })} - {saved.name} - {/snippet} - - {/each} - {:catch error} -
- Loading failed: {error.message} -
- {/await} - {/if} - - - {#snippet child({ props })} - - {/snippet} - - - - {#each examples as example (example.id)} +
Saved on this device
+ {#await getUserExperiments()} +

Loading experiments…

+ {:then savedExperiments} + {#each savedExperiments as saved} {#snippet child({ props })} {example.name}{saved.name} {/snippet} - {/each} -
-
- - {#if apiEnabled} - - - - - - -
- -
- -
- - -
-
-
+ {:else}

No saved experiments yet.

{/each} + {:catch cause}

+ Saved experiments are unavailable. Your local work is still here. +

{/await} {/if} - - {#if apiEnabled} - - - - - - - download()} - > - Download - - - {#snippet child({ props })} - - {/snippet} - - - - {/if} -
-
- {/if} -
- - {#if error} - - {/if} - - {#if chip} - - {#if controls && 1 === Math.round(3)} -
-
Chip {chip?.name}
- -
- -
- -
+ Share -
-
- {/if} - -
- - +

Share this experiment

+ {#if isBundledExample} +

This is a bundled example. Save a copy to share your changes.

+ {:else} + + {#if savingState !== 'SAVED'}

Save to apply your sharing preference.

{/if} + {/if} + + +

{copyStatus}

+ + + {:else} + - - - + ••• + + download()} + class="hardware-menu-item">Download .zip - - - {#each inputPins as pin} - - - - - {/each} - -
Input Pins
NameValue
{pin.name} -
+ {#if apiEnabled && experiment && !isBundledExample} + + {#snippet child({ props })}{/snippet} + + {/if} + +
+ {/if} + + +
+
+ onTabChange({ detail: Number(value) as EditorTab })} + activationMode="manual" + > + + HDL + Tests + {#if testStats} + {testStats.passed} / {testStats.total} + {/if} + + Output + + {#if selectedTab === EditorTab.DIFF} +

+ Compare actual output with expected values.{readOnlyAssignment + ? ' Expected values are supplied.' + : ' Expected values are editable.'} +

+ {/if} +
+
+
+ {!initialized + ? 'Loading editor…' + : codeError + ? 'Check the HDL' + : chip + ? `${chip.name} · compiled` + : 'HDL · ready'} + {storageNotice + ? 'Draft not saved' + : savingState === 'UNSAVED' + ? 'Local draft' + : savingState === 'SAVED' + ? isBundledExample + ? 'Example' + : 'Saved' + : 'Local workspace'} +
+
-
- - - - - - +
Internal Pins
NameValue
+ + - {#each internalPins as pin} - - - - + {#each inputPins as pin} + {/each}
Input pins
PinValue
{pin.name}{pin.value ? '1' : '0'}
{pin.name}
-
- -
- - - - - - +
Output Pins
NameValue
+ + - {#each outputPins as pin} - - - - - {/each} + {#each outputPins as pin}{/each}
Output pins
PinValue
{pin.name}{pin.value ? '1' : '0'}
{pin.name}{runtimeError ? '—' : pin.value}
-
- {:else if controls} -
- Add CHIP to start or check one of the examples like the Xor Gate. -
- {/if} + {#if internalPins.length} +
+ Internal signals {internalPins.length} + + + + {#each internalPins as pin}{/each} +
Internal pins
PinValue
{pin.name}{runtimeError ? '—' : pin.value}
+
+ {/if} + {:else if error} +

+ Simulation is paused. Repair the circuit to inspect its signals. +

+ {:else} + +

Describe a chip in HDL, or begin with a working example.

+ Xor Gate + {/if} +
+ How this workspace works +

+ HDL describes the chip and its connections. Tests sets + inputs and checks each case. Output compares the actual result with the expected + values. +

+

+ This simulator runs single-bit, combinational circuits. Explore word-sized signals and + selectors in the bus and routing lab. +

+ Read the HDL explanation ↗ +
+
-
+ + {#if error} + + {/if} + {#if storageNotice}

{storageNotice}

{/if} + diff --git a/src/lib/components/Header.svelte b/src/lib/components/Header.svelte deleted file mode 100644 index cd7b493..0000000 --- a/src/lib/components/Header.svelte +++ /dev/null @@ -1,173 +0,0 @@ - - - diff --git a/src/lib/components/Loading.svelte b/src/lib/components/Loading.svelte index ef48044..d2d47c6 100644 --- a/src/lib/components/Loading.svelte +++ b/src/lib/components/Loading.svelte @@ -2,12 +2,12 @@ export let name: string; -
-

Retrieving {name}

+

Loading {name}…

-
- This should take little to no time... - - -
-
+ diff --git a/src/lib/components/Problem.svelte b/src/lib/components/Problem.svelte index 2397931..b45c899 100644 --- a/src/lib/components/Problem.svelte +++ b/src/lib/components/Problem.svelte @@ -2,13 +2,49 @@ export let message: string; - + + + 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 @@ + + + + + + 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 @@ - - - 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 @@ + + + + + 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. +

+
+ +
+
+ +
+

{message}

+ {#if error}{/if}{#if session}{#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.

+ {#if Object.keys(files).length}

{Object.keys(files).join(', ')}

+ {/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 +
+ +
+

PROJECT 0{chapter.project} · {chapter.title}

+

{task.title}

+

{task.goal}

+
+
+ {taskIndex + 1} / {chapter.tasks.length} +
+ Steps in this layer +
    + {#each chapter.tasks as item, index (item.id)}
  1. + +
  2. {/each} +
+
+
+

{task.explanation}

+ {#if task.kind === 'symbols'} +
{symbolProgram}
{/if} + {#if task.kind === 'hdl'} +
+ {task.chip}.hdl +
+ + {:else}{/if} +
+ Draft saved on this device +
+ {#if result}
+ {result.passed ? 'It works.' : 'Keep building.'} +

{result.message}

+ {#if result.passed}{#if taskIndex < chapter.tasks.length - 1}{: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} +
+
+ Need a hint? +

{task.hint}

+ Read the full explanation +
+ {#if task.kind === 'hdl' || task.kind === 'assembly'}
+ {task.kind === 'hdl' ? 'Inspect signals and clock' : 'Step through the program'} + {#if circuit}
+ {#each Object.entries(task.inputs ?? {}) as [pin, width] (pin)}{/each} +
+
+ {phase} +
+
+ {#each Object.entries(outputs) as [pin, value] (pin)}
+
{pin}
+
+ {value}0b{value.toString(2).padStart(task.outputs?.[pin] ?? 1, '0')} +
+
{/each} +
{/if} + {#if preview} +
+
+
A
+
{preview.a}
+
+
+
D
+
{preview.d}
+
+
+
PC
+
{preview.pc}
+
+
+
RAM[2]
+
{preview.ram[2]}
+
+
{/if} + {#if error}{/if} +
{/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} +
+ +
+ {#if !parts.length}

+ Add a part, then connect its pins to inputs, outputs, or named internal wires. +

{/if} +
+ {#each parts as part, index (index)}{/each} +
+ {#if parts[selected]} + {@const part = parts[selected]} +
+
+

{part.type} Part {selected + 1}

+ +
+ {#each Object.entries(part.connections) as [pin, wire] (pin)}{/each} +
+ Connect part pin slices +

+ Split a bus pin into slices when different wires supply different bits. Connecting a + slice replaces that pin’s whole-bus binding. +

+ +
+

+ Examples: in[0], out[0..7], carry, + true. An output creates an internal wire when you give it a new name. +

+
+ {/if} + {/if} +
+ {/if} + {#if mode !== 'visual'}{/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 +
+

FROM SIGNALS TO ASSEMBLY

+

Build it up.

+

Each layer uses the one beneath it. One working piece at a time.

+
+ +
    + {#each courseChapters as chapter (chapter.id)} + {@const count = chapter.tasks.filter((task) => + completed.includes(taskKey(chapter, task)), + ).length} +
  1. + 0{chapter.project}

    {chapter.title}

    +

    {chapter.description}

    {count === chapter.tasks.length ? 'Complete' : `${count} / ${chapter.tasks.length}`} +
    +
  2. + {/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 = ''; + frame.srcdoc = ` + +
+
+ LOGIC ANALYZER{certified ? 'VERIFIED' : outputs ? 'LIVE' : 'IDLE'} +
+ `${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} + +
+ {samples.length} / 12 CHANGESINPUT → OUTPUT +
+
+ + 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); + + + + + + + + + + + + + + + + + + + + + + {#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 @@ + + +
+
+
+

LAYER 00 / LOGIC

+

Reference

+
+ +
+ +
+ + +
+ {#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} + + {/each} +
+ +
+
+
+ + +
+ {#if gate !== 'NOT'} +
+ + +
+ {/if} +
+
+ 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. +

+
+ + + {#if gate !== 'NOT'}{/if} + {#each rows as [x, y]}{#if gate !== 'NOT'}{/if}{/each} +
{gate} truth table
{gate === 'NOT' ? 'in' : 'A'}BOUT
{Number(x)}{Number(y)}{Number(evaluate(gate, x, y))}
+
+ {: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
+
+ + + +
+ 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}{/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}{/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]} +
+ Read the full explanation +

{fullExplanations[chapter].label}

+ {#if chapter === 'expressions'} + Try the Boolean functions tool + {:else if chapter === 'scale'} + Try the buses and routing tool + {:else if chapter === 'blueprints'} + Inspect the worked XOR in the simulator + {/if} +
+ {/if} +
+ CHIPS AND CODE / REFERENCE{chapters.find((item) => item.id === chapter)?.number} — 05 +
+
+
+
+ + 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 === 'signal' || (view === 'guide' && referenceReturn === 'signal')} + + {/if} + {#if view === 'workbench' || (view === 'guide' && referenceReturn === 'workbench')} + + {/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}

+
+ + {: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 → +
+ + {/if} +
+ {:else if view === 'collection'} +
+

Your chips.

+

Each one is a building block for what comes next.

+
+ {#each verifiedMissions as mission} + + {/each} +
+ {#if !nextMission}Continue through the computer →{/if} + {#if nextMission}{/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

+
+ +
+ + {#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.

+ +

No prerequisites. Free in your browser.

+ {:else} +

{chapter.label}

+

{chapter.title}

+

{chapter.body}

+ {/if} +
+
+ +
+ {#if index === 0}

+ Scroll to look inside +

{/if} +
+ {/each} +
+ +
+ +
+
+

FROM SIGNALS TO SOFTWARE

+

Then build it{' '}
back up.

+

+ Combine signals with gates. Build working circuits. Understand what your code is built on. +

+ +

Build from signals through a working computer and assembler.

+ +
+ +
+
+ + 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}
+
+ REFERENCE +
+

{mission.chip}, under the hood.

+

{mission.explanation}

+ Read the full background Gate specifications +
{/if} + +
+
+

+ CHALLENGE {String(mission.number).padStart(2, '0')} / + {mission.location} +

+

{mission.title}

+

{mission.goal}

+
+
+ + {#if live.result} +
+ INPUT SIGNALS + {#each mission.inputs as pin} + + {/each} +
+ {/if} +
+ +
+ {#if codeError || reportError || report} + + {codeError + ? 'Check the code' + : reportError + ? 'Check the connections' + : report + ? `${report.passed} / ${report.total} pass` + : ''} + + {/if} + {#if restoreReady} + + {:else if live.result || codeError || reportError} + + {/if} +
+
+ {#if codeError} + + {/if} +
+
+ {#if editorMode !== 'code'} +
+
+
+ Circuit +
+ {#each mission.availableParts as type}{/each} +
+
+ + {#if missionId !== 'nand'} +
+ +

{guidedInstruction}

+ {#if selectedSource}{/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} + + + + + + {/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'} + + + + {/if} + {/each} + + {signal(gate.id, liveSignals) === null + ? '·' + : Number(signal(gate.id, liveSignals))} + {#if missionId !== 'nand'} + + + + {/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'} + + + + {/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}{/if} +
+ + {#if circuit.gates.length > 0} +
+ {#each circuit.gates as gate, index (gate.id)} +
+
+ {String(index + 1).padStart(2, '0')}{gate.type} +
+ {#each gatePins(gate.type) as pin} + + {/each} +
+ {/each} +
+ {/if} +
+ CHIP OUTPUTS{#each mission.outputs as pin}{/each} +
+
+
+ {/if} +
+ {/if} + {#if editorMode !== 'visual'} +
+
+ {mission.chip}.hdl +
+ {#if editorMode === 'code' && !live.result && !codeError && mission.outputs.every((pin) => !!circuit.outputs[pin])} +

{guidedInstruction}

+ {/if} +
+ + +
+
+ {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.'}

+ +
+
+{/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 @@ + + +
+ +
+

SIGNALS & LOGIC

+

AND, with its answer flipped.

+

+ NAND means NOT AND. It flips the answer of an AND gate. Try the same inputs. +

+
+ +
+
+ {#each ['a', 'b'] as pin} + + {/each} +
+ + + out{Number(output)} + +
+ +
+ {Math.min(step + 1, cases.length)} of {cases.length} +

{instruction}

+ {#if confirmed} + + {#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} + + {:else} +
+ + +
+ + {/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 @@ + + +
+ + +
+

{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 + +
+ +
+ Output + +
+
+ {:else} +
+
+ {#if stage === 'not'} + + {:else} + {#each ['a', 'b'] as pin} + + {/each} + {/if} +
+ + +
+ {/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} + + {/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 @@ + + +
+ +
+ +
+ Project files +
+ +
+
+ +
+
+{#if 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 + - -
- -
-
-
-
-
-

- Wondering how computers work? -

-

- 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. -

-
-
-
- - - - Start Learning 🤯 -
-
-
-
-
+
+ goto('/learn')} onwatch={() => (introOpen = true)} />
- -