Repository: mbad0la/Architect Branch: master Commit: 6fefaebc7d3a Files: 13 Total size: 26.8 KB Directory structure: gitextract_b37vrddc/ ├── .gitignore ├── Combinational/ │ ├── arithmetics.js │ ├── decoders.js │ └── gates.js ├── Connectors/ │ └── transport.js ├── LICENSE ├── README.md ├── Sequential/ │ └── ff.js ├── Utility/ │ ├── ioManager.js │ └── new.js ├── index.js ├── package.json └── test.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ node_modules ================================================ FILE: Combinational/arithmetics.js ================================================ const { AndGate, XorGate, OrGate } = require('./gates') const { wires } = require('../Connectors/transport') const { Hardware } = require('../Utility/new') class HalfAdder extends Hardware { constructor(x, s) { if (x.length != 2 || s.length != 2) throw new Error('Invalid Connection/s') super([x, s]) this.components.push(new XorGate([x[0]], [x[1]], [s[1]])) this.components.push(new AndGate([x[0]], [x[1]], [s[0]])) } } class FullAdder extends Hardware { constructor(x, s) { if (x.length != 3 || s.length != 2) throw new Error('Invalid Connection/s') super([x, s]) this.internalWiring = wires(3) this.components.push(new HalfAdder([x[0], x[1]], [this.internalWiring[0], this.internalWiring[1]])) this.components.push(new HalfAdder([this.internalWiring[1], x[2]], [this.internalWiring[2], s[1]])) this.components.push(new OrGate([this.internalWiring[0]], [this.internalWiring[2]], [s[0]])) } } class PipoAdder extends Hardware { constructor(a, b, s) { if (a.length != b.length || s.length != a.length + 1) throw new Error('Invalid Connection/s') super([a, b, s]) let size = a.length this.internalWiring = wires(size) if (size > 1) { this.components.push(new FullAdder([a[0], b[0], this.internalWiring[0]], [this.internalWiring[1], s[size]])) for(let i = 1; i < size - 1; i++) { this.components.push(new FullAdder([a[i], b[i], this.internalWiring[i]], [this.internalWiring[i+1], s[size-i]])) } this.components.push(new FullAdder([a[size-1], b[size-1], this.internalWiring[size-1]], [s[0], s[1]])) } else { this.components.push(new FullAdder([a[0], b[0], this.internalWiring[0]], [s[0], s[1]])) } this.internalWiring[0].propagateSignal(0) } } module.exports = { HalfAdder, FullAdder, PipoAdder } ================================================ FILE: Combinational/decoders.js ================================================ const { Hardware } = require('../Utility/new') const { wires } = require('../Connectors/transport') const { NotGate, AndGate } = require('./gates') class Decoder1x2 extends Hardware { constructor(x, o) { if (x.length != 1 || o.length != 1) throw new Error('Invalid Connection/s') super([x, [o[0], x[0]]]) this.components.push(new NotGate(x, o)) } } class Decoder2x4 extends Hardware { constructor(x0, x1, o) { if(x0.length != 1 || x1.length != 1 || o.length != 4) throw new Error('Invalid Connection/s') super([x0, x1, o]) this.internalWiring = wires(2) this.components.push(new Decoder1x2(x0, [this.internalWiring[0]])) this.components.push(new Decoder1x2(x1, [this.internalWiring[1]])) this.components.push(new AndGate([this.internalWiring[0]], [this.internalWiring[1]], [o[0]])) this.components.push(new AndGate([this.internalWiring[0]], x1, [o[1]])) this.components.push(new AndGate(x0, [this.internalWiring[1]], [o[2]])) this.components.push(new AndGate(x0, x1, [o[3]])) } } module.exports = { Decoder1x2, Decoder2x4 } ================================================ FILE: Combinational/gates.js ================================================ const { Hardware } = require('../Utility/new') class AndGate extends Hardware { constructor(x, y, o) { if (x.length != 1 || y.length != 1 || o.length != 1) throw new Error('Invalid Connection/s') super([x, y, o]) this.x = x this.y = y this.o = o this.hardware = this.hardware.bind(this) x[0].on('signal', this.hardware) y[0].on('signal', this.hardware) } hardware() { let xSig = this.x[0].getSignal() let ySig = this.y[0].getSignal() if (xSig === 0 || ySig === 0) { this.o[0].propagateSignal(0) } else if (xSig === undefined || ySig === undefined) { this.o[0].propagateSignal(undefined) } else this.o[0].propagateSignal(xSig && ySig) } } class TriInpAndGate extends Hardware { constructor(x, y, z, o) { if (x.length != 1 || y.length != 1 || z.length != 1 || o.length != 1) throw new Error('Invalid Connection/s') super([x, y, z, o]) this.x = x this.y = y this.z = z this.o = o this.hardware = this.hardware.bind(this) x[0].on('signal', this.hardware) y[0].on('signal', this.hardware) z[0].on('signal', this.hardware) } hardware() { let xSig = this.x[0].getSignal() let ySig = this.y[0].getSignal() let zSig = this.z[0].getSignal() if (xSig === 0 || ySig === 0 || zSig === 0) { this.o[0].propagateSignal(0) } else if (xSig === undefined || ySig === undefined || zSig === undefined) { this.o[0].propagateSignal(undefined) } else this.o[0].propagateSignal(xSig && ySig && zSig) } } class OrGate extends Hardware { constructor(x, y, o) { if (x.length != 1 || y.length != 1 || o.length != 1) throw new Error('Invalid Connection/s') super([x, y, o]) this.x = x this.y = y this.o = o this.hardware = this.hardware.bind(this) x[0].on('signal', this.hardware) y[0].on('signal', this.hardware) } hardware() { let xSig = this.x[0].getSignal() let ySig = this.y[0].getSignal() if (xSig === 1 || ySig === 1) { this.o[0].propagateSignal(1) } else if (xSig === undefined || ySig === undefined) { this.o[0].propagateSignal(undefined) } else this.o[0].propagateSignal(xSig || ySig) } } class XorGate extends Hardware { constructor(x, y, o) { if (x.length != 1 || y.length != 1 || o.length != 1) throw new Error('Invalid Connection/s') super([x, y, o]) this.x = x this.y = y this.o = o this.hardware = this.hardware.bind(this) x[0].on('signal', this.hardware) y[0].on('signal', this.hardware) } hardware() { let xSig = this.x[0].getSignal() let ySig = this.y[0].getSignal() if (xSig === undefined || ySig === undefined) { this.o[0].propagateSignal(undefined) } else this.o[0].propagateSignal(Number(xSig != ySig)) } } class NotGate extends Hardware { constructor(x, o) { if (x.length != 1 || o.length != 1) throw new Error('Invalid Connection/s') super([x, o]) this.x = x this.o = o this.hardware = this.hardware.bind(this) x[0].on('signal', this.hardware) } hardware() { let xSig = this.x[0].getSignal() if (xSig === undefined) { this.o[0].propagateSignal(undefined) } else this.o[0].propagateSignal(Number(!xSig)) } } class NandGate extends Hardware { constructor(x, y, o) { if (x.length != 1 || y.length != 1 || o.length != 1) throw new Error('Invalid Connection/s') super([x, y, o]) this.x = x this.y = y this.o = o this.hardware = this.hardware.bind(this) x[0].on('signal', this.hardware) y[0].on('signal', this.hardware) } hardware() { let xSig = this.x[0].getSignal() let ySig = this.y[0].getSignal() if (xSig === 0 || ySig === 0) { this.o[0].propagateSignal(1) } else if (xSig === undefined || ySig === undefined) { this.o[0].propagateSignal(undefined) } else this.o[0].propagateSignal(Number(!(xSig && ySig))) } } class NorGate extends Hardware { constructor(x, y, o) { if (x.length != 1 || y.length != 1 || o.length != 1) throw new Error('Invalid Connection/s') super([x, y, o]) this.x = x this.y = y this.o = o this.hardware = this.hardware.bind(this) x[0].on('signal', this.hardware) y[0].on('signal', this.hardware) } hardware() { let xSig = this.x[0].getSignal() let ySig = this.y[0].getSignal() if (xSig === 1 || ySig === 1) { this.o[0].propagateSignal(0) } else if (xSig === undefined || ySig === undefined) { this.o[0].propagateSignal(undefined) } else this.o[0].propagateSignal(Number(!(xSig || ySig))) } } class XnorGate extends Hardware { constructor(x, y, o) { if (x.length != 1 || y.length != 1 || o.length != 1) throw new Error('Invalid Connection/s') super([x, y, o]) this.x = x this.y = y this.o = o this.hardware = this.hardware.bind(this) x[0].on('signal', this.hardware) y[0].on('signal', this.hardware) } hardware() { let xSig = this.x[0].getSignal() let ySig = this.y[0].getSignal() if (xSig === undefined || ySig === undefined) { this.o[0].propagateSignal(undefined) } else this.o[0].propagateSignal(Number(xSig == ySig)) } } module.exports = { AndGate, TriInpAndGate, OrGate, XorGate, NotGate, NandGate, NorGate, XnorGate } ================================================ FILE: Connectors/transport.js ================================================ const EventEmitter = require('events') class Wire extends EventEmitter { constructor(sig) { super() this.signal = sig this.propagateSignal = this.propagateSignal.bind(this) this.getSignal = this.getSignal.bind(this) } propagateSignal(newSignal) { let oldSignal = this.signal this.signal = newSignal if (oldSignal != this.signal) this.emit('signal') } getSignal() { return this.signal } } class Pulse extends Wire { constructor(t, i) { super() this.i = i this.timePeriod = t this.alter = this.alter.bind(this) this.switchOn = this.switchOn.bind(this) this.switchOff = this.switchOff.bind(this) this.interval = undefined } alter() { this.propagateSignal(Number(!this.signal)) } switchOn() { if (!this.interval) { this.signal = this.i this.interval = setInterval(this.alter, this.timePeriod) } } switchOff() { if (this.interval) { clearInterval(this.interval) this.signal = undefined this.interval = undefined } } } function wires(n) { let wireSet = [] for(let i = 0; i < n ; i++) { wireSet.push(new Wire()) } return wireSet } module.exports = { Pulse, wires } ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2017 Mayank Badola Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ ![Architect](media/banner.png) > Highly Extensible Hardware Description Library for JavaScript Developers Hardware is event-driven. And it is functional in nature, having abstractions on abstractions. Makes sense to have JavaScript emulate it doesn't it? ### Motivation Hardware Description can be fun and very educational, but I had to learn [VHDL](https://en.wikipedia.org/wiki/VHDL) to be able to do so. Hence, being a JavaScript Enthusiast, I decided to write this library down for JavaScript Developers who wanted to get into Hardware Description but were reluctant to learn a new language for it. For people not acquainted with both VHDL and JS, I'm pretty sure the learning curve would be lesser for this library. Although I cannot state that my library is better as it is not easy to compete with a language intended for hardware description, nevertheless, I will keep on hacking this library to see how this experiment goes. Let's get to business! ### Installation `npm install architectjs` ### Existing Hardware Abstractions * Gates * AndGate * TriInpAndGate * OrGate * XorGate * NotGate * NandGate * NorGate * XnorGate * Decoders * Decoder1x2 * Decoder2x4 * Arithmetics * HalfAdder * FullAdder * PipoAdder * Flip-Flops * SRFlipFlop * DFlipFlop ### :electric_plug: Plug-n-Play Use existing abstractions seemlessly. Let's plug in an AND-Gate ```js const { wires } = require('architectjs')('Connectors') const { AndGate } = require('architectjs')('Gates') const { StringIO } = require('architectjs')('IO') // provision wires to connect to your hardware const inputA = wires(1) const inputB = wires(1) const output = wires(1) // initialise the hardware const hWare = new AndGate(inputA, inputB, output) // wrap hardware in a I/O BlackBox // this is compulsory, to be able to do I/O using strings const ioHandler = new StringIO(hWare) console.log(ioHandler.input('1', '1')) // prints 1 console.log(ioHandler.input('0', '0')) // prints 0 ``` Say what? `AND` is way too easy to be called an abstraction? No worries, let's plug in this generalised Parallel-in-Parallel-out Adder! ```js const { wires } = require('architectjs')('Connectors') const { PipoAdder } = require('architectjs')('Arithmetics') const { StringIO } = require('architectjs')('IO') // code for 4-bit adder const inputA = wires(4) const inputB = wires(4) const sum = wires(5) const hWare = new PipoAdder(inputA, inputB, sum) const ioHandler = new StringIO(hWare) console.log(ioHandler.input('1111', '1111')) // prints 11110 ``` Or maybe we want to build something from existing abstractions? #### Abstraction Rules and Specs * Every Class/hardware extends on `Hardware`. * Every initialisation argument to the class instance has to be an array of `Wire` instances (obtained from the `wires` method). * An array consisting of I/O `wires` is passed onto the parent class `Hardware`, with only the last element being the output parameter. It is necessary to provide every input parameter and the output parameter to be able to wrap this in a `StringIO` instance to do I/O operations with `string` arguments. * Every class instance has two instance variables available from the parent `Hardware` instance : * internalWiring - Array of `Wire` instances (initially empty). * components - Array of abstractions used to build your hardware (initially empty). * Your entire logic goes into your Class' constructor. * `internalWiring` variable is used to initialise `Wire` instances that are not a part of the I/O for the hardware but are required to inter-connect the sub-components in your abstraction. * `components` variable is used to store instances of subcomponents used in your hardware. This helps a designer to quickly refer to all the build blocks that went into making a particular piece of hardware. Let's build a 4-input AND Gate using the above rules and specifications. ```js const { wires } = require('architectjs')('Connectors') const { AndGate } = require('architectjs')('Gates') const { StringIO } = require('architectjs')('IO') const { Hardware } = require('architectjs')('Base') class FourInpAndGate extends Hardware { constructor(a, b, c, d, o) { super([a, b, c, d, o]) this.internalWiring = wires(2) // declare wires to be used internally this.components.push(new AndGate(a, b, this.internalWiring[0])) this.components.push(new AndGate(c, d, this.internalWiring[1])) this.components.push(new AndGate(this.internalWiring[0], this.internalWiring[1], o)) } } const a = wires(1) const b = wires(1) const c = wires(1) const d = wires(1) const o = wires(1) const fourInpAnd = new FourInpAndGate(a, b, c, d, o) const ioHandler = new StringIO(fourInpAnd) console.log(ioHandler('0', '1', '1', '1')) // prints 0 console.log(ioHandler('1', '1', '1', '1')) // prints 1 ``` ### Creating a Declarative Hardware Component #### Some Basic Rules * Every Class/hardware extends on `Hardware`. * All the logic goes inside the `hardware` method of your component's Class. * Event to be listened for must be `signal`. #### Let's get started Every `Wire` instance extends on `EventEmitter`, thus this library essentially works by registering listeners in a Class instance and binding them to the `hardware` method of the Class. With the help of `getSignal` and `propagateSignal` methods of `Wire`, read changes from input `Wire` instances, use your logic on them, and emit result through the output `Wire` instance. Let's set this up with an example taken from this library ```js const { Hardware } = require('architectjs')('Base') class AndGate extends Hardware { constructor(x, y, o) { if (x.length != 1 || y.length != 1 || o.length != 1) throw new Error('Invalid Connection/s') super([x, y, o]) this.x = x this.y = y this.o = o this.hardware = this.hardware.bind(this) x[0].on('signal', this.hardware) y[0].on('signal', this.hardware) } hardware() { let xSig = this.x[0].getSignal() let ySig = this.y[0].getSignal() if (xSig === 0 || ySig === 0) { this.o[0].propagateSignal(0) } else if (xSig === undefined || ySig === undefined) { this.o[0].propagateSignal(undefined) } else this.o[0].propagateSignal(xSig && ySig) } } ``` ### Development New Hardware Component Proposals should be put up as an issue to discuss it's vialibility and modelling. I won't be considering anything else other than component proposals at the moment. I am also facing some problems in figuring out how to implement clock-edge driven circuits and circuits that have a feedback to them. Most of time, infinte events are triggered due to the feedbacking in the circuits. There are just so many possibilities to do here! Would love to get contributions from the community :smile: ================================================ FILE: Sequential/ff.js ================================================ const { AndGate, NorGate, NandGate, NotGate } = require('../Combinational/gates') const { wires } = require('../Connectors/transport') const { Hardware } = require('../Utility/new') class SRFlipFlop extends Hardware { constructor(s, r, qqbar, c) { if (s.length != 1 || r.length != 1 || qqbar.length != 2) throw new Error('Invalid Connection/s') super([s, r, [qqbar[0]]]) this.internalWiring = wires(2) this.components.push(new AndGate([c], s, [this.internalWiring[0]])) this.components.push(new AndGate([c], r, [this.internalWiring[1]])) this.components.push(new NorGate([this.internalWiring[0]], [qqbar[0]], [qqbar[1]])) this.components.push(new NorGate([this.internalWiring[1]], [qqbar[1]], [qqbar[0]])) } } class DFlipFlop extends Hardware { constructor(d, qqbar, c) { if (d.length != 1 || qqbar.length != 2) throw new Error('Invalid Connection/s') super([d, [qqbar[0]]]) this.internalWiring = wires(3) this.components.push(new NotGate(d, [this.internalWiring[0]])) this.components.push(new NandGate([c], d, [this.internalWiring[1]])) this.components.push(new NandGate([c], [this.internalWiring[0]], [this.internalWiring[2]])) this.components.push(new NandGate([this.internalWiring[1]], [qqbar[1]], [qqbar[0]])) this.components.push(new NandGate([this.internalWiring[2]], [qqbar[0]], [qqbar[1]])) } } module.exports = { SRFlipFlop, DFlipFlop } ================================================ FILE: Utility/ioManager.js ================================================ class StringIO { constructor({ioMapping}) { let inputGroup = ioMapping.length - 1 this.i = ioMapping.slice(0, inputGroup) this.o = ioMapping[inputGroup] } input(...inputSeqs) { let inpIndex = inputSeqs[0].length - 1 let totalInps = this.i.length let pos = 0 while (inpIndex >= 0) { for (let inpNum = 0; inpNum < totalInps; ++inpNum) { this.i[inpNum][pos].propagateSignal(Number(inputSeqs[inpNum][inpIndex])) } ++pos --inpIndex } let outBuff = this.o.map((wire) => { return wire.getSignal() }) outBuff = outBuff.join('') return outBuff } } module.exports = { StringIO } ================================================ FILE: Utility/new.js ================================================ class Hardware { constructor(io) { this.ioMapping = io this.internalWiring = [] this.components = [] } } module.exports = { Hardware } ================================================ FILE: index.js ================================================ module.exports = function(path) { return { 'Gates': require('./Combinational/gates'), 'Arithmetics': require('./Combinational/arithmetics'), 'Connectors': require('./Connectors/transport'), 'Sequential': require('./Sequential/ff'), 'IO': require('./Utility/ioManager'), 'Base': require('./Utility/new') } [ path ] } ================================================ FILE: package.json ================================================ { "name": "architectjs", "version": "0.1.2", "description": "Hardware Description and Emulation Library", "keywords": [ "hardware", "design", "emulation", "hardware emulation", "vhdl", "architect", "architectjs", "library" ], "scripts": { "test": "ava" }, "repository": "mbad0la/Architect", "author": { "name": "Mayank Badola", "email": "badola21295@gmail.com", "url": "https://mayankbadola.me" }, "license": "MIT", "devDependencies": { "ava": "^0.25.0" } } ================================================ FILE: test.js ================================================ import test from 'ava' import { wires, Pulse } from './Connectors/transport' import { NotGate, AndGate, TriInpAndGate, XorGate } from './Combinational/gates' import { PipoAdder, HalfAdder, FullAdder } from './Combinational/arithmetics' import { SRFlipFlop } from './Sequential/ff' import { StringIO } from './Utility/ioManager' import { Decoder1x2, Decoder2x4 } from './Combinational/decoders' test('Not-Gate : 1', t => { const inputA = wires(1) const output = wires(1) const hWare = new NotGate(inputA, output) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('1'), '0') }) test('Not-Gate : 2', t => { const inputA = wires(1) const output = wires(1) const hWare = new NotGate(inputA, output) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('0'), '1') }) test('And-Gate : 1', t => { const inputA = wires(1) const inputB = wires(1) const output = wires(1) const hWare = new AndGate(inputA, inputB, output) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('0', '0'), '0') }) test('And-Gate : 2', t => { const inputA = wires(1) const inputB = wires(1) const output = wires(1) const hWare = new AndGate(inputA, inputB, output) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('0', '1'), '0') }) test('And-Gate : 3', t => { const inputA = wires(1) const inputB = wires(1) const output = wires(1) const hWare = new AndGate(inputA, inputB, output) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('1', '1'), '1') }) test('Tri-Input And-Gate', t => { const inputX = wires(1) const inputY = wires(1) const inputZ = wires(1) const output = wires(1) const hWare = new TriInpAndGate(inputX, inputY, inputZ, output) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('1', '1', '1'), '1') }) test('Xor-Gate : 1', t => { const inputA = wires(1) const inputB = wires(1) const output = wires(1) const hWare = new XorGate(inputA, inputB, output) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('1', '1'), '0') }) test('Xor-Gate : 2', t => { const inputA = wires(1) const inputB = wires(1) const output = wires(1) const hWare = new XorGate(inputA, inputB, output) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('0', '1'), '1') }) test('Overflow for HalfAdder', t => { const inputA = wires(2) const sum = wires(2) const hWare = new HalfAdder(inputA, sum) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('11'), '10') }) test('Overflow for FullAdder', t => { const inputA = wires(3) const sum = wires(2) const hWare = new FullAdder(inputA, sum) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('111'), '11') }) test('Overflow for Parallel Adder (1 bit)', t => { const inputA = wires(1) const inputB = wires(1) const sum = wires(2) const hWare = new PipoAdder(inputA, inputB, sum) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('1', '1'), '10') }) test('Overflow for Parallel Adder (2 bit)', t => { const inputA = wires(2) const inputB = wires(2) const sum = wires(3) const hWare = new PipoAdder(inputA, inputB, sum) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('11', '11'), '110') }) test('Overflow for Parallel Adder (4 bit)', t => { const inputA = wires(4) const inputB = wires(4) const sum = wires(5) const hWare = new PipoAdder(inputA, inputB, sum) const ioHandler = new StringIO(hWare) t.is(ioHandler.input('1111', '1111'), '11110') }) test('HalfAdder - 1 bit PIPO Equivalence : 1', t => { const inputA = wires(1) const inputB = wires(1) const sum1 = wires(2) const halfAdderInput = wires(2) const sum2 = wires(2) const hWare1 = new PipoAdder(inputA, inputB, sum1) const hWare2 = new HalfAdder(halfAdderInput, sum2) const ioHandler1 = new StringIO(hWare1) const ioHandler2 = new StringIO(hWare2) t.is(ioHandler1.input('1', '1'), ioHandler2.input('11')) }) test('HalfAdder - 1 bit PIPO Equivalence : 2', t => { const inputA = wires(1) const inputB = wires(1) const sum1 = wires(2) const halfAdderInput = wires(2) const sum2 = wires(2) const hWare1 = new PipoAdder(inputA, inputB, sum1) const hWare2 = new HalfAdder(halfAdderInput, sum2) const ioHandler1 = new StringIO(hWare1) const ioHandler2 = new StringIO(hWare2) t.is(ioHandler1.input('1', '0'), ioHandler2.input('10')) }) test('HalfAdder - 1 bit PIPO Equivalence : 3', t => { const inputA = wires(1) const inputB = wires(1) const sum1 = wires(2) const halfAdderInput = wires(2) const sum2 = wires(2) const hWare1 = new PipoAdder(inputA, inputB, sum1) const hWare2 = new HalfAdder(halfAdderInput, sum2) const ioHandler1 = new StringIO(hWare1) const ioHandler2 = new StringIO(hWare2) t.is(ioHandler1.input('0', '0'), ioHandler2.input('00')) }) test('SR-Flip-Flop : Set', t => { const s = wires(1) const r = wires(1) const qqbar = wires(2) const clock = new Pulse(500, 1) clock.switchOn() const ff = new SRFlipFlop(s, r, qqbar, clock) const ioHandler = new StringIO(ff) t.is(ioHandler.input('1', '0'), '1') clock.switchOff() }) test('SR-Flip-Flop : Reset', t => { const s = wires(1) const r = wires(1) const qqbar = wires(2) const clock = new Pulse(500, 1) clock.switchOn() const ff = new SRFlipFlop(s, r, qqbar, clock) const ioHandler = new StringIO(ff) t.is(ioHandler.input('0', '1'), '0') clock.switchOff() }) test('SR-Flip-Flop : No Change', t => { const s = wires(1) const r = wires(1) const qqbar = wires(2) const clock = new Pulse(500, 1) clock.switchOn() const ff = new SRFlipFlop(s, r, qqbar, clock) const ioHandler = new StringIO(ff) const prevQ = ioHandler.input('0', '1') t.is(ioHandler.input('0', '0'), prevQ) clock.switchOff() }) test('1x2 Decoder : 1', t => { const inputA = wires(1) const outputA = wires(1) const linerDecoder = new Decoder1x2(inputA, outputA) const ioHandler = new StringIO(linerDecoder) t.is(ioHandler.input('0'), '10') }) test('1x2 Decoder : 2', t => { const inputA = wires(1) const outputA = wires(1) const linerDecoder = new Decoder1x2(inputA, outputA) const ioHandler = new StringIO(linerDecoder) t.is(ioHandler.input('1'), '01') }) test('2x4 Decoder : 1', t => { const inputX = wires(1) const inputY = wires(1) const output = wires(4) const d2x4 = new Decoder2x4(inputX, inputY, output) const ioHandler = new StringIO(d2x4) t.is(ioHandler.input('0', '0'), '1000') }) test('2x4 Decoder : 2', t => { const inputX = wires(1) const inputY = wires(1) const output = wires(4) const d2x4 = new Decoder2x4(inputX, inputY, output) const ioHandler = new StringIO(d2x4) t.is(ioHandler.input('1' ,'0'), '0010') }) test('2x4 Decoder : 3', t => { const inputX = wires(1) const inputY = wires(1) const output = wires(4) const d2x4 = new Decoder2x4(inputX, inputY, output) const ioHandler = new StringIO(d2x4) t.is(ioHandler.input('1', '1'), '0001') })