├── .babelrc ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc ├── .travis.yml ├── .watchmanconfig ├── LICENSE ├── README.md ├── bin └── hdl-js ├── examples ├── And.hdl ├── And16.hdl ├── Decoder.hdl ├── MipsAlu.hdl ├── MipsAlu16.hdl ├── Mux.hdl ├── Not16.hdl ├── RAM16K.hdl ├── RAM64.hdl └── __tests__ │ ├── And-hdl-test.js │ ├── Decoder-hdl-test.js │ └── MipsAlu-hdl-test.js ├── index.js ├── package-lock.json ├── package.json ├── scripts ├── build.js ├── git-pre-commit └── git-pre-push └── src ├── bin └── hdl-js-cli.js ├── emulator └── hardware │ ├── BuiltInGate.js │ ├── Clock.js │ ├── CompositeGate.js │ ├── Gate.js │ ├── HDLClassFactory.js │ ├── Pin.js │ ├── __tests__ │ ├── BuiltInGate-test.js │ ├── Clock-test.js │ ├── CompositeGate-test.js │ ├── Gate-test.js │ ├── HDLClassFactory-test.js │ └── Pin-test.js │ ├── builtin-gates │ ├── ALU.js │ ├── ARegister.js │ ├── Add16.js │ ├── And.js │ ├── And16.js │ ├── Bit.js │ ├── DFF.js │ ├── DMux.js │ ├── DMux4Way.js │ ├── DMux8Way.js │ ├── DRegister.js │ ├── FullAdder.js │ ├── HalfAdder.js │ ├── Inc16.js │ ├── Keyboard.js │ ├── MipsAlu.js │ ├── Mux.js │ ├── Mux16.js │ ├── Mux4Way16.js │ ├── Mux8Way16.js │ ├── Nand.js │ ├── Nor.js │ ├── Nor16Way.js │ ├── Not.js │ ├── Not16.js │ ├── Or.js │ ├── Or16.js │ ├── Or8Way.js │ ├── PC.js │ ├── RAM.js │ ├── RAM16K.js │ ├── RAM4K.js │ ├── RAM512.js │ ├── RAM64.js │ ├── RAM8.js │ ├── Register.js │ ├── Screen.js │ ├── Xor.js │ ├── __tests__ │ │ ├── ALU-test.js │ │ ├── ARegister-test.js │ │ ├── Add16-test.js │ │ ├── And-test.js │ │ ├── And16-test.js │ │ ├── Bit-test.js │ │ ├── DFF-test.js │ │ ├── DMux-test.js │ │ ├── DMux4Way-test.js │ │ ├── DMux8Way-test.js │ │ ├── DRegister-test.js │ │ ├── FullAdder-test.js │ │ ├── HalfAdder-test.js │ │ ├── Inc16-test.js │ │ ├── Keyboard-test.js │ │ ├── MipsAlu-test.js │ │ ├── Mux-test.js │ │ ├── Mux16-test.js │ │ ├── Mux4Way16-test.js │ │ ├── Mux8Way16-test.js │ │ ├── Nand-test.js │ │ ├── Nor-test.js │ │ ├── Nor16Way-test.js │ │ ├── Not-test.js │ │ ├── Not16-test.js │ │ ├── Or-test.js │ │ ├── Or16-test.js │ │ ├── Or8Way-test.js │ │ ├── PC-test.js │ │ ├── RAM-test.js │ │ ├── RAM16K-test.js │ │ ├── RAM4K-test.js │ │ ├── RAM512-test.js │ │ ├── RAM64-test.js │ │ ├── RAM8-test.js │ │ ├── Register-test.js │ │ ├── Screen-test.js │ │ ├── Xor-test.js │ │ └── all-list-test.js │ └── index.js │ ├── gate-test-util.js │ ├── index.js │ └── scripting │ ├── ScriptInterpreter.js │ ├── __tests__ │ ├── ScriptInterpreter-test.js │ └── script-parser-test.js │ ├── examples │ ├── And.cmp │ ├── And.out │ ├── And.tst │ ├── Example.tst │ └── n2t │ │ ├── .gitignore │ │ ├── 01 │ │ ├── And.cmp │ │ ├── And.tst │ │ ├── And16.cmp │ │ ├── And16.tst │ │ ├── DMux.cmp │ │ ├── DMux.tst │ │ ├── DMux4Way.cmp │ │ ├── DMux4Way.tst │ │ ├── DMux8Way.cmp │ │ ├── DMux8Way.tst │ │ ├── Mux.cmp │ │ ├── Mux.tst │ │ ├── Mux16.cmp │ │ ├── Mux16.tst │ │ ├── Mux4Way16.cmp │ │ ├── Mux4Way16.tst │ │ ├── Mux8Way16.cmp │ │ ├── Mux8Way16.tst │ │ ├── Not.cmp │ │ ├── Not.tst │ │ ├── Not16.cmp │ │ ├── Not16.tst │ │ ├── Or.cmp │ │ ├── Or.tst │ │ ├── Or16.cmp │ │ ├── Or16.tst │ │ ├── Or8Way.cmp │ │ ├── Or8Way.tst │ │ ├── Xor.cmp │ │ └── Xor.tst │ │ ├── 02 │ │ ├── ALU-nostat.cmp │ │ ├── ALU-nostat.tst │ │ ├── ALU.cmp │ │ ├── ALU.tst │ │ ├── Add16.cmp │ │ ├── Add16.tst │ │ ├── FullAdder.cmp │ │ ├── FullAdder.tst │ │ ├── HalfAdder.cmp │ │ ├── HalfAdder.tst │ │ ├── Inc16.cmp │ │ └── Inc16.tst │ │ └── 03 │ │ ├── Bit.cmp │ │ ├── Bit.tst │ │ ├── PC.cmp │ │ ├── PC.tst │ │ ├── RAM16K.cmp │ │ ├── RAM16K.tst │ │ ├── RAM4K.cmp │ │ ├── RAM4K.tst │ │ ├── RAM512.cmp │ │ ├── RAM512.tst │ │ ├── RAM64.cmp │ │ ├── RAM64.tst │ │ ├── RAM8.cmp │ │ ├── RAM8.tst │ │ ├── Register.cmp │ │ └── Register.tst │ ├── generated │ └── script-parser-gen.js │ ├── script-parser.g │ └── script-parser.js ├── generator ├── __tests__ │ └── generator-test.js └── index.js ├── hdl-js.js ├── parser ├── __tests__ │ └── hdl-parser-test.js ├── generated │ └── hdl-parser.js ├── hdl.g └── index.js ├── table-printer.js └── util ├── __tests__ ├── numbers-test.js └── string-util-test.js ├── numbers.js └── string-util.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "targets": { 7 | "node": "0.12" 8 | } 9 | } 10 | ], 11 | "flow" 12 | ] 13 | } -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | src/parser/generated/hdl-parser.js 2 | src/emulator/hardware/scripting/generated/script-parser-gen.js 3 | dist/ -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true, 5 | "jest": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "rules": { 9 | "indent": ["error", 2, { "SwitchCase": 1 }], 10 | "linebreak-style": [ 11 | "error", 12 | "unix" 13 | ], 14 | "quotes": [ 15 | "error", 16 | "single", 17 | { 18 | "allowTemplateLiterals": true, 19 | "avoidEscape": true 20 | } 21 | ], 22 | "semi": [ 23 | "error", 24 | "always" 25 | ], 26 | "no-useless-escape": 0, 27 | "no-console": ["error", { "allow": ["warn", "error", "info"] }] 28 | } 29 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | node_modules/ 3 | .npm-debug.log 4 | npm-debug.log -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /examples/ 2 | /scripts/ 3 | /src/ 4 | .gitignore 5 | .eslintignore 6 | .prettierignore 7 | .prettierrc 8 | .watchmanconfig 9 | .eslintrc 10 | .babelrc 11 | .travis.yml 12 | .module-cache 13 | __tests__ -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | src/parser/generated/hdl-parser.js 2 | src/emulator/hardware/scripting/generated/script-parser-gen.js 3 | dist/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": true, 4 | "useTabs": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5", 7 | "bracketSpacing": false 8 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "8" -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DmitrySoshnikov/hdl-js/ac657f917bf4b90c40b8df08726be5217986a0c5/.watchmanconfig -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Dmitry Soshnikov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /bin/hdl-js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | require('../dist/bin/hdl-js-cli')(); -------------------------------------------------------------------------------- /examples/And.hdl: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | 5 | /** 6 | * And gate: 7 | * out = 1 if (a == 1 and b == 1) 8 | * 0 otherwise 9 | */ 10 | 11 | CHIP And { 12 | 13 | IN a, b; 14 | OUT out; 15 | 16 | PARTS: 17 | 18 | Nand(a=a, b=b, out=n); 19 | Nand(a=n, b=n, out=out); 20 | } 21 | -------------------------------------------------------------------------------- /examples/And16.hdl: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | 5 | /** 6 | * 16-bit bitwise And: 7 | * for i = 0..15: out[i] = (a[i] and b[i]) 8 | */ 9 | 10 | CHIP And16 { 11 | 12 | IN a[16], b[16]; 13 | OUT out[16]; 14 | 15 | PARTS: 16 | 17 | And(a=a[0], b=b[0], out=out[0]); 18 | And(a=a[1], b=b[1], out=out[1]); 19 | And(a=a[2], b=b[2], out=out[2]); 20 | And(a=a[3], b=b[3], out=out[3]); 21 | And(a=a[4], b=b[4], out=out[4]); 22 | And(a=a[5], b=b[5], out=out[5]); 23 | And(a=a[6], b=b[6], out=out[6]); 24 | And(a=a[7], b=b[7], out=out[7]); 25 | And(a=a[8], b=b[8], out=out[8]); 26 | And(a=a[9], b=b[9], out=out[9]); 27 | And(a=a[10], b=b[10], out=out[10]); 28 | And(a=a[11], b=b[11], out=out[11]); 29 | And(a=a[12], b=b[12], out=out[12]); 30 | And(a=a[13], b=b[13], out=out[13]); 31 | And(a=a[14], b=b[14], out=out[14]); 32 | And(a=a[15], b=b[15], out=out[15]); 33 | } 34 | -------------------------------------------------------------------------------- /examples/Decoder.hdl: -------------------------------------------------------------------------------- 1 | /** 2 | * Decoder: 3 | * 4 | * Assert one of four outputs based on two inputs 5 | */ 6 | 7 | CHIP Decoder { 8 | IN a, b; 9 | OUT o1, o2, o3, o4; 10 | 11 | PARTS: 12 | 13 | Not(in=a, out=not_a); 14 | Not(in=b, out=not_b); 15 | And(a=not_a, b=not_b, out=o1); 16 | And(a=not_a, b=b, out=o2); 17 | And(a=a, b=not_b, out=o3); 18 | And(a=a, b=b, out=o4); 19 | } 20 | -------------------------------------------------------------------------------- /examples/MipsAlu.hdl: -------------------------------------------------------------------------------- 1 | /** 2 | * Example of an ALU, similar to MIPS architecture. 3 | * 4 | * ./bin/hdl-js --gate examples/MipsAlu.hdl --describe 5 | * 6 | * Logic: 7 | * 8 | * a & b: op = 0 9 | * a | b: op = 1 10 | * a NOR b => ~a & ~b: op = 0, na = 1, nb = 1 11 | * 12 | * Math: 13 | * 14 | * a + b: op = 2 15 | * a - b: op = 2, nb = 1, cin = 1 16 | * b - a: op = 2, na = 1, cin = 1 17 | * 18 | * Example `a - b`: 19 | * 20 | * ./bin/hdl-js -g examples/MipsAlu.hdl -e '[{a: 1, b: 1, nb: 1, cin: 1, op: 2}]' 21 | */ 22 | CHIP MipsAlu { 23 | 24 | IN 25 | a, /* 1-bit input */ 26 | b, /* 1-bit input */ 27 | na, /* negate a? */ 28 | nb, /* negate b? */ 29 | less, /* "less than" propagated */ 30 | cin, /* carry-in (from previous ALU result) */ 31 | op[2] /* opcode: 0 - AND, 1 - OR, 2 - ADD, 3 - propagate `less` */ 32 | ; 33 | 34 | OUT 35 | out, /* 1-bit output */ 36 | cout, /* carry-out from full-adder */ 37 | set /* adder result, used as `less` input for LSB in 1st ALU */ 38 | ; 39 | 40 | PARTS: 41 | 42 | // A = na ? ~a : a; 43 | Not(in=a, out=not_a); 44 | Mux(a=a, b=not_a, sel=na, out=A); 45 | 46 | // B = nb ? ~b : b; 47 | Not(in=b, out=not_b); 48 | Mux(a=b, b=not_b, sel=nb, out=B); 49 | 50 | // op = 0, And: 51 | And(a=A, b=B, out=A_and_B); 52 | 53 | // op = 1, Or: 54 | Or(a=A, b=B, out=A_or_B); 55 | 56 | // op = 2, Add/Sub 57 | FullAdder(a=A, b=B, c=cin, sum=A_plus_B, sum=set, carry=cout); 58 | 59 | // The opcode mux: 60 | Mux4Way16(a=A_and_B, b=A_or_B, c=A_plus_B, d=less, sel=op, out=out); 61 | } -------------------------------------------------------------------------------- /examples/MipsAlu16.hdl: -------------------------------------------------------------------------------- 1 | /** 2 | * 16-bit ALU from MIPS architecture. 3 | * 4 | * Built as a combination of 16 1-bit ALUs. 5 | */ 6 | 7 | CHIP MipsAlu16 { 8 | 9 | IN 10 | a[16], /* 16-bit input */ 11 | b[16], /* 16-bit input */ 12 | na, /* negate a? */ 13 | nb, /* negate b? */ 14 | cin, /* carry-in (from previous ALU in the chain) */ 15 | op[2] /* opcode: 0 - And, 1 - Or, 2 - Add, 3 - "Less than" */ 16 | ; 17 | 18 | OUT 19 | out[16], /* 16-bit output */ 20 | over, /* overflow? */ 21 | zero /* out is zero? */ 22 | ; 23 | 24 | PARTS: 25 | 26 | MipsAlu(a=a[0], b=b[0], na=na, nb=nb, cin=cin, less=set, op=op, cout=cout0, out=out[0]); 27 | MipsAlu(a=a[1], b=b[1], na=na, nb=nb, cin=cout0, less=false, op=op, cout=cout1, out=out[1]); 28 | MipsAlu(a=a[2], b=b[2], na=na, nb=nb, cin=cout1, less=false, op=op, cout=cout2, out=out[2]); 29 | MipsAlu(a=a[3], b=b[3], na=na, nb=nb, cin=cout2, less=false, op=op, cout=cout3, out=out[3]); 30 | MipsAlu(a=a[4], b=b[4], na=na, nb=nb, cin=cout3, less=false, op=op, cout=cout4, out=out[4]); 31 | MipsAlu(a=a[5], b=b[5], na=na, nb=nb, cin=cout4, less=false, op=op, cout=cout5, out=out[5]); 32 | MipsAlu(a=a[6], b=b[6], na=na, nb=nb, cin=cout5, less=false, op=op, cout=cout6, out=out[6]); 33 | MipsAlu(a=a[7], b=b[7], na=na, nb=nb, cin=cout6, less=false, op=op, cout=cout7, out=out[7]); 34 | MipsAlu(a=a[8], b=b[8], na=na, nb=nb, cin=cout7, less=false, op=op, cout=cout8, out=out[8]); 35 | MipsAlu(a=a[9], b=b[9], na=na, nb=nb, cin=cout8, less=false, op=op, cout=cout9, out=out[9]); 36 | MipsAlu(a=a[10], b=b[10], na=na, nb=nb, cin=cout9, less=false, op=op, cout=cout10, out=out[10]); 37 | MipsAlu(a=a[11], b=b[11], na=na, nb=nb, cin=cout10, less=false, op=op, cout=cout11, out=out[11]); 38 | MipsAlu(a=a[12], b=b[12], na=na, nb=nb, cin=cout11, less=false, op=op, cout=cout12, out=out[12]); 39 | MipsAlu(a=a[13], b=b[13], na=na, nb=nb, cin=cout12, less=false, op=op, cout=cout13, out=out[13]); 40 | MipsAlu(a=a[14], b=b[14], na=na, nb=nb, cin=cout13, less=false, op=op, cout=cout14, out=out[14]); 41 | MipsAlu(a=a[15], b=b[15], na=na, nb=nb, cin=cout14, less=false, op=op, cout=over, set=set, out=out[15]); 42 | Nor16Way(in=out, out=zero); 43 | } -------------------------------------------------------------------------------- /examples/Mux.hdl: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | 5 | /** 6 | * Multiplexor: 7 | * out = a if sel == 0 8 | * b otherwise 9 | */ 10 | 11 | CHIP Mux { 12 | IN a, b, sel; 13 | OUT out; 14 | 15 | PARTS: 16 | 17 | Not(in=sel, out=nel); 18 | And(a=a, b=nel, out=A); 19 | And(a=b, b=sel, out=B); 20 | Or(a=A, b=B, out=out); 21 | } 22 | -------------------------------------------------------------------------------- /examples/Not16.hdl: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | 5 | /** 6 | * 16-bit Not: 7 | * for i=0..15: out[i] = not in[i] 8 | */ 9 | 10 | CHIP Not16 { 11 | IN in[16]; 12 | OUT out[16]; 13 | 14 | PARTS: 15 | 16 | Not(in=in[0], out=out[0]); 17 | Not(in=in[1], out=out[1]); 18 | Not(in=in[2], out=out[2]); 19 | Not(in=in[3], out=out[3]); 20 | Not(in=in[4], out=out[4]); 21 | Not(in=in[5], out=out[5]); 22 | Not(in=in[6], out=out[6]); 23 | Not(in=in[7], out=out[7]); 24 | Not(in=in[8], out=out[8]); 25 | Not(in=in[9], out=out[9]); 26 | Not(in=in[10], out=out[10]); 27 | Not(in=in[11], out=out[11]); 28 | Not(in=in[12], out=out[12]); 29 | Not(in=in[13], out=out[13]); 30 | Not(in=in[14], out=out[14]); 31 | Not(in=in[15], out=out[15]); 32 | } 33 | -------------------------------------------------------------------------------- /examples/RAM16K.hdl: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | 5 | /** 6 | * Memory of 16K registers, each 16 bit-wide. Out holds the value 7 | * stored at the memory location specified by address. If load==1, then 8 | * the in value is loaded into the memory location specified by address 9 | * (the loaded value will be emitted to out from the next time step onward). 10 | */ 11 | 12 | CHIP RAM16K { 13 | 14 | IN in[16], load, address[14]; 15 | OUT out[16]; 16 | 17 | PARTS: 18 | 19 | DMux4Way(in=load, sel=address[12..13], a=l1, b=l2, c=l3, d=l4); 20 | RAM4K(in=in, load=l1, address=address[0..11], out=r1); 21 | RAM4K(in=in, load=l2, address=address[0..11], out=r2); 22 | RAM4K(in=in, load=l3, address=address[0..11], out=r3); 23 | RAM4K(in=in, load=l4, address=address[0..11], out=r4); 24 | Mux4Way16(a=r1, b=r2, c=r3, d=r4, sel=address[12..13], out=out); 25 | } 26 | -------------------------------------------------------------------------------- /examples/RAM64.hdl: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | 5 | /** 6 | * Memory of 64 registers, each 16-bit wide. 7 | * The chip facilitates read and write operations, as follows: 8 | * Read: out(t) = RAM64[address(t)](t) 9 | * Write: If load(t-1) then RAM64[address(t-1)](t) = in(t-1) 10 | * In words: the chip always outputs the value stored at the memory 11 | * location specified by address. If load == 1, the in value is loaded 12 | * into the memory location specified by address. This value becomes 13 | * available through the out output starting from the next time step. 14 | */ 15 | 16 | CHIP RAM64 { 17 | 18 | IN in[16], load, address[6]; 19 | OUT out[16]; 20 | 21 | BUILTIN RAM64; 22 | CLOCKED in, load; 23 | } 24 | -------------------------------------------------------------------------------- /examples/__tests__/And-hdl-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const HDLClassFactory = require('../../src/emulator/hardware/HDLClassFactory'); 9 | 10 | describe('And.hdl', () => { 11 | it('spec', () => { 12 | const And = HDLClassFactory.fromHDLFile(__dirname + '/../And.hdl'); 13 | 14 | const spec = And.Spec; 15 | 16 | expect(spec).toEqual({ 17 | name: 'And', 18 | 19 | description: `Compiled from HDL composite Gate class "And".`, 20 | 21 | inputPins: [ 22 | {name: 'a', size: 1}, 23 | {name: 'b', size: 1}, 24 | ], 25 | 26 | outputPins: [ 27 | {name: 'out', size: 1}, 28 | ], 29 | 30 | internalPins: [ 31 | {name: 'n', size: 1}, 32 | ], 33 | 34 | truthTable: [], 35 | }); 36 | }); 37 | 38 | it('parts', () => { 39 | const and = 40 | HDLClassFactory.fromHDLFile(__dirname + '/../And.hdl') 41 | .defaultFromSpec(); 42 | 43 | const partNames = and.getParts().map(part => part.getClass().name); 44 | expect(partNames).toEqual(['Nand', 'Nand']); 45 | }); 46 | 47 | it('truthTable', () => { 48 | const and = 49 | HDLClassFactory.fromHDLFile(__dirname + '/../And.hdl') 50 | .defaultFromSpec(); 51 | 52 | const truthTable = [ 53 | {a: 0, b: 0, n: 1, out: 0}, 54 | {a: 0, b: 1, n: 1, out: 0}, 55 | {a: 1, b: 0, n: 1, out: 0}, 56 | {a: 1, b: 1, n: 0, out: 1}, 57 | ]; 58 | 59 | const {result} = and.execOnData(truthTable); 60 | expect(result).toEqual(truthTable); 61 | }); 62 | }); -------------------------------------------------------------------------------- /examples/__tests__/Decoder-hdl-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const HDLClassFactory = require('../../src/emulator/hardware/HDLClassFactory'); 9 | 10 | describe('Decoder.hdl', () => { 11 | it('spec', () => { 12 | const Decoder = HDLClassFactory.fromHDLFile(__dirname + '/../Decoder.hdl'); 13 | 14 | const spec = Decoder.Spec; 15 | 16 | expect(spec).toEqual({ 17 | name: 'Decoder', 18 | 19 | description: `Compiled from HDL composite Gate class "Decoder".`, 20 | 21 | inputPins: [ 22 | {name: 'a', size: 1}, 23 | {name: 'b', size: 1}, 24 | ], 25 | 26 | outputPins: [ 27 | {name: 'o1', size: 1}, 28 | {name: 'o2', size: 1}, 29 | {name: 'o3', size: 1}, 30 | {name: 'o4', size: 1}, 31 | ], 32 | 33 | internalPins: [ 34 | {name: 'not_a', size: 1}, 35 | {name: 'not_b', size: 1}, 36 | ], 37 | 38 | truthTable: [], 39 | }); 40 | }); 41 | 42 | it('parts', () => { 43 | const decoder = 44 | HDLClassFactory.fromHDLFile(__dirname + '/../Decoder.hdl') 45 | .defaultFromSpec(); 46 | 47 | const partNames = decoder.getParts().map(part => part.getClass().name); 48 | expect(partNames).toEqual(['Not', 'Not', 'And', 'And', 'And', 'And']); 49 | }); 50 | 51 | it('truthTable', () => { 52 | const decoder = 53 | HDLClassFactory.fromHDLFile(__dirname + '/../Decoder.hdl') 54 | .defaultFromSpec(); 55 | 56 | const truthTable = [ 57 | {a: 0, b: 0, not_a: 1, not_b: 1, o1: 1, o2: 0, o3: 0, o4: 0}, 58 | {a: 0, b: 1, not_a: 1, not_b: 0, o1: 0, o2: 1, o3: 0, o4: 0}, 59 | {a: 1, b: 0, not_a: 0, not_b: 1, o1: 0, o2: 0, o3: 1, o4: 0}, 60 | {a: 1, b: 1, not_a: 0, not_b: 0, o1: 0, o2: 0, o3: 0, o4: 1}, 61 | ]; 62 | 63 | const {result} = decoder.execOnData(truthTable); 64 | expect(result).toEqual(truthTable); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /examples/__tests__/MipsAlu-hdl-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const HDLClassFactory = require('../../src/emulator/hardware/HDLClassFactory'); 9 | 10 | describe('MipsAlu.hdl', () => { 11 | it('spec', () => { 12 | const And = HDLClassFactory.fromHDLFile(__dirname + '/../MipsAlu.hdl'); 13 | 14 | const spec = And.Spec; 15 | 16 | expect(spec).toEqual({ 17 | name: 'MipsAlu', 18 | 19 | description: `Compiled from HDL composite Gate class "MipsAlu".`, 20 | 21 | inputPins: [ 22 | {name: 'a', size: 1}, 23 | {name: 'b', size: 1}, 24 | 25 | {name: 'na', size: 1}, 26 | {name: 'nb', size: 1}, 27 | 28 | {name: 'less', size: 1}, 29 | {name: 'cin', size: 1}, 30 | 31 | {name: 'op', size: 2}, 32 | ], 33 | 34 | outputPins: [ 35 | {name: 'out', size: 1}, 36 | 37 | {name: 'cout', size: 1}, 38 | {name: 'set', size: 1}, 39 | ], 40 | 41 | internalPins: [ 42 | {name: 'not_a', size: 1}, 43 | {name: 'A', size: 1}, 44 | 45 | {name: 'not_b', size: 1}, 46 | {name: 'B', size: 1}, 47 | 48 | {name: 'A_and_B', size: 1}, 49 | {name: 'A_or_B', size: 1}, 50 | {name: 'A_plus_B', size: 1}, 51 | ], 52 | 53 | truthTable: [], 54 | }); 55 | }); 56 | 57 | it('parts', () => { 58 | const mipsAlu = 59 | HDLClassFactory.fromHDLFile(__dirname + '/../MipsAlu.hdl') 60 | .defaultFromSpec(); 61 | 62 | const partNames = mipsAlu.getParts().map(part => part.getClass().name); 63 | expect(partNames).toEqual([ 64 | 'Not', 65 | 'Mux', 66 | 'Not', 67 | 'Mux', 68 | 'And', 69 | 'Or', 70 | 'FullAdder', 71 | 'Mux4Way16', 72 | ]); 73 | }); 74 | 75 | it('truthTable', () => { 76 | const mipsAlu = 77 | HDLClassFactory.fromHDLFile(__dirname + '/../MipsAlu.hdl') 78 | .defaultFromSpec(); 79 | 80 | // Random table. 81 | const truthTable = [ 82 | {a: 1, b: 0, na: 1, nb: 0, less: 0, cin: 0, op: 0b00, not_a: 0, A: 0, not_b: 1, B: 0, A_and_B: 0, A_or_B: 0, A_plus_B: 0, out: 0, cout: 0, set: 0}, 83 | {a: 0, b: 1, na: 1, nb: 0, less: 0, cin: 1, op: 0b10, not_a: 1, A: 1, not_b: 0, B: 1, A_and_B: 1, A_or_B: 1, A_plus_B: 1, out: 1, cout: 1, set: 1}, 84 | {a: 0, b: 0, na: 1, nb: 1, less: 0, cin: 1, op: 0b11, not_a: 1, A: 1, not_b: 1, B: 1, A_and_B: 1, A_or_B: 1, A_plus_B: 1, out: 0, cout: 1, set: 1}, 85 | {a: 0, b: 0, na: 0, nb: 0, less: 1, cin: 0, op: 0b11, not_a: 1, A: 0, not_b: 1, B: 0, A_and_B: 0, A_or_B: 0, A_plus_B: 0, out: 1, cout: 0, set: 0}, 86 | {a: 0, b: 1, na: 0, nb: 1, less: 1, cin: 1, op: 0b10, not_a: 1, A: 0, not_b: 0, B: 0, A_and_B: 0, A_or_B: 0, A_plus_B: 1, out: 1, cout: 0, set: 1}, 87 | ]; 88 | 89 | const {result} = mipsAlu.execOnData(truthTable); 90 | expect(result).toEqual(truthTable); 91 | }); 92 | }); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | module.exports = require('./dist/hdl-js'); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hdl-js", 3 | "version": "0.0.72", 4 | "license": "MIT", 5 | "description": "Hardware definition language (HDL) and Hardware simulator", 6 | "repository": "DmitrySoshnikov/hdl-js", 7 | "homepage": "https://github.com/DmitrySoshnikov/hdl-js", 8 | "bugs": "https://github.com/DmitrySoshnikov/hdl-js/issues", 9 | "scripts": { 10 | "build": "node scripts/build.js", 11 | "watch": "node scripts/build.js --watch", 12 | "test": "jest", 13 | "prepublish": "npm run build && npm test", 14 | "eslint": "eslint src/ && eslint bin/hdl-js" 15 | }, 16 | "bin": { 17 | "hdl-js": "./bin/hdl-js" 18 | }, 19 | "keywords": [ 20 | "HDL", 21 | "Hardware", 22 | "Emulator", 23 | "Boolean logic", 24 | "Simulator" 25 | ], 26 | "author": "Dmitry Soshnikov", 27 | "dependencies": { 28 | "cli-table3": "^0.5.0", 29 | "colors": "^1.1.2", 30 | "yargs": "^10.0.3" 31 | }, 32 | "devDependencies": { 33 | "babel-cli": "^6.26.0", 34 | "babel-preset-env": "1.6.1", 35 | "babel-preset-flow": "6.23.0", 36 | "eslint": "^4.11.0", 37 | "jest-cli": "^19.0.2", 38 | "prettier": "^1.11.1", 39 | "shelljs": "^0.7.8", 40 | "syntax-cli": "^0.1.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | const colors = require('colors'); 7 | const shell = require('shelljs'); 8 | 9 | // Whether we're in the watch mode (continuous JS code transpiling). 10 | const watchMode = process.argv[2] || ''; 11 | 12 | let watchMsg = ''; 13 | if (watchMode) { 14 | watchMsg = ` (watch mode)`; 15 | } 16 | 17 | console.info(colors.bold(`Building${watchMsg}...\n`)); 18 | 19 | // ---------------------------------------------------------- 20 | // Rebuild HDL parser. 21 | 22 | console.info(colors.bold('[1/4] Generating HDL parser module...')); 23 | 24 | shell.exec( 25 | `node node_modules/syntax-cli/bin/syntax -g src/parser/hdl.g -o src/parser/generated/hdl-parser.js -m lalr1 --loc` 26 | ); 27 | 28 | // ---------------------------------------------------------- 29 | // Rebuild Script parser. 30 | 31 | console.info(colors.bold('[2/4] Generating Script parser module...')); 32 | 33 | shell.exec( 34 | `node node_modules/syntax-cli/bin/syntax -g src/emulator/hardware/scripting/script-parser.g -o src/emulator/hardware/scripting/generated/script-parser-gen.js -m lalr1 --loc` 35 | ); 36 | 37 | // ---------------------------------------------------------- 38 | // Git hooks. 39 | 40 | console.info(colors.bold('[3/4] Installing Git hooks...\n')); 41 | 42 | // Setup pre-commit hook. 43 | console.info(' - pre-commit: .git/hooks/pre-commit'); 44 | shell.exec('unlink .git/hooks/pre-commit'); 45 | shell.chmod('+x', './scripts/git-pre-commit'); 46 | shell.ln('-s', '../../scripts/git-pre-commit', '.git/hooks/pre-commit'); 47 | 48 | // Setup pre-push hook. 49 | console.info(' - pre-push: .git/hooks/pre-push\n'); 50 | shell.exec('unlink .git/hooks/pre-push'); 51 | shell.chmod('+x', './scripts/git-pre-push'); 52 | shell.ln('-s', '../../scripts/git-pre-push', '.git/hooks/pre-push'); 53 | 54 | // ---------------------------------------------------------- 55 | // Transform code for older Node versions. 56 | 57 | console.info(colors.bold('[4/4] Transpiling JS code...\n')); 58 | 59 | shell.exec( 60 | `"node_modules/.bin/babel" ${process.argv[2] || 61 | ''} src/ --out-dir dist/ --ignore __tests__` 62 | ); 63 | 64 | console.info(colors.bold('\nAll done.\n')); 65 | -------------------------------------------------------------------------------- /scripts/git-pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Prettier 4 | 5 | jsfiles=$(git diff HEAD --name-only --diff-filter=ACM "*.js" | tr '\n' ' ') 6 | 7 | if [ ! -z "$jsfiles" ] 8 | then 9 | # Prettify all staged .js files 10 | echo "$jsfiles" | xargs ./node_modules/.bin/prettier --write 11 | 12 | # Add back the modified/prettified files to staging 13 | echo "$jsfiles" | xargs git add 14 | fi 15 | 16 | # Pre-commit validaitons: 17 | 18 | npm test 19 | 20 | npm run eslint -------------------------------------------------------------------------------- /scripts/git-pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Pre-commit validaitons: 4 | 5 | npm test 6 | 7 | npm run eslint -------------------------------------------------------------------------------- /src/emulator/hardware/BuiltInGate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Gate = require('./Gate'); 9 | const Pin = require('./Pin'); 10 | 11 | /** 12 | * Base class for all builtin gates. 13 | */ 14 | class BuiltInGate extends Gate { 15 | /** 16 | * Creates a gate instance with the given name. 17 | */ 18 | constructor(options) { 19 | super(options); 20 | this._validate(); 21 | } 22 | 23 | /** 24 | * Validates inputs, and outputs of this gate. 25 | */ 26 | _validate() { 27 | this._validatePins(this.getInputPins(), 'inputPins'); 28 | this._validatePins(this.getOutputPins(), 'outputPins'); 29 | } 30 | 31 | /** 32 | * Validates pin numbers. 33 | */ 34 | _validatePins(pins, kind) { 35 | const spec = BuiltInGate.validateSpec(this.getClass().Spec); 36 | 37 | if (pins.length !== spec[kind].length) { 38 | throw new Error( 39 | `"${this._name}" gate: expect ${spec[kind].length} ${kind} ` + 40 | `(${spec[kind].join(', ')}), got ${pins.length}.` 41 | ); 42 | } 43 | 44 | // Check that for sized-pins, a `Pin` is passed. 45 | spec[kind].forEach((pinName, index) => { 46 | const size = typeof pinName === 'string' ? null : pinName.size; 47 | if (size && pins[index].getSize() !== size) { 48 | throw new TypeError( 49 | `"${this._name}" gate: expect gate #${index} from ${kind} to have ` + 50 | `size ${size}, ${pins[index].getSize()} is given.` 51 | ); 52 | } 53 | }); 54 | } 55 | 56 | /** 57 | * Returns HDL code for this built-in gate. 58 | * 59 | * Describes inputs/outputs with the BUILTIN part. 60 | */ 61 | static getHDLCode() { 62 | if (!this._hdlCode) { 63 | const spec = this.Spec; 64 | const docBlock = spec.description 65 | .split('\n') 66 | .map(line => ` * ${line}`) 67 | .join('\n'); 68 | 69 | const inputs = spec.inputPins.map(pin => Pin.toFullName(pin)).join(', '); 70 | 71 | const outputs = spec.outputPins 72 | .map(pin => Pin.toFullName(pin)) 73 | .join(', '); 74 | 75 | this._hdlCode = `/** 76 | ${docBlock} 77 | */ 78 | CHIP ${spec.name} { 79 | IN ${inputs}; 80 | OUT ${outputs}; 81 | 82 | BUILTIN ${spec.name}; 83 | }`; 84 | } 85 | return this._hdlCode; 86 | } 87 | 88 | static validateSpec(spec) { 89 | return super.validateSpec(spec, [ 90 | 'name', 91 | 'description', 92 | 'inputPins', 93 | 'outputPins', 94 | 'truthTable', 95 | ]); 96 | } 97 | 98 | /** 99 | * Prints truth table. 100 | */ 101 | static printTruthTable({ 102 | table = null, 103 | columns = [], 104 | formatRadix, 105 | formatStringLengh, 106 | transformValue = null, 107 | } = {}) { 108 | super.printTruthTable({ 109 | table: table || BuiltInGate.validateSpec(this.Spec).truthTable, 110 | columns, 111 | formatRadix, 112 | formatStringLengh, 113 | transformValue, 114 | }); 115 | } 116 | 117 | /** 118 | * Evaluates this gate. 119 | */ 120 | eval() { 121 | // Noop. 122 | return; 123 | } 124 | 125 | /** 126 | * Handler for the rising edge of the clock: updates internal state, 127 | * outputs are not updated ("latched"). 128 | */ 129 | clockUp() { 130 | // Noop. 131 | return; 132 | } 133 | 134 | /** 135 | * Handler for the falling edge of the clock: commits the internal state, 136 | * values to the output. 137 | */ 138 | clockDown() { 139 | // Noop. 140 | return; 141 | } 142 | 143 | /** 144 | * Whether this gate is clocked. 145 | */ 146 | static isClocked() { 147 | // Child classes can override. 148 | return false; 149 | } 150 | } 151 | 152 | module.exports = BuiltInGate; 153 | -------------------------------------------------------------------------------- /src/emulator/hardware/Clock.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const EventEmitter = require('events'); 9 | 10 | const {isNegativeZero} = require('../../util/numbers'); 11 | 12 | /** 13 | * The system clock is used to synchronize handling of all 14 | * the "clocked chips" (such as data storage, etc). 15 | * 16 | * The clocked gates update their internal state when clock goes up 17 | * (aka the "rising edge"), and commit the changes to the output pins, 18 | * when clock goes down (aka the "falling edge"). 19 | * 20 | * The low 21 | * 22 | * A rising edge followed by a falling edge is a "Clock Cycle". 23 | * 24 | * A clock operates with a "Clock Rate" -- a number of clock 25 | * cycles per second, measured in Hz (default is 1Hz -- 1 cycle per second). 26 | */ 27 | class Clock extends EventEmitter { 28 | /** 29 | * Creates a clock instance. 30 | */ 31 | constructor({rate = 1, value = -0} = {}) { 32 | super(); 33 | this.setRate(rate); 34 | this.setValue(value); 35 | 36 | // Tracks the halfs in a cycle, to emit full 'cycle' event 37 | // from tick, followed by tock. 38 | this._halfs = 0; 39 | 40 | // There might be more than 11 (default in Node) listeners of the clock. 41 | this.setMaxListeners(Infinity); 42 | } 43 | 44 | /** 45 | * Resets the clock. 46 | * 47 | * Initial clock value is -0. Each tick: set positive sign, 48 | * each tock: increase, set negative sign back. 49 | */ 50 | reset() { 51 | this.setValue(-0); 52 | return this; 53 | } 54 | 55 | /** 56 | * Sets clock value. 57 | */ 58 | setValue(value) { 59 | this._value = value; 60 | 61 | // Next full 'cycle' event will be relatively 62 | // this set value, so reset the halfs counter. 63 | this._halfs = 0; 64 | 65 | this.emit('change', this._value); 66 | return this; 67 | } 68 | 69 | /** 70 | * Returns clock value. 71 | */ 72 | getValue() { 73 | return this._value; 74 | } 75 | 76 | /** 77 | * Sets the clock rate. 78 | */ 79 | setRate(rate) { 80 | this._rate = rate; 81 | return this; 82 | } 83 | 84 | /** 85 | * Returns the clock rate. 86 | */ 87 | getRate() { 88 | return this._rate; 89 | } 90 | 91 | /** 92 | * Starts the clock, and continues running it, 93 | * executing number of cycles withing 1 second. 94 | */ 95 | start() { 96 | this.cyclesForRate(); 97 | this._timeoutID = setTimeout(() => this.start(), 1000); 98 | return this; 99 | } 100 | 101 | /** 102 | * Stops the clock. 103 | */ 104 | stop() { 105 | clearTimeout(this._timeoutID); 106 | return this; 107 | } 108 | 109 | /** 110 | * Rising edge (aka "tick"), half-cycle. 111 | * 112 | * Goes from -0 to +0, from -1 to +1, etc; 113 | * notifies the clocked gates. 114 | */ 115 | tick() { 116 | // setValue resets `halfs`, so save it. 117 | const halfs = this._halfs; 118 | 119 | this.setValue(-this._value); 120 | this.emit('tick', this._value); 121 | 122 | this._halfs = halfs; 123 | this._emitHalfsEvent(); 124 | return this; 125 | } 126 | 127 | /** 128 | * Falling edge (aka "tock"), half-cycle. 129 | * 130 | * Goes from +0 to -1, from +1 to -2, etc; 131 | * notifies the clocked gates. 132 | */ 133 | tock() { 134 | // setValue resets `halfs`, so save it. 135 | const halfs = this._halfs; 136 | 137 | this.setValue(-(Math.abs(this._value) + 1)); 138 | this.emit('tock', this._value); 139 | 140 | this._halfs = halfs; 141 | this._emitHalfsEvent(); 142 | return this; 143 | } 144 | 145 | /** 146 | * Emits full cycle after tick -> tock. 147 | */ 148 | _emitHalfsEvent() { 149 | this._halfs++; 150 | 151 | if (this._halfs > 0) { 152 | this.emit('next', this._value); 153 | } 154 | 155 | if (this._halfs === 2) { 156 | this.emit('cycle', this._value); 157 | this._halfs = 0; 158 | } 159 | } 160 | 161 | /** 162 | * Next half-cycle (tick or tock). 163 | */ 164 | next() { 165 | if (this.isDown()) { 166 | this.tick(); 167 | } else { 168 | this.tock(); 169 | } 170 | return this; 171 | } 172 | 173 | /** 174 | * One full cycle. 175 | */ 176 | cycle() { 177 | if (this.isDown()) { 178 | this.tick(); 179 | this.tock(); 180 | } else { 181 | this.tock(); 182 | this.tick(); 183 | } 184 | return this; 185 | } 186 | 187 | /** 188 | * Runs several cycles. 189 | */ 190 | cycles(n) { 191 | for (let i = 0; i < n; i++) { 192 | this.cycle(); 193 | } 194 | return this; 195 | } 196 | 197 | /** 198 | * Runs several cycles, according to the clock rate. 199 | */ 200 | cyclesForRate() { 201 | this.cycles(this._rate); 202 | return this; 203 | } 204 | 205 | /** 206 | * Whether the clock is up. 207 | */ 208 | isUp() { 209 | return !this.isDown(); 210 | } 211 | 212 | /** 213 | * Whether the clock is down. 214 | */ 215 | isDown() { 216 | return isNegativeZero(this._value) || this._value < 0; 217 | } 218 | } 219 | 220 | /** 221 | * Default System clock, so all chips 222 | * cat subscribe to it. 223 | */ 224 | Clock.SystemClock = new Clock({rate: 1}); 225 | 226 | module.exports = Clock; 227 | -------------------------------------------------------------------------------- /src/emulator/hardware/__tests__/BuiltInGate-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | const Pin = require('../Pin'); 10 | 11 | describe('BuiltInGate', () => { 12 | it('BuiltInGate interface', () => { 13 | // Inputs. 14 | const a = new Pin({name: 'a', value: 1}); 15 | const b = new Pin({name: 'b', value: 0}); 16 | 17 | // Output. 18 | const out = new Pin({name: 'out', value: 0}); 19 | 20 | class MyBuiltInGate extends BuiltInGate {} 21 | 22 | MyBuiltInGate.Spec = { 23 | name: 'MyBuiltInGate', 24 | description: 'MyBuiltInGate', 25 | inputPins: ['a', 'b'], 26 | outputPins: ['out'], 27 | truthTable: [], 28 | }; 29 | 30 | const gate = new MyBuiltInGate({ 31 | name: 'And', 32 | inputPins: [a, b], 33 | outputPins: [out], 34 | }); 35 | 36 | expect(gate.getName()).toBe('And'); 37 | expect(gate.getInputPins()).toEqual([a, b]); 38 | expect(gate.getOutputPins()).toEqual([out]); 39 | expect(() => gate.eval()).not.toThrow(); 40 | }); 41 | 42 | it('default from spec', () => { 43 | const And = require('../builtin-gates/And'); 44 | const and = And.defaultFromSpec(); 45 | 46 | expect(and.getName()).toBe(And.name); 47 | expect(and.getInputPins().length).toEqual(2); 48 | expect(and.getOutputPins().length).toEqual(1); 49 | 50 | expect(() => and.getPin('a')).not.toThrow(); 51 | expect(() => and.getPin('b')).not.toThrow(); 52 | expect(() => and.getPin('out')).not.toThrow(); 53 | 54 | // Pin[16]: 55 | 56 | const Not16 = require('../builtin-gates/Not16'); 57 | const not16 = Not16.defaultFromSpec(); 58 | 59 | expect(not16.getName()).toBe(Not16.name); 60 | expect(not16.getInputPins().length).toEqual(1); 61 | expect(not16.getOutputPins().length).toEqual(1); 62 | 63 | expect(not16.getPin('in').getSize()).toBe(16); 64 | expect(not16.getPin('out').getSize()).toBe(16); 65 | }); 66 | 67 | it('getHDLCode', () => { 68 | const And16 = require('../builtin-gates/And16'); 69 | 70 | const expectedHDLCode = `/** 71 | * Implements bitwise 16-bit And & operation. 72 | */ 73 | CHIP And16 { 74 | IN a[16], b[16]; 75 | OUT out[16]; 76 | 77 | BUILTIN And16; 78 | }`; 79 | 80 | expect(And16.getHDLCode()).toBe(expectedHDLCode); 81 | }); 82 | 83 | it('generateTruthTable: simple', () => { 84 | const and = require('../builtin-gates/And').defaultFromSpec(); 85 | 86 | expect(and.generateTruthTable()).toEqual([ 87 | {a: 0, b: 0, out: 0}, 88 | {a: 0, b: 1, out: 0}, 89 | {a: 1, b: 0, out: 0}, 90 | {a: 1, b: 1, out: 1}, 91 | ]); 92 | }); 93 | 94 | it('generateTruthTable: complex', () => { 95 | const and16 = require('../builtin-gates/And16').defaultFromSpec(); 96 | 97 | const generatedTT = and16.generateTruthTable(); 98 | expect(generatedTT.length).toBe(5); 99 | 100 | const {result: actualTT, conflicts} = and16.execOnData(generatedTT); 101 | 102 | expect(actualTT).toEqual(generatedTT); 103 | expect(conflicts.length).toBe(0); 104 | }); 105 | 106 | it('generateTruthTable: enforceRandom', () => { 107 | const and = require('../builtin-gates/And').defaultFromSpec(); 108 | 109 | const generatedTT = and.generateTruthTable({enforceRandom: true}); 110 | expect(generatedTT.length).toBe(5); 111 | 112 | const {result: actualTT, conflicts} = and.execOnData(generatedTT); 113 | 114 | expect(actualTT).toEqual(generatedTT); 115 | expect(conflicts.length).toBe(0); 116 | }); 117 | }); 118 | -------------------------------------------------------------------------------- /src/emulator/hardware/__tests__/Clock-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Clock = require('../Clock'); 9 | const {SystemClock} = require('../Clock'); 10 | 11 | describe('Clock', () => { 12 | it('default values', () => { 13 | const clock = new Clock(); 14 | expect(clock.getRate()).toBe(1); 15 | expect(clock.getValue()).toBe(-0); 16 | }); 17 | 18 | it('passed values', () => { 19 | const clock = new Clock({ 20 | rate: 10, 21 | value: -5, 22 | }); 23 | expect(clock.getRate()).toBe(10); 24 | expect(clock.getValue()).toBe(-5); 25 | }); 26 | 27 | it('passed values', () => { 28 | const clock = new Clock({ 29 | rate: 10, 30 | value: -5, 31 | }); 32 | expect(clock.getRate()).toBe(10); 33 | expect(clock.getValue()).toBe(-5); 34 | }); 35 | 36 | it('change', () => { 37 | let data; 38 | 39 | const clock = new Clock({rate: 1, value: -5}).on( 40 | 'change', 41 | value => (data = value) 42 | ); 43 | 44 | clock.setValue(-10); 45 | expect(data).toBe(-10); 46 | }); 47 | 48 | it('tick', () => { 49 | let data; 50 | 51 | const clock = new Clock({rate: 1, value: -5}).on( 52 | 'tick', 53 | value => (data = value) 54 | ); 55 | 56 | clock.tick(); 57 | expect(data).toBe(+5); 58 | }); 59 | 60 | it('tock', () => { 61 | let data; 62 | 63 | const clock = new Clock({rate: 1, value: +5}).on( 64 | 'tock', 65 | value => (data = value) 66 | ); 67 | 68 | clock.tock(); 69 | expect(data).toBe(-6); 70 | }); 71 | 72 | it('next', () => { 73 | let data; 74 | 75 | const clock = new Clock({rate: 1, value: +5}).on( 76 | 'next', 77 | value => (data = value) 78 | ); 79 | 80 | clock.next(); 81 | expect(data).toBe(-6); 82 | 83 | // tick, tock also emit 'next' 84 | clock.tick(); 85 | expect(data).toBe(+6); 86 | // clock.tock(); 87 | // expect(data).toBe(+7); 88 | }); 89 | 90 | it('cycle', () => { 91 | let data; 92 | 93 | const clock = new Clock({rate: 1, value: -5}).on( 94 | 'cycle', 95 | value => (data = value) 96 | ); 97 | 98 | clock.cycle(); 99 | expect(data).toBe(-6); 100 | 101 | // tick -> tock also emit 'cycle' 102 | clock.tick(); 103 | clock.tock(); 104 | expect(data).toBe(-7); 105 | }); 106 | 107 | it('cycles', () => { 108 | let data = []; 109 | 110 | const clock = new Clock({rate: 1}).on('cycle', value => data.push(value)); 111 | 112 | clock.cycles(5); 113 | expect(data).toEqual([-1, -2, -3, -4, -5]); 114 | }); 115 | 116 | it('cycles for rate', () => { 117 | let data = []; 118 | 119 | const clock = new Clock({rate: 5}).on('cycle', value => data.push(value)); 120 | 121 | clock.cyclesForRate(); 122 | expect(data).toEqual([-1, -2, -3, -4, -5]); 123 | }); 124 | 125 | it('System clock', () => { 126 | let data = []; 127 | 128 | SystemClock.on('cycle', value => data.push(value)); 129 | 130 | SystemClock.cycle(); 131 | SystemClock.cycle(); 132 | SystemClock.cycle(); 133 | expect(data).toEqual([-1, -2, -3]); 134 | }); 135 | }); 136 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/ARegister.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const colors = require('colors'); 9 | const Register = require('./Register'); 10 | 11 | /** 12 | * 16-bit A (Address) register. 13 | */ 14 | class ARegister extends Register {} 15 | 16 | /** 17 | * Specification of the `ARegister` gate. 18 | */ 19 | ARegister.Spec = { 20 | name: 'ARegister', 21 | 22 | description: `16-bit A (Address) register. 23 | 24 | If load[t]=1 then out[t+1] = in[t] else out does not change. 25 | 26 | Clock rising edge updates the value from the input, 27 | if the \`load\` is set; otherwise, preserves the state. 28 | 29 | ${colors.bold('↗')} : value = load ? in : value 30 | 31 | Clock falling edge propagates the value to the output: 32 | 33 | ${colors.bold('↘')} : out = value 34 | `, 35 | 36 | inputPins: [{name: 'in', size: 16}, {name: 'load', size: 1}], 37 | outputPins: [{name: 'out', size: 16}], 38 | 39 | truthTable: Register.Spec.truthTable, 40 | }; 41 | 42 | module.exports = ARegister; 43 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Add16.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | const {int16Table} = require('../../../util/numbers'); 11 | 12 | /** 13 | * Canonical truth table for the `Add16` gate. 14 | */ 15 | const TRUTH_TABLE = int16Table([ 16 | {a: 0b0000000000000000, b: 0b0000000000000000, out: 0b0000000000000000}, 17 | {a: 0b0000000000000000, b: 0b1111111111111111, out: 0b1111111111111111}, 18 | {a: 0b1111111111111111, b: 0b1111111111111111, out: 0b1111111111111110}, 19 | {a: 0b1010101010101010, b: 0b0101010101010101, out: 0b1111111111111111}, 20 | {a: 0b0011110011000011, b: 0b0000111111110000, out: 0b0100110010110011}, 21 | {a: 0b0001001000110100, b: 0b1001100001110110, out: 0b1010101010101010}, 22 | ]); 23 | 24 | /** 25 | * A 16-bit integer adder. 26 | */ 27 | class Add16 extends BuiltInGate { 28 | /** 29 | * IN a[16], b[16]; 30 | * OUT out[16]; 31 | * 32 | * Abstract: 33 | * 34 | * HalfAdder(a=a[0], b=b[0], sum=out[0], carry=c1); 35 | * FullAdder(a=a[1], b=b[1], c=c1, sum=out[1], carry=c2); 36 | * ... 37 | * 38 | * Technically use JS + operator on 16-bit values. 39 | */ 40 | eval() { 41 | const a = this.getInputPins()[0].getValue(); 42 | const b = this.getInputPins()[1].getValue(); 43 | 44 | this.getOutputPins()[0].setValue(a + b); 45 | } 46 | } 47 | 48 | /** 49 | * Specification of the `Add16` gate. 50 | */ 51 | Add16.Spec = { 52 | name: 'Add16', 53 | 54 | description: 'A 16-bit integer adder: out = int16(a + b)', 55 | 56 | inputPins: [{name: 'a', size: 16}, {name: 'b', size: 16}], 57 | 58 | outputPins: [{name: 'out', size: 16}], 59 | 60 | truthTable: TRUTH_TABLE, 61 | }; 62 | 63 | module.exports = Add16; 64 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/And.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | /** 11 | * Canonical truth table for the `And` gate. 12 | */ 13 | const TRUTH_TABLE = [ 14 | {a: 0, b: 0, out: 0}, 15 | {a: 0, b: 1, out: 0}, 16 | {a: 1, b: 0, out: 0}, 17 | {a: 1, b: 1, out: 1}, 18 | ]; 19 | 20 | /** 21 | * A bitwise 1-bit And gate. 22 | */ 23 | class And extends BuiltInGate { 24 | /** 25 | * a & b 26 | */ 27 | eval() { 28 | const a = this.getInputPins()[0].getValue(); 29 | const b = this.getInputPins()[1].getValue(); 30 | 31 | this.getOutputPins()[0].setValue(a & b); 32 | } 33 | } 34 | 35 | /** 36 | * Specification of the `And` gate. 37 | */ 38 | And.Spec = { 39 | name: 'And', 40 | description: 'Implements bitwise 1-bit And & operation.', 41 | inputPins: ['a', 'b'], 42 | outputPins: ['out'], 43 | truthTable: TRUTH_TABLE, 44 | }; 45 | 46 | module.exports = And; 47 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/And16.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | const {int16Table} = require('../../../util/numbers'); 11 | 12 | /** 13 | * Canonical truth table for the `And16` gate. 14 | */ 15 | const TRUTH_TABLE = int16Table([ 16 | {a: 0b0000000000000000, b: 0b0000000000000000, out: 0b0000000000000000}, 17 | {a: 0b0000000000000000, b: 0b1111111111111111, out: 0b0000000000000000}, 18 | {a: 0b1111111111111111, b: 0b1111111111111111, out: 0b1111111111111111}, 19 | {a: 0b1010101010101010, b: 0b0101010101010101, out: 0b0000000000000000}, 20 | {a: 0b0011110011000011, b: 0b0000111111110000, out: 0b0000110011000000}, 21 | {a: 0b0001001000110100, b: 0b1001100001110110, out: 0b0001000000110100}, 22 | ]); 23 | 24 | /** 25 | * A bitwise 16-bit And gate. 26 | */ 27 | class And16 extends BuiltInGate { 28 | /** 29 | * IN a[16], b[16]; 30 | * OUT out[16]; 31 | * 32 | * for i = 0..15: out[i] = (a[i] & b[i]) 33 | * 34 | * Abstract: 35 | * 36 | * And(a=a[0], b=b[0], out=out[0]); 37 | * And(a=a[1], b=b[1], out=out[1]); 38 | * ... 39 | * 40 | * Technically use JS bitwise operations at needed index. 41 | */ 42 | eval() { 43 | const a = this.getInputPins()[0].getValue(); 44 | const b = this.getInputPins()[1].getValue(); 45 | 46 | // In JS implementation doesn't differ from the simple `And` gate. 47 | this.getOutputPins()[0].setValue(a & b); 48 | } 49 | } 50 | 51 | /** 52 | * Specification of the `And16` gate. 53 | */ 54 | And16.Spec = { 55 | name: 'And16', 56 | 57 | description: 'Implements bitwise 16-bit And & operation.', 58 | 59 | inputPins: [{name: 'a', size: 16}, {name: 'b', size: 16}], 60 | 61 | outputPins: [{name: 'out', size: 16}], 62 | 63 | truthTable: TRUTH_TABLE, 64 | }; 65 | 66 | module.exports = And16; 67 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Bit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const colors = require('colors'); 9 | const BuiltInGate = require('../BuiltInGate'); 10 | 11 | /** 12 | * Canonical truth table for the `Bit` gate. 13 | */ 14 | const TRUTH_TABLE = [ 15 | {$clock: -0, in: 0, load: 0, out: 0}, 16 | {$clock: +0, in: 1, load: 1, out: 0}, 17 | {$clock: -1, in: 1, load: 0, out: 1}, 18 | {$clock: +1, in: 1, load: 0, out: 1}, 19 | {$clock: -2, in: 1, load: 0, out: 1}, 20 | {$clock: +2, in: 0, load: 1, out: 1}, 21 | {$clock: -3, in: 0, load: 0, out: 0}, 22 | ]; 23 | 24 | /** 25 | * 1 bit memory register. 26 | * If load[t]=1 then out[t+1] = in[t] else out does not change. 27 | * 28 | * Abstract: 29 | * 30 | * IN in, load; 31 | * OUT out; 32 | * 33 | * Mux(a=t0, b=in, sel=load, out=t1); 34 | * DFF(in=t1, out=t0, out=out); 35 | */ 36 | class Bit extends BuiltInGate { 37 | /** 38 | * Bit is a sequential gate. 39 | */ 40 | static isClocked() { 41 | return true; 42 | } 43 | 44 | init() { 45 | /** 46 | * The state (0/1) of the bit. 47 | */ 48 | this._state = 0; 49 | } 50 | 51 | /** 52 | * On rising edge Bit updates the internal state 53 | * if the `load` is set, otherwise -- preserves the state. 54 | */ 55 | clockUp() { 56 | const load = this.getInputPins()[1].getValue(); 57 | 58 | if (load) { 59 | this._state = this.getInputPins()[0].getValue(); 60 | } 61 | } 62 | 63 | /** 64 | * On the falling edge Bit propagates the state 65 | * to the output pin. 66 | */ 67 | clockDown() { 68 | this.getOutputPins()[0].setValue(this._state); 69 | } 70 | } 71 | 72 | /** 73 | * Specification of the `Bit` gate. 74 | */ 75 | Bit.Spec = { 76 | name: 'Bit', 77 | 78 | description: [ 79 | '1 bit memory register.', 80 | '', 81 | 'If load[t]=1 then out[t+1] = in[t] else out does not change.', 82 | '', 83 | 'Clock rising edge updates internal state from the input,', 84 | 'if the `load` is set; otherwise, preserves the state.', 85 | '', 86 | ` ${colors.bold('↗')} : state = load ? in : state`, 87 | '', 88 | 'Clock falling edge propagates the internal state to the output:', 89 | '', 90 | ` ${colors.bold('↘')} : out = state`, 91 | ].join('\n'), 92 | 93 | inputPins: ['in', 'load'], 94 | outputPins: ['out'], 95 | 96 | truthTable: TRUTH_TABLE, 97 | }; 98 | 99 | module.exports = Bit; 100 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/DFF.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const colors = require('colors'); 9 | const BuiltInGate = require('../BuiltInGate'); 10 | 11 | /** 12 | * Canonical truth table for the `DFF` gate. 13 | */ 14 | const TRUTH_TABLE = [ 15 | {$clock: -0, in: 0, out: 0}, 16 | {$clock: +0, in: 1, out: 0}, 17 | {$clock: -1, in: 0, out: 1}, 18 | {$clock: +1, in: 0, out: 0}, 19 | ]; 20 | 21 | /** 22 | * Data/Delay Flip-Flop chip. 23 | */ 24 | class DFF extends BuiltInGate { 25 | /** 26 | * DFF is a sequential gate. 27 | */ 28 | static isClocked() { 29 | return true; 30 | } 31 | 32 | init() { 33 | /** 34 | * The state (0/1) of the D-flip-flop. 35 | */ 36 | this._state = 0; 37 | } 38 | 39 | /** 40 | * On rising edge DFF updates the internal state 41 | * from the input pin. 42 | */ 43 | clockUp() { 44 | this._state = this.getInputPins()[0].getValue(); 45 | } 46 | 47 | /** 48 | * On the falling edge DFF propagates the state 49 | * to the output pin. 50 | */ 51 | clockDown() { 52 | this.getOutputPins()[0].setValue(this._state); 53 | } 54 | } 55 | 56 | /** 57 | * Specification of the `DFF` gate. 58 | */ 59 | DFF.Spec = { 60 | name: 'DFF', 61 | 62 | description: [ 63 | 'DFF (Data/Delay Flip-Flop) chip.', 64 | '', 65 | 'Clock rising edge updates internal state from the input:', 66 | '', 67 | ` ${colors.bold('↗')} : state = in`, 68 | '', 69 | 'Clock falling edge propagates the internal state to the output:', 70 | '', 71 | ` ${colors.bold('↘')} : out = state`, 72 | ].join('\n'), 73 | 74 | inputPins: ['in'], 75 | outputPins: ['out'], 76 | 77 | truthTable: TRUTH_TABLE, 78 | }; 79 | 80 | module.exports = DFF; 81 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/DMux.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | /** 11 | * Canonical truth table for the `DMux` gate. 12 | */ 13 | const TRUTH_TABLE = [ 14 | {in: 0, sel: 0, a: 0, b: 0}, 15 | {in: 0, sel: 1, a: 0, b: 0}, 16 | {in: 1, sel: 0, a: 1, b: 0}, 17 | {in: 1, sel: 1, a: 0, b: 1}, 18 | ]; 19 | 20 | /** 21 | * 1 bit demultiplexer. 22 | * if sel=0 {out1=in; out2=0} else {out1=0; out2=in} 23 | */ 24 | class DMux extends BuiltInGate { 25 | eval() { 26 | const _in = this.getInputPins()[0].getValue(); 27 | const sel = this.getInputPins()[1].getValue(); 28 | 29 | this.getOutputPins()[0].setValue(sel === 0 ? _in : 0); 30 | this.getOutputPins()[1].setValue(sel === 0 ? 0 : _in); 31 | } 32 | } 33 | 34 | /** 35 | * Specification of the `DMux` gate. 36 | */ 37 | DMux.Spec = { 38 | name: 'DMux', 39 | 40 | description: [ 41 | 'Implements 1-bit demultiplexer (DMux) gate.', 42 | '', 43 | '{a = in, b = 0 }, when sel = 0', 44 | '{a = 0, b = in}, when sel = 1', 45 | ].join('\n'), 46 | 47 | inputPins: ['in', 'sel'], 48 | outputPins: ['a', 'b'], 49 | 50 | truthTable: TRUTH_TABLE, 51 | }; 52 | 53 | module.exports = DMux; 54 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/DMux4Way.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | const {int16Table} = require('../../../util/numbers'); 11 | 12 | /** 13 | * Canonical truth table for the `DMux4Way` gate. 14 | */ 15 | const TRUTH_TABLE = int16Table([ 16 | {in: 0, sel: 0b00, a: 0, b: 0, c: 0, d: 0}, 17 | {in: 0, sel: 0b01, a: 0, b: 0, c: 0, d: 0}, 18 | {in: 0, sel: 0b10, a: 0, b: 0, c: 0, d: 0}, 19 | {in: 0, sel: 0b11, a: 0, b: 0, c: 0, d: 0}, 20 | {in: 1, sel: 0b00, a: 1, b: 0, c: 0, d: 0}, 21 | {in: 1, sel: 0b01, a: 0, b: 1, c: 0, d: 0}, 22 | {in: 1, sel: 0b10, a: 0, b: 0, c: 1, d: 0}, 23 | {in: 1, sel: 0b11, a: 0, b: 0, c: 0, d: 1}, 24 | ]); 25 | 26 | /** 27 | * 1 bit 4-way demultiplexor. 28 | * 29 | * The 2-bit sel choose to which output to channel the input (0->a .. 3->d). 30 | * The other outputs are set to 0. 31 | * 32 | * {a, b, c, d} = {in, 0, 0, 0} if sel == 00 33 | * {0, in, 0, 0} if sel == 01 34 | * {0, 0, in, 0} if sel == 10 35 | * {0, 0, 0, in} if sel == 11 36 | * 37 | * Abstract: 38 | * 39 | * IN in, sel[2]; 40 | * OUT a, b, c, d; 41 | * 42 | * PARTS: 43 | * 44 | * DMux(in=in, sel=sel[1], a=ab, b=cd); 45 | * DMux(in=ab, sel=sel[0], a=a, b=b); 46 | * DMux(in=cd, sel=sel[0], a=c, b=d); 47 | */ 48 | class DMux4Way extends BuiltInGate { 49 | eval() { 50 | const _in = this.getInputPins()[0].getValue(); 51 | const sel = this.getInputPins()[1].getValue(); 52 | 53 | this.getOutputPins()[0].setValue(sel === 0 ? _in : 0); 54 | this.getOutputPins()[1].setValue(sel === 1 ? _in : 0); 55 | this.getOutputPins()[2].setValue(sel === 2 ? _in : 0); 56 | this.getOutputPins()[3].setValue(sel === 3 ? _in : 0); 57 | } 58 | } 59 | 60 | /** 61 | * Specification of the `DMux4Way` gate. 62 | */ 63 | DMux4Way.Spec = { 64 | name: 'DMux4Way', 65 | 66 | description: [ 67 | '1 bit 4-way demultiplexor.', 68 | '', 69 | 'The 2-bit sel choose to which output to channel the input (0->a .. 3->d).', 70 | 'The other outputs are set to 0.', 71 | ].join('\n'), 72 | 73 | inputPins: ['in', {name: 'sel', size: 2}], 74 | 75 | outputPins: ['a', 'b', 'c', 'd'], 76 | 77 | truthTable: TRUTH_TABLE, 78 | }; 79 | 80 | module.exports = DMux4Way; 81 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/DMux8Way.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | const {int16Table} = require('../../../util/numbers'); 11 | 12 | /** 13 | * Canonical truth table for the `DMux8Way` gate. 14 | */ 15 | const TRUTH_TABLE = int16Table([ 16 | {in: 0, sel: 0b000, a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0}, 17 | {in: 0, sel: 0b001, a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0}, 18 | {in: 0, sel: 0b010, a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0}, 19 | {in: 0, sel: 0b011, a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0}, 20 | {in: 0, sel: 0b100, a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0}, 21 | {in: 0, sel: 0b101, a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0}, 22 | {in: 0, sel: 0b110, a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0}, 23 | {in: 0, sel: 0b111, a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0}, 24 | {in: 1, sel: 0b000, a: 1, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0}, 25 | {in: 1, sel: 0b001, a: 0, b: 1, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0}, 26 | {in: 1, sel: 0b010, a: 0, b: 0, c: 1, d: 0, e: 0, f: 0, g: 0, h: 0}, 27 | {in: 1, sel: 0b011, a: 0, b: 0, c: 0, d: 1, e: 0, f: 0, g: 0, h: 0}, 28 | {in: 1, sel: 0b100, a: 0, b: 0, c: 0, d: 0, e: 1, f: 0, g: 0, h: 0}, 29 | {in: 1, sel: 0b101, a: 0, b: 0, c: 0, d: 0, e: 0, f: 1, g: 0, h: 0}, 30 | {in: 1, sel: 0b110, a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 1, h: 0}, 31 | {in: 1, sel: 0b111, a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 1}, 32 | ]); 33 | 34 | /** 35 | * 1 bit 8-way demultiplexor. 36 | * 37 | * The 3-bit sel choose to which output to channel the input (0->a .. 7->h). 38 | * The other outputs are set to 0. 39 | * 40 | * {a, b, c, d, e, f, g, h} = {in, 0, 0, 0, 0, 0, 0, 0} if sel == 000 41 | * {0, in, 0, 0, 0, 0, 0, 0} if sel == 001 42 | * ... 43 | * {0, 0, 0, 0, 0, 0, 0, in} if sel == 111 44 | */ 45 | class DMux8Way extends BuiltInGate { 46 | /** 47 | * IN in, sel[3]; 48 | * OUT a, b, c, d, e, f, g, h; 49 | * 50 | * Abstract: 51 | * 52 | * DMux(in=in, sel=sel[2], a=abcd, b=efgh); 53 | * DMux4Way(in=abcd, sel=sel[0..1], a=a, b=b, c=c, d=d); 54 | * DMux4Way(in=efgh, sel=sel[0..1], a=e, b=f, c=g, d=h); 55 | */ 56 | eval() { 57 | const _in = this.getInputPins()[0].getValue(); 58 | const sel = this.getInputPins()[1].getValue(); 59 | 60 | this.getOutputPins()[0].setValue(sel === 0b000 ? _in : 0); 61 | this.getOutputPins()[1].setValue(sel === 0b001 ? _in : 0); 62 | this.getOutputPins()[2].setValue(sel === 0b010 ? _in : 0); 63 | this.getOutputPins()[3].setValue(sel === 0b011 ? _in : 0); 64 | this.getOutputPins()[4].setValue(sel === 0b100 ? _in : 0); 65 | this.getOutputPins()[5].setValue(sel === 0b101 ? _in : 0); 66 | this.getOutputPins()[6].setValue(sel === 0b110 ? _in : 0); 67 | this.getOutputPins()[7].setValue(sel === 0b111 ? _in : 0); 68 | } 69 | } 70 | 71 | /** 72 | * Specification of the `DMux8Way` gate. 73 | */ 74 | DMux8Way.Spec = { 75 | name: 'DMux8Way', 76 | 77 | description: [ 78 | '1 bit 8-way demultiplexor.', 79 | '', 80 | 'The 3-bit sel choose to which output to channel the input (0->a .. 7->h).', 81 | 'The other outputs are set to 0.', 82 | ].join('\n'), 83 | 84 | inputPins: ['in', {name: 'sel', size: 3}], 85 | 86 | outputPins: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], 87 | 88 | truthTable: TRUTH_TABLE, 89 | }; 90 | 91 | module.exports = DMux8Way; 92 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/DRegister.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const colors = require('colors'); 9 | const Register = require('./Register'); 10 | 11 | /** 12 | * 16-bit D (Data) register. 13 | */ 14 | class DRegister extends Register {} 15 | 16 | /** 17 | * Specification of the `DRegister` gate. 18 | */ 19 | DRegister.Spec = { 20 | name: 'DRegister', 21 | 22 | description: `16-bit D (Data) register. 23 | 24 | If load[t]=1 then out[t+1] = in[t] else out does not change. 25 | 26 | Clock rising edge updates the value from the input, 27 | if the \`load\` is set; otherwise, preserves the state. 28 | 29 | ${colors.bold('↗')} : value = load ? in : value 30 | 31 | Clock falling edge propagates the value to the output: 32 | 33 | ${colors.bold('↘')} : out = value 34 | `, 35 | 36 | inputPins: [{name: 'in', size: 16}, {name: 'load', size: 1}], 37 | outputPins: [{name: 'out', size: 16}], 38 | 39 | truthTable: Register.Spec.truthTable, 40 | }; 41 | 42 | module.exports = DRegister; 43 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/FullAdder.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | /** 11 | * Canonical truth table for the `FullAdder` gate. 12 | */ 13 | const TRUTH_TABLE = [ 14 | {a: 0, b: 0, c: 0, sum: 0, carry: 0}, 15 | {a: 0, b: 0, c: 1, sum: 1, carry: 0}, 16 | {a: 0, b: 1, c: 0, sum: 1, carry: 0}, 17 | {a: 0, b: 1, c: 1, sum: 0, carry: 1}, 18 | {a: 1, b: 0, c: 0, sum: 1, carry: 0}, 19 | {a: 1, b: 0, c: 1, sum: 0, carry: 1}, 20 | {a: 1, b: 1, c: 0, sum: 0, carry: 1}, 21 | {a: 1, b: 1, c: 1, sum: 1, carry: 1}, 22 | ]; 23 | 24 | /** 25 | * A FullAdder. 26 | * 27 | * The `sum` returns the LSB of the sum of the three bits a, b and c. 28 | * The `carry` returns the carry bit. 29 | */ 30 | class FullAdder extends BuiltInGate { 31 | /** 32 | * t = a + b + c 33 | * sum = t % 2 34 | * carry = t / 2 35 | */ 36 | eval() { 37 | const a = this.getInputPins()[0].getValue(); 38 | const b = this.getInputPins()[1].getValue(); 39 | const c = this.getInputPins()[2].getValue(); 40 | 41 | const t = a + b + c; 42 | 43 | this.getOutputPins()[0].setValue(t % 2); // sum 44 | this.getOutputPins()[1].setValue(Math.trunc(t / 2)); // carry 45 | } 46 | } 47 | 48 | /** 49 | * Specification of the `FullAdder` gate. 50 | */ 51 | FullAdder.Spec = { 52 | name: 'FullAdder', 53 | 54 | description: [ 55 | 'Implements 3-bits adder (full-adder) gate.', 56 | '', 57 | 'The `sum` returns LSB (the least significant bit) of the sum', 58 | 'of the three bits `a`, `b` and `c`.', 59 | '', 60 | 'The `carry` returns the carry bit.', 61 | ].join('\n'), 62 | 63 | inputPins: ['a', 'b', 'c'], 64 | outputPins: ['sum', 'carry'], 65 | 66 | truthTable: TRUTH_TABLE, 67 | }; 68 | 69 | module.exports = FullAdder; 70 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/HalfAdder.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | /** 11 | * Canonical truth table for the `HalfAdder` gate. 12 | */ 13 | const TRUTH_TABLE = [ 14 | {a: 0, b: 0, sum: 0, carry: 0}, 15 | {a: 0, b: 1, sum: 1, carry: 0}, 16 | {a: 1, b: 0, sum: 1, carry: 0}, 17 | {a: 1, b: 1, sum: 0, carry: 1}, 18 | ]; 19 | 20 | /** 21 | * A HalfAdder. 22 | * `sum` returns the LSB of the sum of the two bits a and b. 23 | * `carry` returns the carry bit. 24 | */ 25 | class HalfAdder extends BuiltInGate { 26 | /** 27 | * sum = a ^ b 28 | * carry = a & b 29 | */ 30 | eval() { 31 | const a = this.getInputPins()[0].getValue(); 32 | const b = this.getInputPins()[1].getValue(); 33 | 34 | this.getOutputPins()[0].setValue(a ^ b); 35 | this.getOutputPins()[1].setValue(a & b); 36 | } 37 | } 38 | 39 | /** 40 | * Specification of the `HalfAdder` gate. 41 | */ 42 | HalfAdder.Spec = { 43 | name: 'HalfAdder', 44 | 45 | description: [ 46 | 'Implements 2-bits adder (half-adder) gate.', 47 | '', 48 | 'The `sum` returns LSB (the least significant bit) of the sum', 49 | 'of the two bits `a`, and `b`.', 50 | '', 51 | 'The `carry` returns the carry bit.', 52 | ].join('\n'), 53 | 54 | inputPins: ['a', 'b'], 55 | outputPins: ['sum', 'carry'], 56 | 57 | truthTable: TRUTH_TABLE, 58 | }; 59 | 60 | module.exports = HalfAdder; 61 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Inc16.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | const {int16Table} = require('../../../util/numbers'); 11 | 12 | /** 13 | * Canonical truth table for the `Inc16` gate. 14 | */ 15 | const TRUTH_TABLE = int16Table([ 16 | {in: 0b0000000000000000, out: 0b0000000000000001}, 17 | {in: 0b1111111111111111, out: 0b0000000000000000}, 18 | {in: 0b0000000000000101, out: 0b0000000000000110}, 19 | {in: 0b1111111111111011, out: 0b1111111111111100}, 20 | ]); 21 | 22 | /** 23 | * Adds the constant 1 to the input. 24 | */ 25 | class Inc16 extends BuiltInGate { 26 | /** 27 | * IN in[16]; 28 | * OUT out[16]; 29 | * 30 | * Abstract: 31 | * 32 | * HalfAdder(a=in[0], b=1, sum=out[0], carry=c1); 33 | * HalfAdder(a=in[1], b=c1, sum=out[1], carry=c2); 34 | * ... 35 | * 36 | * Technically use JS + operator on 16-bit values. 37 | */ 38 | eval() { 39 | const _in = this.getInputPins()[0].getValue(); 40 | 41 | this.getOutputPins()[0].setValue(_in + 1); 42 | } 43 | } 44 | 45 | /** 46 | * Specification of the `Inc16` gate. 47 | */ 48 | Inc16.Spec = { 49 | name: 'Inc16', 50 | 51 | description: 'Adds the constant 1 to the input.', 52 | 53 | inputPins: [{name: 'in', size: 16}], 54 | 55 | outputPins: [{name: 'out', size: 16}], 56 | 57 | truthTable: TRUTH_TABLE, 58 | }; 59 | 60 | module.exports = Inc16; 61 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Keyboard.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | const EventEmitter = require('events'); 10 | 11 | /** 12 | * Main static emitter used for static methods on `Keyboard`. 13 | */ 14 | const keyboardEmitter = new EventEmitter(); 15 | 16 | /** 17 | * A keyboard, implemented as a 16 bit register that stores 18 | * the currently pressed key code. 19 | */ 20 | class Keyboard extends BuiltInGate { 21 | constructor(options) { 22 | super(options); 23 | 24 | Keyboard.on('key', key => { 25 | // Ctrl-c 26 | if (key === '\u0003') { 27 | this._listening = false; 28 | process.exit(); 29 | } 30 | 31 | this.getOutputPins()[0].setValue(key.charCodeAt(0)); 32 | }); 33 | } 34 | 35 | /** 36 | * Default blocking listener for CLI. 37 | * 38 | * Other clients should call `Keyboard.emit('key', key)` 39 | * in their listeners. 40 | */ 41 | listen() { 42 | if (this._listening) { 43 | return; 44 | } 45 | 46 | const {stdin} = process; 47 | 48 | stdin.setRawMode(true); 49 | stdin.setEncoding('utf8'); 50 | 51 | stdin.on('data', key => Keyboard.emit('key', key)); 52 | stdin.resume(); 53 | 54 | this._listening = true; 55 | return this; 56 | } 57 | 58 | /** 59 | * Facade method for subscription. 60 | */ 61 | static emit(eventName, data) { 62 | keyboardEmitter.emit(eventName, data); 63 | return this; 64 | } 65 | 66 | /** 67 | * Facade method for subscription. 68 | */ 69 | static on(eventName, listener) { 70 | keyboardEmitter.on(eventName, listener); 71 | return this; 72 | } 73 | 74 | /** 75 | * Facade method for removing subscription. 76 | */ 77 | static removeListener(eventName, listener) { 78 | keyboardEmitter.removeListener(eventName, listener); 79 | return this; 80 | } 81 | } 82 | 83 | /** 84 | * Specification of the `Keyboard` gate. 85 | */ 86 | Keyboard.Spec = { 87 | name: 'Keyboard', 88 | 89 | description: `A keyboard, implemented as a 16 bit register that stores 90 | the currently pressed key code.`, 91 | 92 | inputPins: [], 93 | outputPins: [{name: 'out', size: 16}], 94 | 95 | truthTable: [], 96 | }; 97 | 98 | module.exports = Keyboard; 99 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/MipsAlu.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | /** 11 | * Canonical truth table for the MipsAlu 12 | */ 13 | // prettier-ignore 14 | const TRUTH_TABLE = [ 15 | // Add 16 | {a: 1, b: 1, na: 0, nb: 0, less: 0, cin: 0, op: 0b10, out: 0, cout: 1, set: 0}, 17 | {a: 1, b: 1, na: 0, nb: 0, less: 0, cin: 1, op: 0b10, out: 1, cout: 1, set: 0}, 18 | {a: 0, b: 0, na: 0, nb: 0, less: 0, cin: 1, op: 0b10, out: 1, cout: 0, set: 0}, 19 | 20 | // Sub 21 | {a: 1, b: 1, na: 0, nb: 1, less: 0, cin: 1, op: 0b10, out: 0, cout: 1, set: 0}, 22 | 23 | // And 24 | {a: 1, b: 1, na: 0, nb: 0, less: 0, cin: 0, op: 0b00, out: 1, cout: 0, set: 0}, 25 | 26 | // Or 27 | {a: 1, b: 1, na: 0, nb: 0, less: 0, cin: 0, op: 0b01, out: 1, cout: 0, set: 0}, 28 | {a: 0, b: 1, na: 0, nb: 0, less: 0, cin: 0, op: 0b01, out: 1, cout: 0, set: 0}, 29 | {a: 0, b: 0, na: 0, nb: 0, less: 0, cin: 0, op: 0b01, out: 0, cout: 0, set: 0}, 30 | ]; 31 | 32 | /** 33 | * A 1-bit MipsAlu 34 | */ 35 | class MipsAlu extends BuiltInGate { 36 | /** 37 | * Logic: 38 | * 39 | * a & b: op = 0 40 | * a | b: op = 1 41 | * a NOR b => ~a & ~b: op = 0, na = 1, nb = 1 42 | * 43 | * Math: 44 | * 45 | * a + b: op = 2 46 | * a - b: op = 2, nb = 1, cin = 1 47 | * b - a: op = 2, na = 1, cin = 1 48 | * 49 | */ 50 | eval() { 51 | const [a, b, na, nb, less, cin, op] = this.getInputPins().map(pin => 52 | pin.getValue() 53 | ); 54 | 55 | const A = na ? 1 - a : a; 56 | const B = nb ? 1 - b : b; 57 | 58 | switch (op) { 59 | case 0b00: { 60 | this.getOutputPins()[0].setValue(A & B); 61 | break; 62 | } 63 | case 0b01: { 64 | this.getOutputPins()[0].setValue(A | B); 65 | break; 66 | } 67 | case 0b10: { 68 | const sum = A + B + cin; 69 | this.getOutputPins()[0].setValue(sum % 2); 70 | this.getOutputPins()[1].setValue(Math.trunc(sum / 2)); 71 | break; 72 | } 73 | case 0b11: { 74 | this.getOutputPins()[0].setValue(less); 75 | break; 76 | } 77 | } 78 | } 79 | } 80 | 81 | /** 82 | * Specification of the `MipsAlu` gate. 83 | */ 84 | MipsAlu.Spec = { 85 | name: 'MipsAlu', 86 | 87 | description: `1-bit Mips Alu. 88 | 89 | Implements 1-bit MIPS ALU chip. 90 | 91 | The actual ALU operation is controlled by the 2-bit "op" input, which takes the following values: 92 | 93 | - 0 - AND 94 | - 1 - OR 95 | - 2 - ADD 96 | - 3 - propagate "less" input 97 | 98 | Other operations can be achieved by manipulating different inputs, and the "op" code. 99 | For example, to do a subtraction operation "a - b", we need to set cin = 1, and nb = 1. 100 | 101 | Setting inputs "na" and "nb" negates the inputs "a" and "b" before performing the operation. 102 | `, 103 | inputPins: ['a', 'b', 'na', 'nb', 'less', 'cin', {name: 'op', size: 2}], 104 | outputPins: ['out', 'cout', 'set'], 105 | truthTable: TRUTH_TABLE, 106 | }; 107 | 108 | module.exports = MipsAlu; 109 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Mux.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | /** 11 | * Canonical truth table for the `Mux` gate. 12 | */ 13 | const TRUTH_TABLE = [ 14 | {a: 0, b: 0, sel: 0, out: 0}, 15 | {a: 0, b: 0, sel: 1, out: 0}, 16 | {a: 0, b: 1, sel: 0, out: 0}, 17 | {a: 0, b: 1, sel: 1, out: 1}, 18 | {a: 1, b: 0, sel: 0, out: 1}, 19 | {a: 1, b: 0, sel: 1, out: 0}, 20 | {a: 1, b: 1, sel: 0, out: 1}, 21 | {a: 1, b: 1, sel: 1, out: 1}, 22 | ]; 23 | 24 | /** 25 | * 1-bit 2-way multiplexor. 26 | * if sel=1 out=b else out=a. 27 | */ 28 | class Mux extends BuiltInGate { 29 | eval() { 30 | const a = this.getInputPins()[0].getValue(); 31 | const b = this.getInputPins()[1].getValue(); 32 | 33 | const sel = this.getInputPins()[2].getValue(); 34 | 35 | this.getOutputPins()[0].setValue(sel === 0 ? a : b); 36 | } 37 | } 38 | 39 | /** 40 | * Specification of the `Mux` gate. 41 | */ 42 | Mux.Spec = { 43 | name: 'Mux', 44 | 45 | description: [ 46 | 'Implements 1-bit 2-way multiplexor (Mux) gate.', 47 | '', 48 | 'out = a, when sel = 0', 49 | 'out = b, when sel = 1', 50 | ].join('\n'), 51 | 52 | inputPins: ['a', 'b', 'sel'], 53 | outputPins: ['out'], 54 | 55 | truthTable: TRUTH_TABLE, 56 | }; 57 | 58 | module.exports = Mux; 59 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Mux16.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | const {int16Table} = require('../../../util/numbers'); 11 | 12 | /** 13 | * Canonical truth table for the `Mux16` gate. 14 | */ 15 | const TRUTH_TABLE = int16Table([ 16 | { 17 | a: 0b0000000000000000, 18 | b: 0b0000000000000000, 19 | sel: 0, 20 | out: 0b0000000000000000, 21 | }, 22 | { 23 | a: 0b0000000000000000, 24 | b: 0b0000000000000000, 25 | sel: 1, 26 | out: 0b0000000000000000, 27 | }, 28 | { 29 | a: 0b0000000000000000, 30 | b: 0b0001001000110100, 31 | sel: 0, 32 | out: 0b0000000000000000, 33 | }, 34 | { 35 | a: 0b0000000000000000, 36 | b: 0b0001001000110100, 37 | sel: 1, 38 | out: 0b0001001000110100, 39 | }, 40 | { 41 | a: 0b1001100001110110, 42 | b: 0b0000000000000000, 43 | sel: 0, 44 | out: 0b1001100001110110, 45 | }, 46 | { 47 | a: 0b1001100001110110, 48 | b: 0b0000000000000000, 49 | sel: 1, 50 | out: 0b0000000000000000, 51 | }, 52 | { 53 | a: 0b1010101010101010, 54 | b: 0b0101010101010101, 55 | sel: 0, 56 | out: 0b1010101010101010, 57 | }, 58 | { 59 | a: 0b1010101010101010, 60 | b: 0b0101010101010101, 61 | sel: 1, 62 | out: 0b0101010101010101, 63 | }, 64 | ]); 65 | 66 | /** 67 | * A 16-bit Mux gate. 68 | */ 69 | class Mux16 extends BuiltInGate { 70 | /** 71 | * IN a[16], b[16], sel; 72 | * OUT out[16]; 73 | * 74 | * for i = 0..15 out[i] = a[i] if sel == 0 75 | * b[i] if sel == 1 76 | * Abstract: 77 | * 78 | * Mux(a=a[0], b=b[0], sel=sel, out=out[0]); 79 | * Mux(a=a[1], b=b[1], sel=sel, out=out[1]); 80 | * ... 81 | * 82 | * Technically at JS implementation is the same as in 1-bit Mux. 83 | */ 84 | eval() { 85 | const a = this.getInputPins()[0].getValue(); 86 | const b = this.getInputPins()[1].getValue(); 87 | 88 | const sel = this.getInputPins()[2].getValue(); 89 | 90 | this.getOutputPins()[0].setValue(sel === 0 ? a : b); 91 | } 92 | } 93 | 94 | /** 95 | * Specification of the `Mux16` gate. 96 | */ 97 | Mux16.Spec = { 98 | name: 'Mux16', 99 | 100 | description: 'Implements bitwise 16-bit And & operation.', 101 | 102 | inputPins: [ 103 | // Data pins. 104 | {name: 'a', size: 16}, 105 | {name: 'b', size: 16}, 106 | 107 | // 1-bit selector. 108 | {name: 'sel', size: 1}, 109 | ], 110 | 111 | outputPins: [{name: 'out', size: 16}], 112 | 113 | truthTable: TRUTH_TABLE, 114 | }; 115 | 116 | module.exports = Mux16; 117 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Mux4Way16.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | const {int16Table} = require('../../../util/numbers'); 11 | 12 | /** 13 | * Canonical truth table for the `Mux4Way16` gate. 14 | */ 15 | const TRUTH_TABLE = int16Table([ 16 | { 17 | a: 0b0000000000000000, 18 | b: 0b0000000000000000, 19 | c: 0b0000000000000000, 20 | d: 0b0000000000000000, 21 | sel: 0b00, 22 | out: 0b0000000000000000, 23 | }, 24 | { 25 | a: 0b0000000000000000, 26 | b: 0b0000000000000000, 27 | c: 0b0000000000000000, 28 | d: 0b0000000000000000, 29 | sel: 0b01, 30 | out: 0b0000000000000000, 31 | }, 32 | { 33 | a: 0b0000000000000000, 34 | b: 0b0000000000000000, 35 | c: 0b0000000000000000, 36 | d: 0b0000000000000000, 37 | sel: 0b10, 38 | out: 0b0000000000000000, 39 | }, 40 | { 41 | a: 0b0000000000000000, 42 | b: 0b0000000000000000, 43 | c: 0b0000000000000000, 44 | d: 0b0000000000000000, 45 | sel: 0b11, 46 | out: 0b0000000000000000, 47 | }, 48 | { 49 | a: 0b0001001000110100, 50 | b: 0b1001100001110110, 51 | c: 0b1010101010101010, 52 | d: 0b0101010101010101, 53 | sel: 0b00, 54 | out: 0b0001001000110100, 55 | }, 56 | { 57 | a: 0b0001001000110100, 58 | b: 0b1001100001110110, 59 | c: 0b1010101010101010, 60 | d: 0b0101010101010101, 61 | sel: 0b01, 62 | out: 0b1001100001110110, 63 | }, 64 | { 65 | a: 0b0001001000110100, 66 | b: 0b1001100001110110, 67 | c: 0b1010101010101010, 68 | d: 0b0101010101010101, 69 | sel: 0b10, 70 | out: 0b1010101010101010, 71 | }, 72 | { 73 | a: 0b0001001000110100, 74 | b: 0b1001100001110110, 75 | c: 0b1010101010101010, 76 | d: 0b0101010101010101, 77 | sel: 0b11, 78 | out: 0b0101010101010101, 79 | }, 80 | ]); 81 | 82 | /** 83 | * 4-way 16-bit multiplexor. 84 | * The two sel[0..1] bits select the output to be one of the four input buses: 85 | * (0->a ... 3->d). 86 | */ 87 | class Mux4Way16 extends BuiltInGate { 88 | /** 89 | * IN a[16], b[16], c[16], d[16], sel[2]; 90 | * OUT out[16]; 91 | * 92 | * Abstract: 93 | * 94 | * Mux16(a=a, b=b, sel=sel[0], out=ab); 95 | * Mux16(a=c, b=d, sel=sel[0], out=cd); 96 | * Mux16(a=ab, b=cd, sel=sel[1], out=out); 97 | */ 98 | eval() { 99 | const a = this.getInputPins()[0].getValue(); 100 | const b = this.getInputPins()[1].getValue(); 101 | const c = this.getInputPins()[2].getValue(); 102 | const d = this.getInputPins()[3].getValue(); 103 | 104 | const sel = this.getInputPins()[4].getValue(); 105 | 106 | let out = 0; 107 | 108 | switch (sel) { 109 | case 0b00: 110 | out = a; 111 | break; 112 | case 0b01: 113 | out = b; 114 | break; 115 | case 0b10: 116 | out = c; 117 | break; 118 | case 0b11: 119 | out = d; 120 | break; 121 | } 122 | 123 | this.getOutputPins()[0].setValue(out); 124 | } 125 | } 126 | 127 | /** 128 | * Specification of the `Mux4Way16` gate. 129 | */ 130 | Mux4Way16.Spec = { 131 | name: 'Mux4Way16', 132 | 133 | description: [ 134 | '4-way 16-bit multiplexor gate.', 135 | '', 136 | 'The two sel[0..1] bits select the output to be one ', 137 | 'of the four input buses: (0->a ... 3->d).', 138 | ].join('\n'), 139 | 140 | inputPins: [ 141 | // Data pins. 142 | {name: 'a', size: 16}, 143 | {name: 'b', size: 16}, 144 | {name: 'c', size: 16}, 145 | {name: 'd', size: 16}, 146 | 147 | // Selector. 148 | {name: 'sel', size: 2}, 149 | ], 150 | 151 | outputPins: [{name: 'out', size: 16}], 152 | 153 | truthTable: TRUTH_TABLE, 154 | }; 155 | 156 | module.exports = Mux4Way16; 157 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Nand.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | /** 11 | * Canonical truth table for the `Nand` gate. 12 | */ 13 | const TRUTH_TABLE = [ 14 | {a: 0, b: 0, out: 1}, 15 | {a: 0, b: 1, out: 1}, 16 | {a: 1, b: 0, out: 1}, 17 | {a: 1, b: 1, out: 0}, 18 | ]; 19 | 20 | /** 21 | * A bitwise 1-bit Nand (negative-And) gate. 22 | */ 23 | class Nand extends BuiltInGate { 24 | /** 25 | * Nand is the very basic chip on top of which any other chip can 26 | * be implemented: https://en.wikipedia.org/wiki/NAND_gate. 27 | * 28 | * It shares this property with the Nand gate. 29 | * 30 | * In the internal implementation we build it on top of the `&` operation. 31 | */ 32 | eval() { 33 | const a = this.getInputPins()[0].getValue(); 34 | const b = this.getInputPins()[1].getValue(); 35 | 36 | this.getOutputPins()[0].setValue(0x1 - (a & b)); 37 | } 38 | } 39 | 40 | /** 41 | * Specification of the `Nand` gate. 42 | */ 43 | Nand.Spec = { 44 | name: 'Nand', 45 | 46 | description: [ 47 | 'Implements bitwise 1-bit Nand (negative-And) gate.', 48 | '', 49 | 'The "Nand" gate similarly to the "Nor" gate is a basic', 50 | 'building block for all other gates.', 51 | ].join('\n'), 52 | 53 | inputPins: ['a', 'b'], 54 | outputPins: ['out'], 55 | 56 | truthTable: TRUTH_TABLE, 57 | }; 58 | 59 | module.exports = Nand; 60 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Nor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | /** 11 | * Canonical truth table for the `Nor` gate. 12 | */ 13 | const TRUTH_TABLE = [ 14 | {a: 0, b: 0, out: 1}, 15 | {a: 0, b: 1, out: 0}, 16 | {a: 1, b: 0, out: 0}, 17 | {a: 1, b: 1, out: 0}, 18 | ]; 19 | 20 | /** 21 | * A bitwise 1-bit Nor (negative-Or) gate. 22 | */ 23 | class Nor extends BuiltInGate { 24 | /** 25 | * Nor is the very basic chip on top of which any other chip can 26 | * be implemented: https://en.wikipedia.org/wiki/NOR_gate. 27 | * 28 | * It shares this property with the Nand gate. 29 | * 30 | * In the internal implementation we build it on top of the `&` operation. 31 | */ 32 | eval() { 33 | const a = this.getInputPins()[0].getValue(); 34 | const b = this.getInputPins()[1].getValue(); 35 | 36 | this.getOutputPins()[0].setValue(0x1 - (a | b)); 37 | } 38 | } 39 | 40 | /** 41 | * Specification of the `Nor` gate. 42 | */ 43 | Nor.Spec = { 44 | name: 'Nor', 45 | 46 | description: [ 47 | 'Implements bitwise 1-bit Nor (negative-Or) gate.', 48 | '', 49 | 'The "Nor" gate similarly to the "Nand" gate is a basic', 50 | 'building block for all other gates.', 51 | ].join('\n'), 52 | 53 | inputPins: ['a', 'b'], 54 | outputPins: ['out'], 55 | 56 | truthTable: TRUTH_TABLE, 57 | }; 58 | 59 | module.exports = Nor; 60 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Nor16Way.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | const {int16Table} = require('../../../util/numbers'); 11 | 12 | /** 13 | * Canonical truth table for the `Nor8Way` gate. 14 | */ 15 | const TRUTH_TABLE = int16Table([ 16 | {in: 0b0000000000000000, out: 0b1}, 17 | {in: 0b1111111111111111, out: 0b0}, 18 | {in: 0b0001000000010000, out: 0b0}, 19 | {in: 0b0000000100000001, out: 0b0}, 20 | {in: 0b0010011000100110, out: 0b0}, 21 | ]); 22 | 23 | /** 24 | * Or of 16 inputs into 1 output. 25 | * out=1 if all inputs are 0, and 0 otherwise. 26 | */ 27 | class Nor16Way extends BuiltInGate { 28 | /** 29 | * IN in[16]; 30 | * OUT out; 31 | * 32 | * out = (in[0] nor in[1] nor ... nor in[7]) 33 | * 34 | * Abstract: 35 | * 36 | * Nor(a=in[0], b=in[1], out=out1); 37 | * Nor(a=out1, b=in[2], out=out2); 38 | * ... 39 | */ 40 | eval() { 41 | const _in = this.getInputPins()[0].getValue(); 42 | 43 | this.getOutputPins()[0].setValue(_in === 0 ? 1 : 0); 44 | } 45 | } 46 | 47 | /** 48 | * Specification of the `Nor16Way` gate. 49 | */ 50 | Nor16Way.Spec = { 51 | name: 'Nor16Way', 52 | 53 | description: 'Nor of 16 inputs into 1 output.', 54 | 55 | inputPins: [{name: 'in', size: 16}], 56 | 57 | outputPins: ['out'], 58 | 59 | truthTable: TRUTH_TABLE, 60 | }; 61 | 62 | module.exports = Nor16Way; 63 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Not.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | /** 11 | * Canonical truth table for the `Not` gate. 12 | */ 13 | const TRUTH_TABLE = [{in: 0, out: 1}, {in: 1, out: 0}]; 14 | 15 | /** 16 | * A bitwise 1-bit Not gate. 17 | */ 18 | class Not extends BuiltInGate { 19 | /** 20 | * ~in 21 | */ 22 | eval() { 23 | const a = this.getInputPins()[0].getValue(); 24 | this.getOutputPins()[0].setValue(1 - a); 25 | } 26 | } 27 | 28 | /** 29 | * Specification of the `Not` gate. 30 | */ 31 | Not.Spec = { 32 | name: 'Not', 33 | description: 'Implements bitwise 1-bit Not ~ operation.', 34 | inputPins: ['in'], 35 | outputPins: ['out'], 36 | truthTable: TRUTH_TABLE, 37 | }; 38 | 39 | module.exports = Not; 40 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Not16.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | const {int16Table} = require('../../../util/numbers'); 11 | 12 | /** 13 | * Canonical truth table for the `Not16` gate. 14 | */ 15 | const TRUTH_TABLE = int16Table([ 16 | {in: 0b0000000000000000, out: 0b1111111111111111}, 17 | {in: 0b1111111111111111, out: 0b0000000000000000}, 18 | {in: 0b1010101010101010, out: 0b0101010101010101}, 19 | {in: 0b0011110011000011, out: 0b1100001100111100}, 20 | {in: 0b0001001000110100, out: 0b1110110111001011}, 21 | ]); 22 | 23 | /** 24 | * A bitwise 16-bit Not gate. 25 | */ 26 | class Not16 extends BuiltInGate { 27 | /** 28 | * IN a[16]; 29 | * OUT out[16]; 30 | * 31 | * for i = 0..15: out[i] = ~a[i] 32 | * 33 | * Abstract: 34 | * 35 | * Not(a=a[0], out=out[0]); 36 | * Not(a=a[1], out=out[1]); 37 | * ... 38 | * 39 | * Technically use JS bitwise operations at needed index. 40 | */ 41 | eval() { 42 | const a = this.getInputPins()[0].getValue(); 43 | 44 | // JS ~ operator applies bitwise Not for all bits: 45 | this.getOutputPins()[0].setValue(~a); 46 | } 47 | } 48 | 49 | /** 50 | * Specification of the `Not16` gate. 51 | */ 52 | Not16.Spec = { 53 | name: 'Not16', 54 | 55 | description: 'Implements bitwise 16-bit Not ~ operation.', 56 | 57 | inputPins: [{name: 'in', size: 16}], 58 | 59 | outputPins: [{name: 'out', size: 16}], 60 | 61 | truthTable: TRUTH_TABLE, 62 | }; 63 | 64 | module.exports = Not16; 65 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Or.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | /** 11 | * Canonical truth table for the `Or` gate. 12 | */ 13 | const TRUTH_TABLE = [ 14 | {a: 0, b: 0, out: 0}, 15 | {a: 0, b: 1, out: 1}, 16 | {a: 1, b: 0, out: 1}, 17 | {a: 1, b: 1, out: 1}, 18 | ]; 19 | 20 | /** 21 | * A bitwise 1-bit Or gate. 22 | */ 23 | class Or extends BuiltInGate { 24 | /** 25 | * a | b 26 | */ 27 | eval() { 28 | const a = this.getInputPins()[0].getValue(); 29 | const b = this.getInputPins()[1].getValue(); 30 | 31 | this.getOutputPins()[0].setValue(a | b); 32 | } 33 | } 34 | 35 | /** 36 | * Specification of the `Or` gate. 37 | */ 38 | Or.Spec = { 39 | name: 'Or', 40 | description: 'Implements bitwise 1-bit Or | operation.', 41 | inputPins: ['a', 'b'], 42 | outputPins: ['out'], 43 | truthTable: TRUTH_TABLE, 44 | }; 45 | 46 | module.exports = Or; 47 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Or16.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | const {int16Table} = require('../../../util/numbers'); 11 | 12 | /** 13 | * Canonical truth table for the `Or16` gate. 14 | */ 15 | const TRUTH_TABLE = int16Table([ 16 | {a: 0b0000000000000000, b: 0b0000000000000000, out: 0b0000000000000000}, 17 | {a: 0b0000000000000000, b: 0b1111111111111111, out: 0b1111111111111111}, 18 | {a: 0b1111111111111111, b: 0b1111111111111111, out: 0b1111111111111111}, 19 | {a: 0b1010101010101010, b: 0b0101010101010101, out: 0b1111111111111111}, 20 | {a: 0b0011110011000011, b: 0b0000111111110000, out: 0b0011111111110011}, 21 | {a: 0b0001001000110100, b: 0b1001100001110110, out: 0b1001101001110110}, 22 | ]); 23 | 24 | /** 25 | * A bitwise 16-bit Or gate. 26 | */ 27 | class Or16 extends BuiltInGate { 28 | /** 29 | * IN a[16], b[16]; 30 | * OUT out[16]; 31 | * 32 | * for i = 0..15: out[i] = (a[i] | b[i]) 33 | * 34 | * Abstract: 35 | * 36 | * Or(a=a[0], b=b[0], out=out[0]); 37 | * Or(a=a[1], b=b[1], out=out[1]); 38 | * ... 39 | * 40 | * Technically use JS bitwise operations at needed index. 41 | */ 42 | eval() { 43 | const a = this.getInputPins()[0].getValue(); 44 | const b = this.getInputPins()[1].getValue(); 45 | 46 | // In JS implementation doesn't differ from the simple `Or` gate. 47 | // Use 16-bit values with 0xFFFF mask. 48 | this.getOutputPins()[0].setValue((a | b) & 0xffff); 49 | } 50 | } 51 | 52 | /** 53 | * Specification of the `Or16` gate. 54 | */ 55 | Or16.Spec = { 56 | name: 'Or16', 57 | 58 | description: 'Implements bitwise 16-bit Or | operation.', 59 | 60 | inputPins: [{name: 'a', size: 16}, {name: 'b', size: 16}], 61 | 62 | outputPins: [{name: 'out', size: 16}], 63 | 64 | truthTable: TRUTH_TABLE, 65 | }; 66 | 67 | module.exports = Or16; 68 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Or8Way.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | const {int16Table} = require('../../../util/numbers'); 11 | 12 | /** 13 | * Canonical truth table for the `Or8Way` gate. 14 | */ 15 | const TRUTH_TABLE = int16Table([ 16 | {in: 0b00000000, out: 0b0}, 17 | {in: 0b11111111, out: 0b1}, 18 | {in: 0b00010000, out: 0b1}, 19 | {in: 0b00000001, out: 0b1}, 20 | {in: 0b00100110, out: 0b1}, 21 | ]); 22 | 23 | /** 24 | * Or of 8 inputs into 1 output. 25 | * out=1 if one or more of the inputs is 1 and 0 otherwise. 26 | */ 27 | class Or8Way extends BuiltInGate { 28 | /** 29 | * IN in[8]; 30 | * OUT out; 31 | * 32 | * out = (in[0] | in[1] | ... | in[7]) 33 | * 34 | * Abstract: 35 | * 36 | * Or(a=in[0], b=in[1], out=out1); 37 | * Or(a=out1, b=in[2], out=out2); 38 | * ... 39 | */ 40 | eval() { 41 | const _in = this.getInputPins()[0].getValue(); 42 | 43 | this.getOutputPins()[0].setValue(_in === 0 ? 0 : 1); 44 | } 45 | } 46 | 47 | /** 48 | * Specification of the `Or8Way` gate. 49 | */ 50 | Or8Way.Spec = { 51 | name: 'Or8Way', 52 | 53 | description: 'Or | of 8 inputs into 1 output.', 54 | 55 | inputPins: [{name: 'in', size: 8}], 56 | 57 | outputPins: ['out'], 58 | 59 | truthTable: TRUTH_TABLE, 60 | }; 61 | 62 | module.exports = Or8Way; 63 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/PC.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const colors = require('colors'); 9 | const BuiltInGate = require('../BuiltInGate'); 10 | 11 | const {int16Table, int16} = require('../../../util/numbers'); 12 | 13 | /** 14 | * Canonical truth table for the `PC` gate. 15 | */ 16 | const TRUTH_TABLE = int16Table([ 17 | {$clock: -0, in: 0, load: 0, inc: 0, reset: 0, out: 0}, 18 | 19 | // PC = 5 20 | {$clock: +0, in: 5, load: 1, inc: 0, reset: 0, out: 0}, 21 | {$clock: -1, in: 5, load: 1, inc: 0, reset: 0, out: 5}, 22 | 23 | // PC++ 24 | {$clock: +1, in: 5, load: 0, inc: 1, reset: 0, out: 5}, 25 | {$clock: -2, in: 5, load: 0, inc: 1, reset: 0, out: 6}, 26 | 27 | // PC++ 28 | {$clock: +2, in: 6, load: 0, inc: 1, reset: 0, out: 6}, 29 | {$clock: -3, in: 6, load: 0, inc: 1, reset: 0, out: 7}, 30 | 31 | // Reset (PC = 0) 32 | {$clock: +3, in: 6, load: 0, inc: 0, reset: 1, out: 6}, 33 | {$clock: -4, in: 6, load: 0, inc: 0, reset: 1, out: 0}, 34 | 35 | // Preserve 36 | {$clock: +4, in: 0, load: 0, inc: 0, reset: 0, out: 0}, 37 | {$clock: -5, in: 0, load: 0, inc: 0, reset: 0, out: 0}, 38 | ]); 39 | 40 | /** 41 | * A 16-bit counter with load and reset controls. 42 | * 43 | * out[t+1] = 0, when reset[t] = 1 44 | * out[t+1] = in[t], when load[t] = 1 45 | * out[t+1] = out[t] + 1, when inc[t] = 1 (default counting behavior) 46 | * out[t+1] = out[t], otherwise (preserves as a register) 47 | * 48 | * Abstract: 49 | * 50 | * IN in[16], load, inc, reset; 51 | * OUT out[16]; 52 | * 53 | * Inc16(in=t0, out=t1); 54 | * Mux16(a=t0, b=t1, sel=inc, out=t2); 55 | * ... 56 | * Register(in=t4, load=true, out=t0, out=out); 57 | */ 58 | class PC extends BuiltInGate { 59 | /** 60 | * PC is a sequential gate. 61 | */ 62 | static isClocked() { 63 | return true; 64 | } 65 | 66 | init() { 67 | /** 68 | * The 16-bit value of the PC register. 69 | */ 70 | this._value = 0; 71 | } 72 | 73 | /** 74 | * On rising edge PC register updates the internal 75 | * value according to the logic. 76 | */ 77 | clockUp() { 78 | const _in = this.getInputPins()[0].getValue(); 79 | const load = this.getInputPins()[1].getValue(); 80 | const inc = this.getInputPins()[2].getValue(); 81 | const reset = this.getInputPins()[3].getValue(); 82 | 83 | if (reset === 1) { 84 | this._value = 0; 85 | } else if (load === 1) { 86 | this._value = int16(_in); 87 | } else if (inc === 1) { 88 | this._value++; 89 | } 90 | } 91 | 92 | /** 93 | * On the falling edge PC register propagates 94 | * the value to the output pin. 95 | */ 96 | clockDown() { 97 | this.getOutputPins()[0].setValue(this._value); 98 | } 99 | } 100 | 101 | /** 102 | * Specification of the `PC` gate. 103 | */ 104 | PC.Spec = { 105 | name: 'PC', 106 | 107 | description: ` 108 | A 16-bit counter with load and reset controls. 109 | 110 | out[t+1] = 0, when reset[t] = 1 111 | out[t+1] = in[t], when load[t] = 1 112 | out[t+1] = out[t] + 1, when inc[t] = 1 (default counting behavior) 113 | out[t+1] = out[t], otherwise, preserves the value 114 | 115 | Clock rising edge PC updates the value from the input, 116 | if the \`load\` is set; otherwise, preserves the state. 117 | 118 | ${colors.bold('↗')} : value = in, when ${colors.bold('load')} 119 | 0, when ${colors.bold('reset')} 120 | +1, when ${colors.bold('inc')} 121 | 122 | Clock falling edge PC propagates the value to the output: 123 | 124 | ${colors.bold('↘')} : out = value 125 | `, 126 | 127 | inputPins: [ 128 | // 16-bit value. 129 | {name: 'in', size: 16}, 130 | 131 | // Control bits. 132 | {name: 'load', size: 1}, 133 | {name: 'inc', size: 1}, 134 | {name: 'reset', size: 1}, 135 | ], 136 | outputPins: [{name: 'out', size: 16}], 137 | 138 | truthTable: TRUTH_TABLE, 139 | }; 140 | 141 | module.exports = PC; 142 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/RAM16K.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const colors = require('colors'); 9 | const RAM = require('./RAM'); 10 | 11 | const {int16Table} = require('../../../util/numbers'); 12 | 13 | /** 14 | * Canonical truth table for the `RAM16K` gate. 15 | */ 16 | const TRUTH_TABLE = int16Table([ 17 | { 18 | $clock: -0, 19 | in: 0b0000000000000000, 20 | load: 0, 21 | address: 0, 22 | out: 0b0000000000000000, 23 | }, 24 | { 25 | $clock: +0, 26 | in: 0b0000000000010101, 27 | load: 1, 28 | address: 0, 29 | out: 0b0000000000000000, 30 | }, 31 | { 32 | $clock: -1, 33 | in: 0b0000000000000001, 34 | load: 0, 35 | address: 0, 36 | out: 0b0000000000010101, 37 | }, 38 | { 39 | $clock: +1, 40 | in: 0b0000000000010101, 41 | load: 0, 42 | address: 0, 43 | out: 0b0000000000010101, 44 | }, 45 | { 46 | $clock: -2, 47 | in: 0b0000000000010101, 48 | load: 0, 49 | address: 0, 50 | out: 0b0000000000010101, 51 | }, 52 | { 53 | $clock: +2, 54 | in: 0b1101001000010101, 55 | load: 1, 56 | address: 2, 57 | out: 0b0000000000000000, 58 | }, 59 | { 60 | $clock: -3, 61 | in: 0b1101001000010101, 62 | load: 0, 63 | address: 2, 64 | out: 0b1101001000010101, 65 | }, 66 | { 67 | $clock: +3, 68 | in: 0b1111111111111111, 69 | load: 1, 70 | address: 16383, 71 | out: 0b0000000000000000, 72 | }, 73 | { 74 | $clock: -4, 75 | in: 0b0000000000000000, 76 | load: 1, 77 | address: 16383, 78 | out: 0b1111111111111111, 79 | }, 80 | { 81 | $clock: +4, 82 | in: 0b0000000000000000, 83 | load: 1, 84 | address: 16383, 85 | out: 0b1111111111111111, 86 | }, 87 | { 88 | $clock: -5, 89 | in: 0b0000000000000000, 90 | load: 0, 91 | address: 16383, 92 | out: 0b0000000000000000, 93 | }, 94 | ]); 95 | 96 | /** 97 | * RAM chip of 4K 16-bit registers. 98 | * 99 | * The output is the value stored at the memory location specified by address. 100 | * If load=1, loads the input into the memory location specified by address. 101 | * 102 | * Abstract: 103 | * 104 | * IN in[16], load, address[14]; 105 | * OUT out[16]; 106 | * 107 | * DMux8Way(in=load, sel=address, ...); 108 | * RAM4K(in=in, load=l1, address=address[0..11], out=r1); 109 | RAM4K(in=in, load=l2, address=address[0..11], out=r2); 110 | * ... 111 | * Mux8Way16(...); 112 | */ 113 | class RAM16K extends RAM { 114 | constructor(options) { 115 | super(Object.assign({size: 16 * 1024}, options)); 116 | } 117 | } 118 | 119 | /** 120 | * Specification of the `RAM16K` gate. 121 | */ 122 | RAM16K.Spec = { 123 | name: 'RAM16K', 124 | 125 | description: [ 126 | 'Memory chip consisting of 16K 16-bit registers.', 127 | '', 128 | 'If load[t]=1 then out[t+1] = in[t] else out does not change.', 129 | '', 130 | 'Clock rising edge updates the value from the input by the address,', 131 | 'if the `load` is set; otherwise, preserves the state.', 132 | '', 133 | ` ${colors.bold('↗')} : value[address] = load ? in : value[address]`, 134 | '', 135 | 'Clock falling edge propagates the value at the address to the output:', 136 | '', 137 | ` ${colors.bold('↘')} : out = value[address]`, 138 | ].join('\n'), 139 | 140 | inputPins: [ 141 | {name: 'in', size: 16}, 142 | {name: 'load', size: 1}, 143 | {name: 'address', size: 14}, 144 | ], 145 | 146 | outputPins: [{name: 'out', size: 16}], 147 | 148 | truthTable: TRUTH_TABLE, 149 | }; 150 | 151 | module.exports = RAM16K; 152 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/RAM4K.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const colors = require('colors'); 9 | const RAM = require('./RAM'); 10 | 11 | const {int16Table} = require('../../../util/numbers'); 12 | 13 | /** 14 | * Canonical truth table for the `RAM4K` gate. 15 | */ 16 | const TRUTH_TABLE = int16Table([ 17 | { 18 | $clock: -0, 19 | in: 0b0000000000000000, 20 | load: 0, 21 | address: 0, 22 | out: 0b0000000000000000, 23 | }, 24 | { 25 | $clock: +0, 26 | in: 0b0000000000010101, 27 | load: 1, 28 | address: 0, 29 | out: 0b0000000000000000, 30 | }, 31 | { 32 | $clock: -1, 33 | in: 0b0000000000000001, 34 | load: 0, 35 | address: 0, 36 | out: 0b0000000000010101, 37 | }, 38 | { 39 | $clock: +1, 40 | in: 0b0000000000010101, 41 | load: 0, 42 | address: 0, 43 | out: 0b0000000000010101, 44 | }, 45 | { 46 | $clock: -2, 47 | in: 0b0000000000010101, 48 | load: 0, 49 | address: 0, 50 | out: 0b0000000000010101, 51 | }, 52 | { 53 | $clock: +2, 54 | in: 0b1101001000010101, 55 | load: 1, 56 | address: 2, 57 | out: 0b0000000000000000, 58 | }, 59 | { 60 | $clock: -3, 61 | in: 0b1101001000010101, 62 | load: 0, 63 | address: 2, 64 | out: 0b1101001000010101, 65 | }, 66 | { 67 | $clock: +3, 68 | in: 0b1111111111111111, 69 | load: 1, 70 | address: 4095, 71 | out: 0b0000000000000000, 72 | }, 73 | { 74 | $clock: -4, 75 | in: 0b0000000000000000, 76 | load: 1, 77 | address: 4095, 78 | out: 0b1111111111111111, 79 | }, 80 | { 81 | $clock: +4, 82 | in: 0b0000000000000000, 83 | load: 1, 84 | address: 4095, 85 | out: 0b1111111111111111, 86 | }, 87 | { 88 | $clock: -5, 89 | in: 0b0000000000000000, 90 | load: 0, 91 | address: 4095, 92 | out: 0b0000000000000000, 93 | }, 94 | ]); 95 | 96 | /** 97 | * RAM chip of 4K 16-bit registers. 98 | * 99 | * The output is the value stored at the memory location specified by address. 100 | * If load=1, loads the input into the memory location specified by address. 101 | * 102 | * Abstract: 103 | * 104 | * IN in[16], load, address[12]; 105 | * OUT out[16]; 106 | * 107 | * DMux8Way(in=load, sel=address, ...); 108 | * RAM512(in=in, load=l1, address=address[0..8], out=r1); 109 | RAM512(in=in, load=l2, address=address[0..8], out=r2); 110 | * ... 111 | * Mux8Way16(...); 112 | */ 113 | class RAM4K extends RAM { 114 | constructor(options) { 115 | super(Object.assign({size: 4 * 1024}, options)); 116 | } 117 | } 118 | 119 | /** 120 | * Specification of the `RAM4K` gate. 121 | */ 122 | RAM4K.Spec = { 123 | name: 'RAM4K', 124 | 125 | description: [ 126 | 'Memory chip consisting of 4K 16-bit registers.', 127 | '', 128 | 'If load[t]=1 then out[t+1] = in[t] else out does not change.', 129 | '', 130 | 'Clock rising edge updates the value from the input by the address,', 131 | 'if the `load` is set; otherwise, preserves the state.', 132 | '', 133 | ` ${colors.bold('↗')} : value[address] = load ? in : value[address]`, 134 | '', 135 | 'Clock falling edge propagates the value at the address to the output:', 136 | '', 137 | ` ${colors.bold('↘')} : out = value[address]`, 138 | ].join('\n'), 139 | 140 | inputPins: [ 141 | {name: 'in', size: 16}, 142 | {name: 'load', size: 1}, 143 | {name: 'address', size: 12}, 144 | ], 145 | 146 | outputPins: [{name: 'out', size: 16}], 147 | 148 | truthTable: TRUTH_TABLE, 149 | }; 150 | 151 | module.exports = RAM4K; 152 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/RAM512.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const colors = require('colors'); 9 | const RAM = require('./RAM'); 10 | 11 | const {int16Table} = require('../../../util/numbers'); 12 | 13 | /** 14 | * Canonical truth table for the `RAM512` gate. 15 | */ 16 | const TRUTH_TABLE = int16Table([ 17 | { 18 | $clock: -0, 19 | in: 0b0000000000000000, 20 | load: 0, 21 | address: 0, 22 | out: 0b0000000000000000, 23 | }, 24 | { 25 | $clock: +0, 26 | in: 0b0000000000010101, 27 | load: 1, 28 | address: 0, 29 | out: 0b0000000000000000, 30 | }, 31 | { 32 | $clock: -1, 33 | in: 0b0000000000000001, 34 | load: 0, 35 | address: 0, 36 | out: 0b0000000000010101, 37 | }, 38 | { 39 | $clock: +1, 40 | in: 0b0000000000010101, 41 | load: 0, 42 | address: 0, 43 | out: 0b0000000000010101, 44 | }, 45 | { 46 | $clock: -2, 47 | in: 0b0000000000010101, 48 | load: 0, 49 | address: 0, 50 | out: 0b0000000000010101, 51 | }, 52 | { 53 | $clock: +2, 54 | in: 0b1101001000010101, 55 | load: 1, 56 | address: 2, 57 | out: 0b0000000000000000, 58 | }, 59 | { 60 | $clock: -3, 61 | in: 0b1101001000010101, 62 | load: 0, 63 | address: 2, 64 | out: 0b1101001000010101, 65 | }, 66 | { 67 | $clock: +3, 68 | in: 0b1111111111111111, 69 | load: 1, 70 | address: 511, 71 | out: 0b0000000000000000, 72 | }, 73 | { 74 | $clock: -4, 75 | in: 0b0000000000000000, 76 | load: 1, 77 | address: 511, 78 | out: 0b1111111111111111, 79 | }, 80 | { 81 | $clock: +4, 82 | in: 0b0000000000000000, 83 | load: 1, 84 | address: 511, 85 | out: 0b1111111111111111, 86 | }, 87 | { 88 | $clock: -5, 89 | in: 0b0000000000000000, 90 | load: 0, 91 | address: 511, 92 | out: 0b0000000000000000, 93 | }, 94 | ]); 95 | 96 | /** 97 | * RAM chip of 512 16-bit registers. 98 | * 99 | * The output is the value stored at the memory location specified by address. 100 | * If load=1, loads the input into the memory location specified by address. 101 | * 102 | * Abstract: 103 | * 104 | * IN in[16], load, address[9]; 105 | * OUT out[16]; 106 | * 107 | * DMux8Way(in=load, sel=address, ...); 108 | * RAM64(in=in, load=l1, address=address[0..5], out=r1); 109 | RAM64(in=in, load=l2, address=address[0..5], out=r2); 110 | * ... 111 | * Mux8Way16(...); 112 | */ 113 | class RAM512 extends RAM { 114 | constructor(options) { 115 | super(Object.assign({size: 512}, options)); 116 | } 117 | } 118 | 119 | /** 120 | * Specification of the `RAM512` gate. 121 | */ 122 | RAM512.Spec = { 123 | name: 'RAM512', 124 | 125 | description: [ 126 | 'Memory chip consisting of 512 16-bit registers.', 127 | '', 128 | 'If load[t]=1 then out[t+1] = in[t] else out does not change.', 129 | '', 130 | 'Clock rising edge updates the value from the input by the address,', 131 | 'if the `load` is set; otherwise, preserves the state.', 132 | '', 133 | ` ${colors.bold('↗')} : value[address] = load ? in : value[address]`, 134 | '', 135 | 'Clock falling edge propagates the value at the address to the output:', 136 | '', 137 | ` ${colors.bold('↘')} : out = value[address]`, 138 | ].join('\n'), 139 | 140 | inputPins: [ 141 | {name: 'in', size: 16}, 142 | {name: 'load', size: 1}, 143 | {name: 'address', size: 9}, 144 | ], 145 | 146 | outputPins: [{name: 'out', size: 16}], 147 | 148 | truthTable: TRUTH_TABLE, 149 | }; 150 | 151 | module.exports = RAM512; 152 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/RAM64.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const colors = require('colors'); 9 | const RAM = require('./RAM'); 10 | 11 | const {int16Table} = require('../../../util/numbers'); 12 | 13 | /** 14 | * Canonical truth table for the `RAM64` gate. 15 | */ 16 | const TRUTH_TABLE = int16Table([ 17 | { 18 | $clock: -0, 19 | in: 0b0000000000000000, 20 | load: 0, 21 | address: 0, 22 | out: 0b0000000000000000, 23 | }, 24 | { 25 | $clock: +0, 26 | in: 0b0000000000010101, 27 | load: 1, 28 | address: 0, 29 | out: 0b0000000000000000, 30 | }, 31 | { 32 | $clock: -1, 33 | in: 0b0000000000000001, 34 | load: 0, 35 | address: 0, 36 | out: 0b0000000000010101, 37 | }, 38 | { 39 | $clock: +1, 40 | in: 0b0000000000010101, 41 | load: 0, 42 | address: 0, 43 | out: 0b0000000000010101, 44 | }, 45 | { 46 | $clock: -2, 47 | in: 0b0000000000010101, 48 | load: 0, 49 | address: 0, 50 | out: 0b0000000000010101, 51 | }, 52 | { 53 | $clock: +2, 54 | in: 0b1101001000010101, 55 | load: 1, 56 | address: 2, 57 | out: 0b0000000000000000, 58 | }, 59 | { 60 | $clock: -3, 61 | in: 0b1101001000010101, 62 | load: 0, 63 | address: 2, 64 | out: 0b1101001000010101, 65 | }, 66 | { 67 | $clock: +3, 68 | in: 0b1111111111111111, 69 | load: 1, 70 | address: 63, 71 | out: 0b0000000000000000, 72 | }, 73 | { 74 | $clock: -4, 75 | in: 0b0000000000000000, 76 | load: 1, 77 | address: 63, 78 | out: 0b1111111111111111, 79 | }, 80 | { 81 | $clock: +4, 82 | in: 0b0000000000000000, 83 | load: 1, 84 | address: 63, 85 | out: 0b1111111111111111, 86 | }, 87 | { 88 | $clock: -5, 89 | in: 0b0000000000000000, 90 | load: 0, 91 | address: 63, 92 | out: 0b0000000000000000, 93 | }, 94 | ]); 95 | 96 | /** 97 | * RAM chip of 64 16-bit registers. 98 | * 99 | * The output is the value stored at the memory location specified by address. 100 | * If load=1, loads the input into the memory location specified by address. 101 | * 102 | * Abstract: 103 | * 104 | * IN in[16], load, address[6]; 105 | * OUT out[16]; 106 | * 107 | * DMux8Way(in=load, sel=address, ...); 108 | * RAM8(in=in, load=l1, address=address[0..2], out=r1); 109 | RAM8(in=in, load=l2, address=address[0..2], out=r2); 110 | * ... 111 | * Mux8Way16(...); 112 | */ 113 | class RAM64 extends RAM { 114 | constructor(options) { 115 | super(Object.assign({size: 64}, options)); 116 | } 117 | } 118 | 119 | /** 120 | * Specification of the `RAM64` gate. 121 | */ 122 | RAM64.Spec = { 123 | name: 'RAM64', 124 | 125 | description: [ 126 | 'Memory chip consisting of 64 16-bit registers.', 127 | '', 128 | 'If load[t]=1 then out[t+1] = in[t] else out does not change.', 129 | '', 130 | 'Clock rising edge updates the value from the input by the address,', 131 | 'if the `load` is set; otherwise, preserves the state.', 132 | '', 133 | ` ${colors.bold('↗')} : value[address] = load ? in : value[address]`, 134 | '', 135 | 'Clock falling edge propagates the value at the address to the output:', 136 | '', 137 | ` ${colors.bold('↘')} : out = value[address]`, 138 | ].join('\n'), 139 | 140 | inputPins: [ 141 | {name: 'in', size: 16}, 142 | {name: 'load', size: 1}, 143 | {name: 'address', size: 6}, 144 | ], 145 | 146 | outputPins: [{name: 'out', size: 16}], 147 | 148 | truthTable: TRUTH_TABLE, 149 | }; 150 | 151 | module.exports = RAM64; 152 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/RAM8.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const colors = require('colors'); 9 | const RAM = require('./RAM'); 10 | 11 | const {int16Table} = require('../../../util/numbers'); 12 | 13 | /** 14 | * Canonical truth table for the `RAM8` gate. 15 | */ 16 | const TRUTH_TABLE = int16Table([ 17 | { 18 | $clock: -0, 19 | in: 0b0000000000000000, 20 | load: 0, 21 | address: 0, 22 | out: 0b0000000000000000, 23 | }, 24 | { 25 | $clock: +0, 26 | in: 0b0000000000010101, 27 | load: 1, 28 | address: 0, 29 | out: 0b0000000000000000, 30 | }, 31 | { 32 | $clock: -1, 33 | in: 0b0000000000000001, 34 | load: 0, 35 | address: 0, 36 | out: 0b0000000000010101, 37 | }, 38 | { 39 | $clock: +1, 40 | in: 0b0000000000010101, 41 | load: 0, 42 | address: 0, 43 | out: 0b0000000000010101, 44 | }, 45 | { 46 | $clock: -2, 47 | in: 0b0000000000010101, 48 | load: 0, 49 | address: 0, 50 | out: 0b0000000000010101, 51 | }, 52 | { 53 | $clock: +2, 54 | in: 0b1101001000010101, 55 | load: 1, 56 | address: 2, 57 | out: 0b0000000000000000, 58 | }, 59 | { 60 | $clock: -3, 61 | in: 0b1101001000010101, 62 | load: 0, 63 | address: 2, 64 | out: 0b1101001000010101, 65 | }, 66 | { 67 | $clock: +3, 68 | in: 0b1111111111111111, 69 | load: 1, 70 | address: 3, 71 | out: 0b0000000000000000, 72 | }, 73 | { 74 | $clock: -4, 75 | in: 0b0000000000000000, 76 | load: 1, 77 | address: 3, 78 | out: 0b1111111111111111, 79 | }, 80 | { 81 | $clock: +4, 82 | in: 0b0000000000000000, 83 | load: 1, 84 | address: 3, 85 | out: 0b1111111111111111, 86 | }, 87 | { 88 | $clock: -5, 89 | in: 0b0000000000000000, 90 | load: 0, 91 | address: 3, 92 | out: 0b0000000000000000, 93 | }, 94 | ]); 95 | 96 | /** 97 | * RAM chip of 8 16-bit registers. 98 | * 99 | * The output is the value stored at the memory location specified by address. 100 | * If load=1, loads the input into the memory location specified by address. 101 | * 102 | * Abstract: 103 | * 104 | * IN in[16], load, address[3]; 105 | * OUT out[16]; 106 | * 107 | * DMux8Way(in=load, sel=address, ...); 108 | * Register(in=in, load=l1, out=r1); 109 | * Register(in=in, load=l2, out=r2); 110 | * ... 111 | * Mux8Way16(...); 112 | */ 113 | class RAM8 extends RAM { 114 | constructor(options) { 115 | super(Object.assign({size: 8}, options)); 116 | } 117 | } 118 | 119 | /** 120 | * Specification of the `RAM8` gate. 121 | */ 122 | RAM8.Spec = { 123 | name: 'RAM8', 124 | 125 | description: [ 126 | 'Memory chip consisting of 8 16-bit registers.', 127 | '', 128 | 'If load[t]=1 then out[t+1] = in[t] else out does not change.', 129 | '', 130 | 'Clock rising edge updates the value from the input by the address,', 131 | 'if the `load` is set; otherwise, preserves the state.', 132 | '', 133 | ` ${colors.bold('↗')} : value[address] = load ? in : value[address]`, 134 | '', 135 | 'Clock falling edge propagates the value at the address to the output:', 136 | '', 137 | ` ${colors.bold('↘')} : out = value[address]`, 138 | ].join('\n'), 139 | 140 | inputPins: [ 141 | {name: 'in', size: 16}, 142 | {name: 'load', size: 1}, 143 | {name: 'address', size: 3}, 144 | ], 145 | 146 | outputPins: [{name: 'out', size: 16}], 147 | 148 | truthTable: TRUTH_TABLE, 149 | }; 150 | 151 | module.exports = RAM8; 152 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Register.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const colors = require('colors'); 9 | const BuiltInGate = require('../BuiltInGate'); 10 | 11 | const {int16Table, int16} = require('../../../util/numbers'); 12 | 13 | /** 14 | * Canonical truth table for the `Register` gate. 15 | */ 16 | const TRUTH_TABLE = int16Table([ 17 | {$clock: -0, in: 0b0000000000000000, load: 0, out: 0b0000000000000000}, 18 | {$clock: +0, in: 0b0000000000010101, load: 1, out: 0b0000000000000000}, 19 | {$clock: -1, in: 0b0000000000000001, load: 0, out: 0b0000000000010101}, 20 | {$clock: +1, in: 0b0000000000010101, load: 0, out: 0b0000000000010101}, 21 | {$clock: -2, in: 0b0000000000010101, load: 0, out: 0b0000000000010101}, 22 | {$clock: +2, in: 0b1101001000010101, load: 1, out: 0b0000000000010101}, 23 | {$clock: -3, in: 0b1101001000010101, load: 0, out: 0b1101001000010101}, 24 | ]); 25 | 26 | /** 27 | * 16-bit register. 28 | * 29 | * Abstract: 30 | * 31 | * IN in[16], load; 32 | * OUT out[16]; 33 | * 34 | * Bit(in=in[0], load=load, out=out[0]); 35 | * Bit(in=in[1], load=load, out=out[1]); 36 | * ... 37 | */ 38 | class Register extends BuiltInGate { 39 | /** 40 | * Register is a sequential gate. 41 | */ 42 | static isClocked() { 43 | return true; 44 | } 45 | 46 | init() { 47 | /** 48 | * The 16-bit value of the register. 49 | */ 50 | this._value = 0; 51 | } 52 | 53 | /** 54 | * On rising edge Register updates the value if the 55 | * `load` is set, otherwise -- preserves the state. 56 | */ 57 | clockUp() { 58 | const load = this.getInputPins()[1].getValue(); 59 | 60 | if (load) { 61 | this._value = int16(this.getInputPins()[0].getValue()); 62 | } 63 | } 64 | 65 | /** 66 | * On the falling edge Register propagates 67 | * the value to the output pin. 68 | */ 69 | clockDown() { 70 | this.getOutputPins()[0].setValue(this._value); 71 | } 72 | } 73 | 74 | /** 75 | * Specification of the `Register` gate. 76 | */ 77 | Register.Spec = { 78 | name: 'Register', 79 | 80 | description: [ 81 | '16-bit memory register.', 82 | '', 83 | 'If load[t]=1 then out[t+1] = in[t] else out does not change.', 84 | '', 85 | 'Clock rising edge updates the value from the input,', 86 | 'if the `load` is set; otherwise, preserves the state.', 87 | '', 88 | ` ${colors.bold('↗')} : value = load ? in : value`, 89 | '', 90 | 'Clock falling edge propagates the value to the output:', 91 | '', 92 | ` ${colors.bold('↘')} : out = value`, 93 | ].join('\n'), 94 | 95 | inputPins: [{name: 'in', size: 16}, {name: 'load', size: 1}], 96 | outputPins: [{name: 'out', size: 16}], 97 | 98 | truthTable: TRUTH_TABLE, 99 | }; 100 | 101 | module.exports = Register; 102 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Screen.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const RAM = require('./RAM'); 9 | 10 | const {int16Table, getBitAt, setBitAt} = require('../../../util/numbers'); 11 | 12 | /** 13 | * Canonical truth table for the `Screen` gate. 14 | */ 15 | // prettier-ignore 16 | const TRUTH_TABLE = int16Table([ 17 | {$clock: -0, in: 0b0000000000000000, load: 0, address: 0, out: 0b0000000000000000}, 18 | {$clock: +0, in: 0b0000000000010101, load: 1, address: 0, out: 0b0000000000000000}, 19 | {$clock: -1, in: 0b0000000000000001, load: 0, address: 0, out: 0b0000000000010101}, 20 | {$clock: +1, in: 0b0000000000010101, load: 0, address: 0, out: 0b0000000000010101}, 21 | {$clock: -2, in: 0b0000000000010101, load: 0, address: 0, out: 0b0000000000010101}, 22 | {$clock: +2, in: 0b1101001000010101, load: 1, address: 2, out: 0b0000000000000000}, 23 | {$clock: -3, in: 0b1101001000010101, load: 0, address: 2, out: 0b1101001000010101}, 24 | {$clock: +3, in: 0b1111111111111111, load: 1, address: 8191, out: 0b0000000000000000}, 25 | {$clock: -4, in: 0b0000000000000000, load: 1, address: 8191, out: 0b1111111111111111}, 26 | {$clock: +4, in: 0b0000000000000000, load: 1, address: 8191, out: 0b1111111111111111}, 27 | {$clock: -5, in: 0b0000000000000000, load: 0, address: 8191, out: 0b0000000000000000}, 28 | ]); 29 | 30 | const WORD_SIZE = 16; 31 | const ROWS = 256; 32 | const COLUMNS = 512; 33 | const WORDS_IN_ROW = COLUMNS / WORD_SIZE; 34 | 35 | /** 36 | * A 256 x 512 screen, implemented with 8K registers, each register 37 | * represents 16 pixels. 38 | * 39 | * 256 rows, each row contains 32 words (512 / 16). 40 | * 41 | * The output is the value stored at the memory location specified by address. 42 | * If load=1, loads the input into the memory location specified by address. 43 | */ 44 | class Screen extends RAM { 45 | constructor(options) { 46 | super(Object.assign({size: ROWS * WORDS_IN_ROW}, options)); 47 | } 48 | 49 | /** 50 | * Clears the screen. 51 | */ 52 | clear() { 53 | this.reset(); 54 | return this; 55 | } 56 | 57 | /** 58 | * Returns a value of a pixel at (row, column) position. 59 | * 60 | * word = Screen[32 * row + column / 16] 61 | * bit number: column / 16 62 | */ 63 | getPixelAt(row, column) { 64 | const word = this.getWordForLocation(row, column); 65 | return getBitAt(word, column % WORD_SIZE); 66 | } 67 | 68 | /** 69 | * Sets a value of a pixel at (row, column) coordinates. 70 | */ 71 | setPixelAt(row, column, value) { 72 | const address = this.getAddressForLocation(row, column); 73 | let word = this.getValueAt(address); 74 | word = setBitAt(word, column % WORD_SIZE, value); 75 | this.setValueAt(address, word); 76 | return this; 77 | } 78 | 79 | /** 80 | * Returns a word corresponding to row, and column. 81 | * 82 | * Screen[32 * row + column / 16] 83 | */ 84 | getWordForLocation(row, column) { 85 | return this._storage[this.getAddressForLocation(row, column)]; 86 | } 87 | 88 | /** 89 | * Returns absolute address corresponding to location. 90 | */ 91 | getAddressForLocation(row, column) { 92 | this._checkLocation(row, column); 93 | return WORDS_IN_ROW * row + Math.trunc(column / WORD_SIZE); 94 | } 95 | 96 | /** 97 | * Validates locations. 98 | */ 99 | _checkLocation(row, column) { 100 | if (row < 0 || row > ROWS - 1) { 101 | throw new TypeError( 102 | `Screen: invalid row ${row}, max row is ${ROWS - 1}.` 103 | ); 104 | } 105 | 106 | if (column < 0 || column > COLUMNS - 1) { 107 | throw new TypeError( 108 | `Screen: invalid column ${column}, max column is ${COLUMNS - 1}.` 109 | ); 110 | } 111 | } 112 | } 113 | 114 | /** 115 | * Specification of the `Screen` gate. 116 | */ 117 | Screen.Spec = { 118 | name: 'Screen', 119 | 120 | description: `A 256 x 512 screen, implemented with 8K registers, each register 121 | represents 16 pixels. 122 | 123 | 256 rows, each row contains 32 words (512 / 16). 124 | 125 | The output is the value stored at the memory location specified by address. 126 | If load=1, loads the input into the memory location specified by address.`, 127 | 128 | inputPins: [ 129 | {name: 'in', size: 16}, 130 | {name: 'load', size: 1}, 131 | {name: 'address', size: 13}, 132 | ], 133 | 134 | outputPins: [{name: 'out', size: 16}], 135 | 136 | truthTable: TRUTH_TABLE, 137 | }; 138 | 139 | module.exports = Screen; 140 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/Xor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('../BuiltInGate'); 9 | 10 | /** 11 | * Canonical truth table for the `Xor` gate. 12 | */ 13 | const TRUTH_TABLE = [ 14 | {a: 0, b: 0, out: 0}, 15 | {a: 0, b: 1, out: 1}, 16 | {a: 1, b: 0, out: 1}, 17 | {a: 1, b: 1, out: 0}, 18 | ]; 19 | 20 | /** 21 | * A bitwise 1-bit Xor gate. 22 | */ 23 | class Xor extends BuiltInGate { 24 | /** 25 | * a ^ b 26 | */ 27 | eval() { 28 | const a = this.getInputPins()[0].getValue(); 29 | const b = this.getInputPins()[1].getValue(); 30 | 31 | this.getOutputPins()[0].setValue(a ^ b); 32 | } 33 | } 34 | 35 | /** 36 | * Specification of the `Xor` gate. 37 | */ 38 | Xor.Spec = { 39 | name: 'Xor', 40 | description: 'Implements bitwise 1-bit Xor ^ operation.', 41 | inputPins: ['a', 'b'], 42 | outputPins: ['out'], 43 | truthTable: TRUTH_TABLE, 44 | }; 45 | 46 | module.exports = Xor; 47 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/ALU-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const ALU = require('../ALU'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('ALU', () => { 12 | it('ALU interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(ALU)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/ARegister-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const GateTestUtil = require('../../gate-test-util'); 9 | const ARegister = require('../DRegister'); 10 | 11 | describe('ARegister', () => { 12 | it('ARegister interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(ARegister)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Add16-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Add16 = require('../Add16'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Add16', () => { 12 | it('Add16 interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Add16)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/And-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const And = require('../And'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('And', () => { 12 | it('And interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(And)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/And16-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const And16 = require('../And16'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('And16', () => { 12 | it('And16 interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(And16)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/DFF-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const DFF = require('../DFF'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('DFF', () => { 12 | it('DFF interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(DFF)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/DMux-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const DMux = require('../DMux'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('DMux', () => { 12 | it('DMux interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(DMux)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/DMux4Way-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const DMux4Way = require('../DMux4Way'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('DMux4Way', () => { 12 | it('DMux4Way interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(DMux4Way)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/DMux8Way-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const DMux8Way = require('../DMux8Way'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('DMux8Way', () => { 12 | it('DMux8Way interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(DMux8Way)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/DRegister-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const GateTestUtil = require('../../gate-test-util'); 9 | const DRegister = require('../DRegister'); 10 | 11 | describe('DRegister', () => { 12 | it('DRegister interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(DRegister)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/FullAdder-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const FullAdder = require('../FullAdder'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('FullAdder', () => { 12 | it('FullAdder interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(FullAdder)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/HalfAdder-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const HalfAdder = require('../HalfAdder'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('HalfAdder', () => { 12 | it('HalfAdder interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(HalfAdder)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Inc16-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Inc16 = require('../Inc16'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Inc16', () => { 12 | it('Inc16 interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Inc16)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Keyboard-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Keyboard = require('../Keyboard'); 9 | 10 | describe('Keyboard', () => { 11 | it('Keyboard interface', () => { 12 | const keyboard = Keyboard.defaultFromSpec(); 13 | 14 | Keyboard.emit('key', 'A'); 15 | expect(keyboard.getPinValues()).toEqual({out: 65}); 16 | 17 | Keyboard.emit('key', 'a'); 18 | expect(keyboard.getPinValues()).toEqual({out: 97}); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/MipsAlu-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const MipsAlu = require('../MipsAlu'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('MipsAlu', () => { 12 | it('MipsAlu interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(MipsAlu)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Mux-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Mux = require('../Mux'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Mux', () => { 12 | it('Mux interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Mux)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Mux16-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Mux16 = require('../Mux16'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Mux16', () => { 12 | it('Mux16 interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Mux16)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Mux4Way16-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Mux4Way16 = require('../Mux4Way16'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Mux4Way16', () => { 12 | it('Mux4Way16 interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Mux4Way16)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Mux8Way16-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Mux8Way16 = require('../Mux8Way16'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Mux8Way16', () => { 12 | it('Mux8Way16 interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Mux8Way16)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Nand-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Nand = require('../Nand'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Nand', () => { 12 | it('Nand interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Nand)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Nor-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Nor = require('../Nor'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Nor', () => { 12 | it('Nor interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Nor)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Nor16Way-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Nor16Way = require('../Nor16Way'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Nor16Way', () => { 12 | it('Nor16Way interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Nor16Way)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Not-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Not = require('../Not'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Not', () => { 12 | it('Not interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Not)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Not16-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Not16 = require('../Not16'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Not16', () => { 12 | it('Not16 interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Not16)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Or-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Or = require('../Or'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Or', () => { 12 | it('Or interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Or)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Or16-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Or16 = require('../Or16'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Or16', () => { 12 | it('Or16 interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Or16)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Or8Way-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Or8Way = require('../Or8Way'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Or8Way', () => { 12 | it('Or8Way interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Or8Way)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/PC-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const GateTestUtil = require('../../gate-test-util'); 9 | const PC = require('../PC'); 10 | 11 | const {SystemClock} = require('../../Clock'); 12 | 13 | const {int16Table} = require('../../../../util/numbers'); 14 | 15 | /** 16 | * Testing data. 17 | */ 18 | const data = int16Table([ 19 | {$clock: -0, in: 0, reset: 0, load: 0, inc: 0, out: 0}, 20 | {$clock: +0, in: 0, reset: 0, load: 0, inc: 0, out: 0}, 21 | {$clock: -1, in: 0, reset: 0, load: 0, inc: 0, out: 0}, 22 | {$clock: +1, in: 0, reset: 0, load: 0, inc: 1, out: 0}, 23 | {$clock: -2, in: 0, reset: 0, load: 0, inc: 1, out: 1}, 24 | {$clock: +2, in: -32123, reset: 0, load: 0, inc: 1, out: 1}, 25 | {$clock: -3, in: -32123, reset: 0, load: 0, inc: 1, out: 2}, 26 | {$clock: +3, in: -32123, reset: 0, load: 1, inc: 1, out: 2}, 27 | {$clock: -4, in: -32123, reset: 0, load: 1, inc: 1, out: -32123}, 28 | {$clock: +4, in: -32123, reset: 0, load: 0, inc: 1, out: -32123}, 29 | {$clock: -5, in: -32123, reset: 0, load: 0, inc: 1, out: -32122}, 30 | {$clock: +5, in: -32123, reset: 0, load: 0, inc: 1, out: -32122}, 31 | {$clock: -6, in: -32123, reset: 0, load: 0, inc: 1, out: -32121}, 32 | {$clock: +6, in: 12345, reset: 0, load: 1, inc: 0, out: -32121}, 33 | {$clock: -7, in: 12345, reset: 0, load: 1, inc: 0, out: 12345}, 34 | {$clock: +7, in: 12345, reset: 1, load: 1, inc: 0, out: 12345}, 35 | {$clock: -8, in: 12345, reset: 1, load: 1, inc: 0, out: 0}, 36 | {$clock: +8, in: 12345, reset: 0, load: 1, inc: 1, out: 0}, 37 | {$clock: -9, in: 12345, reset: 0, load: 1, inc: 1, out: 12345}, 38 | {$clock: +9, in: 12345, reset: 1, load: 1, inc: 1, out: 12345}, 39 | {$clock: -10, in: 12345, reset: 1, load: 1, inc: 1, out: 0}, 40 | {$clock: +10, in: 12345, reset: 0, load: 0, inc: 1, out: 0}, 41 | {$clock: -11, in: 12345, reset: 0, load: 0, inc: 1, out: 1}, 42 | {$clock: +11, in: 12345, reset: 1, load: 0, inc: 1, out: 1}, 43 | {$clock: -12, in: 12345, reset: 1, load: 0, inc: 1, out: 0}, 44 | {$clock: +12, in: 0, reset: 0, load: 1, inc: 1, out: 0}, 45 | {$clock: -13, in: 0, reset: 0, load: 1, inc: 1, out: 0}, 46 | {$clock: +13, in: 0, reset: 0, load: 0, inc: 1, out: 0}, 47 | {$clock: -14, in: 0, reset: 0, load: 0, inc: 1, out: 1}, 48 | {$clock: +14, in: 22222, reset: 1, load: 0, inc: 0, out: 1}, 49 | {$clock: -15, in: 22222, reset: 1, load: 0, inc: 0, out: 0}, 50 | ]); 51 | 52 | describe('PC', () => { 53 | it('PC interface', () => { 54 | expect(() => GateTestUtil.autoTestGate(PC)).not.toThrow(); 55 | }); 56 | 57 | it('testing data', () => { 58 | SystemClock.reset(); 59 | 60 | expect(() => 61 | GateTestUtil.testTruthTable(data, PC.defaultFromSpec()) 62 | ).not.toThrow(); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/RAM-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const RAM = require('../RAM'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | const {SystemClock} = require('../../Clock'); 12 | 13 | describe('RAM', () => { 14 | it('RAM interface', () => { 15 | expect(() => GateTestUtil.autoTestGate(RAM)).not.toThrow(); 16 | }); 17 | 18 | it('storage', () => { 19 | SystemClock.reset(); 20 | 21 | // Default is 8 registers. 22 | const ram8Chip = RAM.defaultFromSpec(); 23 | 24 | ram8Chip 25 | .setPinValues({ 26 | in: 0b0000000000010101, 27 | load: 1, 28 | address: 0, 29 | }) 30 | .clockCycle(); 31 | 32 | expect(ram8Chip.getValueAt(0)).toBe(0b0000000000010101); 33 | 34 | ram8Chip 35 | .setPinValues({ 36 | in: 255, 37 | load: 1, 38 | address: 2, 39 | }) 40 | .clockCycle(); 41 | 42 | expect(ram8Chip.getValueAt(2)).toBe(255); 43 | 44 | expect(() => ram8Chip.getValueAt(15)).toThrow( 45 | new TypeError(`Chip "RAM": invalid address 15, the max address is 7.`) 46 | ); 47 | }); 48 | 49 | it('reset', () => { 50 | SystemClock.reset(); 51 | 52 | const ram8Chip = RAM.defaultFromSpec(); 53 | 54 | ram8Chip 55 | .setPinValues({ 56 | in: 0b0000000000010101, 57 | load: 1, 58 | address: 0, 59 | }) 60 | .clockCycle(); 61 | 62 | ram8Chip.reset(); 63 | 64 | expect(ram8Chip.getValueAt(0)).toBe(0); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/RAM16K-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const RAM16K = require('../RAM16K'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | const {SystemClock} = require('../../Clock'); 12 | 13 | describe('RAM16K', () => { 14 | it('RAM16K interface', () => { 15 | expect(() => GateTestUtil.autoTestGate(RAM16K)).not.toThrow(); 16 | }); 17 | 18 | it('storage', () => { 19 | SystemClock.reset(); 20 | 21 | const ram16KChip = new RAM16K(RAM16K.Spec); 22 | 23 | ram16KChip 24 | .setPinValues({ 25 | in: 0b0000000000010101, 26 | load: 1, 27 | address: 0, 28 | }) 29 | .clockCycle(); 30 | 31 | expect(ram16KChip.getValueAt(0)).toBe(0b0000000000010101); 32 | 33 | ram16KChip 34 | .setPinValues({ 35 | in: 255, 36 | load: 1, 37 | address: 16383, 38 | }) 39 | .clockCycle(); 40 | 41 | expect(ram16KChip.getValueAt(16383)).toBe(255); 42 | 43 | expect(() => ram16KChip.getValueAt(16387)).toThrow( 44 | new TypeError( 45 | `Chip "RAM16K": invalid address 16387, the max address is 16383.` 46 | ) 47 | ); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/RAM4K-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const RAM4K = require('../RAM4K'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | const {SystemClock} = require('../../Clock'); 12 | 13 | describe('RAM4K', () => { 14 | it('RAM4K interface', () => { 15 | expect(() => GateTestUtil.autoTestGate(RAM4K)).not.toThrow(); 16 | }); 17 | 18 | it('storage', () => { 19 | SystemClock.reset(); 20 | 21 | const ram4KChip = new RAM4K(RAM4K.Spec); 22 | 23 | ram4KChip 24 | .setPinValues({ 25 | in: 0b0000000000010101, 26 | load: 1, 27 | address: 0, 28 | }) 29 | .clockCycle(); 30 | 31 | expect(ram4KChip.getValueAt(0)).toBe(0b0000000000010101); 32 | 33 | ram4KChip 34 | .setPinValues({ 35 | in: 255, 36 | load: 1, 37 | address: 4095, 38 | }) 39 | .clockCycle(); 40 | 41 | expect(ram4KChip.getValueAt(4095)).toBe(255); 42 | 43 | expect(() => ram4KChip.getValueAt(4099)).toThrow( 44 | new TypeError( 45 | `Chip "RAM4K": invalid address 4099, the max address is 4095.` 46 | ) 47 | ); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/RAM512-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const RAM512 = require('../RAM512'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | const {SystemClock} = require('../../Clock'); 12 | 13 | describe('RAM512', () => { 14 | it('RAM512 interface', () => { 15 | expect(() => GateTestUtil.autoTestGate(RAM512)).not.toThrow(); 16 | }); 17 | 18 | it('storage', () => { 19 | SystemClock.reset(); 20 | 21 | const ram512Chip = new RAM512(RAM512.Spec); 22 | 23 | ram512Chip 24 | .setPinValues({ 25 | in: 0b0000000000010101, 26 | load: 1, 27 | address: 0, 28 | }) 29 | .clockCycle(); 30 | 31 | expect(ram512Chip.getValueAt(0)).toBe(0b0000000000010101); 32 | 33 | ram512Chip 34 | .setPinValues({ 35 | in: 255, 36 | load: 1, 37 | address: 511, 38 | }) 39 | .clockCycle(); 40 | 41 | expect(ram512Chip.getValueAt(511)).toBe(255); 42 | 43 | expect(() => ram512Chip.getValueAt(515)).toThrow( 44 | new TypeError( 45 | `Chip "RAM512": invalid address 515, the max address is 511.` 46 | ) 47 | ); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/RAM64-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const RAM64 = require('../RAM64'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | const {SystemClock} = require('../../Clock'); 12 | 13 | describe('RAM64', () => { 14 | it('RAM64 interface', () => { 15 | expect(() => GateTestUtil.autoTestGate(RAM64)).not.toThrow(); 16 | }); 17 | 18 | it('storage', () => { 19 | SystemClock.reset(); 20 | 21 | const ram64Chip = new RAM64(RAM64.Spec); 22 | 23 | ram64Chip 24 | .setPinValues({ 25 | in: 0b0000000000010101, 26 | load: 1, 27 | address: 0, 28 | }) 29 | .clockCycle(); 30 | 31 | expect(ram64Chip.getValueAt(0)).toBe(0b0000000000010101); 32 | 33 | ram64Chip 34 | .setPinValues({ 35 | in: 255, 36 | load: 1, 37 | address: 63, 38 | }) 39 | .clockCycle(); 40 | 41 | expect(ram64Chip.getValueAt(63)).toBe(255); 42 | 43 | expect(() => ram64Chip.getValueAt(67)).toThrow( 44 | new TypeError(`Chip "RAM64": invalid address 67, the max address is 63.`) 45 | ); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/RAM8-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const RAM8 = require('../RAM8'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | const {SystemClock} = require('../../Clock'); 12 | 13 | describe('RAM8', () => { 14 | it('RAM8 interface', () => { 15 | expect(() => GateTestUtil.autoTestGate(RAM8)).not.toThrow(); 16 | }); 17 | 18 | it('storage', () => { 19 | SystemClock.reset(); 20 | 21 | const ram8Chip = new RAM8(RAM8.Spec); 22 | 23 | ram8Chip 24 | .setPinValues({ 25 | in: 0b0000000000010101, 26 | load: 1, 27 | address: 0, 28 | }) 29 | .clockCycle(); 30 | 31 | expect(ram8Chip.getValueAt(0)).toBe(0b0000000000010101); 32 | 33 | ram8Chip 34 | .setPinValues({ 35 | in: 255, 36 | load: 1, 37 | address: 2, 38 | }) 39 | .clockCycle(); 40 | 41 | expect(ram8Chip.getValueAt(2)).toBe(255); 42 | 43 | expect(() => ram8Chip.getValueAt(15)).toThrow( 44 | new TypeError(`Chip "RAM8": invalid address 15, the max address is 7.`) 45 | ); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/Xor-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const Xor = require('../Xor'); 9 | const GateTestUtil = require('../../gate-test-util'); 10 | 11 | describe('Xor', () => { 12 | it('Xor interface', () => { 13 | expect(() => GateTestUtil.autoTestGate(Xor)).not.toThrow(); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/__tests__/all-list-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const fs = require('fs'); 9 | const path = require('path'); 10 | 11 | const BuiltInGates = require('../index'); 12 | 13 | const builtinGatesFromDirectory = fs 14 | .readdirSync(__dirname + '/../') 15 | .filter(file => /^[A-Z]/.test(file)) 16 | .map(file => path.basename(file, '.js')) 17 | .sort(); 18 | 19 | describe('list all builtins', () => { 20 | it('checks list', () => { 21 | // Make sure to sync the gates in the directory with this list. 22 | // We do not use `fs` in the actual implementation to support 23 | // browser environment. 24 | expect(builtinGatesFromDirectory).toEqual(Object.keys(BuiltInGates).sort()); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/emulator/hardware/builtin-gates/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | /** 9 | * A map from gate name to gate class. 10 | */ 11 | const BuiltInGates = {}; 12 | 13 | /** 14 | * A list of exposed built-in gates. 15 | */ 16 | [ 17 | 'ALU', 18 | 'ARegister', 19 | 'Add16', 20 | 'And', 21 | 'And16', 22 | 'Bit', 23 | 'DFF', 24 | 'DMux', 25 | 'DMux4Way', 26 | 'DMux8Way', 27 | 'DRegister', 28 | 'FullAdder', 29 | 'HalfAdder', 30 | 'Inc16', 31 | 'Keyboard', 32 | 'MipsAlu', 33 | 'Mux', 34 | 'Mux16', 35 | 'Mux4Way16', 36 | 'Mux8Way16', 37 | 'Nand', 38 | 'Nor', 39 | 'Nor16Way', 40 | 'Not', 41 | 'Not16', 42 | 'Or', 43 | 'Or16', 44 | 'Or8Way', 45 | 'PC', 46 | 'RAM', 47 | 'RAM16K', 48 | 'RAM4K', 49 | 'RAM512', 50 | 'RAM64', 51 | 'RAM8', 52 | 'Register', 53 | 'Screen', 54 | 'Xor', 55 | ].forEach(gate => (BuiltInGates[gate] = require('./' + gate))); 56 | 57 | module.exports = BuiltInGates; 58 | -------------------------------------------------------------------------------- /src/emulator/hardware/gate-test-util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const assert = require('assert'); 9 | const Pin = require('./Pin'); 10 | 11 | const {SystemClock} = require('./Clock'); 12 | 13 | /** 14 | * Evaluates the gate logic on the truth table input. 15 | * 16 | * Example for `And` gate: 17 | * 18 | * [ 19 | * {a: 0, b: 0, out: 0}, 20 | * {a: 0, b: 1, out: 0}, 21 | * {a: 1, b: 0, out: 0}, 22 | * {a: 1, b: 1, out: 1}, 23 | * ] 24 | * 25 | * Throws if some `out` is not evaluate to the expected value. 26 | */ 27 | function testTruthTable(table, gate) { 28 | SystemClock.reset(); 29 | const {result} = gate.execOnData(table); 30 | assert.deepEqual(table, result); 31 | } 32 | 33 | /** 34 | * Automatically tests a gate based on it spec. 35 | */ 36 | function autoTestGate(GateClass) { 37 | const spec = GateClass.Spec; 38 | 39 | expect(spec.name).toBe(GateClass.name); 40 | 41 | const createPins = pinNames => { 42 | return pinNames.map(pinName => { 43 | let name, 44 | size = 1; 45 | if (typeof pinName === 'string') { 46 | name = pinName; 47 | } else { 48 | ({name, size} = pinName); 49 | } 50 | return new Pin({name, size}); 51 | }); 52 | }; 53 | 54 | const inputPins = createPins(spec.inputPins); 55 | const outputPins = createPins(spec.outputPins); 56 | 57 | const gate = new GateClass({ 58 | inputPins, 59 | outputPins, 60 | }); 61 | 62 | expect(gate.getName()).toBe(GateClass.name); 63 | expect(gate.getInputPins()).toEqual(inputPins); 64 | expect(gate.getOutputPins()).toEqual(outputPins); 65 | 66 | testTruthTable(spec.truthTable, gate); 67 | } 68 | 69 | module.exports = { 70 | autoTestGate, 71 | testTruthTable, 72 | }; 73 | -------------------------------------------------------------------------------- /src/emulator/hardware/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const BuiltInGate = require('./BuiltInGate'); 9 | const BuiltInGates = require('./builtin-gates'); 10 | const Clock = require('./Clock'); 11 | const CompositeGate = require('./CompositeGate'); 12 | const Gate = require('./Gate'); 13 | const HDLClassFactory = require('./HDLClassFactory'); 14 | const Pin = require('./Pin'); 15 | const ScriptInterpreter = require('./scripting/ScriptInterpreter'); 16 | 17 | /** 18 | * Simulates hardware chips (gates) evaluation. 19 | */ 20 | const HardwareEmulator = { 21 | /** 22 | * Expose `Clock` class. 23 | */ 24 | Clock, 25 | 26 | /** 27 | * Expose `Gate` class. 28 | */ 29 | Gate, 30 | 31 | /** 32 | * Expose `Pin` class. 33 | */ 34 | Pin, 35 | 36 | /** 37 | * Expose `BuiltInGate` class. 38 | */ 39 | BuiltInGate, 40 | 41 | /** 42 | * Expose `CompositeGate` class. 43 | */ 44 | CompositeGate, 45 | 46 | /** 47 | * Expose `HDLClassFactory` object. 48 | */ 49 | HDLClassFactory, 50 | 51 | /** 52 | * Expose a map of all built-in gates. 53 | */ 54 | BuiltInGates, 55 | 56 | /** 57 | * Script interpreter module. 58 | */ 59 | ScriptInterpreter, 60 | }; 61 | 62 | module.exports = HardwareEmulator; 63 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/__tests__/ScriptInterpreter-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const ScriptInterpreter = require('../ScriptInterpreter'); 9 | const fs = require('fs'); 10 | const os = require('os'); 11 | 12 | const EXAMPLES_DIR = __dirname + '/../examples'; 13 | 14 | const expectedAndOut = [ 15 | '| a | b | out |', 16 | '| 0 | 0 | 0 |', 17 | '| 0 | 1 | 0 |', 18 | '| 1 | 0 | 0 |', 19 | '| 1 | 1 | 1 |', 20 | '', 21 | ].join('\n'); 22 | 23 | describe('script-interpreter', () => { 24 | it('full run', () => { 25 | const script = new ScriptInterpreter({ 26 | file: EXAMPLES_DIR + '/And.tst', 27 | }); 28 | 29 | script.exec(); 30 | 31 | const actualOut = fs.readFileSync(EXAMPLES_DIR + '/And.out', 'utf-8'); 32 | expect(actualOut).toBe(expectedAndOut); 33 | }); 34 | 35 | it('nextStep', () => { 36 | const script = new ScriptInterpreter({ 37 | file: EXAMPLES_DIR + '/And.tst', 38 | }); 39 | 40 | // Total And.tst has 5 steps (groups of commands): 41 | for (let i = 0; i < 5; i++) { 42 | script.nextStep(); 43 | } 44 | 45 | const actualOut = fs.readFileSync(EXAMPLES_DIR + '/And.out', 'utf-8'); 46 | expect(actualOut).toBe(expectedAndOut); 47 | }); 48 | 49 | it('nextCommand', () => { 50 | const script = new ScriptInterpreter({ 51 | file: EXAMPLES_DIR + '/And.tst', 52 | }); 53 | 54 | // Total And.tst has 20 commands: 55 | for (let i = 0; i < 20; i++) { 56 | script.nextCommand(); 57 | } 58 | 59 | const actualOut = fs.readFileSync(EXAMPLES_DIR + '/And.out', 'utf-8'); 60 | expect(actualOut).toBe(expectedAndOut); 61 | }); 62 | 63 | it('repeat', () => { 64 | const workingDirectory = os.tmpdir(); 65 | 66 | const script = new ScriptInterpreter({ 67 | script: ` 68 | load And, 69 | output-file And.out, 70 | output-list a%B3.1.3 b%B3.1.3 out%B3.1.3; 71 | 72 | repeat 2 { 73 | set a 0, set b 0, eval, output; 74 | set a 1, set b 1, eval, output; 75 | } 76 | `, 77 | workingDirectory, 78 | }); 79 | 80 | script.exec(); 81 | 82 | const expectedOut = [ 83 | '| a | b | out |', 84 | '| 0 | 0 | 0 |', 85 | '| 1 | 1 | 1 |', 86 | '| 0 | 0 | 0 |', 87 | '| 1 | 1 | 1 |', 88 | '', 89 | ].join('\n'); 90 | 91 | const actualOut = fs.readFileSync(workingDirectory + '/And.out', 'utf-8'); 92 | expect(actualOut).toBe(expectedOut); 93 | }); 94 | 95 | it('while', () => { 96 | const workingDirectory = os.tmpdir(); 97 | 98 | const script = new ScriptInterpreter({ 99 | script: ` 100 | load And16, 101 | output-file And.out, 102 | output-list a%B1.16.1 b%B1.16.1 out%B1.16.1; 103 | 104 | while a[1] <> 1 { 105 | set a[1] 1, set b[1] 0, eval, output; 106 | set a[2] 1, set b[1] 1, eval, output; 107 | } 108 | `, 109 | workingDirectory, 110 | }); 111 | 112 | script.exec(); 113 | 114 | const expectedOut = [ 115 | '| a | b | out |', 116 | '| 0000000000000010 | 0000000000000000 | 0000000000000000 |', 117 | '| 0000000000000110 | 0000000000000010 | 0000000000000010 |', 118 | '', 119 | ].join('\n'); 120 | 121 | const actualOut = fs.readFileSync(workingDirectory + '/And.out', 'utf-8'); 122 | expect(actualOut).toBe(expectedOut); 123 | }); 124 | 125 | it('virtual directory', () => { 126 | const virtualDirectory = { 127 | // Gate file: 128 | 'MyGate.hdl': ` 129 | CHIP MyAnd { 130 | IN x, y; 131 | OUT z; 132 | 133 | PARTS: 134 | 135 | Nand(a=x, b=y, out=n); 136 | Nand(a=n, b=n, out=z); 137 | } 138 | `, 139 | 140 | // Script file: 141 | 'MyGate.tst': ` 142 | load MyGate.hdl, 143 | output-file MyGate.out, 144 | compare-to MyGate.cmp, 145 | output-list x%B3.1.3 y%B3.1.3 n%B3.1.3 z%B3.1.3; 146 | 147 | set x 1, set y 0, eval, output; 148 | set x 1, set y 1, eval, output; 149 | `, 150 | 151 | 'MyGate.cmp': [ 152 | '| x | y | n | z |', 153 | '| 1 | 0 | 1 | 0 |', 154 | '| 1 | 1 | 0 | 1 |', 155 | '', 156 | ].join('\n'), 157 | }; 158 | 159 | const script = new ScriptInterpreter({ 160 | script: virtualDirectory['MyGate.tst'], 161 | workingDirectory: virtualDirectory, 162 | }); 163 | 164 | script.exec(); 165 | 166 | expect(virtualDirectory['MyGate.out']).toBe(virtualDirectory['MyGate.cmp']); 167 | }); 168 | }); 169 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/And.cmp: -------------------------------------------------------------------------------- 1 | | a | b | out | 2 | | 0 | 0 | 0 | 3 | | 0 | 1 | 0 | 4 | | 1 | 0 | 0 | 5 | | 1 | 1 | 1 | 6 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/And.out: -------------------------------------------------------------------------------- 1 | | a | b | out | 2 | | 0 | 0 | 0 | 3 | | 0 | 1 | 0 | 4 | | 1 | 0 | 0 | 5 | | 1 | 1 | 1 | 6 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/And.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | 5 | load And.hdl, 6 | output-file And.out, 7 | compare-to And.cmp, 8 | output-list a%B3.1.3 b%B3.1.3 out%B3.1.3; 9 | 10 | set a 0, 11 | set b 0, 12 | eval, 13 | output; 14 | 15 | set a 0, 16 | set b 1, 17 | eval, 18 | output; 19 | 20 | set a 1, 21 | set b 0, 22 | eval, 23 | output; 24 | 25 | set a 1, 26 | set b 1, 27 | eval, 28 | output; -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/Example.tst: -------------------------------------------------------------------------------- 1 | /** 2 | * Examle script file. Used for unit testing. 3 | */ 4 | 5 | load MyGate.hdl, 6 | output-file MyGate.out, 7 | compare-to MyGate.cmp, 8 | output-list a%B3.1.3 b%X5.2.1 out%D1.1.1 RAM[16]%X5.5.5 z[]%S1.3.1; 9 | 10 | echo "Hello world!", 11 | echo 'Single quotes', 12 | clear-echo; 13 | 14 | set RAM[16] %XF5F0, 15 | set a -5, 16 | set b %B101, 17 | set out %D15, 18 | eval, 19 | output; 20 | 21 | repeat 5 { 22 | eval, ticktock; 23 | } 24 | 25 | while a <> 15 { 26 | tick, tock; 27 | } 28 | 29 | while b > 0 { set b -1, eval; } 30 | while b >= 0 { tick, } 31 | while b <= 0 { tock; } 32 | while b = 15 { set b 10, eval, } -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/.gitignore: -------------------------------------------------------------------------------- 1 | **/*.out -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/And.cmp: -------------------------------------------------------------------------------- 1 | | a | b | out | 2 | | 0 | 0 | 0 | 3 | | 0 | 1 | 0 | 4 | | 1 | 0 | 0 | 5 | | 1 | 1 | 1 | 6 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/And.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/And.tst 5 | 6 | load And.hdl, 7 | output-file And.out, 8 | compare-to And.cmp, 9 | output-list a%B3.1.3 b%B3.1.3 out%B3.1.3; 10 | 11 | set a 0, 12 | set b 0, 13 | eval, 14 | output; 15 | 16 | set a 0, 17 | set b 1, 18 | eval, 19 | output; 20 | 21 | set a 1, 22 | set b 0, 23 | eval, 24 | output; 25 | 26 | set a 1, 27 | set b 1, 28 | eval, 29 | output; 30 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/And16.cmp: -------------------------------------------------------------------------------- 1 | | a | b | out | 2 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 3 | | 0000000000000000 | 1111111111111111 | 0000000000000000 | 4 | | 1111111111111111 | 1111111111111111 | 1111111111111111 | 5 | | 1010101010101010 | 0101010101010101 | 0000000000000000 | 6 | | 0011110011000011 | 0000111111110000 | 0000110011000000 | 7 | | 0001001000110100 | 1001100001110110 | 0001000000110100 | 8 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/And16.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/And16.tst 5 | 6 | load And16.hdl, 7 | output-file And16.out, 8 | compare-to And16.cmp, 9 | output-list a%B1.16.1 b%B1.16.1 out%B1.16.1; 10 | 11 | set a %B0000000000000000, 12 | set b %B0000000000000000, 13 | eval, 14 | output; 15 | 16 | set a %B0000000000000000, 17 | set b %B1111111111111111, 18 | eval, 19 | output; 20 | 21 | set a %B1111111111111111, 22 | set b %B1111111111111111, 23 | eval, 24 | output; 25 | 26 | set a %B1010101010101010, 27 | set b %B0101010101010101, 28 | eval, 29 | output; 30 | 31 | set a %B0011110011000011, 32 | set b %B0000111111110000, 33 | eval, 34 | output; 35 | 36 | set a %B0001001000110100, 37 | set b %B1001100001110110, 38 | eval, 39 | output; -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/DMux.cmp: -------------------------------------------------------------------------------- 1 | | in | sel | a | b | 2 | | 0 | 0 | 0 | 0 | 3 | | 0 | 1 | 0 | 0 | 4 | | 1 | 0 | 1 | 0 | 5 | | 1 | 1 | 0 | 1 | 6 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/DMux.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/DMux.tst 5 | 6 | load DMux.hdl, 7 | output-file DMux.out, 8 | compare-to DMux.cmp, 9 | output-list in%B3.1.3 sel%B3.1.3 a%B3.1.3 b%B3.1.3; 10 | 11 | set in 0, 12 | set sel 0, 13 | eval, 14 | output; 15 | 16 | set sel 1, 17 | eval, 18 | output; 19 | 20 | set in 1, 21 | set sel 0, 22 | eval, 23 | output; 24 | 25 | set sel 1, 26 | eval, 27 | output; 28 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/DMux4Way.cmp: -------------------------------------------------------------------------------- 1 | | in | sel | a | b | c | d | 2 | | 0 | 00 | 0 | 0 | 0 | 0 | 3 | | 0 | 01 | 0 | 0 | 0 | 0 | 4 | | 0 | 10 | 0 | 0 | 0 | 0 | 5 | | 0 | 11 | 0 | 0 | 0 | 0 | 6 | | 1 | 00 | 1 | 0 | 0 | 0 | 7 | | 1 | 01 | 0 | 1 | 0 | 0 | 8 | | 1 | 10 | 0 | 0 | 1 | 0 | 9 | | 1 | 11 | 0 | 0 | 0 | 1 | 10 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/DMux4Way.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/DMux4Way.tst 5 | 6 | load DMux4Way.hdl, 7 | output-file DMux4Way.out, 8 | compare-to DMux4Way.cmp, 9 | 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; 10 | 11 | set in 0, 12 | set sel %B00, 13 | eval, 14 | output; 15 | 16 | set sel %B01, 17 | eval, 18 | output; 19 | 20 | set sel %B10, 21 | eval, 22 | output; 23 | 24 | set sel %B11, 25 | eval, 26 | output; 27 | 28 | set in 1, 29 | set sel %B00, 30 | eval, 31 | output; 32 | 33 | set sel %B01, 34 | eval, 35 | output; 36 | 37 | set sel %B10, 38 | eval, 39 | output; 40 | 41 | set sel %B11, 42 | eval, 43 | output; 44 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/DMux8Way.cmp: -------------------------------------------------------------------------------- 1 | | in | sel | a | b | c | d | e | f | g | h | 2 | | 0 | 000 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | | 0 | 001 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 4 | | 0 | 010 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 5 | | 0 | 011 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 6 | | 0 | 100 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 7 | | 0 | 101 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 8 | | 0 | 110 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 9 | | 0 | 111 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 10 | | 1 | 000 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 11 | | 1 | 001 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 12 | | 1 | 010 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 13 | | 1 | 011 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 14 | | 1 | 100 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 15 | | 1 | 101 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 16 | | 1 | 110 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 17 | | 1 | 111 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 18 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/DMux8Way.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/DMux8Way.tst 5 | 6 | load DMux8Way.hdl, 7 | output-file DMux8Way.out, 8 | compare-to DMux8Way.cmp, 9 | 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; 10 | 11 | set in 0, 12 | set sel %B000, 13 | eval, 14 | output; 15 | 16 | set sel %B001, 17 | eval, 18 | output; 19 | 20 | set sel %B010, 21 | eval, 22 | output; 23 | 24 | set sel %B011, 25 | eval, 26 | output; 27 | 28 | set sel %B100, 29 | eval, 30 | output; 31 | 32 | set sel %B101, 33 | eval, 34 | output; 35 | 36 | set sel %B110, 37 | eval, 38 | output; 39 | 40 | set sel %B111, 41 | eval, 42 | output; 43 | 44 | set in 1, 45 | set sel %B000, 46 | eval, 47 | output; 48 | 49 | set sel %B001, 50 | eval, 51 | output; 52 | 53 | set sel %B010, 54 | eval, 55 | output; 56 | 57 | set sel %B011, 58 | eval, 59 | output; 60 | 61 | set sel %B100, 62 | eval, 63 | output; 64 | 65 | set sel %B101, 66 | eval, 67 | output; 68 | 69 | set sel %B110, 70 | eval, 71 | output; 72 | 73 | set sel %B111, 74 | eval, 75 | output; 76 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Mux.cmp: -------------------------------------------------------------------------------- 1 | | a | b | sel | out | 2 | | 0 | 0 | 0 | 0 | 3 | | 0 | 0 | 1 | 0 | 4 | | 0 | 1 | 0 | 0 | 5 | | 0 | 1 | 1 | 1 | 6 | | 1 | 0 | 0 | 1 | 7 | | 1 | 0 | 1 | 0 | 8 | | 1 | 1 | 0 | 1 | 9 | | 1 | 1 | 1 | 1 | 10 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Mux.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/Mux.tst 5 | 6 | load Mux.hdl, 7 | output-file Mux.out, 8 | compare-to Mux.cmp, 9 | output-list a%B3.1.3 b%B3.1.3 sel%B3.1.3 out%B3.1.3; 10 | 11 | set a 0, 12 | set b 0, 13 | set sel 0, 14 | eval, 15 | output; 16 | 17 | set sel 1, 18 | eval, 19 | output; 20 | 21 | set a 0, 22 | set b 1, 23 | set sel 0, 24 | eval, 25 | output; 26 | 27 | set sel 1, 28 | eval, 29 | output; 30 | 31 | set a 1, 32 | set b 0, 33 | set sel 0, 34 | eval, 35 | output; 36 | 37 | set sel 1, 38 | eval, 39 | output; 40 | 41 | set a 1, 42 | set b 1, 43 | set sel 0, 44 | eval, 45 | output; 46 | 47 | set sel 1, 48 | eval, 49 | output; 50 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Mux16.cmp: -------------------------------------------------------------------------------- 1 | | a | b | sel | out | 2 | | 0000000000000000 | 0000000000000000 | 0 | 0000000000000000 | 3 | | 0000000000000000 | 0000000000000000 | 1 | 0000000000000000 | 4 | | 0000000000000000 | 0001001000110100 | 0 | 0000000000000000 | 5 | | 0000000000000000 | 0001001000110100 | 1 | 0001001000110100 | 6 | | 1001100001110110 | 0000000000000000 | 0 | 1001100001110110 | 7 | | 1001100001110110 | 0000000000000000 | 1 | 0000000000000000 | 8 | | 1010101010101010 | 0101010101010101 | 0 | 1010101010101010 | 9 | | 1010101010101010 | 0101010101010101 | 1 | 0101010101010101 | 10 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Mux16.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/Mux16.tst 5 | 6 | load Mux16.hdl, 7 | output-file Mux16.out, 8 | compare-to Mux16.cmp, 9 | output-list a%B1.16.1 b%B1.16.1 sel%D2.1.2 out%B1.16.1; 10 | 11 | set a 0, 12 | set b 0, 13 | set sel 0, 14 | eval, 15 | output; 16 | 17 | set sel 1, 18 | eval, 19 | output; 20 | 21 | set a %B0000000000000000, 22 | set b %B0001001000110100, 23 | set sel 0, 24 | eval, 25 | output; 26 | 27 | set sel 1, 28 | eval, 29 | output; 30 | 31 | set a %B1001100001110110, 32 | set b %B0000000000000000, 33 | set sel 0, 34 | eval, 35 | output; 36 | 37 | set sel 1, 38 | eval, 39 | output; 40 | 41 | set a %B1010101010101010, 42 | set b %B0101010101010101, 43 | set sel 0, 44 | eval, 45 | output; 46 | 47 | set sel 1, 48 | eval, 49 | output; -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Mux4Way16.cmp: -------------------------------------------------------------------------------- 1 | | a | b | c | d | sel | out | 2 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 00 | 0000000000000000 | 3 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 01 | 0000000000000000 | 4 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 10 | 0000000000000000 | 5 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 11 | 0000000000000000 | 6 | | 0001001000110100 | 1001100001110110 | 1010101010101010 | 0101010101010101 | 00 | 0001001000110100 | 7 | | 0001001000110100 | 1001100001110110 | 1010101010101010 | 0101010101010101 | 01 | 1001100001110110 | 8 | | 0001001000110100 | 1001100001110110 | 1010101010101010 | 0101010101010101 | 10 | 1010101010101010 | 9 | | 0001001000110100 | 1001100001110110 | 1010101010101010 | 0101010101010101 | 11 | 0101010101010101 | 10 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Mux4Way16.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/Mux4Way16.tst 5 | 6 | load Mux4Way16.hdl, 7 | output-file Mux4Way16.out, 8 | compare-to Mux4Way16.cmp, 9 | 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; 10 | 11 | set a 0, 12 | set b 0, 13 | set c 0, 14 | set d 0, 15 | set sel 0, 16 | eval, 17 | output; 18 | 19 | set sel 1, 20 | eval, 21 | output; 22 | 23 | set sel 2, 24 | eval, 25 | output; 26 | 27 | set sel 3, 28 | eval, 29 | output; 30 | 31 | set a %B0001001000110100, 32 | set b %B1001100001110110, 33 | set c %B1010101010101010, 34 | set d %B0101010101010101, 35 | set sel 0, 36 | eval, 37 | output; 38 | 39 | set sel 1, 40 | eval, 41 | output; 42 | 43 | set sel 2, 44 | eval, 45 | output; 46 | 47 | set sel 3, 48 | eval, 49 | output; 50 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Mux8Way16.cmp: -------------------------------------------------------------------------------- 1 | | a | b | c | d | e | f | g | h | sel | out | 2 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 000 | 0000000000000000 | 3 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 001 | 0000000000000000 | 4 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 010 | 0000000000000000 | 5 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 011 | 0000000000000000 | 6 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 100 | 0000000000000000 | 7 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 101 | 0000000000000000 | 8 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 110 | 0000000000000000 | 9 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 0000000000000000 | 111 | 0000000000000000 | 10 | | 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 000 | 0001001000110100 | 11 | | 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 001 | 0010001101000101 | 12 | | 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 010 | 0011010001010110 | 13 | | 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 011 | 0100010101100111 | 14 | | 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 100 | 0101011001111000 | 15 | | 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 101 | 0110011110001001 | 16 | | 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 110 | 0111100010011010 | 17 | | 0001001000110100 | 0010001101000101 | 0011010001010110 | 0100010101100111 | 0101011001111000 | 0110011110001001 | 0111100010011010 | 1000100110101011 | 111 | 1000100110101011 | 18 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Mux8Way16.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/Mux8Way16.tst 5 | 6 | load Mux8Way16.hdl, 7 | output-file Mux8Way16.out, 8 | compare-to Mux8Way16.cmp, 9 | 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; 10 | 11 | set a 0, 12 | set b 0, 13 | set c 0, 14 | set d 0, 15 | set e 0, 16 | set f 0, 17 | set g 0, 18 | set h 0, 19 | set sel 0, 20 | eval, 21 | output; 22 | 23 | set sel 1, 24 | eval, 25 | output; 26 | 27 | set sel 2, 28 | eval, 29 | output; 30 | 31 | set sel 3, 32 | eval, 33 | output; 34 | 35 | set sel 4, 36 | eval, 37 | output; 38 | 39 | set sel 5, 40 | eval, 41 | output; 42 | 43 | set sel 6, 44 | eval, 45 | output; 46 | 47 | set sel 7, 48 | eval, 49 | output; 50 | 51 | set a %B0001001000110100, 52 | set b %B0010001101000101, 53 | set c %B0011010001010110, 54 | set d %B0100010101100111, 55 | set e %B0101011001111000, 56 | set f %B0110011110001001, 57 | set g %B0111100010011010, 58 | set h %B1000100110101011, 59 | set sel 0, 60 | eval, 61 | output; 62 | 63 | set sel 1, 64 | eval, 65 | output; 66 | 67 | set sel 2, 68 | eval, 69 | output; 70 | 71 | set sel 3, 72 | eval, 73 | output; 74 | 75 | set sel 4, 76 | eval, 77 | output; 78 | 79 | set sel 5, 80 | eval, 81 | output; 82 | 83 | set sel 6, 84 | eval, 85 | output; 86 | 87 | set sel 7, 88 | eval, 89 | output; 90 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Not.cmp: -------------------------------------------------------------------------------- 1 | | in | out | 2 | | 0 | 1 | 3 | | 1 | 0 | 4 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Not.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/Not.tst 5 | 6 | load Not.hdl, 7 | output-file Not.out, 8 | compare-to Not.cmp, 9 | output-list in%B3.1.3 out%B3.1.3; 10 | 11 | set in 0, 12 | eval, 13 | output; 14 | 15 | set in 1, 16 | eval, 17 | output; 18 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Not16.cmp: -------------------------------------------------------------------------------- 1 | | in | out | 2 | | 0000000000000000 | 1111111111111111 | 3 | | 1111111111111111 | 0000000000000000 | 4 | | 1010101010101010 | 0101010101010101 | 5 | | 0011110011000011 | 1100001100111100 | 6 | | 0001001000110100 | 1110110111001011 | 7 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Not16.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/Not16.tst 5 | 6 | load Not16.hdl, 7 | output-file Not16.out, 8 | compare-to Not16.cmp, 9 | output-list in%B1.16.1 out%B1.16.1; 10 | 11 | set in %B0000000000000000, 12 | eval, 13 | output; 14 | 15 | set in %B1111111111111111, 16 | eval, 17 | output; 18 | 19 | set in %B1010101010101010, 20 | eval, 21 | output; 22 | 23 | set in %B0011110011000011, 24 | eval, 25 | output; 26 | 27 | set in %B0001001000110100, 28 | eval, 29 | output; -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Or.cmp: -------------------------------------------------------------------------------- 1 | | a | b | out | 2 | | 0 | 0 | 0 | 3 | | 0 | 1 | 1 | 4 | | 1 | 0 | 1 | 5 | | 1 | 1 | 1 | 6 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Or.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/Or.tst 5 | 6 | load Or.hdl, 7 | output-file Or.out, 8 | compare-to Or.cmp, 9 | output-list a%B3.1.3 b%B3.1.3 out%B3.1.3; 10 | 11 | set a 0, 12 | set b 0, 13 | eval, 14 | output; 15 | 16 | set a 0, 17 | set b 1, 18 | eval, 19 | output; 20 | 21 | set a 1, 22 | set b 0, 23 | eval, 24 | output; 25 | 26 | set a 1, 27 | set b 1, 28 | eval, 29 | output; 30 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Or16.cmp: -------------------------------------------------------------------------------- 1 | | a | b | out | 2 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 3 | | 0000000000000000 | 1111111111111111 | 1111111111111111 | 4 | | 1111111111111111 | 1111111111111111 | 1111111111111111 | 5 | | 1010101010101010 | 0101010101010101 | 1111111111111111 | 6 | | 0011110011000011 | 0000111111110000 | 0011111111110011 | 7 | | 0001001000110100 | 1001100001110110 | 1001101001110110 | 8 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Or16.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/Or16.tst 5 | 6 | load Or16.hdl, 7 | output-file Or16.out, 8 | compare-to Or16.cmp, 9 | output-list a%B1.16.1 b%B1.16.1 out%B1.16.1; 10 | 11 | set a %B0000000000000000, 12 | set b %B0000000000000000, 13 | eval, 14 | output; 15 | 16 | set a %B0000000000000000, 17 | set b %B1111111111111111, 18 | eval, 19 | output; 20 | 21 | set a %B1111111111111111, 22 | set b %B1111111111111111, 23 | eval, 24 | output; 25 | 26 | set a %B1010101010101010, 27 | set b %B0101010101010101, 28 | eval, 29 | output; 30 | 31 | set a %B0011110011000011, 32 | set b %B0000111111110000, 33 | eval, 34 | output; 35 | 36 | set a %B0001001000110100, 37 | set b %B1001100001110110, 38 | eval, 39 | output; -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Or8Way.cmp: -------------------------------------------------------------------------------- 1 | | in | out | 2 | | 00000000 | 0 | 3 | | 11111111 | 1 | 4 | | 00010000 | 1 | 5 | | 00000001 | 1 | 6 | | 00100110 | 1 | 7 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Or8Way.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/Or8Way.tst 5 | 6 | load Or8Way.hdl, 7 | output-file Or8Way.out, 8 | compare-to Or8Way.cmp, 9 | output-list in%B2.8.2 out%B2.1.2; 10 | 11 | set in %B00000000, 12 | eval, 13 | output; 14 | 15 | set in %B11111111, 16 | eval, 17 | output; 18 | 19 | set in %B00010000, 20 | eval, 21 | output; 22 | 23 | set in %B00000001, 24 | eval, 25 | output; 26 | 27 | set in %B00100110, 28 | eval, 29 | output; -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Xor.cmp: -------------------------------------------------------------------------------- 1 | | a | b | out | 2 | | 0 | 0 | 0 | 3 | | 0 | 1 | 1 | 4 | | 1 | 0 | 1 | 5 | | 1 | 1 | 0 | 6 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/01/Xor.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/01/Xor.tst 5 | 6 | load Xor.hdl, 7 | output-file Xor.out, 8 | compare-to Xor.cmp, 9 | output-list a%B3.1.3 b%B3.1.3 out%B3.1.3; 10 | 11 | set a 0, 12 | set b 0, 13 | eval, 14 | output; 15 | 16 | set a 0, 17 | set b 1, 18 | eval, 19 | output; 20 | 21 | set a 1, 22 | set b 0, 23 | eval, 24 | output; 25 | 26 | set a 1, 27 | set b 1, 28 | eval, 29 | output; 30 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/02/ALU-nostat.cmp: -------------------------------------------------------------------------------- 1 | | x | y |zx |nx |zy |ny | f |no | out | 2 | | 0000000000000000 | 1111111111111111 | 1 | 0 | 1 | 0 | 1 | 0 | 0000000000000000 | 3 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 1 | 1 | 1 | 1 | 0000000000000001 | 4 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 1 | 0 | 1 | 0 | 1111111111111111 | 5 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 0 | 0 | 0000000000000000 | 6 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 0 | 0 | 1111111111111111 | 7 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 0 | 1 | 1111111111111111 | 8 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 0 | 1 | 0000000000000000 | 9 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 1 | 1 | 0000000000000000 | 10 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 1 | 1 | 0000000000000001 | 11 | | 0000000000000000 | 1111111111111111 | 0 | 1 | 1 | 1 | 1 | 1 | 0000000000000001 | 12 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 1 | 1 | 1 | 0000000000000000 | 13 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 1 | 0 | 1111111111111111 | 14 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 1 | 0 | 1111111111111110 | 15 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 0 | 0 | 1 | 0 | 1111111111111111 | 16 | | 0000000000000000 | 1111111111111111 | 0 | 1 | 0 | 0 | 1 | 1 | 0000000000000001 | 17 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 0 | 1 | 1 | 1 | 1111111111111111 | 18 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 0 | 0 | 0 | 0 | 0000000000000000 | 19 | | 0000000000000000 | 1111111111111111 | 0 | 1 | 0 | 1 | 0 | 1 | 1111111111111111 | 20 | | 0101101110100000 | 0001111011010010 | 1 | 0 | 1 | 0 | 1 | 0 | 0000000000000000 | 21 | | 0101101110100000 | 0001111011010010 | 1 | 1 | 1 | 1 | 1 | 1 | 0000000000000001 | 22 | | 0101101110100000 | 0001111011010010 | 1 | 1 | 1 | 0 | 1 | 0 | 1111111111111111 | 23 | | 0101101110100000 | 0001111011010010 | 0 | 0 | 1 | 1 | 0 | 0 | 0101101110100000 | 24 | | 0101101110100000 | 0001111011010010 | 1 | 1 | 0 | 0 | 0 | 0 | 0001111011010010 | 25 | | 0101101110100000 | 0001111011010010 | 0 | 0 | 1 | 1 | 0 | 1 | 1010010001011111 | 26 | | 0101101110100000 | 0001111011010010 | 1 | 1 | 0 | 0 | 0 | 1 | 1110000100101101 | 27 | | 0101101110100000 | 0001111011010010 | 0 | 0 | 1 | 1 | 1 | 1 | 1010010001100000 | 28 | | 0101101110100000 | 0001111011010010 | 1 | 1 | 0 | 0 | 1 | 1 | 1110000100101110 | 29 | | 0101101110100000 | 0001111011010010 | 0 | 1 | 1 | 1 | 1 | 1 | 0101101110100001 | 30 | | 0101101110100000 | 0001111011010010 | 1 | 1 | 0 | 1 | 1 | 1 | 0001111011010011 | 31 | | 0101101110100000 | 0001111011010010 | 0 | 0 | 1 | 1 | 1 | 0 | 0101101110011111 | 32 | | 0101101110100000 | 0001111011010010 | 1 | 1 | 0 | 0 | 1 | 0 | 0001111011010001 | 33 | | 0101101110100000 | 0001111011010010 | 0 | 0 | 0 | 0 | 1 | 0 | 0111101001110010 | 34 | | 0101101110100000 | 0001111011010010 | 0 | 1 | 0 | 0 | 1 | 1 | 0011110011001110 | 35 | | 0101101110100000 | 0001111011010010 | 0 | 0 | 0 | 1 | 1 | 1 | 1100001100110010 | 36 | | 0101101110100000 | 0001111011010010 | 0 | 0 | 0 | 0 | 0 | 0 | 0001101010000000 | 37 | | 0101101110100000 | 0001111011010010 | 0 | 1 | 0 | 1 | 0 | 1 | 0101111111110010 | 38 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/02/ALU.cmp: -------------------------------------------------------------------------------- 1 | | x | y |zx |nx |zy |ny | f |no | out |zr |ng | 2 | | 0000000000000000 | 1111111111111111 | 1 | 0 | 1 | 0 | 1 | 0 | 0000000000000000 | 1 | 0 | 3 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 1 | 1 | 1 | 1 | 0000000000000001 | 0 | 0 | 4 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 1 | 0 | 1 | 0 | 1111111111111111 | 0 | 1 | 5 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 0 | 0 | 0000000000000000 | 1 | 0 | 6 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 0 | 0 | 1111111111111111 | 0 | 1 | 7 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 0 | 1 | 1111111111111111 | 0 | 1 | 8 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 0 | 1 | 0000000000000000 | 1 | 0 | 9 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 1 | 1 | 0000000000000000 | 1 | 0 | 10 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 1 | 1 | 0000000000000001 | 0 | 0 | 11 | | 0000000000000000 | 1111111111111111 | 0 | 1 | 1 | 1 | 1 | 1 | 0000000000000001 | 0 | 0 | 12 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 1 | 1 | 1 | 0000000000000000 | 1 | 0 | 13 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 1 | 1 | 1 | 0 | 1111111111111111 | 0 | 1 | 14 | | 0000000000000000 | 1111111111111111 | 1 | 1 | 0 | 0 | 1 | 0 | 1111111111111110 | 0 | 1 | 15 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 0 | 0 | 1 | 0 | 1111111111111111 | 0 | 1 | 16 | | 0000000000000000 | 1111111111111111 | 0 | 1 | 0 | 0 | 1 | 1 | 0000000000000001 | 0 | 0 | 17 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 0 | 1 | 1 | 1 | 1111111111111111 | 0 | 1 | 18 | | 0000000000000000 | 1111111111111111 | 0 | 0 | 0 | 0 | 0 | 0 | 0000000000000000 | 1 | 0 | 19 | | 0000000000000000 | 1111111111111111 | 0 | 1 | 0 | 1 | 0 | 1 | 1111111111111111 | 0 | 1 | 20 | | 0000000000010001 | 0000000000000011 | 1 | 0 | 1 | 0 | 1 | 0 | 0000000000000000 | 1 | 0 | 21 | | 0000000000010001 | 0000000000000011 | 1 | 1 | 1 | 1 | 1 | 1 | 0000000000000001 | 0 | 0 | 22 | | 0000000000010001 | 0000000000000011 | 1 | 1 | 1 | 0 | 1 | 0 | 1111111111111111 | 0 | 1 | 23 | | 0000000000010001 | 0000000000000011 | 0 | 0 | 1 | 1 | 0 | 0 | 0000000000010001 | 0 | 0 | 24 | | 0000000000010001 | 0000000000000011 | 1 | 1 | 0 | 0 | 0 | 0 | 0000000000000011 | 0 | 0 | 25 | | 0000000000010001 | 0000000000000011 | 0 | 0 | 1 | 1 | 0 | 1 | 1111111111101110 | 0 | 1 | 26 | | 0000000000010001 | 0000000000000011 | 1 | 1 | 0 | 0 | 0 | 1 | 1111111111111100 | 0 | 1 | 27 | | 0000000000010001 | 0000000000000011 | 0 | 0 | 1 | 1 | 1 | 1 | 1111111111101111 | 0 | 1 | 28 | | 0000000000010001 | 0000000000000011 | 1 | 1 | 0 | 0 | 1 | 1 | 1111111111111101 | 0 | 1 | 29 | | 0000000000010001 | 0000000000000011 | 0 | 1 | 1 | 1 | 1 | 1 | 0000000000010010 | 0 | 0 | 30 | | 0000000000010001 | 0000000000000011 | 1 | 1 | 0 | 1 | 1 | 1 | 0000000000000100 | 0 | 0 | 31 | | 0000000000010001 | 0000000000000011 | 0 | 0 | 1 | 1 | 1 | 0 | 0000000000010000 | 0 | 0 | 32 | | 0000000000010001 | 0000000000000011 | 1 | 1 | 0 | 0 | 1 | 0 | 0000000000000010 | 0 | 0 | 33 | | 0000000000010001 | 0000000000000011 | 0 | 0 | 0 | 0 | 1 | 0 | 0000000000010100 | 0 | 0 | 34 | | 0000000000010001 | 0000000000000011 | 0 | 1 | 0 | 0 | 1 | 1 | 0000000000001110 | 0 | 0 | 35 | | 0000000000010001 | 0000000000000011 | 0 | 0 | 0 | 1 | 1 | 1 | 1111111111110010 | 0 | 1 | 36 | | 0000000000010001 | 0000000000000011 | 0 | 0 | 0 | 0 | 0 | 0 | 0000000000000001 | 0 | 0 | 37 | | 0000000000010001 | 0000000000000011 | 0 | 1 | 0 | 1 | 0 | 1 | 0000000000010011 | 0 | 0 | 38 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/02/Add16.cmp: -------------------------------------------------------------------------------- 1 | | a | b | out | 2 | | 0000000000000000 | 0000000000000000 | 0000000000000000 | 3 | | 0000000000000000 | 1111111111111111 | 1111111111111111 | 4 | | 1111111111111111 | 1111111111111111 | 1111111111111110 | 5 | | 1010101010101010 | 0101010101010101 | 1111111111111111 | 6 | | 0011110011000011 | 0000111111110000 | 0100110010110011 | 7 | | 0001001000110100 | 1001100001110110 | 1010101010101010 | 8 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/02/Add16.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/02/Add16.tst 5 | 6 | load Add16.hdl, 7 | output-file Add16.out, 8 | compare-to Add16.cmp, 9 | output-list a%B1.16.1 b%B1.16.1 out%B1.16.1; 10 | 11 | set a %B0000000000000000, 12 | set b %B0000000000000000, 13 | eval, 14 | output; 15 | 16 | set a %B0000000000000000, 17 | set b %B1111111111111111, 18 | eval, 19 | output; 20 | 21 | set a %B1111111111111111, 22 | set b %B1111111111111111, 23 | eval, 24 | output; 25 | 26 | set a %B1010101010101010, 27 | set b %B0101010101010101, 28 | eval, 29 | output; 30 | 31 | set a %B0011110011000011, 32 | set b %B0000111111110000, 33 | eval, 34 | output; 35 | 36 | set a %B0001001000110100, 37 | set b %B1001100001110110, 38 | eval, 39 | output; 40 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/02/FullAdder.cmp: -------------------------------------------------------------------------------- 1 | | a | b | c | sum | carry | 2 | | 0 | 0 | 0 | 0 | 0 | 3 | | 0 | 0 | 1 | 1 | 0 | 4 | | 0 | 1 | 0 | 1 | 0 | 5 | | 0 | 1 | 1 | 0 | 1 | 6 | | 1 | 0 | 0 | 1 | 0 | 7 | | 1 | 0 | 1 | 0 | 1 | 8 | | 1 | 1 | 0 | 0 | 1 | 9 | | 1 | 1 | 1 | 1 | 1 | 10 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/02/FullAdder.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/02/FullAdder.tst 5 | 6 | load FullAdder.hdl, 7 | output-file FullAdder.out, 8 | compare-to FullAdder.cmp, 9 | output-list a%B3.1.3 b%B3.1.3 c%B3.1.3 sum%B3.1.3 carry%B3.1.3; 10 | 11 | set a 0, 12 | set b 0, 13 | set c 0, 14 | eval, 15 | output; 16 | 17 | set c 1, 18 | eval, 19 | output; 20 | 21 | set b 1, 22 | set c 0, 23 | eval, 24 | output; 25 | 26 | set c 1, 27 | eval, 28 | output; 29 | 30 | set a 1, 31 | set b 0, 32 | set c 0, 33 | eval, 34 | output; 35 | 36 | set c 1, 37 | eval, 38 | output; 39 | 40 | set b 1, 41 | set c 0, 42 | eval, 43 | output; 44 | 45 | set c 1, 46 | eval, 47 | output; 48 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/02/HalfAdder.cmp: -------------------------------------------------------------------------------- 1 | | a | b | sum | carry | 2 | | 0 | 0 | 0 | 0 | 3 | | 0 | 1 | 1 | 0 | 4 | | 1 | 0 | 1 | 0 | 5 | | 1 | 1 | 0 | 1 | 6 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/02/HalfAdder.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/02/HalfAdder.tst 5 | 6 | load HalfAdder.hdl, 7 | output-file HalfAdder.out, 8 | compare-to HalfAdder.cmp, 9 | output-list a%B3.1.3 b%B3.1.3 sum%B3.1.3 carry%B3.1.3; 10 | 11 | set a 0, 12 | set b 0, 13 | eval, 14 | output; 15 | 16 | set a 0, 17 | set b 1, 18 | eval, 19 | output; 20 | 21 | set a 1, 22 | set b 0, 23 | eval, 24 | output; 25 | 26 | set a 1, 27 | set b 1, 28 | eval, 29 | output; 30 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/02/Inc16.cmp: -------------------------------------------------------------------------------- 1 | | in | out | 2 | | 0000000000000000 | 0000000000000001 | 3 | | 1111111111111111 | 0000000000000000 | 4 | | 0000000000000101 | 0000000000000110 | 5 | | 1111111111111011 | 1111111111111100 | 6 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/02/Inc16.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/02/Inc16.tst 5 | 6 | load Inc16.hdl, 7 | output-file Inc16.out, 8 | compare-to Inc16.cmp, 9 | output-list in%B1.16.1 out%B1.16.1; 10 | 11 | set in %B0000000000000000, // in = 0 12 | eval, 13 | output; 14 | 15 | set in %B1111111111111111, // in = -1 16 | eval, 17 | output; 18 | 19 | set in %B0000000000000101, // in = 5 20 | eval, 21 | output; 22 | 23 | set in %B1111111111111011, // in = -5 24 | eval, 25 | output; 26 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/03/PC.cmp: -------------------------------------------------------------------------------- 1 | | time | in |reset|load | inc | out | 2 | | 0+ | 0 | 0 | 0 | 0 | 0 | 3 | | 1 | 0 | 0 | 0 | 0 | 0 | 4 | | 1+ | 0 | 0 | 0 | 1 | 0 | 5 | | 2 | 0 | 0 | 0 | 1 | 1 | 6 | | 2+ | -32123 | 0 | 0 | 1 | 1 | 7 | | 3 | -32123 | 0 | 0 | 1 | 2 | 8 | | 3+ | -32123 | 0 | 1 | 1 | 2 | 9 | | 4 | -32123 | 0 | 1 | 1 | -32123 | 10 | | 4+ | -32123 | 0 | 0 | 1 | -32123 | 11 | | 5 | -32123 | 0 | 0 | 1 | -32122 | 12 | | 5+ | -32123 | 0 | 0 | 1 | -32122 | 13 | | 6 | -32123 | 0 | 0 | 1 | -32121 | 14 | | 6+ | 12345 | 0 | 1 | 0 | -32121 | 15 | | 7 | 12345 | 0 | 1 | 0 | 12345 | 16 | | 7+ | 12345 | 1 | 1 | 0 | 12345 | 17 | | 8 | 12345 | 1 | 1 | 0 | 0 | 18 | | 8+ | 12345 | 0 | 1 | 1 | 0 | 19 | | 9 | 12345 | 0 | 1 | 1 | 12345 | 20 | | 9+ | 12345 | 1 | 1 | 1 | 12345 | 21 | | 10 | 12345 | 1 | 1 | 1 | 0 | 22 | | 10+ | 12345 | 0 | 0 | 1 | 0 | 23 | | 11 | 12345 | 0 | 0 | 1 | 1 | 24 | | 11+ | 12345 | 1 | 0 | 1 | 1 | 25 | | 12 | 12345 | 1 | 0 | 1 | 0 | 26 | | 12+ | 0 | 0 | 1 | 1 | 0 | 27 | | 13 | 0 | 0 | 1 | 1 | 0 | 28 | | 13+ | 0 | 0 | 0 | 1 | 0 | 29 | | 14 | 0 | 0 | 0 | 1 | 1 | 30 | | 14+ | 22222 | 1 | 0 | 0 | 1 | 31 | | 15 | 22222 | 1 | 0 | 0 | 0 | 32 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/examples/n2t/03/PC.tst: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/03/a/PC.tst 5 | 6 | load PC.hdl, 7 | output-file PC.out, 8 | compare-to PC.cmp, 9 | 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; 10 | 11 | set in 0, 12 | set reset 0, 13 | set load 0, 14 | set inc 0, 15 | tick, 16 | output; 17 | 18 | tock, 19 | output; 20 | 21 | set inc 1, 22 | tick, 23 | output; 24 | 25 | tock, 26 | output; 27 | 28 | set in -32123, 29 | tick, 30 | output; 31 | 32 | tock, 33 | output; 34 | 35 | set load 1, 36 | tick, 37 | output; 38 | 39 | tock, 40 | output; 41 | 42 | set load 0, 43 | tick, 44 | output; 45 | 46 | tock, 47 | output; 48 | 49 | tick, 50 | output; 51 | 52 | tock, 53 | output; 54 | 55 | set in 12345, 56 | set load 1, 57 | set inc 0, 58 | tick, 59 | output; 60 | 61 | tock, 62 | output; 63 | 64 | set reset 1, 65 | tick, 66 | output; 67 | 68 | tock, 69 | output; 70 | 71 | set reset 0, 72 | set inc 1, 73 | tick, 74 | output; 75 | 76 | tock, 77 | output; 78 | 79 | set reset 1, 80 | tick, 81 | output; 82 | 83 | tock, 84 | output; 85 | 86 | set reset 0, 87 | set load 0, 88 | tick, 89 | output; 90 | 91 | tock, 92 | output; 93 | 94 | set reset 1, 95 | tick, 96 | output; 97 | 98 | tock, 99 | output; 100 | 101 | set in 0, 102 | set reset 0, 103 | set load 1, 104 | tick, 105 | output; 106 | 107 | tock, 108 | output; 109 | 110 | set load 0, 111 | set inc 1, 112 | tick, 113 | output; 114 | 115 | tock, 116 | output; 117 | 118 | set in 22222, 119 | set reset 1, 120 | set inc 0, 121 | tick, 122 | output; 123 | 124 | tock, 125 | output; 126 | -------------------------------------------------------------------------------- /src/emulator/hardware/scripting/script-parser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const ScriptParser = require('./generated/script-parser-gen'); 9 | const fs = require('fs'); 10 | 11 | Object.assign(ScriptParser, { 12 | /** 13 | * Parses script file. 14 | */ 15 | parseFile(filePath, options) { 16 | return this.parse(fs.readFileSync(filePath, 'utf-8'), options); 17 | }, 18 | }); 19 | 20 | module.exports = ScriptParser; 21 | -------------------------------------------------------------------------------- /src/generator/__tests__/generator-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | const generator = require('..'); 7 | const parser = require('../../parser'); 8 | const HDLClassFactory = require('../../emulator/hardware/HDLClassFactory'); 9 | 10 | describe('generator-from-ast', () => { 11 | it('basic chip', () => { 12 | const originalHDL = [ 13 | 'CHIP Custom {', 14 | ' IN a, b[4];', 15 | ' OUT out[8], out2;', 16 | '', 17 | ' PARTS:', 18 | '', 19 | ' Nand(a=a, b=b[1], out[3]=n);', 20 | ' MyGate(a[0..7]=a[1], b=b[8..15], out[3]=n);', 21 | ' Const(a=1, b=0, c=true, d=false, e=15, out[3]=n);', 22 | '', 23 | ' BUILTIN Nand, MyGate;', 24 | '', 25 | ' CLOCKED a, out2;', 26 | '}', 27 | ].join('\n'); 28 | 29 | const ast = parser.parse(originalHDL); 30 | 31 | const generatedHDL = generator.fromAST(ast); 32 | const astFromGenerated = parser.parse(generatedHDL); 33 | 34 | // Check ASTs are equivalent: 35 | expect(ast).toEqual(astFromGenerated); 36 | 37 | const expectedHDL = [ 38 | `/**`, 39 | ` * Automatically generated by hdl-js "Custom" gate.`, 40 | ` */`, 41 | originalHDL, 42 | ].join('\n'); 43 | 44 | expect(generatedHDL).toEqual(expectedHDL); 45 | }); 46 | 47 | it('from custom AST', () => { 48 | const ast = { 49 | type: 'Chip', 50 | name: 'And', 51 | inputs: [{type: 'Name', value: 'a'}, {type: 'Name', value: 'b'}], 52 | outputs: [{type: 'Name', value: 'out'}], 53 | builtins: [{type: 'Name', value: 'And'}], 54 | }; 55 | 56 | const hdl = generator.fromAST(ast); 57 | 58 | const parsed = parser.parse(hdl); 59 | expect(Object.assign({}, ast, {clocked: [], parts: []})).toEqual(parsed); 60 | 61 | const expectedHDL = [ 62 | `/**`, 63 | ` * Automatically generated by hdl-js "And" gate.`, 64 | ` */`, 65 | `CHIP And {`, 66 | ` IN a, b;`, 67 | ` OUT out;`, 68 | ``, 69 | ` BUILTIN And;`, 70 | `}`, 71 | ].join('\n'); 72 | 73 | expect(hdl).toEqual(expectedHDL); 74 | }); 75 | 76 | it('from CompositeGate instance', () => { 77 | const originalHDL = [ 78 | 'CHIP Custom {', 79 | ' IN a, b[4];', 80 | ' OUT out[8], out2;', 81 | '', 82 | ' PARTS:', 83 | '', 84 | ' Nand(a=a, b=b[1], out[3]=n);', 85 | ' And(a=a[1], b=b[2], out=out2);', 86 | '}', 87 | ].join('\n'); 88 | 89 | const gate = HDLClassFactory.fromHDL(originalHDL).defaultFromSpec(); 90 | 91 | const expectedHDL = [ 92 | `/**`, 93 | ` * Automatically generated by hdl-js "Custom" gate.`, 94 | ` */`, 95 | originalHDL, 96 | ].join('\n'); 97 | 98 | const generatedHDL = generator.fromCompositeGate(gate); 99 | expect(generatedHDL).toEqual(expectedHDL); 100 | }); 101 | }); 102 | -------------------------------------------------------------------------------- /src/generator/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | /** 9 | * Helper `gen` function calls node type handler. 10 | */ 11 | function gen(node) { 12 | return node ? generator[node.type](node) : ''; 13 | } 14 | 15 | /** 16 | * Generates input pins. 17 | */ 18 | function genInputs(inputs) { 19 | return `IN ${inputs.map(gen).join(', ')};`; 20 | } 21 | 22 | /** 23 | * Generates output pins. 24 | */ 25 | function genOutputs(outputs) { 26 | return `OUT ${outputs.map(gen).join(', ')};`; 27 | } 28 | 29 | /** 30 | * Generates parts implementation. 31 | */ 32 | function genParts(parts) { 33 | if (!parts || parts.length === 0) { 34 | return ''; 35 | } 36 | 37 | return ` 38 | 39 | PARTS: 40 | 41 | ${parts.map(gen).join(';\n')};`; 42 | } 43 | 44 | /** 45 | * Generates builtin chips list. 46 | */ 47 | function genBuiltins(builtins) { 48 | if (!builtins || builtins.length === 0) { 49 | return ''; 50 | } 51 | 52 | return ` 53 | 54 | BUILTIN ${builtins.map(gen).join(', ')};`; 55 | } 56 | 57 | /** 58 | * Generates clocked pins. 59 | */ 60 | function genClocked(clocked) { 61 | if (!clocked || clocked.length === 0) { 62 | return ''; 63 | } 64 | 65 | return ` 66 | 67 | CLOCKED ${clocked.map(gen).join(', ')};`; 68 | } 69 | 70 | /** 71 | * AST handler. 72 | */ 73 | const generator = { 74 | Chip(node) { 75 | return ( 76 | ` 77 | CHIP ${node.name} { 78 | ${genInputs(node.inputs)} 79 | ${genOutputs(node.outputs)}` + 80 | // Optional parts: 81 | genParts(node.parts) + 82 | genBuiltins(node.builtins) + 83 | genClocked(node.clocked) + 84 | ` 85 | } 86 | ` 87 | ); 88 | }, 89 | 90 | Name(node) { 91 | const name = node.value; 92 | 93 | // a[1] 94 | if (node.hasOwnProperty('index')) { 95 | return `${name}[${node.index}]`; 96 | } 97 | 98 | // a[1] 99 | if (node.hasOwnProperty('size')) { 100 | return `${name}[${node.size}]`; 101 | } 102 | 103 | // a[0..3] 104 | if (node.hasOwnProperty('range')) { 105 | return `${name}[${node.range.from}..${node.range.to}]`; 106 | } 107 | 108 | // a 109 | return name; 110 | }, 111 | 112 | ChipCall(node) { 113 | const args = node.arguments.map(gen).join(', '); 114 | 115 | return `${node.name}(${args})`; 116 | }, 117 | 118 | Argument(node) { 119 | return `${gen(node.name)}=${gen(node.value)}`; 120 | }, 121 | 122 | Constant(node) { 123 | return node.raw; 124 | }, 125 | }; 126 | 127 | /** 128 | * Reformats the code according to options. 129 | */ 130 | function reformat(code, {indent = 2} = {}) { 131 | return code 132 | .trim() 133 | .split('\n') 134 | .map((line, index, arr) => { 135 | line = line.trim(); 136 | if (line && index > 0 && index < arr.length - 1) { 137 | line = ' '.repeat(indent) + line; 138 | } 139 | return line; 140 | }) 141 | .join('\n'); 142 | } 143 | 144 | module.exports = { 145 | /** 146 | * Generates an HDL code from AST. 147 | * 148 | * options: {indent = 2} 149 | */ 150 | fromAST(node, options) { 151 | const hdl = reformat(gen(node), options); 152 | return [ 153 | `/**`, 154 | ` * Automatically generated by hdl-js "${node.name}" gate.`, 155 | ` */`, 156 | hdl, 157 | ].join('\n'); 158 | }, 159 | 160 | /** 161 | * Generates an HDL code from a CompositeGate instance. 162 | * 163 | * options: see `generateFromAST`. 164 | */ 165 | fromCompositeGate(compositeGate, options) { 166 | return this.fromAST(compositeGate.toAST(), options); 167 | }, 168 | }; 169 | -------------------------------------------------------------------------------- /src/hdl-js.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const parser = require('./parser'); 9 | const emulator = require('./emulator/hardware'); 10 | const generator = require('./generator'); 11 | 12 | const {HDLClassFactory} = emulator; 13 | 14 | /** 15 | * An API object for HDL processing. 16 | */ 17 | const hdl = { 18 | /** 19 | * Parser module exposed. 20 | */ 21 | parser, 22 | 23 | /** 24 | * Emulator module exposed. 25 | */ 26 | emulator, 27 | 28 | /** 29 | * Code generator module exposed. 30 | */ 31 | generator, 32 | 33 | /** 34 | * Parses an HDL string, producing an AST. 35 | * 36 | * @param string hdlCode 37 | * 38 | * an HDL string. 39 | * 40 | * @param Object options 41 | * 42 | * parsing options for this parse call. Default are: 43 | * 44 | * - captureLocations: boolean 45 | * - any other custom options 46 | * 47 | * @return Object AST 48 | */ 49 | parse(hdlCode, options) { 50 | return parser.parse(`${hdlCode}`, options); 51 | }, 52 | 53 | /** 54 | * Facade method; similar to `parse`, but reads a file first. 55 | */ 56 | parseFile(fileName, options) { 57 | return parser.parseFile(fileName, options); 58 | }, 59 | 60 | /** 61 | * Loads a custom composite gate class from HDL file. 62 | */ 63 | fromHDLFile(fileName) { 64 | return HDLClassFactory.fromHDLFile(fileName); 65 | }, 66 | 67 | /** 68 | * Loads a custom composite gate class from HDL file. 69 | */ 70 | fromHDL(hdl) { 71 | return HDLClassFactory.fromHDL(hdl); 72 | }, 73 | 74 | /** 75 | * Generates an HDL code from an AST. 76 | */ 77 | generateFromAST(ast, options) { 78 | return generator.generateFromAST(ast, options); 79 | }, 80 | 81 | /** 82 | * Generates an HDL from a CompositeGate instance. 83 | */ 84 | generateFromCompositeGate(compositeGate, options) { 85 | return generator.fromCompositeGate(compositeGate, options); 86 | }, 87 | }; 88 | 89 | module.exports = hdl; 90 | -------------------------------------------------------------------------------- /src/parser/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const fs = require('fs'); 9 | const hdlParser = require('./generated/hdl-parser'); 10 | 11 | // By default do not capture locations; callers may override. 12 | hdlParser.setOptions({captureLocations: false}); 13 | 14 | /** 15 | * Extensions to the generated parser. 16 | */ 17 | Object.assign(hdlParser, { 18 | /** 19 | * Parses a file with HDL code. 20 | */ 21 | parseFile(fileName, options) { 22 | return this.parse(fs.readFileSync(fileName, 'utf-8'), options); 23 | }, 24 | }); 25 | 26 | module.exports = hdlParser; 27 | -------------------------------------------------------------------------------- /src/table-printer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | const Table = require('cli-table3'); 7 | 8 | /** 9 | * Wrapper class over `cli-table3` with default options preset. 10 | */ 11 | class TablePrinter { 12 | constructor(options) { 13 | return new Table( 14 | Object.assign({}, options, { 15 | style: { 16 | head: ['blue'], 17 | border: ['gray'], 18 | }, 19 | }) 20 | ); 21 | } 22 | } 23 | 24 | module.exports = TablePrinter; 25 | -------------------------------------------------------------------------------- /src/util/__tests__/numbers-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const { 9 | getBitAt, 10 | getBitRange, 11 | int16, 12 | setBitAt, 13 | setBitRange, 14 | uint16, 15 | } = require('../numbers'); 16 | 17 | describe('numbers', () => { 18 | it('int16', () => { 19 | expect(int16(0xffff)).toBe(-1); 20 | expect(int16(~0b0000000000000000)).toBe(-1); 21 | 22 | expect(int16(0b1111111111111111)).toBe(-1); 23 | expect(int16('1111111111111111')).toBe(-1); 24 | }); 25 | 26 | it('uint16', () => { 27 | expect(uint16(0xffff)).toBe(0xffff); 28 | expect(uint16(~0b0000000000000000)).toBe(0xffff); 29 | }); 30 | 31 | it('getBitAt', () => { 32 | expect(getBitAt(0b101, 0)).toBe(1); 33 | expect(getBitAt(0b101, 1)).toBe(0); 34 | expect(getBitAt(0b101, 2)).toBe(1); 35 | }); 36 | 37 | it('setBitAt', () => { 38 | expect(setBitAt(0b101, 0, 0)).toBe(0b100); 39 | expect(setBitAt(0b101, 1, 1)).toBe(0b111); 40 | expect(setBitAt(0b101, 2, 0)).toBe(0b001); 41 | }); 42 | 43 | it('getBitRange', () => { 44 | expect(getBitRange(0b101, 0, 2)).toBe(0b101); 45 | expect(getBitRange(0b101, 0, 1)).toBe(0b01); 46 | expect(getBitRange(0b101, 1, 2)).toBe(0b10); 47 | }); 48 | 49 | it('setBitRange', () => { 50 | expect(setBitRange(0b101, 0, 2, 0b010)).toBe(0b010); 51 | expect(setBitRange(0b101, 0, 1, 0b10)).toBe(0b110); 52 | expect(setBitRange(0b101, 1, 2, 0b01)).toBe(0b011); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /src/util/__tests__/string-util-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const {centerString} = require('../string-util'); 9 | 10 | describe('string-util', () => { 11 | it('centers', () => { 12 | expect(centerString('a', 5)).toBe(' a '); 13 | expect(centerString('a', 5, '-')).toBe('--a--'); 14 | 15 | expect(centerString('a', 6)).toBe(' a '); 16 | expect(centerString('ab', 6)).toBe(' ab '); 17 | 18 | expect(centerString('a', 1)).toBe('a'); 19 | expect(centerString('a', 2)).toBe('a '); 20 | expect(centerString('a', 3)).toBe(' a '); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /src/util/numbers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | /** 9 | * Converts a number to signed 16-bit integer. 10 | */ 11 | function int16(v) { 12 | if (typeof v === 'string') { 13 | v = Number.parseInt(v, 2); 14 | } 15 | 16 | return (v << 16) >> 16; 17 | } 18 | 19 | /** 20 | * Converts all rows in a table to `int16`. 21 | */ 22 | function int16Table(table) { 23 | for (const row of table) { 24 | for (const pin in row) { 25 | if (pin === '$clock') { 26 | continue; 27 | } 28 | row[pin] = int16(row[pin]); 29 | } 30 | } 31 | return table; 32 | } 33 | 34 | /** 35 | * Converts a number to unsigned 16-bit integer. 36 | */ 37 | function uint16(v) { 38 | return v & 0xffff; 39 | } 40 | 41 | /** 42 | * Test for a neagtive zero. 43 | */ 44 | function isNegativeZero(value) { 45 | return value === 0 && 1 / value === -Infinity; 46 | } 47 | 48 | /** 49 | * Converts a number value to decimal string with the sign. 50 | */ 51 | function toSignedString(value) { 52 | if (isNegativeZero(value)) { 53 | return '-0'; 54 | } 55 | 56 | return (value >= 0 ? '+' : '') + value; 57 | } 58 | 59 | /** 60 | * Returns the value of particular bit in a 16-bit number. 61 | */ 62 | function getBitAt(number, index) { 63 | return (number >> index) & 1; 64 | } 65 | 66 | /** 67 | * Sets a particular bit to the value. 68 | */ 69 | function setBitAt(number, index, value) { 70 | // Set 1. 71 | if (value === 1) { 72 | number |= 1 << index; 73 | } else { 74 | // Set 0 ("clear"). 75 | number &= ~(1 << index); 76 | } 77 | return number; 78 | } 79 | 80 | /** 81 | * Returns a bit range. 82 | */ 83 | function getBitRange(number, from, to) { 84 | return (number >> from) & ((1 << (to + 1 - from)) - 1); 85 | } 86 | 87 | /** 88 | * Sets a bits range. 89 | */ 90 | function setBitRange(number, from, to, range) { 91 | const mask = ((1 << (to + 1 - from)) - 1) << from; 92 | return (number & ~mask) | ((range << from) & mask); 93 | } 94 | 95 | module.exports = { 96 | getBitAt, 97 | getBitRange, 98 | int16, 99 | int16Table, 100 | isNegativeZero, 101 | setBitAt, 102 | setBitRange, 103 | toSignedString, 104 | uint16, 105 | }; 106 | -------------------------------------------------------------------------------- /src/util/string-util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * Copyright (c) 2017-present Dmitry Soshnikov 4 | */ 5 | 6 | 'use strict'; 7 | 8 | function centerString(string, maxLength, padCh = ' ') { 9 | if (string.length < maxLength) { 10 | const len = maxLength - string.length; 11 | const remain = len % 2 == 0 ? '' : padCh; 12 | const pads = padCh.repeat(parseInt(len / 2)); 13 | return pads + string + pads + remain; 14 | } 15 | return string; 16 | } 17 | 18 | module.exports = { 19 | centerString, 20 | }; 21 | --------------------------------------------------------------------------------