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 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
🔌 Plug-n-Play
Use existing abstractions seemlessly.
Let's plug in an AND-Gate
const wires = 'Connectors'const AndGate = 'Gates'const StringIO = 'IO' // provision wires to connect to your hardwareconst inputA = const inputB = const output = // initialise the hardwareconst hWare = inputA inputB output// wrap hardware in a I/O BlackBox// this is compulsory, to be able to do I/O using stringsconst ioHandler = hWare console // prints 1 console // 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!
const wires = 'Connectors'const PipoAdder = 'Arithmetics'const StringIO = 'IO' // code for 4-bit adderconst inputA = const inputB = const sum = const hWare = inputA inputB sumconst ioHandler = hWareconsole // 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 thewires
method). - An array consisting of I/O
wires
is passed onto the parent classHardware
, 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 aStringIO
instance to do I/O operations withstring
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).
- internalWiring - Array of
- Your entire logic goes into your Class' constructor.
internalWiring
variable is used to initialiseWire
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.
const wires = 'Connectors'const AndGate = 'Gates'const StringIO = 'IO'const Hardware = 'Base' { supera b c d o thisinternalWiring = // declare wires to be used internally thiscomponents thiscomponents thiscomponents } const a = const b = const c = const d = const o = const fourInpAnd = a b c d oconst ioHandler = fourInpAnd console // prints 0 console // 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
const Hardware = 'Base' { if xlength != 1 || ylength != 1 || olength != 1 throw 'Invalid Connection/s' superx y o thisx = x thisy = y thiso = o thishardware = thishardware x0 y0 } { let xSig = thisx0 let ySig = thisy0 if xSig === 0 || ySig === 0 thiso0 else if xSig === undefined || ySig === undefined thiso0 else thiso0 }
Development
There are just so many possibilities to do here! Would love to get contributions from the community 😄