A prototype digital logic simulator.
The goal of this project is to show how one can build a digital logic simulator that can simulator a digital circuit.
It sounds like pulling hair, but it is actually important to differentiate 3 different concepts. Component, ComponentFactory and MappedComponentFactory.
A component is analogus to an Adder, if there is 3 Adder in the circuit, there are 3 instances of the Adder Component object.
A component factory describes how one can create component. There is only one AdderFactory. It does not describe how it is connected in the circuit.
A mapped component factory is a component factory together with a mapping of its port to signals. A CompositeComponentFactory contains a collection of MappedComponentFactory so that the Circuit builder can build the circuit and do the port mapping.
There are 3 special components that the simulation program process differently. The inputs, the nand gate, and the probe. The inputs are special because they are specified values on what to feed the circuit that is not generated by something else. The nand gate is the only primitive we have, the rest is built on top of it as composite. The probe needs to output the result so it is also specially coded.
First, the circuit descriptions are read from JSON files, there are all component factories, with a single component factory called testBench which will be used as the root to build the circuit.
Second, a top-down recursive procedure is used to build the circuit and expand all the factories.
Third, we build an event queue. This event queue is used to drive the circuit simulation. Initially, the input events are enqueued.
Fourth, for each ev 57EB ent in the event queue, we process it. When a signal changes, a propagation is computed, and an event is pushed to the event queue. The simulation ends when the event queue is emptied.
An XOR gate is included as an example how one can use the simulator and build interesting circuits.
And XOR gate is defined in xor.json as follow:
{
"Ports": [ "a", "b", "out" ],
"Signals": [ "na", "nb", "nand1", "nand2" ],
"MappedComponentFactories": [
{
"ComponentFactoryName": "not",
"PortMapping": {
"in": "a",
"out": "na"
}
},
{
"ComponentFactoryName": "not",
"PortMapping": {
"in": "b",
"out": "nb"
}
},
{
"ComponentFactoryName": "nand",
"PortMapping": {
"a": "a",
"b": "nb",
"out": "nand1"
}
},
{
"ComponentFactoryName": "nand",
"PortMapping": {
"a": "na",
"b": "b",
"out": "nand2"
}
},
{
"ComponentFactoryName": "nand",
"PortMapping": {
"a": "nand1",
"b": "nand2",
"out": "out"
}
}
]
}
This should be self explanatory, to build a xor gate, I need two not gates and 3 nand gates. a
and b
are connected to the not gate to get the na
and nb
signals. The signals are in turn connected to nand gates to produce the final output.