Rosemary.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Barth, September 30, 1987 2:24:49 pm PDT
Jean-Marc Frailong December 17, 1987 3:05:58 pm PST
DIRECTORY BasicTime, Core, CoreClasses, CoreFlat, Ports, RefTab, Rope;
Rosemary: CEDAR DEFINITIONS = BEGIN
Theory
Rosemary is a simulator which combines a MOSSIM switch level model for transistors with a simple selective trace algorithm for higher level functional blocks. Behavioural procedures must be registered for the functional blocks. A Core data structure is used to express the net list. The net list is flattened into a Rosemary simulation data structure. The simulation data structure can be initialized to hold zeroes or X's everywhere. The steady state reponse to a test vector can be computed.
ROPE: TYPE = Core.ROPE;
Stop: SIGNAL [msg: ROPENIL, data: REF ANYNIL, reason: ATOM ← $Client];
This signal may be raised when a behavioural proc is annoyed by something. It is raised by Rosemary with reason = $BoolWireHasX and data = CoreFlat.FlatWire if some wire attached to a port containing boolean values settles to an X.
Behaviour Registration
BindCellType: PROC [cellType: Core.CellType, roseClassName: ROPE] RETURNS [sameCellType: Core.CellType];
BindCellClass: PROC [cellClass: Core.CellClass, roseClassName: ROPE] RETURNS [sameCellClass: Core.CellClass];
Register: PROC [roseClassName: ROPE, init: InitProc ← NIL, evalSimple: EvalProc ← NIL, copy: StateCopyProc ← NIL, scheduleIfClockEval: BOOLFALSE] RETURNS [sameRoseClassName: ROPE];
InitProc: TYPE = PROC [cellType: Core.CellType, p: Ports.Port, oldStateAny: REF ANYNIL, steady: BOOLFALSE] RETURNS [stateAny: REF ANYNIL, stateValue: Ports.LevelSequence ← NIL];
Initializes the state and the value from the context contained in the cell type. Multiple calls must return different copies of any bits in the state record which actually represent the state of the simulation. If oldStateAny is not NIL then the procedure should reset the state to its initial value rather than allocating new state. Steady=FALSE means that the state variables should be initialized to X if possible. stateValue contains a representation of the state value. It is not required. The InitProc and EvalProc own stateValue, Rosemary guarantees not to change it. The size of stateValue, when specified, must be constant across calls to InitProc and EvalProc.
StateCopyProc: TYPE = PROC [from: REF ANY, to: REF ANY];
Copies the state. Only needed if statePoints > 0 upon instantiation of a simulation which uses the celltype's EvalProc.
EvalProc: TYPE = PROC [p: Ports.Port, stateAny: REF ANY, clockEval: BOOL] RETURNS [stateValue: Ports.LevelSequence ← NIL];
Must be idempotent. clockEval indicates that only ports combinatorially derived from a clock should be changed, i.e. no state should be updated during such an evaluation. stateValue is the same as in InitProc.
Instantiation
SetFixedWire: PROC [wire: Core.Wire, level: Ports.Level ← L] RETURNS [sameWire: Core.Wire];
Sets the value of the wire and indicates that the value of the wire may not be changed by Rosemary. This is only intended to be used for atomic public wires of the root cell type such as Vdd and Gnd. These wires partition the network into disjoint blocks connected through transistor gates. It is not a general purpose mechanism for jamming a value onto a wire.
SetWire: PROC [wire: Core.Wire, level: Ports.Level ← L, size: WireSize ← charge, memory: BOOLFALSE] RETURNS [sameWire: Core.Wire];
Sets the initial value and order of magnitude wire size. If memory is false then the wire is set to X whenever the wire is not driven and the memory boolean in the Settle call is false. This procedure may only be called with atomic, canonical (in the CoreFlat sense) wires.
WireSize: TYPE = Ports.Drive[chargeWeak..chargeStrong];
SetTransistorCellTypeSize: PROC [transistor: Core.CellType, size: TransistorSize] RETURNS [sameTransistor: Core.CellType];
Sets the order of magnitude transistor size.
SetTransistorInstanceSize: PROC [transistor: CoreClasses.CellInstance, size: TransistorSize] RETURNS [sameTransistor: CoreClasses.CellInstance];
TransistorSize: TYPE = Ports.Drive[driveWeak..driveStrong];
Instantiate: PROC [cellType: Core.CellType, testPort: Ports.Port, cutSet: CoreFlat.CutSet ← NIL, statePoints: NAT ← 0] RETURNS [simulation: Simulation];
Flattens the given cell type using the cutSet to determine the leaves of the simulation. statePoints determines the number of checkpoints allocated. The testPort must be constructed by Ports.CreatePort[cellType.public, TRUE]. The testPort is bound into the simulation so that the client may stimulate the network and examine the response.
Relaxation
Initialize: PROC [simulation: Simulation, steady: BOOLTRUE, updateCellProc: UpdateCellProc ← NIL];
Reset the state. If steady then the wires are initialized to "easy" values like L and 0. If not steady then they are initialized to X. The InitProc for each behaviour class is called for each instance. The UpdateCellProc is called after each init (c.f. Settle).
SettleToTest: PROC [simulation: Simulation, flatCell: CoreFlat.FlatCellType, test: Ports.Port];
Given a settled simulation, an instance in it and a test port this procedure converts the values in the settled simulation into a test vector for another simulation. The port of the instance and the test port must have identical structure and may not have port.driveType=separate.
Settle: PROC [simulation: Simulation, updateProc: UpdateProc ← NIL, memory: BOOLTRUE, clockEval: BOOLFALSE, updateCellProc: UpdateCellProc ← NIL];
UpdateProc: TYPE = PROC [roseWire: RoseWire];
UpdateCellProc: TYPE = PROC [roseInstance: RoseCellInstance, stateValue: Ports.LevelSequence];
Relaxes the simulation. The port supplied to instantiate must not be changed during the execution of this procedure. If an update procedure is supplied it is called each time a RoseWire changes value. May raise Stop. If memory is false then all wires which do not have memory are set to X if they are not driven. clockEval is simply passed to all of the eval procs so that they may take appropriate action.
State Access
NotInstantiated: SIGNAL;
Raised when access is requested to data not contained in the current simulation.
GetFlatWire: PROC [roseWire: RoseWire] RETURNS [flatWire: CoreFlat.FlatWireRec];
Maps the Rosemary wire back into the Core data structure. Useful in UpdateProcs.
WireValue: PROC [simulation: Simulation, flatWire: CoreFlat.FlatWire] RETURNS [value: Ports.LevelSequence];
Gets the current value of the wire. May raise NotInstantiated.
GetValues: PROC [simulation: Simulation, flatWire: CoreFlat.FlatWire] RETURNS [values: RoseValues];
Not for the faint of heart. Returns a data structure which describes where the value of the Core wire may be found. Depends upon the Rosemary internal data structures which are not guaranteed to be stable. May raise NotInstantiated.
GetState: PROC [simulation: Simulation, flatCell: CoreFlat.FlatCellType] RETURNS [stateAny: REF ANY];
Returns the ref to flatCell's state. Raises NotInstantiated if flatCell was not a leaf during instantiation.
StatePoint: PROC [simulation: Simulation, point: NAT];
Saves the current state of the simulation. Raises NotInstantiated if the index is greater than or equal to the number of statepoints passed to the instantiation procedure.
RestoreState: PROC [simulation: Simulation, point: NAT];
Restores the state of the simulation. Raises NotInstantiated if the index is greater than or equal to the number of statepoints passed to the instantiation procedure.
Hack
PrintPeriod: PROC [prefix: Rope.ROPE, from, to: BasicTime.GMT];
Data Structures
Not intended to be understood by clients.
The data structures have been optimized for atomic wires with transistors on them. Space optimization of more abstract objects was not a design goal.
The following space estimates are not up to date. This is an unnecessary statement since documentation is always out of date. Right?
Space allocation (including overhead of 2 words per allocated record)
transistor: (7 + 2 + 1) words/RoseTransistorRec + 2 words/RoseTransistor * 3 RoseTransistor/RoseTransistorRec => 16 words/transistor
wire: (25 + 2 + 2) words/RoseWireRec + (1 + 2) words/RoseTransistorSeq * 2 RoseTransistorSeq/RoseWireRec => 32 words/wire + quantization of RoseTransistorSeq
A circuit with 200,000 transistors and 70,000 wires requires ~5.5 MWord of memory. You might conceive of simulating 400,000 transistor circuits on a Dorado with 12 MWord of memory. Maybe. With luck. When hell freezes over. Which is when a simulation will finish if very many of those wires or transistors have to be considered by the simulator during each evaluation.
RoseCellType: TYPE = REF RoseCellTypeRec;
RoseCellTypeRec: TYPE = RECORD [
evalSimple: EvalProc ← NIL,
init: InitProc ← NIL,
copy: StateCopyProc ← NIL,
scheduleIfClockEval: BOOLFALSE];
Simulation: TYPE = REF SimulationRec;
SimulationRec: PUBLIC TYPE = RECORD [
cellType: Core.CellType ← NIL,
coreToRoseWires: RefTab.Ref ← NIL,
coreToRoseInstances: RefTab.Ref ← NIL,
coreToRoseValues: RefTab.Ref ← NIL,
instanceNeedEval: RoseCellInstance ← NIL,
instanceNeedEvalWhenNotClockEval: RoseCellInstance ← NIL,
perturbed: RoseWire ← NIL,
roseBoolWires: RoseWireList ← NIL,
publicBindings: PortBindings ← NIL,
scratchValue: Ports.LevelSequence ← NIL,
scratchDrive: Ports.DriveSequence ← NIL,
vicinityByStrength: ARRAY Ports.Drive OF VicinityRec,
testPort: Ports.Port ← NIL,
statePoints: PortSequence ← NIL,
mosSimTime: INT ← 0];
VicinityRec: TYPE = RECORD[
wires: RoseWires,
firstFree: CARDINAL ← 0];
PortSequence: TYPE = REF PortSequenceRec;
PortSequenceRec: TYPE = RECORD [ports: SEQUENCE size: NAT OF Ports.Port];
RoseCellInstance: TYPE = REF RoseCellInstanceRec;
RoseCellInstanceRec: TYPE = RECORD [
nextNeedEval: RoseCellInstance ← NIL,
nextNeedEvalWhenNotClockEval: RoseCellInstance ← NIL,
roseCellType: RoseCellType ← NIL,
publicPort: Ports.Port ← NIL,
portBindings: PortBindings ← NIL,
state: REF ANYNIL,
statePoints: SRANIL,
instance: CoreFlat.FlatCellTypeRec,
data: REF ANYNIL];
SRA: TYPE = REF SRASeq;
SRASeq: TYPE = RECORD [elements: SEQUENCE size: CARDINAL OF REF ANY];
PortBindings: TYPE = REF PortBindingSeq;
PortBindingSeq: TYPE = RECORD [elements: SEQUENCE size: CARDINAL OF PortBinding];
PortBinding: TYPE = REF PortBindingRec;
PortBindingRec: TYPE = RECORD [
instance: RoseCellInstance ← NIL,
clientPort: Ports.Port ← NIL,
fields: Fields ← NIL,
currentDrive: Ports.Drive ← none,
statePoints: Ports.DriveSequence ← NIL];
DriveSequenceSequence: TYPE = REF DriveSequenceSequenceRec;
DriveSequenceSequenceRec: TYPE = RECORD [elements: SEQUENCE size: CARDINAL OF Ports.DriveSequence];
Fields: TYPE = REF FieldSeq;
FieldSeq: TYPE = RECORD [elements: SEQUENCE size: CARDINAL OF Field];
Field: TYPE = REF FieldRec;
FieldRec: TYPE = RECORD [
portBinding: PortBinding ← NIL,
portStartBit: NAT ← 0,
roseWire: RoseWire ← NIL,
currentDrive: Ports.DriveSequence ← NIL,
currentValue: Ports.LevelSequence ← NIL,
driveStatePoints: DriveSequenceSequence ← NIL,
valueStatePoints: LevelSequenceSeq ← NIL];
RoseWireList: TYPE = LIST OF RoseWire;
RoseWires: TYPE = REF RoseWireSeq;
RoseWireSeq: TYPE = RECORD [elements: SEQUENCE size: CARDINAL OF RoseWire];
RoseWire: TYPE = REF RoseWireRec;
RoseWireRec: TYPE = RECORD [
firstFreeConnection: CARDINAL ← 0,
connections: Fields ← NIL,
currentValue: Ports.LevelSequence ← NIL,
currentValue=NIL => The wire is atomic. The following fields are only significant if the wire is atomic.
nextPerturbedWire: RoseWire ← NIL,
previousPerturbedWire: RoseWire ← NIL,
nextRecomputed: RoseWire ← NIL,
nextVicinityWire: RoseWire ← NIL,
channels: RoseTransistors ← NIL,
notOffChannels: RoseTransistors ← NIL,
validNotOffChannels: CARDINAL ← 0,
gates: RoseTransistors ← NIL,
switchDrive: Ports.Drive ← none,
upDrive: Ports.Drive ← none,
downDrive: Ports.Drive ← none,
wireDrive: Ports.Drive ← charge,
connectionDrive: Ports.Drive ← none,
connectionLevel: Ports.Level ← L,
wireLevel: Ports.Level ← L,
mark: BOOLFALSE,
memory: BOOLFALSE,
statePoints: REF ANYNIL, -- TypeUnion[Ports.LevelSequence, LevelSequenceSeq]
data: REF ANYNIL, -- Normally used by RosemaryUser for plotting
wire: CoreFlat.FlatWireRec];
LevelSequenceSeq: TYPE = REF LevelSequenceSeqRec;
LevelSequenceSeqRec: TYPE = RECORD [elements: SEQUENCE size: CARDINAL OF Ports.LevelSequence];
RoseValues: TYPE = LIST OF RoseValue;
RoseValue: TYPE = RECORD [
roseWire: RoseWire ← NIL,
fieldStart: NAT ← 0,
fieldWidth: NAT ← 0];
RoseWireData: TYPE = REF RoseWireDataRec;
RoseWireDataRec: TYPE = RECORD [value: Ports.Level, size: Ports.Drive, memory: BOOL];
RoseTransistors: TYPE = REF RoseTransistorSeq;
RoseTransistorSeq: TYPE = RECORD [elements: SEQUENCE size: CARDINAL OF RoseTransistor];
RoseTransistor: TYPE = REF RoseTransistorRec;
RoseTransistorRec: TYPE = RECORD [
gate: RoseWire ← NIL,
ch1: RoseWire ← NIL,
ch2: RoseWire ← NIL,
conductivity: Ports.Drive ← drive,
type: CoreClasses.TransistorType ← nE,
instance: CoreFlat.FlatCellTypeRec];
END.