[comp.lsi] SLIC Updated Source Code

shers@mit-caf.MIT.EDU (Alex Sherstinsky) (11/24/88)

The source code for a new switch level simulator for MOS digital ICs  
is included below in a "shar" format.  The new switch level simulator
has certain advantages and disadvantages compared to the existing switch 
level simulators.  The program is distributed free of charge to any person 
or organization willing to observe the copyright formalities and to send 
comments, criticism, and suggestions to the author.
Very Best Wishes,
Alex Sherstinsky (shers@caf.mit.edu)
---- Cut Here and unpack ----
#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  slic.doc
#	  .exrc
#	  Makefile
#	  args.h
#	  dump.h
#	  files.h
#	  func.h
#	  hash.h
#	  main.h
#	  queue.h
#	  runsim.h
#	  state.h
#	  tech.h
#	  args.c
#	  dump.c
#	  files.c
#	  func.c
#	  hash.c
#	  main.c
#	  queue.c
#	  runsim.c
#	  state.c
#
if test -f slic.doc; then echo "File slic.doc exists"; else
echo "x - extracting slic.doc (Text)"
sed 's/^X//' << 'SHAR_EOF' > slic.doc &&
X        SLIC:  Switch Level Integrated Circuits Simulator
X
X                            Alex Sherstinsky,
X                  Microsystems Technology Laboratories,
X                         Building 39, Room 611,
X                 Massachusetts Institute Of Technology,
X                        77 Massachusetts Avenue,
X                           Cambridge, MA 02139
X                        Telephone: (617)253-0710
X               Electronic Mail Address: shers@caf.mit.edu
X
X
X                           Background
X
X
X     One of the crucial steps in the design of a  digital  IC  is
X
Xthe  verification  of  the  layout of individual cells and, ulti-
X
Xmately, the entire chip.  This problem can  be  approached  using
X
Xtwo  different  strategies: net-list comparison and logic simula-
X
Xtion.  If the chip is laid out using an automatic layout  genera-
X
Xtor, then it is advantageous to extract the resulting layout into
X
Xa net-list and compare it with  the  net-list  extracted  from  a
X
Xbehavioral  model of the system.  On the other hand, a simulation
X
Xof the system on the  transistor  level  is  a  more  appropriate
X
Xchoice for designs laid out manually.  The purpose of the simula-
X
Xtion would be to check the operation of the chip  and  to  detect
X
Xerrors  in circuit design and layout.  SPICE is a circuit simula-
X
Xtor that uses the most accurate models for  transistors,  capaci-
X
Xtors,  etc.  However, running SPICE on large circuits is infeasi-
X
Xble using a standard computer resource.  Hence, a need arises for
X
Xa  simulator  whose models for circuit elements are simple enough
X
Xto make simulations run faster and yet adequate  to  capture  the
X
Xessentials of the circuit's performance.
X
X
X     In digital circuits, signals are expected to take on only  a
X
Xfew   discrete levels (e.g., low, high, and don't-care).  In this
X
Xcase, a simulation model that treats MOS transistors as  switches
X
Xcan be explored to yield an acceptable degree of accuracy.
X
X
X     The main objective of the switch level  simulator  presented
X
Xin  this document is to be able to handle, under a certain set of
X
Xassumptions, as wide a variety of MOS circuit topologies as  pos-
X
Xsible (transmission gates, flip flops, etc.) without the need for
X
Xthe user to intervene on the circuit level.  Typical examples  of
X
Xuser  intervention  are:  giving directionality to signal flow in
X
Xmosfets, assigning higher capacitive weight to some  nodes  rela-
X
Xtive to others, and so on.
X
X                      Introduction To SLIC
X
X
X     A logic circuit consists of a set of nodes connected by  MOS
X
Xtransistors.   When  modeling mosfet circuits, the simulator com-
X
Xputes the logical behavior in a highly idealized way according to
X
Xa  switch level algorithm presented below.  This approach has the
X
Xpotential to capture many of the subtleties of MOS circuit opera-
X
Xtion,  such  as  ratioed  circuits, charge sharing, bidirectional
X
Xtransmission gates (pass transistors), MOS diodes, and precharged
X
Xlogic.  However,  the  simulator  makes  no  attempt to model the
X
Xactual circuit timing; the simulator cannot be  used  to  measure
X
Xthe  speed  of a circuit, and it may yield incorrect results when
X
Xthe circuit behavior is sensitive to delays. Even though  a  wide
X
Xvariety  of  circuits  can  be modeled at the switch level, there
X
Xremains one important  circuit  phenomenon  that  SLIC  does  not
X
Xcapture  (because  of  the  lack  of  timing  in its switch level
X
Xmodel): transient charge sharing.  Circuits which  rely  on  this
X
Xphenomenon  to  override a feedback value cannot be modeled.  The
X
Xuser must either redesign these circuits, or change the timing of
X
Xcontrol signals.
X
X
X     In order to benefit the most from SLIC, the following design
X
Xmethodology for digital NMOS or CMOS projects should be used:
X
X1.  Perform all timing and transient charge sharing
X
X    simulations with simulators that do handle  timing,  such  as
X
X    SPICE and CRYSTAL.
X
X2.  Once timing has been figured out and accepted,
X
X    run SLIC on the cell to check the logic.
X
X3.  After that, connect all the cells into blocks
X
X    of higher and higher abstraction and run SLIC  to  check  the
X
X    functionality and, thereby, layout.
X
X
X     SLIC is thus ideal for projects with clearly defined clocked
X
Xdata paths.
X
X
X     Provided circuits are designed and laid  out  to  make  them
X
Xinsensitive to SLIC's limitations, here is a list of the capabil-
X
Xities of SLIC:
X
X1.  All purely combinational circuits.  This includes
X
X    domino logic.  SLIC has no problems with transmission  gates,
X
X    and  can simulate as well as detect W/L circuit design errors
X
X    in the famous six  transistor  CMOS  "exclusive  OR"  (6tXOR)
X
X    gate.
X
X2.  SLIC can simulate a limited variety of SRAM
X
X    and DRAM designs.
X
X3.  SLIC cannot handle unstable circuits
X
X    such as ring oscillators.
X
X
X     SLIC requires no user  intervention  on  the  circuit  level
X
X(i.e., specifying directionality for mosfets, resizing node capa-
X
Xcitances, etc.).  However, a limited degree of user  intervention
X
Xis  allowed  on the command level.  The user can initialize arbi-
X
Xtrary nodes at the beginning of the simulation run  in  order  to
X
Xstart the circuit in a desired state.
X
X                  I/O File Formats Used By SLIC
X
X
X     SLIC reads the ".sim" file (UC Berkeley format).   Here  are
X
Xthe tokens in the ".sim" file, which SLIC uses to read mosfets:
X
Xmos_type gate_name source_name drain_name length width,
X
Xwhere the ordering of source and drain node names is interchange-
X
Xable; and capacitors:
X
XC node_name substrate_node_name.
X
XFor example, here is a ".sim" file for a CMOS inverter:
X
X| units: 100    tech: scmos
Xp in Vdd out 2 20
Xn in GND out 2 10
XC in GND 120
XC Vdd GND 110
XC GND GND 300
XC out GND 200
X
X
X     The commands that drive SLIC (and thus should  be  contained
X
Xin  the  ".drive"  file) are the specification of inputs, clocks,
X
Xoutputs, and initialization (preset)  of  nodes.   SLIC  supports
X
Xcomments as long as the first character on the line is "|".  SLIC
X
Xinterprets all of its commands and bit values in a case  insensi-
X
Xtive  fashion.   Power and ground are treated as ordinary inputs.
X
XThe clocks sequence through all of their values for each value of
X
Xother inputs. The last bit of an input (or a clock) is used again
X
Xin the next cycle of the simulation if the index of that  bit  is
X
Xless  than the index of the bit of some other input (or a clock).
X
XThis feature is common to many switch level simulators.
X
X
X     The simulation program is designed primarily for  simulating
X
Xclocked  systems,  where  a  clocking scheme consists of a set of
X
Xstate sequences to be applied cyclically to a set of input nodes.
X
XThe program assumes that the circuit clocks operate slowly enough
X
Xfor the entire circuit to stabilize between each change of  clock
X
Xand  input  data  values.   For synchronous circuits, the flow of
X
Xtime can be viewed at four levels of granularity:
X
Xcycle:  A complete sequencing of the clocks.
Xphase:  A period in which all clock and input
X        values remain constant.
Xstep:  The basic simulation time unit.
X        Within a phase, unit steps are simulated until  the  net-
X        work  reaches  a  stable  state,  or  the  step  limit is
X        exceeded.
X
X
X     Unclocked circuits can also be simulated by interacting with
X
Xthe  user  at the phase level.  For a combinational circuit, each
X
Xphase represents the propagation of a  set  of  values  from  the
X
Xinputs  to  the outputs.  For an asynchronous circuit, each phase
X
Xrepresents a reaction by the circuit to a change in  the  control
X
Xlines  implementing  the  communication  protocol (generally some
X
Xform of hand-shaking).
X
X| This is an example of a ".drive" file.
X|
X| Supplies
X|
XI Vdd 1
XI GND 0
X|
X| Initialize the state of a T flip flop.
X|
XP TFFQ 1
X|
X| Specification of a two phase non overlapping
X| clock sequence.
X|
X| Observe that this pattern requires four
X| simulation phases. In phases 1 and
X| 3, one clock is active, while in in phases 2
X| and 4, both clocks are inactive.
X| These inactive phases are required to model the
X| nonoverlapping period of the clocks.
X|
XC phi1 1000
XC phi2 0010
X|
X| All other inputs.
X|
XI A 001101XX0010
XI B 0101XX10
X|
X| Note that the last "0" in the value sequence
X| for B will be used for all
X| remaining vectors of the simulation.
X|
X| The specification of output (observation) nodes.
X|
XO DataOut
XO Control
X
X
X     In this example, the same values for Vdd and  GND  are  used
X
Xthroughout  the  entire  duration of the longest input bit string
X
X(input A).  The specified outputs will be reported in the  ".res"
X
Xfile (the file of results) at the end of the simulation.
X
X
X     The symbols in the ".res" file are:
X
X
X1 -- logic high with drive
X0 -- logic low with drive
XH -- logic high without drive
XL -- logic low without drive
XX -- logic don't-care with or without drive
X
X
X     Here is an example of a ".res" file:
X
X>XX0101011H0L:DataOut
X>X01101001010:Control
X
X
X     The simulator assumes that when the circuit does not reach a
X
Xstable  state  within a fixed number of unit steps (determined by
X
Xthe step limit), an unbounded oscillation has occurred.  It  will
X
Xthen stop the simulation phase and print an error message.
X
X                       Switch Level Model
X
X
X     In SLIC, a logic circuit is thought of having two  types  of
X
Xelements:
X
XMosfet:  An MOS transistor acting as either a switch
X        that can connect its source and drain terminals, or as  a
X        diode,  depending  on  the state of its gate, source, and
X        drain terminals.
XNode:  An electrical node acting as either a signal
X        source (input) to the circuit, or a  capacitor  that  can
X        store charge dynamically.
X
XNodes can be divided into two categories:
X
XInput:  Provide strong signals from sources external
X        to the network (e.g.,  power,  ground,  clock,  and  data
X        inputs).
XStorage:  Have states determined by the operation of
X        the network and can retain these states in the absence of
X        applied signals.
X
X
X     A mosfet is a three terminal device  with  node  connections
X
Xgate,  source, and drain.  There is no distinction between source
X
Xand drain connections -- the mosfet is a symmetric, bidirectional
X
Xdevice.   The simulator models three types of mosfets: n-type, p-
X
Xtype, and depletion.  A mosfet  acts  as  a  switch  or  a  diode
X
Xbetween  source  and  drain, controlled by the state of its gate,
X
Xsource, and drain electrodes as follows:
X
X
XNMOS:
X
Xgate     source     drain     intended data flow    mode
X-------------------------------------------------------------
X0        X          X         either direction      switch-off
X1        0          X         source to drain       switch-on
X1        1          0         source to drain       diode-on
X1        1          1         source to drain       diode-off
X1        X          0         drain to source       switch-on
X1        0          1         drain to source       diode-on
X1        1          1         drain to source       diode-off
X
XPMOS:
X
Xgate     source     drain     intended data flow    mode
X-------------------------------------------------------------
X1        X          X         either direction      switch-off
X0        1          X         source to drain       switch-on
X0        0          0         source to drain       diode-off
X0        0          1         source to drain       diode-on
X0        X          1         drain to source       switch-on
X0        0          0         drain to source       diode-off
X0        1          0         drain to source       diode-on
X
XDNMOS:
X
Xgate     source     drain     intended data flow    mode  
X-------------------------------------------------------------
X0        1          1         either direction      switch-off
X0        1          0         source to drain       diode-on
XX        0          X         source to drain       switch-on
X1        1          X         source to drain       switch-on
X0        0          1         drain to source       diode-on
XX        X          0         drain to source       switch-on
X1        X          1         drain to source       switch-on
X
X
X     Each mosfet has a strength associated with it, which  equals
X
Xto  its  W/L  ratio for NMOS transistors and W/L ratio divided by
X
Xthe ratio of the mobilities  of  electrons  and  holes  for  PMOS
X
Xtransistors. Strength of a mosfet indicates (in a simplified way)
X
Xits conductance when turned on relative to  other  mosfets  which
X
Xmay form part of a ratioed path.
X
X
X     The Abstract Data Type (ADT) for each mosfet can access  all
X
Xof  the  nodes associated with the mosfet terminals.  The ADT for
X
Xeach node can access all of the mosfets connected to  that  node.
X
XWith  these  ADTs,  it is possible to start at any node or mosfet
X
Xand visit all nodes and mosfets in the network. This property  is
X
Xused for traversing charge shared sub-networks.
X
X
X     Each node in SLIC has a notion of  "drive"  associated  with
X
Xit.   The  logic  state  of a node is represented by one of three
X
Xlogic values:
X
X
X0               low
X1               high
XX               invalid (between 0 and 1), or uninitialized
X
XA node having one of the above logic values can have any value of
X
Xdrive,  the  lowest  being  no drive (high impedance state).  The
X
Xexternal input nodes have infinite  drive;  the  nodes  that  are
X
Xdisconnected  from  the  rest of the network have no drive.  When
X
Xthere is at least one path of conducting  mosfets  to  a  storage
X
Xnode from some input node(s), the node is driven to a logic state
X
Xdependent only on the strongest path(s), where the drive  of  any
X
Xnode  terminating  a  path  is  less  than the minimum transistor
X
Xstrength in the path.  The drive of a node in a path is  computed
X
Xaccording  to the same formula as the net conductance of a series
X
Xconnection of conductances.  Thus a stronger signal  will  always
X
Xoverride a weaker one, regardless of the logic value.  This means
X
Xthat SLIC does  not  model  signal  dependent  drive  accurately.
X
XNevertheless, a design style that eliminates the concern for sig-
X
Xnal dependent drive is simpler, not much less area efficient, and
X
Xis common.
X
X
X     Each storage node has a capacitance (to substrate)  computed
X
Xfor  it based on the information in the ".sim" file.  Input nodes
X
Xhave infinite capacitance by convention.
X
X                 Principle Of Operation Of SLIC
X
X
X     SLIC reads the ".sim" file and constructs a  hash  table  of
X
Xnodes.   Folded  mosfets  connected  to the same set of terminals
X
X(comb structures) are merged into a  single  mosfet  of  combined
X
Xstrength.   Prior  to  the  first  vector  of the simulation, the
X
Xpreset nodes receive the specified initialization values, but  no
X
Xdrive.
X
X
X     A simulation of a network with SLIC involves two  processes:
X
Xpropagation  of  drive  and  charge  sharing.  During one step, a
X
Xqueue consisting of nodes that need  to  be  evaluated  is  main-
X
Xtained.   The  queue is comprised of perturbed nodes and of nodes
X
Xthat are electrically connected to perturbed nodes via conducting
X
Xmosfets.   Propagation of drive and charge sharing are applied to
X
Xeach node in the queue, obeying the following precedence (in  the
X
Xorder  of  decreasing capability): input nodes (infinite current,
X
Xinfinite capacitance), nodes with drive (finite current, infinite
X
Xcapacitance),  nodes  with no drive (zero current, finite capaci-
X
Xtance).
X
X
X     Drive is propagated from external inputs to as many nodes in
X
Xthe  network  as possible, one node at a time.  Modulated by mos-
X
Xfets, drive flows throughout the network, thereby updating  nodal
X
Xlogic  values.   All  mosfets attached to each node are evaluated
X
Xusing the switch level model.  The evaluation of a mosfet amounts
X
Xto  computing  the drive the given mosfet is capable of imparting
X
Xto the node, based on the logic values and drives present at  the
X
Xmosfet's  terminals.   For  each  logic  value (low, high, don't-
X
Xcare), the maximum drive available from  the  node's  mosfets  is
X
Xcomputed.   The  highest  of  these  drives and the corresponding
X
Xlogic value are assigned to be the node's next  drive  and  logic
X
Xvalue,  after  which the node's ADT is updated. This implies that
X
Xthe node's parameters can influence the rest of  the  network  as
X
Xsoon  as the node has been updated.  In other words, mosfets have
X
Xzero delay.  The use of the zero-delay mosfet model speeds up the
X
Xpropagation  of drive and eliminates difficulties in getting cir-
X
Xcuits with positive feedback to settle during simulation.
X
X
X     Charge sharing is attempted among the  nodes  that  are  not
X
Xdriven, starting with the node for which the propagation of drive
X
Xhas just been performed. When a set of connected storage nodes is
X
Xisolated  from any input nodes, they are charged to a logic state
X
Xdependent only on the state(s) of the node(s)  with  the  largest
X
Xcapacitance.   Thus  the  value  on  a  more capacitive node will
X
Xalways override the value on a less capacitive one.  Charge shar-
X
Xing  sub-networks  are  formed from electrically connected (i.e.,
X
Xseparated by conducting mosfets) groups of non driven nodes.  The
X
Xcapacitances of every node in a charge sharing sub-network can be
X
Xfound charged to one of the three  possible  logic  values:  low,
X
Xhigh, or don't-care.  Thus for each group, three equivalent capa-
X
Xcitances are formed according to  the  logic  level.   The  final
X
Xcharge  shared  logic value for all nodes in the group is decided
X
Xbased on the relative sizes of the three equivalent capacitances.
X
X
X     Propagation of drive and  charge  sharing  process  pair  is
X
Xrepeated  until  the entire network settles, or the step limit is
X
Xexceeded.
X
X
X
X
X                           References
X
X
X
X[1]  R. E. Bryant, "A Switch-Level Model and Simulator for
X
X    MOS Digital  Systems,"  IEEE  Transactions  on  Computers  C-
X
X    33(2):160-177, February, 1984.
SHAR_EOF
chmod 0644 slic.doc || echo "restore of slic.doc fails"
fi
if test -f .exrc; then echo "File .exrc exists"; else
echo "x - extracting .exrc (Text)"
sed 's/^X//' << 'SHAR_EOF' > .exrc &&
Xset ai sm sw=4
SHAR_EOF
chmod 0644 .exrc || echo "restore of .exrc fails"
fi
if test -f Makefile; then echo "File Makefile exists"; else
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X# Makefile for the Switch Level Integrated Circuits simulator (SLIC)
X#******************************************************************************
X#Author: 
X#	Alex Sherstinsky,
X#	Microsystems Technology Laboratories,
X#	Building 39, Room 611,
X#	Massachusetts Institute Of Technology,
X#	77 Massachusetts Avenue,
X#	Cambridge, MA 02139
X#	Telephone: (617)253-0710 
X#	Electronic Mail Address: shers@caf.mit.edu
X#Copyright 1988 Massachusetts Institute Of Technology
X#All rights reserved.
X#This program may not be distributed to other organizations without the 
X#permission of the author.  In no case may it be distributed outside the
X#United States and Canada.  This program is supplied "as is", without any
X#kind of warranty, and M.I.T. does not promise to support it in any way.
X#This program is not to be incorporated into a commercial product, or access
X#to it sold, without prior written agreement from the author.
X#******************************************************************************
X#SLIC
X#******************************************************************************
X# Leaves executable file in slic
X
X#Compiler flags for debugging.
X#cflags  = -g
X#Compiler flags for optimizing.
Xcflags  = -O
Xhead   =  main.h dump.h runsim.h state.h hash.h queue.h files.h args.h tech.h \
X	  func.h 
Xobjs   =  main.o dump.o runsim.o state.o hash.o queue.o files.o args.o func.o 
Xsrcs   =  main.c dump.c runsim.c state.c hash.c queue.c files.c args.c func.c 
X
Xslic:  $(objs)
X	cc $(cflags) $(objs) -o slic
X
Xmain.o:	main.c func.h tech.h args.h files.h queue.h hash.h state.h runsim.h \
X	main.h
X	   cc -c $(cflags) main.c
X
Xdump.o:	dump.c func.h queue.h dump.h
X	cc -c $(cflags) dump.c 
X
Xrunsim.o:	runsim.c func.h tech.h state.h queue.h runsim.h
X	cc -c $(cflags) runsim.c
X
Xstate.o:	state.c func.h tech.h queue.h hash.h runsim.h state.h
X	cc -c $(cflags) state.c
X
Xhash.o:	hash.c func.h tech.h runsim.h state.h queue.h hash.h
X	cc -c $(cflags) hash.c 
X
Xqueue.o:	queue.c func.h queue.h 
X	cc -c $(cflags) queue.c 
X
Xfiles.o:	files.c func.h files.h
X	cc -c $(cflags) files.c 
X
Xargs.o:	args.c func.h args.h 
X	cc -c $(cflags) args.c 
X
Xfunc.o:	func.c func.h 
X	cc -c $(cflags) func.c 
X
Xclean:
X	/bin/rm $(objs)
X
Xlint:
X	lint -u -z $(srcs)
X
Xtar:
X	cd ..; tar -crf slic.tar Slic; cd Slic; /bin/mv ../slic.tar .
SHAR_EOF
chmod 0644 Makefile || echo "restore of Makefile fails"
fi
if test -f args.h; then echo "File args.h exists"; else
echo "x - extracting args.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > args.h &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X/*
XThis module obtains and processes the command line arguments.
X*/
X
X/*
XThe functions that obtain and process the command line arguments.
X*/
X
Xvoid ProcessArgs();
SHAR_EOF
chmod 0644 args.h || echo "restore of args.h fails"
fi
if test -f dump.h; then echo "File dump.h exists"; else
echo "x - extracting dump.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > dump.h &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X/*
XThis module prints the values of output vectors into the ".res" (results) file.
X*/
X
X/*
XFunctions used.
X*/
X
Xvoid DumpRes();
SHAR_EOF
chmod 0644 dump.h || echo "restore of dump.h fails"
fi
if test -f files.h; then echo "File files.h exists"; else
echo "x - extracting files.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > files.h &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X/*
XModule for opening and closing relevant files.
X*/
X
X/*
XFunctions used for dealing with files.
X*/
X
Xvoid OpenFiles();
Xvoid CloseFiles();
SHAR_EOF
chmod 0644 files.h || echo "restore of files.h fails"
fi
if test -f func.h; then echo "File func.h exists"; else
echo "x - extracting func.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > func.h &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X/*
XUseful library declarations.
X*/
X
XFILE * fopen();
Xint fclose();
Xvoid perror();
Xvoid exit();
Xchar * malloc();
Xchar * calloc();
Xvoid free();
Xchar * fgets();
Xint sscanf();
Xint strlen();
Xint strcmp();
Xint strncmp();
Xchar * strcpy();
Xchar * strncpy();
Xchar * strcat();
Xchar * strncat();
Xint fprintf();
Xchar * sprintf();
Xdouble atof();
X
X/*
XUseful constants.
X*/
X
X#define RANDOM_MULTIPLIER 25173/*multiplier used in random number generator*/
X#define RANDOM_INCREMENT 13849/*increment used in random number generator*/
X#define RANDOM_MODULUS 65536/*modulus used in random number generator*/
X
X/*
XUseful functions.
X*/
X
Xint MinInt();
Xfloat MinFloat();
Xint MaxInt();
Xfloat MaxFloat();
Xvoid SwapInt();
Xvoid SwapFloat();
Xint AbsInt();
Xfloat AbsFloat();
Xint SquareInt();
Xfloat SquareFloat();
Xint Odd();
Xint Xor();
Xchar * IntToChar();
Xchar * CharToString();
Xchar * ReverseString();
Xchar * GoRev();
Xchar * MidString();
Xchar * AllocateString();
Xfloat Random();
SHAR_EOF
chmod 0644 func.h || echo "restore of func.h fails"
fi
if test -f hash.h; then echo "File hash.h exists"; else
echo "x - extracting hash.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > hash.h &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X/*
XThis module manages the hash table ADT.
X*/
X
X/*
XUseful constants. 
X*/
X
X#define HASH_SIZE 11731/*number of node queue entries in the hash table*/
X
X/*
XThe ADT for the hash table of nodes.
X*/
X
Xtypedef struct nhashtab {
X    char *name;
X    int node_count;
X    NQUEUE *nqueue_array[HASH_SIZE];
X} NHASHTAB;
X
X/*
XFunctions used to construct the hash table of nodes.
X*/
X
XNHASHTAB * NHashInit();
XNODE * NHashPut();
XNODE * NHashGet();
Xint HashFunction();
SHAR_EOF
chmod 0644 hash.h || echo "restore of hash.h fails"
fi
if test -f main.h; then echo "File main.h exists"; else
echo "x - extracting main.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > main.h &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X/*
XThe main function that performs the Switch Level Integrated Circuits 
Xsimulation (SLIC).
X*/
X
Xvoid main();
SHAR_EOF
chmod 0644 main.h || echo "restore of main.h fails"
fi
if test -f queue.h; then echo "File queue.h exists"; else
echo "x - extracting queue.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > queue.h &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X/*
XThis module manages all queue ADTs.
X*/
X
X/*
XThe nil number to be coerced into the nil pointer on demand by
XMOSFET, NODE, and SIGNAL ADTs.
X*/
X
X#define NIL -1
X
X/*
XThe ADT for storing the relevant information about mosfets.
X*/
X
Xtypedef struct mosfet {
X    char mosfet_type;
X    struct node *term[3];/*gate, source, and drain nodes of a mosfet*/
X    short value[3];/*logic values for gate, source, and drain*/
X    float drive[2];/*drive for source and drain*/
X    float strength;
X    struct mosfet *link;
X} MOSFET;
X
X/*
XThe queue ADT for mosfets.
X*/
X
Xtypedef struct mqueue {
X    char *name;
X    MOSFET *head;
X    MOSFET *tail;
X} MQUEUE;
X
X/*
XThe ADT for storing the relevant information about nodes.
X*/
X
Xtypedef struct node {
X    char *name;
X    short present_value;
X    short next_value;
X    float present_drive;
X    float next_drive;
X    float capacitance;/*node capacitance in fF*/
X    short perturbed;/*flag indicating whether node drive or value changed*/
X    short acquired;/*flag used to mark nodes traversed during charge sharing*/
X    short set;/*flag used to mark nodes set during charge sharing*/
X    MQUEUE *mosfet_queue;
X    struct node *link;
X} NODE;
X
X/*
XThe queue ADT for nodes.
X*/
X
Xtypedef struct nqueue {
X    char *name;
X    NODE *head;
X    NODE *tail;
X} NQUEUE;
X
X/*
XThe ADT for storing the relevant information about signals.
X*/
X
Xtypedef struct signal {
X    char signal_type;
X    char *name;
X    char *value_sequence;
X    NODE *node;
X    struct signal *link;
X} SIGNAL;
X
X/*
XThe queue ADT for signals.
X*/
X
Xtypedef struct squeue {
X    char *name;
X    SIGNAL *head;
X    SIGNAL *tail;
X} SQUEUE;
X
X/*
XFunctions used to construct queues of mosfets, nodes, and signals.
X*/
X
XMQUEUE * MQInit();
Xvoid MQPut();
XMOSFET * MQGet();
XMOSFET * MakeMosfet();
XNQUEUE * NQInit();
Xvoid NQPut();
XNODE * NQGet();
XNODE * MakeNode();
XSQUEUE * SQInit();
Xvoid SQPut();
XSIGNAL * SQGet();
XSIGNAL * MakeSignal();
SHAR_EOF
chmod 0644 queue.h || echo "restore of queue.h fails"
fi
if test -f runsim.h; then echo "File runsim.h exists"; else
echo "x - extracting runsim.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > runsim.h &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X/*
XThis module performs the mechanics of the switch level simulation.
X*/
X
X/*
XUseful constants.
X*/
X
X#define MAX_STEP 128/*max number of steps allowed to settle network*/
X#define SUPER_DRIVE 1.0e6/*given to input nodes*/
X#define SUPER_CAPACITANCE 1.0e6/*given to input nodes*/
X#define NO_DRIVE 0.0/*given to nodes with no driving capability*/
X#define LOGIC_DONTCARE (-1)/*value of logic dontcare (with or without drive)*/
X#define LOGIC_LOW 0/*value of logic 0 (with drive)*/
X#define LOGIC_HIGH 1/*value of logic 1 (with drive)*/
X
X/*
XFunctions used for the mechanics of SLIC.
X*/
X
Xvoid RunSim();
Xvoid ApplyInputVector();
Xvoid DrivePropagation();
Xvoid ChargeSharing();
Xvoid MosfetAction();
Xint MosfetOn();
Xvoid MosfetActive();
Xvoid MosfetDisable();
Xvoid EvaluateNode();
Xvoid GetNodeDrive();
Xvoid SortDrive();
Xvoid UpdateNode();
Xvoid ResolveConflict();
Xvoid RemoveStatic();
Xvoid AccumulateCSValue();
Xvoid SortCapacitance();
Xshort DetermineCSValue();
Xvoid SetCSValue();
Xvoid NodeStats();
Xvoid GenerateEvents();
Xvoid AssignInputs();
Xvoid AssignClocks();
Xvoid AssignPreset();
Xvoid AssignOutputs();
SHAR_EOF
chmod 0644 runsim.h || echo "restore of runsim.h fails"
fi
if test -f state.h; then echo "File state.h exists"; else
echo "x - extracting state.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > state.h &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X/*
XThis module allocates space for and fills in the state ADTs for SLIC.
X*/
X
X/*
XUseful constants.
X*/
X
X#define NMOS 'n'/*symbol for nmos in ".sim" file*/
X#define PMOS 'p'/*symbol for pmos in ".sim" file*/
X#define ENMOS 'e'/*symbol for enhancement nmos in ".sim" file*/
X#define DNMOS 'd'/*symbol for depletion nmos in ".sim" file*/
X#define CAPACITOR 'C'/*symbol for non mosfet capacitance in ".sim" file*/
X#define READ 0/*flag to read node hash table*/
X#define WRITE 1/*flag to create node hash table*/
X#define MAXBITS 64/*max number of bits in an input sequence*/
X#define COMMAND_LENGTH 64/*max number of extra chars in a drive command*/
X#define MAX_TOKENS 8/*max number of tokens in a line of ".sim" file*/
X#define MAX_TOKEN_LENGTH 64/*max number of chars in a terminal name*/
X#define SIM_LINE_LENGTH (MAX_TOKENS * MAX_TOKEN_LENGTH)
X
X/*
XFunctions used for allocating and building the state space for SLIC.
X*/
X
Xvoid BuildState();
Xvoid BuildDrive();
Xvoid BuildNetwork();
Xvoid ReadSimNetlist();
Xvoid ParseSimLine();
Xvoid ReadMosfet();
Xvoid ReadCapacitor();
Xvoid CombineMosfet();
Xvoid ConnectInputsNodes();
Xvoid ConnectClocksNodes();
Xvoid ConnectPresetNodes();
Xvoid ConnectOutputsNodes();
Xvoid CreateNodeQueue();
SHAR_EOF
chmod 0644 state.h || echo "restore of state.h fails"
fi
if test -f tech.h; then echo "File tech.h exists"; else
echo "x - extracting tech.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > tech.h &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X/*
XThis header file contains the essential information about the particular
XMOS technology used.
X*/
X
X/*
XUseful constants.
X*/
X
X#define STRENGTH_RATIO 2.0/*ratio of mobilities of electrons and holes*/
X#define COX 1.5/*mos gate oxide capacitance (fF/sq-micron)*/
X/*Mos diffusion capacitance is not yet included.  Alex Sherstinsky, 10-27-88*/
X#define MIN_DRIVE 1.0/*min non zero drive allowed for a node*/
X#define CAP_FACTOR 10.0/*storage capability ratio for valid logic transfer*/
SHAR_EOF
chmod 0644 tech.h || echo "restore of tech.h fails"
fi
if test -f args.c; then echo "File args.c exists"; else
echo "x - extracting args.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > args.c &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X#include <stdio.h>
X#include <strings.h>
X
X#include "func.h"
X#include "args.h"
X
X/*
XThis function obtains and processes the command line arguments.
X*/
X
Xvoid
XProcessArgs(argc, argv, sim_file_name, drive_file_name, res_file_name)
Xint argc;
Xchar **argv;
Xchar *sim_file_name;
Xchar *drive_file_name;
Xchar *res_file_name;
X
X{
X    if(argc < 2) {
X	(void) fprintf(stdout, "Syntax: slic sim_file_name\n");
X	(void) exit(0);
X    }
X    (void) sscanf(argv[1], "%s", sim_file_name);
X    (void) strcpy(drive_file_name, sim_file_name);
X    (void) strcpy(res_file_name, sim_file_name);
X    (void) strcat(sim_file_name, ".sim");
X    (void) strcat(drive_file_name, ".drive");
X    (void) strcat(res_file_name, ".res");
X}
SHAR_EOF
chmod 0644 args.c || echo "restore of args.c fails"
fi
if test -f dump.c; then echo "File dump.c exists"; else
echo "x - extracting dump.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dump.c &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X#include <stdio.h>
X#include <strings.h>
X
X#include "func.h"
X#include "queue.h"
X#include "dump.h"
X
X/*
XThis routine prints the values of output vectors into the ".res" (results) 
Xfile. 
X*/
X
Xvoid
XDumpRes(res_file, output_queue)
XFILE *res_file;
XSQUEUE *output_queue;
X
X{
X    SIGNAL *output;
X
X    for(output = output_queue->head; output != ((SIGNAL *) NIL);
X    output = output->link) {
X	(void) fprintf(res_file, ">%s:%s\n", 
X	output->value_sequence, output->name);
X    }
X}
SHAR_EOF
chmod 0644 dump.c || echo "restore of dump.c fails"
fi
if test -f files.c; then echo "File files.c exists"; else
echo "x - extracting files.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > files.c &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X#include <stdio.h>
X#include <strings.h>
X
X#include "func.h"
X#include "files.h"
X
X/*
XOpens the relevant files.
X*/
X
Xvoid
XOpenFiles(sim_file_name, drive_file_name, res_file_name, 
Xsim_file, drive_file, res_file)
Xchar *sim_file_name;
Xchar *drive_file_name;
Xchar *res_file_name;
XFILE **sim_file;
XFILE **drive_file;
XFILE **res_file;
X
X{
X    if((*sim_file = (FILE *) fopen(sim_file_name, "r")) == NULL) {
X	(void) perror(sim_file_name);
X	(void) exit(1);
X    }
X    if((*drive_file = (FILE *) fopen(drive_file_name, "r")) == NULL) {
X	(void) perror(drive_file_name);
X	(void) exit(1);
X    }
X    if((*res_file = (FILE *) fopen(res_file_name, "w")) == NULL) {
X	(void) perror(res_file_name);
X	(void) exit(1);
X    }
X}
X
X/*
XCloses the opened files.
X*/
X
Xvoid
XCloseFiles(sim_file, drive_file, res_file)
XFILE **sim_file;
XFILE **drive_file;
XFILE **res_file;
X
X{
X    (void) fclose(*sim_file);
X    (void) fclose(*drive_file);
X    (void) fclose(*res_file);
X}
SHAR_EOF
chmod 0644 files.c || echo "restore of files.c fails"
fi
if test -f func.c; then echo "File func.c exists"; else
echo "x - extracting func.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > func.c &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X#include <stdio.h>
X#include <strings.h>
X
X#include "func.h"
X
X/*
XReturns the minimum of two integers.
X*/
X
Xint
XMinInt(int1, int2)
Xint int1, int2;
X
X{
X    return (int1 < int2) ? int1 : int2;
X}
X
X/*
XReturns the minimum of two floats.
X*/
X
Xfloat
XMinFloat(float1, float2)
Xfloat float1, float2;
X
X{
X    return (float1 < float2) ? float1 : float2;
X}
X
X/*
XReturns the maximum of two integers.
X*/
X
Xint 
XMaxInt(int1, int2)
Xint int1, int2;
X
X{
X    return (int1 > int2) ? int1 : int2;
X}
X
X/*
XReturns the maximum of two floats.
X*/
X
Xfloat 
XMaxFloat(float1, float2)
Xfloat float1, float2;
X
X{
X    return (float1 > float2) ? float1 : float2;
X}
X
X/*
XSwaps two integers.
X*/
X
Xvoid
XSwapInt(int1, int2)
Xint *int1, *int2;
X
X{
X    int tmp;
X
X    tmp = *int1;
X    *int1 = *int2;
X    *int2 = tmp;
X}
X
X/*
XSwaps two floats.
X*/
X
Xvoid
XSwapFloat(float1, float2)
Xfloat *float1, *float2;
X
X{
X    float tmp;
X
X    tmp = *float1;
X    *float1 = *float2;
X    *float2 = tmp;
X}
X
X/*
XReturns absolute value of an integer.
X*/
X
Xint
XAbsInt(int1)
Xint int1;
X
X{
X    return (int1 < 0) ? (- int1) : int1;
X}
X
X/*
XReturns absolute value of an float.
X*/
X
Xfloat
XAbsFloat(float1)
Xfloat float1;
X
X{
X    return((float1 < 0) ? (- float1) : float1);
X}
X
X/*
XReturns the square of the input integer.
X*/
X
Xint
XSquareInt(int1)
Xint int1;
X
X{
X    return(int1 * int1);
X}
X
X/*
XReturns the square of the input float.
X*/
X
Xfloat
XSquareFloat(float1)
Xfloat float1;
X
X{
X    return(float1 * float1);
X}
X
X/*
XReturns 1 if the argument is an Odd integer; 0 otherwise.
X*/
X
Xint
XOdd(int1)
Xint int1;
X
X{
X    return(int1 % 2);
X}
X
X/*
XReturns 1 if the only one of the arguments is 1.
X*/
X
Xint
XXor(int1, int2)
Xint int1;
Xint int2;
X
X{
X    return((int1 && !int2) || (!int1 && int2));
X}
X
X/*
XReturns the character representation of an integer.
X*/
X
Xchar *
XIntToChar(num)
Xint num;
X
X{
X    char string[10];
X    int is_negative = 0;
X    char complete_string[10];
X
X    if(num < 0) {
X	is_negative = 1;
X    }
X    num = (int) AbsInt(num);
X    (void) strcpy(string, "");
X    (void) strcpy(complete_string, "-");
X    while(num / 10) {
X	(void) strcat(string, CharToString('0' + (num % 10)));
X	num /= 10;
X    }
X    (void) strcat(string, CharToString('0' + (num % 10)));
X    (void) strcpy(string, ReverseString(string));
X    if(is_negative) {
X	(void) strcat(complete_string, string);
X	return(complete_string);
X    } else {
X	return(string);
X    }
X}
X
X/*
XMakes a string out of one character.
X*/
X
Xchar *
XCharToString(ch)
Xchar ch;
X
X{
X    char string[2];
X
X    string[0] = ch;
X    string[1] = '\0';
X    return(string);
X}
X
X/*
XReturns the string whose characters appear in reverse order.
X*/
X
Xchar *
XReverseString(string)
Xchar *string;
X
X{
X    char tmp[10];
X
X    (void) strcpy(tmp, "");
X    (void) strcpy(tmp, (char *) GoRev(string, tmp));
X    return(tmp);
X}
X
X/*
XReturns the string whose characters are those of the first argument in reverse.
X*/
X
Xchar *
XGoRev(string, tmp)
Xchar *string;
Xchar *tmp;
X
X{
X    if(*(string+1) == '\0') {
X	return((char *) strcat(tmp, string));
X    } else {
X	return((char *) strcat((char *) GoRev((string+1), tmp), 
X	(char *) CharToString(*string)));
X    }
X}
X
X/*
XReturns the middle of three strings that comprise the overall string.
X*/
X
Xchar *
XMidString(line)
Xchar *line;
X
X{
X    char *middle = (char *) malloc((unsigned) 121 * sizeof(char));
X    char first[20];
X    char third[20];
X
X    (void) sscanf(line, "%s %s %s", first, middle, third);
X    return(middle);
X}
X
X/*
XAllocates a string for a given number of characters and returns a pointer
Xto it.
X*/
X
Xchar *
XAllocateString(num_chars)
Xint num_chars;
X
X{
X    char *string = (char *) malloc((unsigned) (num_chars + 1) * sizeof(char));
X    return(string);
X}
X
X/*
XThis function is a pseudo random number generator.
X*/
X
Xfloat
XRandom(seed)
Xint *seed;
X
X{
X    *seed = ((RANDOM_MULTIPLIER * *seed) + RANDOM_INCREMENT) % RANDOM_MODULUS;
X    return((1.0 * *seed) / RANDOM_MODULUS);
X}
SHAR_EOF
chmod 0644 func.c || echo "restore of func.c fails"
fi
if test -f hash.c; then echo "File hash.c exists"; else
echo "x - extracting hash.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > hash.c &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X#include <stdio.h>
X#include <strings.h>
X
X#include "func.h"
X#include "tech.h"
X#include "runsim.h"
X#include "state.h"
X#include "queue.h"
X#include "hash.h"
X
X/*
XInitializes the hash table of nodes.
X*/
X
XNHASHTAB *
XNHashInit(name)
Xchar *name;
X
X{
X    NHASHTAB *nhashtab;
X    int index;
X    char *string = (char *) malloc((unsigned) 10 * sizeof(char));
X
X    nhashtab = (NHASHTAB *) malloc(sizeof(NHASHTAB));
X    nhashtab->name = (char *) malloc((unsigned) ((int) strlen(name) + 1) * 
X    sizeof(char));
X    (void) strcpy(nhashtab->name, name);
X    nhashtab->node_count = 0;
X    for(index = 0; index < HASH_SIZE; index++) {
X	(void) sprintf(string, "%d", index);
X	(nhashtab->nqueue_array)[index] = (NQUEUE *) NQInit(string);
X    }
X    return(nhashtab);
X}
X
X/*
XHashes and puts a new node into the node hash table.
X*/
X
XNODE *
XNHashPut(nhashtab, node_name, mosfet, mosfet_type, strength)
XNHASHTAB *nhashtab;
Xchar *node_name;
XMOSFET **mosfet;
Xchar mosfet_type;
Xfloat strength;
X
X{
X    int hash_number;
X    MQUEUE *mosfet_queue;
X    NODE *node;
X
X    if(mosfet_type == PMOS) {
X	strength /= STRENGTH_RATIO;
X    } else if(!((mosfet_type == NMOS) || 
X    (mosfet_type == ENMOS) || (mosfet_type == DNMOS))) {
X	(void) fprintf(stdout, "Error:  Unknown mosfet type.  Exit 1.\n");
X	(void) exit(1);
X    }
X    if((node = (NODE *) NHashGet(nhashtab, WRITE, node_name, mosfet,
X    mosfet_type, strength)) == ((NODE *) NIL)) {
X	hash_number = (int) HashFunction(node_name);
X	(void) NQPut((nhashtab->nqueue_array)[hash_number], 
X	node = (NODE *) MakeNode(node_name, 
X	LOGIC_DONTCARE, LOGIC_DONTCARE, NO_DRIVE, NO_DRIVE, 1.0, 0, 0, 0,
X	mosfet_queue = (MQUEUE *) MQInit("mosfet_queue")));
X	(void) MQPut(mosfet_queue, (*mosfet) = (MOSFET *) 
X	MakeMosfet(mosfet_type, ((NODE *) NIL), ((NODE *) NIL), ((NODE *) NIL), 
X	LOGIC_DONTCARE, LOGIC_DONTCARE, LOGIC_DONTCARE, 
X	NO_DRIVE, NO_DRIVE, strength));
X	(nhashtab->node_count)++;
X    }
X    return(node);
X}
X
X/*
XHashes and gets a node number (corresponding to the given node name)
Xfrom the node hash table.
X*/
X
XNODE *
XNHashGet(nhashtab, write, node_name, mosfet, mosfet_type, strength)
XNHASHTAB *nhashtab;
Xint write;
Xchar *node_name;
XMOSFET **mosfet;
Xchar mosfet_type;
Xfloat strength;
X
X{
X    int hash_number;
X    NODE *node;
X
X    if(((nhashtab->nqueue_array)[hash_number = 
X    (int) HashFunction(node_name)])->head == ((NODE *) NIL)) {
X	return((NODE *) NIL);
X    } else {
X	for(node = ((nhashtab->nqueue_array)[hash_number])->head;
X	node != ((NODE *) NIL); node = node->link) {
X	    if(!((int) strcmp(node_name, node->name))) {
X		if(write) {
X		    (void) MQPut(node->mosfet_queue, *mosfet =
X		    (MOSFET *) MakeMosfet(mosfet_type, 
X		    ((NODE *) NIL), ((NODE *) NIL), ((NODE *) NIL), 
X		    LOGIC_DONTCARE, LOGIC_DONTCARE, LOGIC_DONTCARE, 
X		    NO_DRIVE, NO_DRIVE, strength));
X		}
X		return(node);
X	    }
X	}
X	return((NODE *) NIL);
X    }
X}
X
X/*
XThis routine is a hash function for a node name hash into the node hash table.
XThe ideal hash function returns a unique number for each distinct argument.
XSince the number returned by the hash function must be less than the size of
Xthe hash table, finding such a map is not simple. The hash function below uses 
Xthe node name argument in a way that reduces the probability of two different
Xnames mapping into the same hash number.
X*/
X
Xint 
XHashFunction(name)
Xchar *name;
X
X{
X    int index;
X    int sum;
X
X    for(index = 0, sum = 0; index < (int) strlen(name); index++) {
X	sum = sum * 13 + name[index] - '0';
X	sum %= HASH_SIZE;
X    }
X    return((sum < 0) ? (sum + HASH_SIZE) : sum);
X}
SHAR_EOF
chmod 0644 hash.c || echo "restore of hash.c fails"
fi
if test -f main.c; then echo "File main.c exists"; else
echo "x - extracting main.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > main.c &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X#include <stdio.h>
X#include <strings.h>
X
X#include "func.h"
X#include "tech.h"
X#include "args.h"
X#include "files.h"
X#include "queue.h"
X#include "hash.h"
X#include "state.h"
X#include "runsim.h"
X#include "dump.h"
X#include "main.h"
X
Xvoid
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X
X{
X    FILE *sim_file;
X    FILE *drive_file;
X    FILE *res_file;
X    char *sim_file_name = (char *) malloc((unsigned) 100 * sizeof(char));
X    char *drive_file_name = (char *) malloc((unsigned) 100 * sizeof(char));
X    char *res_file_name = (char *) malloc((unsigned) 100 * sizeof(char));
X    int mosfet_count = 0;
X    int node_count = 0;
X    SQUEUE *input_queue;
X    int input_count = 0;
X    int input_duration = 0;
X    SQUEUE *clock_queue;
X    int clock_count = 0;
X    int clock_duration = 0;
X    SQUEUE *preset_queue;
X    SQUEUE *output_queue;
X    int output_count = 0;
X
X    (void) ProcessArgs(argc, argv, 
X    sim_file_name, drive_file_name, res_file_name);
X    (void) OpenFiles(sim_file_name, drive_file_name, res_file_name, 
X    &sim_file, &drive_file, &res_file);
X    (void) BuildState(sim_file, drive_file, 
X    &input_queue, &clock_queue, &preset_queue, &output_queue, 
X    &mosfet_count, &node_count, &input_count, &clock_count, 
X    &output_count, &input_duration, &clock_duration);
X    if((mosfet_count == 0) || (node_count == 0)) {
X	(void) fprintf(stdout, "No network specified.  Exit 0.\n");
X	(void) exit(0);
X    } else if(input_count == 0) {
X	(void) fprintf(stdout, "Error:  No inputs specified.  Exit 1.\n");
X	(void) exit(1);
X    } else if(input_duration == 0) {
X	(void) fprintf(stdout, "Error:  ");
X	(void) fprintf(stdout, "No input values specified.  Exit 1.\n");
X	(void) exit(1);
X    } else if(input_duration > MAXBITS) {
X	(void) fprintf(stdout, "Error:  ");
X	(void) fprintf(stdout, "Input bit string too long.  Exit 1.\n");
X	(void) exit(1);
X    } else if((clock_count != 0) && (clock_duration == 0)) {
X	(void) fprintf(stdout, "Error:  ");
X	(void) fprintf(stdout, "No clock values specified.  Exit 1.\n");
X	(void) exit(1);
X    } else if(clock_duration > MAXBITS) {
X	(void) fprintf(stdout, "Error:  ");
X	(void) fprintf(stdout, "Clock bit string too long.  Exit 1.\n");
X	(void) exit(1);
X    } else if(output_count == 0) {
X	(void) fprintf(stdout, "No outputs indicated to display.  Exit 0.\n");
X	(void) exit(0);
X    } else {
X	(void) RunSim(input_queue, clock_queue, preset_queue, 
X	output_queue, input_duration, clock_duration, node_count);
X	(void) DumpRes(res_file, output_queue);
X    }
X    (void) CloseFiles(&sim_file, &drive_file, &res_file);
X}
SHAR_EOF
chmod 0644 main.c || echo "restore of main.c fails"
fi
if test -f queue.c; then echo "File queue.c exists"; else
echo "x - extracting queue.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > queue.c &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X#include <stdio.h>
X#include <strings.h>
X
X#include "func.h"
X#include "queue.h"
X
X/*
XInitializes the queue of mosfets.
X*/
X
XMQUEUE *
XMQInit(name)
Xchar *name;
X
X{
X    MQUEUE *mqueue;
X
X    mqueue = (MQUEUE *) malloc(sizeof(MQUEUE));
X    mqueue->name = (char *) malloc((unsigned) ((int) strlen(name) + 1) * 
X    sizeof(char));
X    (void) strcpy(mqueue->name, name);
X    mqueue->head = mqueue->tail = ((MOSFET *) NIL);
X    return(mqueue);
X}
X
X/*
XAppends a mosfet to the tail of a mosfet queue.
X*/
X
Xvoid
XMQPut(mqueue, chunk)
XMQUEUE *mqueue;
XMOSFET *chunk;
X
X{
X    if((mqueue->head == ((MOSFET *) NIL)) && 
X    (mqueue->tail == ((MOSFET *) NIL))) {
X	mqueue->head = mqueue->tail = chunk;
X    } else {
X	mqueue->tail->link = chunk;
X	mqueue->tail = chunk;
X    }
X    chunk->link = ((MOSFET *) NIL);
X}
X
X/*
XReturns the mosfet at the head of the mosfet queue and updates 
Xthe mosfet queue.
X*/
X
XMOSFET *
XMQGet(mqueue)
XMQUEUE *mqueue;
X
X{
X    MOSFET *chunk;
X
X    if((mqueue->head == ((MOSFET *) NIL)) && 
X    (mqueue->tail == ((MOSFET *) NIL))) {
X	return((MOSFET *) NIL);
X    } else if(mqueue->head == mqueue->tail) {
X	chunk = mqueue->head;
X	mqueue->head = mqueue->tail = ((MOSFET *) NIL);
X	return(chunk);
X    } else {
X	chunk = mqueue->head;
X	mqueue->head = mqueue->head->link;
X	return(chunk);
X    }
X}
X
X/*
XFills in the MOSFET ADT.
X*/
X
XMOSFET *
XMakeMosfet(mosfet_type, gate_node, source_node, drain_node, 
Xgate_value, source_value, drain_value, 
Xsource_drive, drain_drive, strength)
Xchar mosfet_type;
XNODE *gate_node;
XNODE *source_node;
XNODE *drain_node;
Xshort gate_value;
Xshort source_value;
Xshort drain_value;
Xfloat source_drive;
Xfloat drain_drive;
Xfloat strength;
X
X{
X    MOSFET *chunk;
X
X    chunk = (MOSFET *) malloc(sizeof(MOSFET));
X    chunk->mosfet_type = mosfet_type;
X    chunk->term[0] = gate_node;
X    chunk->term[1] = source_node;
X    chunk->term[2] = drain_node;
X    chunk->value[0] = gate_value;
X    chunk->value[1] = source_value;
X    chunk->value[2] = drain_value;
X    chunk->drive[0] = source_drive;
X    chunk->drive[1] = drain_drive;
X    chunk->strength = strength;
X    return(chunk);
X}
X
X/*
XInitializes the queue of nodes.
X*/
X
XNQUEUE *
XNQInit(name)
Xchar *name;
X
X{
X    NQUEUE *nqueue;
X
X    nqueue = (NQUEUE *) malloc(sizeof(NQUEUE));
X    nqueue->name = (char *) malloc((unsigned) ((int) strlen(name) + 1) * 
X    sizeof(char));
X    (void) strcpy(nqueue->name, name);
X    nqueue->head = nqueue->tail = ((NODE *) NIL);
X    return(nqueue);
X}
X
X/*
XAppends a node to the tail of a node queue.
X*/
X
Xvoid
XNQPut(nqueue, chunk)
XNQUEUE *nqueue;
XNODE *chunk;
X
X{
X    if((nqueue->head == ((NODE *) NIL)) && 
X    (nqueue->tail == ((NODE *) NIL))) {
X	nqueue->head = nqueue->tail = chunk;
X    } else {
X	nqueue->tail->link = chunk;
X	nqueue->tail = chunk;
X    }
X    chunk->link = ((NODE *) NIL);
X}
X
X/*
XReturns the node at the head of the node queue and updates the node queue.
X*/
X
XNODE *
XNQGet(nqueue)
XNQUEUE *nqueue;
X
X{
X    NODE *chunk;
X
X    if((nqueue->head == ((NODE *) NIL)) && 
X    (nqueue->tail == ((NODE *) NIL))) {
X	return((NODE *) NIL);
X    } else if(nqueue->head == nqueue->tail) {
X	chunk = nqueue->head;
X	nqueue->head = nqueue->tail = ((NODE *) NIL);
X	return(chunk);
X    } else {
X	chunk = nqueue->head;
X	nqueue->head = nqueue->head->link;
X	return(chunk);
X    }
X}
X
X/*
XFills in the NODE ADT.
X*/
X
XNODE *
XMakeNode(name, present_value, next_value, present_drive, next_drive, 
Xcapacitance, perturbed, acquired, set, mosfet_queue)
Xchar *name;
Xshort present_value;
Xshort next_value;
Xfloat present_drive;
Xfloat next_drive;
Xfloat capacitance;
Xshort perturbed;
Xshort acquired;
Xshort set;
XMQUEUE *mosfet_queue;
X
X{
X    NODE *chunk;
X
X    chunk = (NODE *) malloc(sizeof(NODE));
X    chunk->name = (char *) malloc((unsigned) ((int) strlen(name) + 1) * 
X    sizeof(char));
X    (void) strcpy(chunk->name, name);
X    chunk->present_value = present_value;
X    chunk->next_value = next_value;
X    chunk->present_drive = present_drive;
X    chunk->next_drive = next_drive;
X    chunk->capacitance = capacitance;
X    chunk->perturbed = perturbed;
X    chunk->acquired = acquired;
X    chunk->set = set;
X    chunk->mosfet_queue = mosfet_queue;
X    return(chunk);
X}
X
X/*
XInitializes the queue of signals.
X*/
X
XSQUEUE *
XSQInit(name)
Xchar *name;
X
X{
X    SQUEUE *squeue;
X
X    squeue = (SQUEUE *) malloc(sizeof(SQUEUE));
X    squeue->name = (char *) malloc((unsigned) ((int) strlen(name) + 1) * 
X    sizeof(char));
X    (void) strcpy(squeue->name, name);
X    squeue->head = squeue->tail = ((SIGNAL *) NIL);
X    return(squeue);
X}
X
X/*
XAppends a signal to the tail of a signal queue.
X*/
X
Xvoid
XSQPut(squeue, chunk)
XSQUEUE *squeue;
XSIGNAL *chunk;
X
X{
X    if((squeue->head == ((SIGNAL *) NIL)) && 
X    (squeue->tail == ((SIGNAL *) NIL))) {
X	squeue->head = squeue->tail = chunk;
X    } else {
X	squeue->tail->link = chunk;
X	squeue->tail = chunk;
X    }
X    chunk->link = ((SIGNAL *) NIL);
X}
X
X/*
XReturns the signal at the head of the signal queue and updates the signal queue.
X*/
X
XSIGNAL *
XSQGet(squeue)
XSQUEUE *squeue;
X
X{
X    SIGNAL *chunk;
X
X    if((squeue->head == ((SIGNAL *) NIL)) && 
X    (squeue->tail == ((SIGNAL *) NIL))) {
X	return((SIGNAL *) NIL);
X    } else if(squeue->head == squeue->tail) {
X	chunk = squeue->head;
X	squeue->head = squeue->tail = ((SIGNAL *) NIL);
X	return(chunk);
X    } else {
X	chunk = squeue->head;
X	squeue->head = squeue->head->link;
X	return(chunk);
X    }
X}
X
X/*
XFills in the SIGNAL ADT.
X*/
X
XSIGNAL *
XMakeSignal(signal_type, name, value_sequence, node, length)
Xchar signal_type;
Xchar *name;
Xchar *value_sequence;
XNODE *node;
Xshort length;
X
X{
X    SIGNAL *chunk;
X
X    chunk = (SIGNAL *) malloc(sizeof(SIGNAL));
X    chunk->signal_type = signal_type;
X    chunk->name = 
X    (char *) malloc((unsigned) ((int) strlen(name) + 1) * 
X    sizeof(char));
X    (void) strcpy(chunk->name, name);
X    if((signal_type == 'O') || (signal_type == 'o')) {
X	chunk->value_sequence = 
X	(char *) calloc((unsigned) (length + 1), sizeof(char));
X    } else {
X	chunk->value_sequence = 
X	(char *) malloc((unsigned) ((int) strlen(value_sequence) + 1) * 
X	sizeof(char));
X	(void) strcpy(chunk->value_sequence, value_sequence);
X    }
X    chunk->node = node;
X    return(chunk);
X}
SHAR_EOF
chmod 0644 queue.c || echo "restore of queue.c fails"
fi
if test -f runsim.c; then echo "File runsim.c exists"; else
echo "x - extracting runsim.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > runsim.c &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X#include <stdio.h>
X#include <strings.h>
X
X#include "func.h"
X#include "tech.h"
X#include "state.h"
X#include "queue.h"
X#include "runsim.h"
X
X/*
XThis function performs the mechanics of the switch level simulation.
X*/
X
Xvoid
XRunSim(input_queue, clock_queue, preset_queue, output_queue,
Xinput_duration, clock_duration, node_count)
XSQUEUE *input_queue;
XSQUEUE *clock_queue;
XSQUEUE *preset_queue;
XSQUEUE *output_queue;
Xint input_duration;
Xint clock_duration;
Xint node_count;
X
X{
X    int input_index;
X    int clock_index;
X    int settling_error = 0;
X    NQUEUE *node_queue;
X
X    node_queue = (NQUEUE *) NQInit("node_queue");
X    (void) AssignPreset(preset_queue, node_queue);
X    for(input_index = 0; (!settling_error && (input_index < input_duration));
X    input_index++) {
X	(void) AssignInputs(input_queue, input_index, node_queue);
X	if(clock_duration > 0) {
X	    for(clock_index = 0; (!settling_error && 
X	    (clock_index < clock_duration)); clock_index++) {
X		(void) AssignClocks(clock_queue, clock_index, node_queue);
X		(void) ApplyInputVector(node_queue, node_count * MAX_STEP,
X		&settling_error);
X		if(settling_error) {
X		    (void) fprintf(stdout, "Error:  ");
X		    (void) fprintf(stdout, "The circuit does not settle.\n");
X		    (void) fprintf(stdout, "Premature termination during ");
X		    (void) fprintf(stdout, "clock phase %d of input %d.\n", 
X		    clock_index, input_index);
X		}
X	    }
X	} else {
X	    (void) ApplyInputVector(node_queue, node_count * MAX_STEP,
X	    &settling_error);
X	    if(settling_error) {
X		    (void) fprintf(stdout, "Error:\n");
X		    (void) fprintf(stdout, "The circuit does not settle.  ");
X		    (void) fprintf(stdout, "Premature termination during ");
X		    (void) fprintf(stdout, "input %d.\n", 
X		    input_index);
X	    }
X	}
X	(void) AssignOutputs(output_queue, input_index);
X    }
X}
X
X/*
XThis function applies to the entire network one vector, consisting of single 
Xbit values of all inputs and clocks.
XThe simulation of an overall network is modeled by two processes: 
Xpropagation of drive and charge sharing.
XDrive is propagated from the external inputs to as many nodes in 
Xthe network as possible.  
XCharge sharing is attempted among the nodes that are not driven.  
XPropagation of drive and charge sharing process pair is repeated until the 
Xentire network settles.
XThe acronym CS used in function names stands for Charge Sharing.
X*/
X
Xvoid
XApplyInputVector(node_queue, max_iter, settling_error)
XNQUEUE *node_queue;
Xint max_iter;
Xint *settling_error;
X
X{
X    NODE *node;
X    int num_step;
X
X    for(node = (NODE *) NQGet(node_queue), num_step = 0; 
X    ((num_step < max_iter) && (node != ((NODE *) NIL))); 
X    node = (NODE *) NQGet(node_queue), num_step++) {
X	node->perturbed = 0;
X	(void) DrivePropagation(node, node_queue);
X	(void) ChargeSharing(node, node_queue); 
X    }
X    if(num_step == max_iter) {
X	*settling_error = 1;
X    }
X}
X
X/*
XThis function helps distribute drive to as many nodes in the network as 
Xpossible.  Super drive, originating from external inputs, is modulated by 
Xmosfets in the network.  Drive propagates throughout the network, thereby
Xupdating nodal logic values.
X*/
X
Xvoid
XDrivePropagation(node, node_queue)
XNODE *node;
XNQUEUE *node_queue;
X
X{
X    (void) MosfetAction(node);
X    (void) EvaluateNode(node);
X    (void) NodeStats(node, node_queue);
X}
X
X/*
XThis function performs charge sharing among electrically connected non driven 
Xnodes in the network.  The charge sharing model lumps all capacitances (from 
Xnode to substrate) into three capacitors connected in parallel, one for each 
Xlogic value: low, high, and dontcare.  The final node value is then determined 
Xbased on the relative sizes of the three capacitors.
X*/
X
Xvoid
XChargeSharing(node, node_queue)
XNODE *node;
XNQUEUE *node_queue;
X
X{
X    float logic_low_capacitance = 0.0;
X    float logic_high_capacitance = 0.0;
X    float logic_dontcare_capacitance = 0.0;
X
X    if((node->present_drive == NO_DRIVE) && !node->acquired) {
X	(void) AccumulateCSValue(node, &logic_low_capacitance, 
X	&logic_high_capacitance, &logic_dontcare_capacitance);
X	(void) SetCSValue(node, node_queue,
X	(short) DetermineCSValue(logic_low_capacitance, 
X	logic_high_capacitance, logic_dontcare_capacitance));
X    }
X}
X
X/*
XThis function traverses all the mosfets of the given node and performs the 
Xaction of an nmos or a pmos (depending on the type of the mosfet in question) 
Xfor a single mosfet.
X*/
X
Xvoid 
XMosfetAction(node)
XNODE *node;
X
X{
X    MOSFET *mosfet;
X    
X    for(mosfet = node->mosfet_queue->head; mosfet != ((MOSFET *) NIL); 
X    mosfet = mosfet->link) {
X	if((node == mosfet->term[1]) || (node == mosfet->term[2])) {
X	    if((int) MosfetOn(node, mosfet)) {
X		(void) MosfetActive(node, mosfet);
X	    } else {
X		(void) MosfetDisable(mosfet);
X	    }
X	}
X    }
X}
X
X/*
XThis function checks whether or not the given mosfet is turned on, which is
Xincluded in switch-on and diode-on modes of operation.  The modes of 
Xoperation in which the given mosfet is turned off are switch-off and diode-off.
X*/
X
Xint 
XMosfetOn(node, mosfet)
XNODE *node;
XMOSFET *mosfet;
X
X{
X    NODE *gate;
X    NODE *source;
X    NODE *drain;
X    char mosfet_type;
X
X    gate = mosfet->term[0];
X    source = mosfet->term[1];
X    drain = mosfet->term[2];
X    mosfet_type = mosfet->mosfet_type;
X    if(((node == source) &&
X    (((mosfet_type == NMOS) || (mosfet_type == ENMOS)) &&
X    ((gate->present_value == LOGIC_HIGH) &&
X    ((drain->present_value == LOGIC_LOW) || 
X    (drain->present_value != source->present_value)))) ||
X    ((mosfet_type == DNMOS) &&
X    !((gate->present_value == LOGIC_LOW) &&
X    (drain->present_value == LOGIC_HIGH) &&
X    (source->present_value == LOGIC_HIGH))) ||
X    ((mosfet_type == PMOS) &&
X    ((gate->present_value == LOGIC_LOW) &&
X    ((drain->present_value == LOGIC_HIGH) || 
X    (drain->present_value != source->present_value))))) ||
X    ((node == drain) &&
X    (((mosfet_type == NMOS) || (mosfet_type == ENMOS)) &&
X    ((gate->present_value == LOGIC_HIGH) &&
X    ((source->present_value == LOGIC_LOW) || 
X    (source->present_value != drain->present_value)))) ||
X    ((mosfet_type == DNMOS) &&
X    !((gate->present_value == LOGIC_LOW) &&
X    (source->present_value == LOGIC_HIGH) &&
X    (drain->present_value == LOGIC_HIGH))) ||
X    ((mosfet_type == PMOS) &&
X    ((gate->present_value == LOGIC_LOW) &&
X    ((source->present_value == LOGIC_HIGH) || 
X    (source->present_value != drain->present_value)))))) {
X	return(1);
X    } else {
X	return(0);
X    }
X}
X
X/*
XThis function simulates the action of a mosfet in the ohmic region of
Xoperation (switch-on mode), or in the high electric field portion of the
Xsaturation region of operation (diode-on mode).
X*/
X
Xvoid
XMosfetActive(node, mosfet)
XNODE *node;
XMOSFET *mosfet;
X
X{
X    NODE *source;
X    NODE *drain;
X
X    source = mosfet->term[1];
X    drain = mosfet->term[2];
X    mosfet->value[1] = drain->present_value;
X    mosfet->value[2] = source->present_value;
X    if(node == source) {
X	if(drain->present_drive > NO_DRIVE) {
X	    mosfet->drive[0] = 
X	    ((drain->present_drive == SUPER_DRIVE) ? mosfet->strength : 
X	    (1.0 / ((1.0 / mosfet->strength) + 
X	    (1.0 / drain->present_drive))));
X	} else {
X	    mosfet->drive[0] = NO_DRIVE;
X	}
X    } else if(node == drain) {
X	if(source->present_drive > NO_DRIVE) {
X	    mosfet->drive[1] = 
X	    ((source->present_drive == SUPER_DRIVE) ? mosfet->strength : 
X	    (1.0 / ((1.0 / mosfet->strength) + 
X	    (1.0 / source->present_drive))));
X	} else {
X	    mosfet->drive[1] = NO_DRIVE;
X	}
X    }
X}
X
X/*
XThis function simulates the action of a mosfet in the cut-off region of
Xoperation (switch-off mode), or at the edge of saturation and cut-off
Xregions of operation (diode-off mode).
X*/
X
Xvoid 
XMosfetDisable(mosfet)
XMOSFET *mosfet;
X
X{
X    mosfet->drive[0] = mosfet->drive[1] = NO_DRIVE;
X}
X
X/*
XThis function determines the new drive and logic value for the given node
Xbased on the terminal drives and logic values of all mosfets connected to
Xthe node.
X*/
X
Xvoid
XEvaluateNode(node)
XNODE *node;
X
X{
X    float logic_high_drive = NO_DRIVE;
X    float logic_low_drive = NO_DRIVE;
X    float logic_dontcare_drive = NO_DRIVE;
X    
X    (void) GetNodeDrive(node, 
X    &logic_low_drive, &logic_high_drive, &logic_dontcare_drive);
X    (void) UpdateNode(node, 
X    logic_low_drive, logic_high_drive, logic_dontcare_drive);
X}
X
X/*
XThis function uses the terminal drives of all mosfets connected to the given 
Xnode to determine the drive for each logic value: low, high, and dontcare.
X*/
X
Xvoid 
XGetNodeDrive(node, 
Xlogic_low_drive, logic_high_drive, logic_dontcare_drive)
XNODE *node;
Xfloat *logic_low_drive;
Xfloat *logic_high_drive;
Xfloat *logic_dontcare_drive;
X
X{
X    MOSFET *mosfet;
X
X    for(mosfet = node->mosfet_queue->head; mosfet != ((MOSFET *) NIL);
X    mosfet = mosfet->link) {
X	(void) SortDrive(node, mosfet,
X	logic_low_drive, logic_high_drive, logic_dontcare_drive);
X    }
X}
X
X/*
XThis function examines the logic value of the appropriate mosfet terminal
Xand updates the corresponding drive.
X*/
X
Xvoid 
XSortDrive(node, mosfet, 
Xlogic_low_drive, logic_high_drive, logic_dontcare_drive)
XNODE *node;
XMOSFET *mosfet;
Xfloat *logic_low_drive;
Xfloat *logic_high_drive;
Xfloat *logic_dontcare_drive;
X
X{
X    if(node == mosfet->term[1]) {
X	if(mosfet->value[1] == LOGIC_LOW) {
X	    *logic_low_drive = (float) MaxFloat(*logic_low_drive,
X	    mosfet->drive[0]);
X	} else if(mosfet->value[1] == LOGIC_HIGH) {
X	    *logic_high_drive = (float) MaxFloat(*logic_high_drive,
X	    mosfet->drive[0]);
X	} else if(mosfet->value[1] == LOGIC_DONTCARE) {
X	    *logic_dontcare_drive = (float) MaxFloat(*logic_dontcare_drive,
X	    mosfet->drive[0]);
X	}
X    } else if(node == mosfet->term[2]) {
X	if(mosfet->value[2] == LOGIC_LOW) {
X	    *logic_low_drive = (float) MaxFloat(*logic_low_drive,
X	    mosfet->drive[1]);
X	} else if(mosfet->value[2] == LOGIC_HIGH) {
X	    *logic_high_drive = (float) MaxFloat(*logic_high_drive,
X	    mosfet->drive[1]);
X	} else if(mosfet->value[2] == LOGIC_DONTCARE) {
X	    *logic_dontcare_drive = (float) MaxFloat(*logic_dontcare_drive,
X	    mosfet->drive[1]);
X	}
X    } 
X}
X
X/*
XThis function considers the drive of each logic value for the given node
Xand produces the new drive and logic value.
X*/
X
Xvoid
XUpdateNode(node, 
Xlogic_low_drive, logic_high_drive, logic_dontcare_drive)
XNODE *node;
Xfloat logic_low_drive;
Xfloat logic_high_drive;
Xfloat logic_dontcare_drive;
X
X{
X    if((logic_low_drive > logic_high_drive) &&
X    (logic_low_drive > logic_dontcare_drive)) {
X	node->next_drive = logic_low_drive;
X	node->next_value = LOGIC_LOW;
X    } else if((logic_high_drive > logic_low_drive) &&
X    (logic_high_drive > logic_dontcare_drive)) {
X	node->next_drive = logic_high_drive;
X	node->next_value = LOGIC_HIGH;
X    } else if((logic_dontcare_drive > logic_low_drive) &&
X    (logic_dontcare_drive > logic_high_drive)) {
X	node->next_drive = logic_dontcare_drive;
X	node->next_value = LOGIC_DONTCARE;
X    } else {
X	(void) ResolveConflict(node, 
X	logic_low_drive, logic_high_drive, logic_dontcare_drive);
X    }
X    (void) RemoveStatic(node);
X}
X
X/*
XThis function determines the drive and value for a node in the case of
Xa conflict between the logic values.
X*/
X
Xvoid 
XResolveConflict(node, logic_low_drive, logic_high_drive, logic_dontcare_drive)
XNODE *node;
Xfloat logic_low_drive;
Xfloat logic_high_drive;
Xfloat logic_dontcare_drive;
X
X{
X    node->next_drive = NO_DRIVE;
X    if(((logic_low_drive == logic_high_drive) &&
X    (logic_low_drive > NO_DRIVE)) ||
X    ((logic_low_drive == logic_dontcare_drive) &&
X    (logic_low_drive > NO_DRIVE)) ||
X    ((logic_high_drive == logic_dontcare_drive) &&
X    (logic_high_drive > NO_DRIVE))) {
X	node->next_value = LOGIC_DONTCARE;
X    }
X}
X
X/*
XThis function clears the drive for a node if the drive has decreased beyond 
Xthe threshold of recognition. 
X*/
X
Xvoid 
XRemoveStatic(node)
XNODE *node;
X
X{
X    if((node->next_drive > NO_DRIVE) && (node->next_drive < MIN_DRIVE)) {
X	node->next_drive = NO_DRIVE;
X    }
X}
X
X/*
XThis function recursively traverses all electrically connected nodes,
Xsorting their capacitances according to their logic values.
X*/
X
Xvoid 
XAccumulateCSValue(node, 
Xlogic_low_capacitance, logic_high_capacitance, logic_dontcare_capacitance)
XNODE *node;
Xfloat *logic_low_capacitance;
Xfloat *logic_high_capacitance;
Xfloat *logic_dontcare_capacitance;
X
X{
X    MOSFET *mosfet;
X
X    if((node->present_drive == NO_DRIVE) && !node->acquired) {
X	node->acquired = 1;
X	node->set = 0;
X	(void) SortCapacitance(node, logic_low_capacitance, 
X	logic_high_capacitance, logic_dontcare_capacitance);
X	for(mosfet = node->mosfet_queue->head; mosfet != ((MOSFET *) NIL);
X	mosfet = mosfet->link) {
X	    if((int) MosfetOn(node, mosfet)) {
X		if(node == mosfet->term[1]) {
X		    (void) AccumulateCSValue(mosfet->term[2], 
X		    logic_low_capacitance, logic_high_capacitance,
X		    logic_dontcare_capacitance);
X		} else if(node == mosfet->term[2]) {
X		    (void) AccumulateCSValue(mosfet->term[1], 
X		    logic_low_capacitance, logic_high_capacitance,
X		    logic_dontcare_capacitance);
X		}
X	    }
X	}
X    }
X}
X
X/*
XThis function examines the logic value of the given node and updates the
Xcorresponding cumulative capacitance.
X*/
X
Xvoid 
XSortCapacitance(node, 
Xlogic_low_capacitance, logic_high_capacitance, logic_dontcare_capacitance)
XNODE *node;
Xfloat *logic_low_capacitance;
Xfloat *logic_high_capacitance;
Xfloat *logic_dontcare_capacitance;
X
X{
X    if(node->present_value == LOGIC_LOW) {
X	*logic_low_capacitance += node->capacitance;
X    } else if(node->present_value == LOGIC_HIGH) {
X	*logic_high_capacitance += node->capacitance;
X    } else if(node->present_value == LOGIC_DONTCARE) {
X	*logic_dontcare_capacitance += node->capacitance;
X    }
X}
X
X/*
XThis function decides on the new charge sharing logic value based on the
Xindividual capacitances of the possible logic values.
X*/
X
Xshort 
XDetermineCSValue(logic_low_capacitance, logic_high_capacitance, 
Xlogic_dontcare_capacitance)
Xfloat logic_low_capacitance;
Xfloat logic_high_capacitance;
Xfloat logic_dontcare_capacitance;
X
X{
X    if(logic_low_capacitance > 
X    ((logic_high_capacitance + logic_dontcare_capacitance) * CAP_FACTOR)) {
X	return(LOGIC_LOW);
X    } else 
X    if(logic_high_capacitance > 
X    ((logic_low_capacitance + logic_dontcare_capacitance) * CAP_FACTOR)) {
X	return(LOGIC_HIGH);
X    } else
X    if(logic_dontcare_capacitance > 
X    ((logic_low_capacitance + logic_high_capacitance) * CAP_FACTOR)) {
X	return(LOGIC_DONTCARE);
X    } else {
X	return(LOGIC_DONTCARE);
X    }
X}
X
X/*
XThis function recursively traverses all electrically connected nodes,
Xsetting their logic values to the given logic value.
X*/
X
Xvoid 
XSetCSValue(node, node_queue, value)
XNODE *node;
XNQUEUE *node_queue;
Xshort value;
X
X{
X    MOSFET *mosfet;
X
X    if((node->present_drive == NO_DRIVE) && !node->set) {
X	node->acquired = 0;
X	node->set = 1;
X	node->next_value = value;
X	(void) NodeStats(node, node_queue);
X	for(mosfet = node->mosfet_queue->head; mosfet != ((MOSFET *) NIL);
X	mosfet = mosfet->link) {
X	    if((int) MosfetOn(node, mosfet)) {
X		if(node == mosfet->term[1]) {
X		    (void) SetCSValue(mosfet->term[2], node_queue, value);
X		} else if(node == mosfet->term[2]) {
X		    (void) SetCSValue(mosfet->term[1], node_queue, value);
X		}
X	    }
X	}
X    }
X}
X
X/*
XThis routine updates the drive and value of the given node and generates
Xnew events if the state of the node has changed.
X*/
X
Xvoid
XNodeStats(node, node_queue)
XNODE *node;
XNQUEUE *node_queue;
X
X{
X    if((node->next_drive != node->present_drive) ||
X    (node->next_value != node->present_value)) {
X	(void) GenerateEvents(node, node_queue);
X    }
X    node->present_drive = node->next_drive;
X    node->present_value = node->next_value;
X}
X
X/*
XThis function records the new events by locating the perturbed nodes 
Xand appending them onto the node queue.
X*/
X
Xvoid 
XGenerateEvents(node, node_queue)
XNODE *node;
XNQUEUE *node_queue;
X
X{
X    MOSFET *mosfet;
X
X    for(mosfet = node->mosfet_queue->head; mosfet != ((MOSFET *) NIL);
X    mosfet = mosfet->link) {
X	if(node == mosfet->term[0]) {
X	    if(!mosfet->term[1]->perturbed &&
X	    (mosfet->term[1]->present_drive < SUPER_DRIVE)) {
X		mosfet->term[1]->perturbed = 1;
X		(void) NQPut(node_queue, mosfet->term[1]);
X	    }
X	    if(!mosfet->term[2]->perturbed &&
X	    (mosfet->term[2]->present_drive < SUPER_DRIVE)) {
X		mosfet->term[2]->perturbed = 1;
X		(void) NQPut(node_queue, mosfet->term[2]);
X	    }
X	} else if(node == mosfet->term[1]) {
X	    if(!mosfet->term[2]->perturbed &&
X	    (mosfet->term[2]->present_drive < SUPER_DRIVE)) {
X		mosfet->term[2]->perturbed = 1;
X		(void) NQPut(node_queue, mosfet->term[2]);
X	    }
X	} else if(node == mosfet->term[2]) {
X	    if(!mosfet->term[1]->perturbed &&
X	    (mosfet->term[1]->present_drive < SUPER_DRIVE)) {
X		mosfet->term[1]->perturbed = 1;
X		(void) NQPut(node_queue, mosfet->term[1]);
X	    }
X	}
X    }
X    if(!node->perturbed && (node->present_drive < SUPER_DRIVE)) {
X	node->perturbed = 1;
X	(void) NQPut(node_queue, node);
X    }
X}
X
X/*
XThis function assigns the input values to corresponding nodes at
Xthe beginning of the run of each input vector. 
X*/
X
Xvoid
XAssignInputs(input_queue, input_index, node_queue)
XSQUEUE *input_queue;
Xint input_index;
XNQUEUE *node_queue;
X
X{
X    SIGNAL *input;
X
X    for(input = input_queue->head; input != ((SIGNAL *) NIL);
X    input = input->link) {
X	if(input_index < (int) strlen(input->value_sequence)) {
X	    if(input->value_sequence[input_index] == '0') {
X		input->node->next_value = LOGIC_LOW;
X	    } else if(input->value_sequence[input_index] == '1') {
X		input->node->next_value = LOGIC_HIGH;
X	    } else if((input->value_sequence[input_index] == 'X') ||
X	    (input->value_sequence[input_index] == 'x')) {
X		input->node->next_value = LOGIC_DONTCARE;
X	    } else {
X		(void) fprintf(stdout, "Error:  ");
X		(void) fprintf(stdout, "No meaningful bit string specified ");
X		(void) fprintf(stdout, "for input '%s'.  Exit 1.\n", 
X		input->name);
X		(void) exit(1);
X	    }
X	} else {
X	    if(input->value_sequence[(int) strlen(input->value_sequence) - 1]
X	    == '0') {
X		input->node->next_value = LOGIC_LOW;
X	    } else 
X	    if(input->value_sequence[(int) strlen(input->value_sequence) - 1] 
X	    == '1') {
X		input->node->next_value = LOGIC_HIGH;
X	    } else
X	    if((input->value_sequence[(int) strlen(input->value_sequence) - 1] 
X	    == 'X') || 
X	    (input->value_sequence[(int) strlen(input->value_sequence) - 1] 
X	    == 'x')) {
X		input->node->next_value = LOGIC_DONTCARE;
X	    } else {
X		(void) fprintf(stdout, "Error:  ");
X		(void) fprintf(stdout, "No meaningful bit string specified ");
X		(void) fprintf(stdout, "for input '%s'.  Exit 1.\n", 
X		input->name);
X		(void) exit(1);
X	    }
X	}
X	(void) NodeStats(input->node, node_queue);
X    }
X}
X
X/*
XThis function assigns the clock values to corresponding nodes at
Xthe beginning of the run of each clock vector. 
X*/
X
Xvoid
XAssignClocks(clock_queue, clock_index, node_queue)
XSQUEUE *clock_queue;
Xint clock_index;
XNQUEUE *node_queue;
X
X{
X    SIGNAL *clock;
X
X    for(clock = clock_queue->head; clock != ((SIGNAL *) NIL);
X    clock = clock->link) {
X	if(clock_index < (int) strlen(clock->value_sequence)) {
X	    if(clock->value_sequence[clock_index] == '0') {
X		clock->node->next_value = LOGIC_LOW;
X	    } else if(clock->value_sequence[clock_index] == '1') {
X		clock->node->next_value = LOGIC_HIGH;
X	    } else if((clock->value_sequence[clock_index] == 'X') ||
X	    (clock->value_sequence[clock_index] == 'x')) {
X		clock->node->next_value = LOGIC_DONTCARE;
X	    } else {
X		(void) fprintf(stdout, "Error:  ");
X		(void) fprintf(stdout, "No meaningful bit string specified ");
X		(void) fprintf(stdout, "for clock '%s'.  Exit 1.\n", 
X		clock->name);
X		(void) exit(1);
X	    }
X	} else {
X	    if(clock->value_sequence[(int) strlen(clock->value_sequence) - 1] 
X	    == '0') {
X		clock->node->next_value = LOGIC_LOW;
X	    } else
X	    if(clock->value_sequence[(int) strlen(clock->value_sequence) - 1] 
X	    == '1') {
X		clock->node->next_value = LOGIC_HIGH;
X	    } else
X	    if((clock->value_sequence[(int) strlen(clock->value_sequence) - 1] 
X	    == 'X') ||
X	    (clock->value_sequence[(int) strlen(clock->value_sequence) - 1] 
X	    == 'x')) {
X		clock->node->next_value = LOGIC_DONTCARE;
X	    } else {
X		(void) fprintf(stdout, "Error:  ");
X		(void) fprintf(stdout, "No meaningful bit string specified ");
X		(void) fprintf(stdout, "for clock '%s'.  Exit 1.\n", 
X		clock->name);
X		(void) exit(1);
X	    }
X	}
X	(void) NodeStats(clock->node, node_queue);
X    }
X}
X
X/*
XThis function assigns the preset values to corresponding nodes at
Xthe beginning of the simulation.
X*/
X
Xvoid
XAssignPreset(preset_queue, node_queue)
XSQUEUE *preset_queue;
XNQUEUE *node_queue;
X
X{
X    SIGNAL *preset;
X
X    for(preset = preset_queue->head; preset != ((SIGNAL *) NIL);
X    preset = preset->link) {
X	if(preset->value_sequence[0] == '0') {
X	    preset->node->next_value = LOGIC_LOW;
X	} else if(preset->value_sequence[0] == '1') {
X	    preset->node->next_value = LOGIC_HIGH;
X	} else if((preset->value_sequence[0] == 'X') ||
X	(preset->value_sequence[0] == 'x')) {
X	    preset->node->next_value = LOGIC_DONTCARE;
X	} else {
X	    (void) fprintf(stdout, "Error:  ");
X	    (void) fprintf(stdout, "No meaningful bit string specified ");
X	    (void) fprintf(stdout, "for preset '%s'.  Exit 1.\n", 
X	    preset->name);
X	    (void) exit(1);
X	}
X	(void) NodeStats(preset->node, node_queue);
X    }
X}
X
X/*
XThis function assigns the output symbols to outputs, using the values of 
Xcorresponding nodes, at the end of the run of each input vector. 
X*/
X
Xvoid
XAssignOutputs(output_queue, output_index)
XSQUEUE *output_queue;
Xint output_index;
X
X{
X    SIGNAL *output;
X
X    for(output = output_queue->head; output != ((SIGNAL *) NIL);
X    output = output->link) {
X	if(output->node->present_value == LOGIC_LOW) {
X	    if(output->node->present_drive > NO_DRIVE) {
X		output->value_sequence[output_index] = '0';
X	    } else {
X		output->value_sequence[output_index] = 'L';
X	    }
X	} else if(output->node->present_value == LOGIC_HIGH) {
X	    if(output->node->present_drive > NO_DRIVE) {
X		output->value_sequence[output_index] = '1';
X	    } else {
X		output->value_sequence[output_index] = 'H';
X	    }
X	} else if(output->node->present_value == LOGIC_DONTCARE) {
X	    output->value_sequence[output_index] = 'X';
X	} else {
X	    (void) fprintf(stdout, "Error:  ");
X	    (void) fprintf(stdout, "Illegal output logic value %d %s[%d]. ");
X	    (void) fprintf(stdout, "Exit 1.\n",
X	    output->node->present_value, output->name, output_index);
X	    (void) exit(1);
X	}
X    }
X}
SHAR_EOF
chmod 0666 runsim.c || echo "restore of runsim.c fails"
fi
if test -f state.c; then echo "File state.c exists"; else
echo "x - extracting state.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > state.c &&
X/*
X*******************************************************************************
XAuthor: 
X	Alex Sherstinsky,
X	Microsystems Technology Laboratories,
X	Building 39, Room 611,
X	Massachusetts Institute Of Technology,
X	77 Massachusetts Avenue,
X	Cambridge, MA 02139
X	Telephone: (617)253-0710 
X	Electronic Mail Address: shers@caf.mit.edu
XCopyright 1988 Massachusetts Institute Of Technology
XAll rights reserved.
XThis program may not be distributed to other organizations without the 
Xpermission of the author.  In no case may it be distributed outside the
XUnited States and Canada.  This program is supplied "as is", without any
Xkind of warranty, and M.I.T. does not promise to support it in any way.
XThis program is not to be incorporated into a commercial product, or access
Xto it sold, without prior written agreement from the author.
X*******************************************************************************
XSLIC
X*******************************************************************************
X*/
X#include <stdio.h>
X#include <strings.h>
X#include <math.h>
X
X#include "func.h"
X#include "tech.h"
X#include "queue.h"
X#include "hash.h"
X#include "runsim.h"
X#include "state.h"
X
X/*
XThis function allocates and builds the state space for the simulator.
X*/
X
Xvoid
XBuildState(sim_file, drive_file, 
Xinput_queue, clock_queue, preset_queue, output_queue,
Xmos_count, node_count, input_count, clock_count, output_count,
Xinput_duration, clock_duration)
XFILE *sim_file;
XFILE *drive_file;
XSQUEUE **input_queue;
XSQUEUE **clock_queue;
XSQUEUE **preset_queue;
XSQUEUE **output_queue;
Xint *mos_count;
Xint *node_count;
Xint *input_count;
Xint *clock_count;
Xint *output_count;
Xint *input_duration;
Xint *clock_duration;
X
X{
X    *input_queue = (SQUEUE *) SQInit("input_queue");
X    *clock_queue = (SQUEUE *) SQInit("clock_queue");
X    *preset_queue = (SQUEUE *) SQInit("preset_queue");
X    *output_queue = (SQUEUE *) SQInit("output_queue");
X    (void) BuildDrive(drive_file, *input_queue, input_count, input_duration,
X    *clock_queue, clock_count, clock_duration, *preset_queue,
X    *output_queue, output_count);
X    (void) BuildNetwork(sim_file, mos_count, node_count, 
X    *input_queue, *clock_queue, *preset_queue, *output_queue);
X}
X
X/*
XThis function reads the ".drive" file, containing specific directions for the
Xsimulation.  It sorts the various types of signals (inputs, clocks, and
Xoutputs) into their respective queues, reporting their count as well.  
XIt also records the maximum duration of inputs and clocks (in the units of 
Xon-chip clock pulses for inputs and in the units of off-chip clock pulses, or 
Xsimply, bits, for clocks).
X*/
X
Xvoid
XBuildDrive(drive_file, input_queue, input_count, input_duration,
Xclock_queue, clock_count, clock_duration, preset_queue, 
Xoutput_queue, output_count)
XFILE *drive_file;
XSQUEUE *input_queue;
Xint *input_count;
Xint *input_duration;
XSQUEUE *clock_queue;
Xint *clock_count;
Xint *clock_duration;
XSQUEUE *preset_queue;
XSQUEUE *output_queue;
Xint *output_count;
X
X{
X    char *drive_line = (char *) malloc((unsigned) (MAXBITS + COMMAND_LENGTH) *
X    sizeof(char));
X    char signal_type;
X    char *signal_name = (char *) malloc((unsigned) MAX_TOKEN_LENGTH * 
X    sizeof(char));
X    char *signal_value_sequence = (char *) malloc((unsigned) MAXBITS * 
X    sizeof(char));
X
X    for(; (char *) fgets(drive_line, MAXBITS + COMMAND_LENGTH, 
X    drive_file) != NULL;) {
X	if((*drive_line == 'I') || (*drive_line == 'i') ||
X	(*drive_line == 'C') || (*drive_line == 'c') ||
X	(*drive_line == 'P') || (*drive_line == 'p')) {
X	    (void) sscanf(drive_line, "%c %s %s", &signal_type, signal_name, 
X	    signal_value_sequence);
X	} else if((*drive_line == 'O') || (*drive_line == 'o')) {
X	    (void) sscanf(drive_line, "%c %s", &signal_type, signal_name);
X	} else if(*drive_line == '|') {
X	    signal_type = '\0';
X	    (void) strcpy(signal_name, "");
X	    (void) strcpy(signal_value_sequence, "");
X	} else {
X	    (void) fprintf(stdout, "Error:  Illegal command %c.  Exit 1.\n",
X	    *drive_line);
X	    (void) exit(1);
X	}
X	if((signal_type == 'I') || (signal_type == 'i')) {
X	    (*input_count)++;
X	    *input_duration = (int) MaxInt(*input_duration, 
X	    (int) strlen(signal_value_sequence));
X	    (void) SQPut(input_queue, (SIGNAL *)
X	    MakeSignal('i', signal_name, signal_value_sequence, 
X	    ((NODE *) NIL), MAXBITS));
X	} else if((signal_type == 'C') || (signal_type == 'c')) {
X	    (*clock_count)++;
X	    *clock_duration = (int) MaxInt(*clock_duration, 
X	    (int) strlen(signal_value_sequence));
X	    (void) SQPut(clock_queue, (SIGNAL *)
X	    MakeSignal('c', signal_name, signal_value_sequence,
X	    ((NODE *) NIL), MAXBITS));
X	} else if((signal_type == 'P') || (signal_type == 'p')) {
X	    (void) SQPut(preset_queue, (SIGNAL *)
X	    MakeSignal('t', signal_name, signal_value_sequence,
X	    ((NODE *) NIL), MAXBITS));
X	} else if((signal_type == 'O') || (signal_type == 'o')) {
X	    (*output_count)++;
X	    (void) SQPut(output_queue, (SIGNAL *)
X	    MakeSignal('o', signal_name, (char *) AllocateString(MAXBITS),
X	    ((NODE *) NIL), MAXBITS));
X	} 
X    }
X}
X
X/*
XThis routine builds the network of nodes and mosfets and establishes the 
Xappropriate connections between the external terminals (inputs, clocks, and 
Xoutputs) and nodes.
X*/
X
Xvoid
XBuildNetwork(sim_file, mos_count, node_count, 
Xinput_queue, clock_queue, preset_queue, output_queue)
XFILE *sim_file;
Xint *mos_count;
Xint *node_count;
XSQUEUE *input_queue;
XSQUEUE *clock_queue;
XSQUEUE *preset_queue;
XSQUEUE *output_queue;
X
X{
X    NHASHTAB *node_hash_table;
X
X    node_hash_table = (NHASHTAB *) NHashInit("node_hash_table");
X    (void) ReadSimNetlist(sim_file, mos_count, node_hash_table);
X    *node_count = node_hash_table->node_count;
X    (void) ConnectInputsNodes(input_queue, node_hash_table);
X    (void) ConnectClocksNodes(clock_queue, node_hash_table);
X    (void) ConnectPresetNodes(preset_queue, node_hash_table);
X    (void) ConnectOutputsNodes(output_queue, node_hash_table);
X}
X
X/*
XThis function reads the ".sim" file, during which it builds a hash table of 
Xnodes and a queue of mosfets.  It also adds capacitances found in the ".sim" 
Xfile to respective nodes.
X*/
X
Xvoid
XReadSimNetlist(sim_file, mos_count, node_hash_table)
XFILE *sim_file;
Xint *mos_count;
XNHASHTAB *node_hash_table;
X
X{
X    char *sim_line;
X    char **token_array;
X    int index;
X    NODE *(node[3]);
X    MOSFET *(mosfet[3]);
X    float width;
X    float length;
X
X    sim_line = (char *) malloc((unsigned) SIM_LINE_LENGTH * sizeof(char *));
X    token_array = (char **) malloc((unsigned) MAX_TOKENS * sizeof(char *));
X    for(index = 0; index < MAX_TOKENS; index++) {
X	token_array[index] = (char *) malloc((unsigned) MAX_TOKEN_LENGTH *
X	sizeof(char));
X    }
X    for(; (char *) fgets(sim_line, SIM_LINE_LENGTH, sim_file) != NULL;) {
X	(void) ParseSimLine(token_array, sim_line);
X	if((*(token_array[0]) == NMOS) || (*(token_array[0]) == PMOS) ||
X	(*(token_array[0]) == ENMOS) || (*(token_array[0]) == DNMOS)) {
X	    (void) ReadMosfet(node_hash_table, token_array[1], token_array[2], 
X	    token_array[3], node, mosfet, mos_count, *(token_array[0]),
X	    (width = (float) atof(token_array[5])) / 
X	    (length = (float) atof(token_array[4])));
X	    (void) CombineMosfet(node[0]);
X	    (void) CombineMosfet(node[1]);
X	    (void) CombineMosfet(node[2]);
X	    node[0]->capacitance += width * length * COX;
X	} else if(*(token_array[0]) == CAPACITOR) {
X	    (void) ReadCapacitor(node_hash_table, 
X	    token_array[1], (float) atof(token_array[3]));
X	}
X    }
X}
X
X/*
XThis function parses a single line from the ".sim" file into tokens.
X*/
X
Xvoid 
XParseSimLine(token_array, sim_line)
Xchar **token_array;
Xchar *sim_line;
X
X{
X    int token_index = 0;
X    int char_count = 0;
X
X    for(; ((*sim_line != '\0') && (token_index < MAX_TOKENS));) {
X	if(*sim_line != ' ') {
X	    token_array[token_index][char_count++] = *(sim_line)++;
X	} else {
X	    for(token_array[token_index][char_count] = '\0',
X	    token_index++, char_count = 0; (*sim_line == ' '); sim_line++) {
X		;
X	    }
X	}
X    }
X}
X
X/*
XThis function puts (if necessary) each node of a new mosfet into the 
Xnode hash table and attributes the mosfet to the nodes.
X*/
X
Xvoid 
XReadMosfet(node_hash_table, gate_terminal_name, source_terminal_name, 
Xdrain_terminal_name, node, mosfet, mos_count, device, strength)
XNHASHTAB *node_hash_table;
Xchar *gate_terminal_name;
Xchar *source_terminal_name;
Xchar *drain_terminal_name;
XNODE **node;
XMOSFET **mosfet;
Xint *mos_count;
Xchar device;
Xfloat strength;
X
X{
X    node[0] = (NODE *) NHashPut(node_hash_table, gate_terminal_name,
X    &(mosfet[0]), device, strength);
X    node[1] = (NODE *) NHashPut(node_hash_table, source_terminal_name,
X    &(mosfet[1]), device, strength);
X    node[2] = (NODE *) NHashPut(node_hash_table, drain_terminal_name,
X    &(mosfet[2]), device, strength);
X    (*mos_count)++;
X    mosfet[0]->term[0] = node[0];
X    mosfet[0]->term[1] = node[1];
X    mosfet[0]->term[2] = node[2];
X    if(node[1] != node[0]) {
X	mosfet[1]->term[0] = node[0];
X	mosfet[1]->term[1] = node[1];
X	mosfet[1]->term[2] = node[2];
X    }
X    if((node[2] != node[0]) && (node[2] != node[1])) {
X	mosfet[2]->term[0] = node[0];
X	mosfet[2]->term[1] = node[1];
X	mosfet[2]->term[2] = node[2];
X    }
X}
X
X/*
XThis function adds a capacitance (lumped to substrate) found in the ".sim" 
Xfile to the given node.  The capacitances reported in the ".sim" file are not
Xassociated with mosfets.  This routine assumes that the units of capacitance 
Xin the ".sim" file are fF.  The node to which the capacitance is connected
Xmust have been previously specified in the ".sim" file as a mosfet terminal.
X*/
X
Xvoid 
XReadCapacitor(node_hash_table, node_name, capacitance)
XNHASHTAB *node_hash_table;
Xchar *node_name;
Xfloat capacitance;
X
X{
X    NODE *node;
X
X    if((node = (NODE *) NHashGet(node_hash_table, READ, 
X    node_name, ((MOSFET **) NIL), '\0', 0.0)) == ((NODE *) NIL)) {
X	(void) fprintf(stdout, "Warning: ");
X	(void) fprintf(stdout, "Node '%s' is not connected to a mosfet.  ",
X	node_name);
X	(void) fprintf(stdout, "Ignored.\n");
X    } else {
X	node->capacitance += capacitance;
X    }
X}
X
X/*
XThis function combines a mosfet newly encountered in the ".sim" file with
Xa previously found mosfet if the terminal connections of the two mosfets
Xare the same.  This accomplishes the unfolding of folded mosfet structures.
X*/
X
Xvoid 
XCombineMosfet(node)
XNODE *node;
X
X{
X    MQUEUE *mosfet_queue;
X    MOSFET *tail;
X    MOSFET *mosfet;
X
X    mosfet_queue = node->mosfet_queue;
X    for(mosfet = mosfet_queue->head, tail = mosfet_queue->tail; 
X    mosfet != tail; mosfet = mosfet->link) {
X	if((mosfet->mosfet_type == tail->mosfet_type) &&
X	(mosfet->term[0] == tail->term[0]) &&
X	(((mosfet->term[1] == tail->term[1]) &&
X	(mosfet->term[2] == tail->term[2])) ||
X	((mosfet->term[1] == tail->term[2]) &&
X	(mosfet->term[2] == tail->term[1])))) {
X	    mosfet->strength += tail->strength;
X	}
X    }
X}
X
X/*
XThis routine connects input signals to their corresponding nodes.
X*/
X
Xvoid
XConnectInputsNodes(input_queue, node_hash_table)
XSQUEUE *input_queue;
XNHASHTAB *node_hash_table;
X
X{
X    SIGNAL *input;
X
X    for(input = input_queue->head; input != ((SIGNAL *) NIL);
X    input = input->link) {
X	if((input->node = (NODE *) NHashGet(node_hash_table, READ, 
X	input->name, ((MOSFET **) NIL), '\0', 0.0)) == ((NODE *) NIL)) {
X	    (void) fprintf(stdout, "Error:  ");
X	    (void) fprintf(stdout, "Input '%s' does not exist.  Exit 1.\n", 
X	    input->name);
X	    (void) exit(1);
X	}
X	input->node->present_drive = input->node->next_drive = SUPER_DRIVE;
X	input->node->capacitance = SUPER_CAPACITANCE;
X    }
X}
X
X/*
XThis routine connects clock signals to their corresponding nodes.
X*/
X
Xvoid
XConnectClocksNodes(clock_queue, node_hash_table)
XSQUEUE *clock_queue;
XNHASHTAB *node_hash_table;
X
X{
X    SIGNAL *clock;
X
X    for(clock = clock_queue->head; clock != ((SIGNAL *) NIL);
X    clock = clock->link) {
X	if((clock->node = (NODE *) NHashGet(node_hash_table, READ, 
X	clock->name, ((MOSFET **) NIL), '\0', 0.0)) == ((NODE *) NIL)) {
X	    (void) fprintf(stdout, "Error:  ");
X	    (void) fprintf(stdout, "Clock '%s' does not exist.  Exit 1.\n", 
X	    clock->name);
X	    (void) exit(1);
X	}
X	clock->node->present_drive = clock->node->next_drive = SUPER_DRIVE;
X	clock->node->capacitance = SUPER_CAPACITANCE;
X    }
X}
X
X/*
XThis routine connects preset signals to their corresponding nodes.
X*/
X
Xvoid
XConnectPresetNodes(preset_queue, node_hash_table)
XSQUEUE *preset_queue;
XNHASHTAB *node_hash_table;
X
X{
X    SIGNAL *preset;
X
X    for(preset = preset_queue->head; preset != ((SIGNAL *) NIL);
X    preset = preset->link) {
X	if((preset->node = (NODE *) NHashGet(node_hash_table, READ, 
X	preset->name, ((MOSFET **) NIL), '\0', 0.0)) == ((NODE *) NIL)) {
X	    (void) fprintf(stdout, "Error:  ");
X	    (void) fprintf(stdout, "Preset '%s' does not exist.  Exit 1.\n", 
X	    preset->name);
X	    (void) exit(1);
X	}
X    }
X}
X
X/*
XThis routine connects output signals to their corresponding nodes.
X*/
X
Xvoid
XConnectOutputsNodes(output_queue, node_hash_table)
XSQUEUE *output_queue;
XNHASHTAB *node_hash_table;
X
X{
X    SIGNAL *output;
X
X    for(output = output_queue->head; output != ((SIGNAL *) NIL);
X    output = output->link) {
X	if((output->node = (NODE *) NHashGet(node_hash_table, READ, 
X	output->name, ((MOSFET **) NIL), '\0', 0.0)) == ((NODE *) NIL)) {
X	    (void) fprintf(stdout, "Error:  ");
X	    (void) fprintf(stdout, "Output '%s' does not exist.  Exit 1.\n", 
X	    output->name);
X	    (void) exit(1);
X	}
X    }
X}
SHAR_EOF
chmod 0644 state.c || echo "restore of state.c fails"
fi
exit 0