Skip to content

How the Simulator Works

Ruturaj Mohite edited this page Nov 4, 2021 · 3 revisions

There are two crucial components to the working of the simulator,

  1. Circuit Elements (such as Input, Output, AND Gate, ROM, LED light etc.)
  2. Nodes (The green dots that are connected by wires)

To understand the working of the simulator, we first need to understand how circuit elements and nodes work.

CircuitElements and Nodes

The CircuitElement class is a superclass for all the circuit elements. It declares some common attributes and functions that all circuit elements have (ex. x position, y position and draw() function).

The most important function here is the resolve() function. This function defines how the element processes the inputs and generates an output. For example, an AND gate takes the inputs and applies the AND operation on them to generate the output. This behaviour would be defined in the resolve() function. Notice how the function is empty. This is because there is no common way to resolve all elements, each element has its own way to process the inputs. This function is therefore only an interface and is overridden in each of individual circuit elements (checkout the resolve implmentation for AND gates ).

A node is the fundamental element of the simulator. Nodes are connected by wires and their job is to propagate values from one circuitElement to another. Every circuitElement has input and output nodes.

Nodes are of 3 types on the CircuitVerse simulator.

  1. Input nodes (used to give inputs to circuitElements)
  2. Output nodes (used to take outputs from circuitElements)
  3. Intermediate nodes (their sole job is to propagate values)

Types of Nodes

The Nodes' resolve() function is a little complex, but in a broad sense, a node's resolve function resolves its neighbour nodes with its own value (basically propagates the value). If the node is of type Input, then it also resolves it's parent CircuitElement (see in figure above that input nodes are attached to a circuitElement).

Circuit Resolution

Now that we know the basic working of these elements, we see how they work in the big picture.

The last section talks about the globalScope. GlobalScope is the Javascript Object that keeps track of what elements and nodes are on the circuit and where.

Every so often (for example on mousedown, and otherwise at regular intervals) the play() function is called (Look for the play() function here ). This function adds all the Input elements on to a Simulation Queue (it uses the globalScope to know which Input elements are present on the circuit) and starts dequeueing them and calling resolve() on them. The simulation queue is a priority queue which contains Nodes and CircuitElements with their priority as the delay attribute. This is the beginning of the resolution algorithm.

The Resolution Algorithm

Once the Input nodes are added onto the simulationQueue, they are dequeued one by one according to their priority and resolve() is called on them. The Input.resolve() function sets the value of the 'output node' of the Input element (see from the figure that output nodes are also attached to the CircuitElements) and queues the 'output node' into the simulationQueue. When this node is dequeued, resolve() is called on this as well, which sets the value of its neigbouring nodes as its value and adds those neighbouring nodes into the simulationQueue. You can see that so on, the value of this node is propagated forward. When an 'input node' is dequeued, it's resolve() function adds its parent element into the simulationQueue.

This algorithm is very similar to the well known shortest path algorithm Dijkstra's algorithm. You can think of each Node and CircuitElement as a Graph Node and the delay attribute as the edge weights in the Dijkstra's algorithm.

Clone this wiki locally