This project is a digital circuit simulator implemented in Javascript. It is designed to simulate circuits synthesized by hardware design tools like Yosys (Github repo here), and it has a companion project yosys2digitaljs, which converts Yosys output files to DigitalJS. It is also intended to be a teaching tool, therefore readability and ease of inspection is one of top concerns for the project.
You can try it out online. The web app is a separate Github project.
You can use DigitalJS in your project by installing it from NPM:
npm install digitaljs
Or you can use the Webpack bundle directly.
To simulate a circuit represented using the JSON input format (described later)
and display it on a div
named #paper
, you need to run the following
JS code (see running example):
// create the simulation object
const circuit = new digitaljs.Circuit(input_goes_here);
// display on #paper
const paper = circuit.displayOn($('#paper'));
// activate real-time simulation
circuit.start();
Circuits are represented using JSON. The top-level object has three keys, devices
,
connectors
and subcircuits
. Under devices
is a list of all devices forming
the circuit, represented as an object, where keys are (unique and internal) device
names. Each device has a number of properties, which are represented by an object.
A mandatory property is type
, which specifies the type of the device. Example
device:
"dev1": {
"type": "And",
"label": "AND1"
}
Under connectors
is a list of connections between device ports, represented as an
array of objects with two keys, from
and to
. Both keys map to an object with two
keys, id
and port
; the first corresponds to a device name, and the second -- to
a valid port name for the device. A connection must lead from an output port to
an input port, and the bitwidth of both ports must be equal. Example connection:
{
"from": {
"id": "dev1",
"port": "out"
},
"to": {
"id": "dev2",
"port": "in"
}
}
Under subcircuits
is a list of subcircuit definitions, represented as an object,
where keys are unique subcircuit names. A subcircuit name can be used as
a celltype
for a device of type Subcircuit
; this instantiates the subcircuit.
A subcircuit definition
follows the representation of whole circuits, with the exception that subcircuits
cannot (currently) define their own subcircuits. A subcircuit can include
Input
and Output
devices, these are mapped to ports on a subcircuit
instance.
- Unary gates:
Not
,Repeater
- Attributes:
bits
(natural number) - Inputs:
in
(bits
-bit) - Outputs:
out
(bits
-bit)
- Attributes:
- N-ary gates:
And
,Nand
,Or
,Nor
,Xor
,Xnor
- Attributes:
bits
(natural number),inputs
(natural number, default 2) - Inputs:
in1
,in2
...inN
(bits
-bit,N
=inputs
) - Outputs:
out
(bits
-bit)
- Attributes:
- Reducing gates:
AndReduce
,NandReduce
,OrReduce
,NorReduce
,XorReduce
,XnorReduce
- Attributes:
bits
(natural number) - Inputs:
in
(bits
-bit) - Outputs:
out
(1-bit)
- Attributes:
- Bit shifts:
ShiftLeft
,ShiftRight
- Attributes:
bits.in1
,bits.in2
andbits.out
(natural number),signed.in1
,signed.in2
,signed.out
andfillx
(boolean) - Inputs:
in1
(bits.in1
-bit),in2
(bits.in2
-bit) - Outputs:
out
(bits.out
-bit)
- Attributes:
- Comparisons:
Eq
,Ne
,Lt
,Le
,Gt
,Ge
- Attributes:
bits.in1
andbits.in2
(natural number),signed.in1
andsigned.in2
(boolean) - Inputs:
in1
(bits.in1
-bit),in2
(bits.in2
-bit) - Outputs:
out
(1-bit)
- Attributes:
- Number constant:
Constant
- Attributes:
constant
(binary string) - Outputs:
out
(constant.length
-bit)
- Attributes:
- Unary arithmetic:
Negation
,UnaryPlus
- Attributes:
bits.in
andbits.out
(natural number),signed
(boolean) - Inputs:
in
(bits.in
-bit) - Outputs:
out
(bits.out
-bit)
- Attributes:
- Binary arithmetic:
Addition
,Subtraction
,Multiplication
,Division
,Modulo
,Power
- Attributes:
bits.in1
,bits.in2
andbits.out
(natural number),signed.in1
andsigned.in2
(boolean) - Inputs:
in1
(bits.in1
-bit),in2
(bits.in2
-bit) - Outputs:
out
(bits.out
-bit)
- Attributes:
- Multiplexer:
Mux
- Attributes:
bits.in
,bits.sel
(natural number) - Inputs:
in0
...inN
(bits.in
-bit,N
= 2**bits.sel
-1),sel
(bits.sel
-bit) - Outputs:
out
(bits.in
-bit)
- Attributes:
- One-hot multiplexer:
Mux1Hot
- Attributes:
bits.in
,bits.sel
(natural number) - Inputs:
in0
...inN
(bits.in
-bit,N
=bits.sel
),sel
(bits.sel
-bit) - Outputs:
out
(bits.in
-bit)
- Attributes:
- Sparse multiplexer:
MuxSparse
- Attributes:
bits.in
,bits.sel
(natural number),inputs
(list of natural numbers),default_input
(optional boolean) - Inputs:
in0
...inN
(bits.in
-bit,N
=inputs.length
, +1 ifdefault_input
is true) - Outputs:
out
(bits.in
-bit)
- Attributes:
- D flip-flop:
Dff
- Attributes:
bits
(natural number),polarity.clock
,polarity.arst
,polarity.srst
,polarity.aload
,polarity.set
,polarity.clr
,polarity.enable
,enable_srst
(optional booleans),initial
(optional binary string),arst_value
,srst_value
(optional binary string),no_data
(optional boolean) - Inputs:
in
(bits
-bit),clk
(1-bit, ifpolarity.clock
is present),arst
(1-bit, ifpolarity.arst
is present),srst
(1-bit, ifpolarity.srst
is present),en
(1-bit, ifpolarity.enable
is present),set
(1-bit, ifpolarity.set
is present),clr
(1-bit, ifpolarity.clr
is present),ain
(bits
-bit, ifpolarity.aload
is present),aload
(1-bit, ifpolarity.aload
is present) - Outputs:
out
(bits
-bit)
- Attributes:
- Memory:
Memory
- Attributes:
bits
,abits
,words
,offset
(natural number),rdports
(array of read port descriptors),wrports
(array of write port descriptors),memdata
(memory contents description) - Read port descriptor attributes:
enable_polarity
,clock_polarity
,arst_polarity
,srst_polarity
(optional booleans),init_value
,arst_value
,srst_value
(optional binary strings),transparent
,collision
(optional booleans or arrays of booleans) - Write port descriptor attributes:
enable_polarity
,clock_polarity
,no_bit_enable
(optional booleans) - Inputs (per read port):
rdKaddr
(abits
-bit),rdKen
(1-bit, ifenable_polarity
is present),rdKclk
(1-bit, ifclock_polarity
is present),rdKarst
(1-bit, ifarst_polarity
is present),rdKsrst
(1-bit, ifsrst_polarity
is present) - Outputs (per read port):
rdKdata
(bits
-bit) - Inputs (per write port):
wrKaddr
(abits
-bit),wrKdata
(bits
-bit),wrKen
(1-bit (whenno_bit_enable
is true) orbits
-bit (otherwise), ifenable_polarity
is present),wrKclk
(1-bit, ifclock_polarity
is present)
- Attributes:
- Clock source:
Clock
- Outputs:
out
(1-bit)
- Outputs:
- Button input:
Button
- Outputs:
out
(1-bit)
- Outputs:
- Lamp output:
Lamp
- Inputs:
in
(1-bit)
- Inputs:
- Number input:
NumEntry
- Attributes:
bits
(natural number),numbase
(string) - Outputs:
out
(bits
-bit)
- Attributes:
- Number output:
NumDisplay
- Attributes:
bits
(natural number),numbase
(string) - Inputs:
in
(bits
-bit)
- Attributes:
- Subcircuit input:
Input
- Attributes:
bits
(natural number) - Outputs:
out
(bits
-bit)
- Attributes:
- Subcircuit output:
Output
- Attributes:
bits
(natural number) - Inputs:
in
(bits
-bit)
- Attributes:
- 7 segment display output:
Display7
- Inputs:
bits
(8-bit only - most significant bit controls decimal point LED)
- Inputs:
- Bus grouping:
BusGroup
- Attributes:
groups
(array of natural numbers) - Inputs:
in0
(groups[0]
-bit) ...inN
(groups[N]
-bit) - Outputs:
out
(sum-of-groups
-bit)
- Attributes:
- Bus ungrouping:
BusUngroup
- Attributes:
groups
(array of natural numbers) - Inputs:
in
(sum-of-groups
-bit) - Outputs:
out0
(groups[0]
-bit) ...outN
(groups[N]
-bit)
- Attributes:
- Bus slicing:
BusSlice
- Attributes:
slice.first
,slice.count
,slice.total
(natural number) - Inputs:
in
(slice.total
-bit) - Outputs:
out
(slice.count
-bit)
- Attributes:
- Zero- and sign-extension:
ZeroExtend
,SignExtend
- Attributes:
extend.input
,extend.output
(natural number) - Inputs:
in
(extend.input
-bit) - Outputs:
out
(extend.output
-bit)
- Attributes:
- Finite state machines:
FSM
- Attributes:
bits.in
,bits.out
,states
,init_state
,current_state
(natural number),trans_table
(array of transition descriptors) - Transition descriptor attributes:
ctrl_in
,ctrl_out
(binary strings),state_in
,state_out
(natural numbers) - Inputs:
clk
(1-bit),arst
(1-bit),in
(bits.in
-bit) - Outputs:
out
(bits.out
-bit)
- Attributes:
Some ideas for further developing the simulator.
- Use JointJS elementTools for configuring/removing gates.
- RAM/ROM import/export for Verilog format and Intel HEX.
- Framebuffer element with character/bitmap display.
- More editing capability: adding and removing blocks, modifying some of blocks' properties.
- Undo-redo capability.
- Saving and loading circuits, including layout and state.
- Generic handling of negation for unary/binary gates (negation on inputs/outputs) for better clarity.
- SVG export.
- Verilog export.
- Smartphone and tablet compatible UI.