next up previous contents
Next: Conclusions Up: Hardware Simulation Using C++ Previous: Implementation of the Simulation

Redefining the virtual process() function

One problem with implementing simulators using structured programming languages has to do with determining which function to call to simulate a component. In some languages, such as Pascal, this means resorting to tag fields in records and using huge case statements which have to be modified each and every time a component is added or deleted from the library. C allows a slightly cleaner solution through the use of pointers to functions. However, this is still deficient since the user must remember to assign the address of the function which processes the inputs to the function pointer of the component structure. This may not seem like a major drawback; however, if one built a circuit using a thousand components and one function pointer assignment was missed, the simulation would likely terminate in error. The user would then have to check through the code making sure that every function pointer assignment was made. If the user were truly unlucky, the program would execute smoothly but produce erroneous simulation results leading the user to think that the circuit design was incorrect.

Object-oriented programming offers a clean, extensible solution to the problem through the use of virtual functions. When the simulate() method sends a process() message, the process routine that is called depends upon which component the simulate() message was sent to. Hence the process() message is resolved during runtime. For example, if the simulate() message was sent to a NAND gate, simulate() would invoke NAND's process() method. If, however, the simulate() message was sent to a NOR gate, NOR's process() method would be invoked instead. The process() function is initially defined in the Component class to output an error message and terminate the execution of the program. Should a user forget to define a process() method for a low-level component, then the component will inherit the process() function from the base class. When the simulate() method attempts to invoke the process() function for that component, an error message is displayed telling the user that it was unable to invoke the component's process() method. The name of the component is also displayed.

The purpose of the process() method is to read inputs from the input ports, process them and generate the appropriate output signals to the output ports. For example, a two-input AND gate would define its process() function as follows:

void And2::process(ckt_time t)
{
        if (I1.get_Signal(t) == HIGH && I2.get_Signal(t) == HIGH)
                O1.send_Signal(Signal(HIGH, t + delay));
        else if (I1.get_Signal(t) == LOW || I2.get_Signal(t) == LOW)
                O1.send_Signal(Signal(LOW, t + delay));
        else 
                O1.send_Signal(Signal(X, t + delay));
}

When getting a signal from a port, there is no need to call an access function in order to determine the value of the signal. This is because the user defined conversion, operator Sig_Val(), automatically converts a signal to a signal value when used in the context of a signal value. As can be seen above, this makes the process() method look much more intuitive.

The designer may perform other actions within the process() method to make the simulation more realistic. (For example, the user may decide to modify the delay time or other parameters internal to the component to simulate say, an increase in resistance due to local heating).

Notice that when a new circuit component is added to the library, no change whatsoever has to be made to the simulation code. If the component is a low-level component then its behaviour is supplied by simply defining the virtual process() method for its class. This makes the library of circuit components much easier to maintain. If the component is composed of subcomponents, then all the designer needs to do is to define how the subcomponents are connected using the enclosing component's constructor.


next up previous contents
Next: Conclusions Up: Hardware Simulation Using C++ Previous: Implementation of the Simulation

Donald Craig
Sat Jul 13 16:02:11 NDT 1996