# User's Guide to the 6.111 C Simulator

Author:
Mark W. Eichin

## Introduction

The C Simulator is a time domain digital simulator. It is a set of macros and libraries in the C programming language that can be used to build a program which simulates the operation of a circuit, which is then compiled and executed. External inputs and outputs are permitted via the filesystem (see Chapter "Simulator data files" and the document [tm:sig]).

## How to create a simulation

Make a copy of the boilerplate simulation file, mysim.c (see this figure). Also make a copy of the Makefile which you will find there. Load mysim.c into your favorite editor (presumably emacs) and prepare to enter your simulation.

You should leave the template file unchanged above and below the lines

/* Simulation BEGINS here, type your work BELOW this line */ /* Simulation ENDS here, only type your work ABOVE this line */ These are comments to tell you where your work should go (the C language begins comments with /* and ends them with */). Everything outside these lines is the same for all simulations, only the code pertaining to your circuit goes between these two lines.

#### Simple circuit.

Let's begin with the simple circuit pictured in this figure. First, trace out each run of wire that is electrically connected. Insert a declaration

MAKEWIRE(A); MAKEWIRE(B); MAKEWIRE(C); MAKEWIRE(D); for each run of wire that you have traced out. Record the names (scribbling them on the schematic might be appropriate) since you will need them later to actually assemble the circuit. Pick any names you want, but keep in mind that
• they have to begin with a letter, though they may contain numbers (they obey the same rules as C identifiers.)
• any wires that are external inputs or outputs should be labelled the way you want to see them in the input or output files (see Chapter "Simulator data files" for more details.)

Now that all the wires have been declared, they should be connected to the circuit. Start by looking up function names for the simulations of each of the circuit elements. If any of them are not in the predefined table, you will have to break them down into existing elements, or define a new C procedure to simulate them (see chapter "Building Submodules".)

Then, using the function for each element, create a connection, as follows:

AND(C, A, B); OR(D, A, B); Once connections have been made, output lines should be defined. Since C and D are interesting, we will output them: OUTPUT(C); OUTPUT(D); And, since the schematic shows A as being carried through to the output of the circuit, we'll print it as well: OUTPUT(A); The input values will be assumed to come from a file automatically. Now that you have entered these into the file, save it, and exit the editor. Now type make mysim. This will compile your simulation, and add the standard simulation libraries to it. If you see messages like\footnote{Bear in mind that different compilers may generate different messages.} "mysim.c", line 33: syntax error "mysim.c":33: syntax error *** Exit 1 Stop. then there was some error in what you typed. Another error you may receive is mysim.c:33: undeclared variable D' (first use here) If D' is a wire name, perhaps you left out the MAKEWIRE(D) statement. Be sure to check the line listed (and lines before it; C may report errors after they happen, but it will never report them before it finds them) and the following things:
• Make sure that you have not left out the semicolons after the commands used. Semicolons separate commands, newlines are ignored.
• Make sure that you have spelled and capitalized the commands correctly. C is both case and spelling sensitive.
• Make sure that you gave the right arguments to the function (check the table again if you are not sure.)
• Make sure that the wire name you used was created in advance (with the MAKEWIRE command). Also be sure that it is spelled correctly.
You may also get an error of the form Undefined: _ANND *** Exit 1 Stop. The undefined symbol will probably be a misspelled command name. Check back in mysim.c for that spelling, and correct it. Check in the table of functions if you are not sure.

#### Complete user code for simulation

/* Simulation BEGINS here, type your work BELOW this line */ MAKEWIRE(A); MAKEWIRE(B); MAKEWIRE(C); MAKEWIRE(D); AND(C, A, B); OR(D, A, B); OUTPUT(A); OUTPUT(C); OUTPUT(D); /* Simulation ENDS here, only type your work ABOVE this line */ \begin{figure} \begin{frepcode}{../src/demo.c} \end{frepcode} \caption{Raw user template} \end{figure}

Once you have successfully compiled the simulation (that is, once make runs through and prints only the compilation commands, and no error messages or Stopped'' messages) you can run it. Typing

mysim by itself will set up the simulation, and process any SETOUTPUT() statements, and run the simulation, printing the results. If you want to read an input file into the simulation, use the command mysim -i filename where filename contains the input statements (see Chapter "Simulator data files"). To record the result in a file outputfile, use the command mysim -o outputfile The -o and -i commands may be mixed. You can use the digital oscilloscope to produce and read the data files.

## Building Submodules

Complex submodules should either be
• implemented in C as new functions, or
• implemented as simulator subunits.
New functions are straightforward to implement, and fast as well, if you are familiar with the internal workings of the simulator. This is currently left to the technical reference manual, but may be detailed here at a later time. A simulator subunit can be created by making a copy of mysub.c. If you are only making one subunit, this will suffice. Follow the same procedure described in Chapter
"How to create a simulation" to construct the simulation, using MAKEWIRE for the internal wiring. To create a template function for the main body of the simulator to use, edit the template line at the top of the file: #define FUNCTION my_func #define MY(OUT, IN1, IN2) make_binop(my_func, OUT, IN1, IN2) #define DONE Use your editor's global replace to change all uses of my to whatever name you want to assign to the function you create. This should change my_func, MY, and later MY_DELAY to appropriate names. MY_DELAY is optional, and probably set it to 1 if your element doesn't use it. The #define MY(OUT, IN1 ... ) ... statement is what creates the macro the user calls to link this element into their wirelist. There are several procedures for creating these:
• make_binop(op, c, a, b) creates a node of circuit element op that has arguments c, a, and b, but only depends on a and b. This is used for and, or, xor, delay, and tristate.
• make_unop(op, b, a) creates a node of circuit element op that has arguments b and a, but only needs to run when a changes. This is used for the not primitive.
• make_tracer(op, line) creates a node which runs the procedure op when line changes state. This is used by the output primitive, and as an obvious way to implement LED's or other indicator devices.
• make_anop(opcount, oparguments, argcount, arguments) is the generic construction macro with arguments of
• opcount: the number of arguments in the oparguments list. The valid range is currently 0 through 9.
• oparguments: the list of the arguments that should cause the procedure to run.
• argcount: the number of arguments in the real arguments list. The valid range is currently 0 through 10.
• arguments: the real arguments, which are passed as a generic list to the procedure which is the first element in the list. By design, the first element of this list must be the procedure to call to process the circuit changes; by convention, the next elements are the output lines, followed by the input (driving) lines.
The primitives you should need are either declarations or statements. The declarations are
• STATE to declare variables that hold the current values of wires.
• Wire for variables which actually hold wires.
Statements include
• SAVEOUTWIRE(argumentlist, wirename) saves the current wire in the list of arguments into the wire called wirename (which must be declared above.) It then advances the argumentlist to the next argument.
• READNEXTSTATE(argumentlist, statename) saves the state of the current wire in the list of arguments into the state variable called statename (which must be declared above.) It also advances the argumentlist to the next argument.
• READNEXTSTATETIME(argumentlist, statename, timeval) saves the state of the current wire in the list of arguments into the state variable called statename (which must be declared above) and the time at which the change will occur into the variable called timeval. It also advances the argumentlist to the next argument.
• SETOUTPUT(wirename, statename, timeval) sets the write named wirename to the value of the state variable called statename at the value of the time expression timeval. timeval is often in the form globaltime+MY_DELAY.
• READNEXTTIME(argumentlist, timevariable) saves a time value from the argument list and stores it into timevariable. It advances the argumentlist to the next argument. (This is used in the DELAY primitive, and is included as an example of other argument choices.)
\begin{figure} \begin{frepcode}{../src/funclib/xor.c}\end{frepcode} \caption{ xor.c: a sample circuit element extension.} \end{figure}

## Simulator data files

(These file formats are based on those used in
[tm:sig].)

The input file format consists of lines which are either assignments or wait statements. An assignment consists of a wire name followed by a space and then a value, which is one of

Tag
Meaning
1
Logic High
0
Logic Low
U
Undefined
X
Tristate
C
Contention
A sample file is included in this Figure.

#### Sample input wave file

A 0 B 0 wait 50 A 1 wait 10 B 1 wait 40 A 0 wait 50 A 1 wait 10 B 0 wait 40 A 0 wait 100

#### Output of simulator run.

wait 1 A 0 wait 10 C 0 C 0 D 1 D 0 wait 40 A 1 wait 10 C 0 D 1 wait 10 C 1 D 1 wait 30 A 0 wait 10 C 0 D 1 wait 40 A 1 wait 10 C 1 D 1 wait 10 C 0 D 1 wait 30 A 0 wait 10 C 0 D 0

A wait statement is a line containing the token wait either alone or followed by a number of time units (nominally nanoseconds) before the next state change. If the number is left out, it means to allow the simulator to settle'' before making the next state change. The simulator currently ignores these statements, as it propagates any non-delayed changes immediately.

## Appendix: Standard Circuit Element Library

The following table lists the standard circuit elements included with the C Simulator. Other specific elements may be have been added for specific projects; see your local documentation for more detail.

and
C <- A .AND. B
or
C <- A .OR. B
xor
C <- A .XOR. B
and
C <- A .AND. B
not
B <- .NOT. A
tristate
if B then C <- A else C <- tristate
delay
B <- A after del ticks
output
write text value of A with timestamp

The D Flip Flop is a bit more complex, and is simulated in the detail described below.

Table from page 5-22, TI databook, for 7474:
|------------------------------------------------|
|              INPUTS            |    OUTPUTS    |
|--------------------------------+---------------|
| preset | clear | clock |   D   |   Q   |  Q'   |
|--------+-------+-------+-------+-------+-------|
|   L    |   H   |   X   |   X   |   H   |  L    |
|   H    |   L   |   X   |   X   |   L   |  H    |
|   L    |   L   |   X   |   X   |   H*  |  H*   |
|   H    |   H   |   ^   |   H   |   H   |  L    |
|   H    |   H   |   ^   |   L   |   L   |  H    |
|   H    |   H   |   L   |   X   |   Q0  |  Q'0  |
|--------+-------+-------+-------+-------+-------|
|                                   *unstable.   |
|------------------------------------------------|