DigSim Structure
Basics
Each simulator component implements the fips.sim.dig.base.Component interface. The implementation holds all information about the configuration paramters, the pin names and descriptions, , serialization, etc ... If two or more pins in the editor-gui get connected, then the editor creates a fips.sim.dig.comp.Pin object and uses it for a setPin call on both components.
When the simulation starts, each component can read the pin with the getValue method. If the pin is an input pin for one component it does also a setValue(HiZ) to let other components drive the pin. If the pin wants to drive a signal onto the line it does setValue(HIGH). Calls for setValue are only neccessary when the outputvalue of a component changed, the pin will assume, that the levels didn't change if no such call is made. If all components have done a setValue, the Pin will merge the values into the output value using a transition matrix:
  final static int transitions[][] = {
    {LOW,     UNKNOWN, UNKNOWN, LOW,      LOW,      LOW,      LOW },
    {UNKNOWN, HIGH,    UNKNOWN, HIGH,     HIGH,     HIGH,     HIGH},
    {UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN,  UNKNOWN,  UNKNOWN,  UNKNOWN},
    {LOW,     HIGH,    UNKNOWN, HiZ,      WEAKLOW,  WEAKHIGH, WEAKUNKN},
    {LOW,     HIGH,    UNKNOWN, WEAKLOW,  WEAKLOW,  WEAKUNKN, WEAKUNKN},
    {LOW,     HIGH,    UNKNOWN, WEAKHIGH, WEAKUNKN, WEAKHIGH, WEAKUNKN},
    {LOW,     HIGH,    UNKNOWN, WEAKUNKN, WEAKUNKN, WEAKUNKN, WEAKUNKN}
  };


Timing
The simulation timing is done by the fips.sim.dig.comp.Timer. Each new component gets registered at the timer object with the addComponent call. To simulation is started by starting the timer. Then the timer does two steps in every simulation cycle:
getNextStep(): The timer calls the getNextStep method of every registered component. The method checks the input values and calculates the time to the first possible output change. For example a 10kHz Clock, that changed its output just now returns 50us, because that is the time when it will change its output again. The Timer calculates the minimum of the return values of all getNextStep calls, because that is the time, when at least one component will change its output.
doStep(): Now the calls the doStep method of every registered component with the time-interval calculated in the getNextStep phase.
Here is an example: You have a clock with 10kHz and a gate with a propagation of 1us. The clock changed its output right now, here are the calls and the return values for the next simulation steps:
clock.getNextStep()=50us
gate.getNextStep()=1us
clock.doStep(1us)
gate.doStep(1us)
clock.getNextStep()=49us
gate.getNextStep()=MaxValue	# *) see below
clock.doStep(49us)
gate.doStep(49us)
* The gate will never again change its output value if the inputs dont change before, so it returns never (maximal value). The getNextStep method does not return us, this was just used to make the example better readable. The method returns a long 64bit value holding the time in fs.

GUI
Each digital component has also a gui. To avoid creating a graphics context for each component, all components will use the context of the editor. The editor needs to know how to handle this, therefor it uses these methods:
getSize(): get the size of the component in units. The value depends on the orientation of the component (see below).
getPinPos(num): get the position of pin num, return value is in units and depends on the orientation setGraphics(offset,scale,orientation): This method is used to tell the component where it should paint into the graphics context and what scale,orientation to use (see below).
doClick(x,y): If the editor got a click-event into the place of a component, it will call the doClick method of the component.

Units: The editor uses a grid to place the components. The component edges and the pins are at grid points. To have the possibility of zooming the components, the grid can be scaled.
Scale: The scaling is done in an exponential way, the default scale is 4, that means that each unit-square in the grid is enlarged to a 16x16 pixel square. A good component should be able to render its gui at any scale, but it's also ok to draw only a good scale4 gui and just show a box for all other scales.
Orientation: Components may be rotated. The rotating is not done by the editor to let components rotate in an intelligent way, e.g. rotate the borders but don't rotate text strings, cause they will get unreadable.

Last updated: 2.12.2002