CSL Notebook Entry
To Design Aids Interest Date August 18, 1983 8:09 pm
From Spreitzer.PA  Location PARC/CSL
Subject Rosemary  File [Indigo]<Rosemary>Draft>Rosemary.doc
Release as[Indigo]<Rosemary>Release>RosemaryDoc.press
Draft
 [Indigo]<Rosemary>Draft>Rosemary.doc
Last edited by Spreitzer.PA
Abstract This document describes Rosemary, a simulator for integrated circuits. This document aspires to describe almost all of what Rosemary is; it is not so much oriented to easily answering the question "How is it used?".
Rosemary
0. Introduction
Rosemary is a simulator for integrated circuits. It understands hierarchical descriptions of circuits. It's "model of computation" is arbitrary Cedar procedures, that communicate almost arbitrary Cedar values, and that are "scheduled" by a selective trace scheduler. It's intended use is for "downward" development of a design.
There is an example worked out in excruciating detail in section 5. It would probably be useful to refer to it while reading the earlier sections.
Here is a Table of Contents:
0. Introduction
1. The world according to Rosemary
1.1 Circuit Designs
1.2 Simulation Structures
1.3 Rosemary
2. The Translator
2.1 Syntax
2.2 Semantics
2.3 Running the Translator
2.4 Relation of the Translator to the absence of Translator
3. The Simulation-Time User Interface
3.1 Displays
3.2 Browsers
3.3 Control Panels
5. Example
1. The world according to Rosemary
There are Circuit Designs, and there are Simulation Structures. And then, there is Rosemary.
1.1 Circuit Designs
A Circuit Design consists of a collection of Subcircuit Designs. A Circuit Design is a hierarchical decomposition, and Subcircuit Designs are the nodes in the hierarchy.
A Subcircuit Design has an Interface, through which it communicates with the rest of the design. A Subcircuit Design's Interface is a set of Items, each of which has a name (text string), an Abstract Type (described later), and a Direction (one of In, Out, or Both).
Given that we have restricted ourselves to describing systems to be built in silicon, we might insist that all Interface Items have the same Abstract Type: that Type would be the only one, the one corresponding to a single electrical node. Or we might distinguish more finely, and make three, one for each of the three primary layers of interconnect (poly, metal, and diffusion). Aside from that issue, we could think of Interfaces as trafficing in Boolean values, or voltages, or any one of a number of other things. Still further, we could imagine treating a collection of wires as a single unit (i.e., a single Interface Item), rather than many individuals. Abstract Types do not make any of those decisions. As far as we are concerned here, Abstract Types have nothing but an identity. They are used only in the following way: when two things are connected, we insist that they have the same Abstract Type.
A Subcircuit Design might, but does not need to, include a description of how it is composed of other Subcircuits (its Structural Description). Such a description is in terms of Instances of other Subcircuit Designs, and Abstract Networks connecting them. An Instance of a Subcircuit Design includes an association between each of the Items of the Interface of that Subcircuit Design and an Abstract Network. Furthermore, each of the Interface Items of the Subcircuit Design we are elaborating must also be associated with an Abstract Network. Thus, these associations describe how things are connected: all of the Interface Items associated with a particular Abstract Network are considered connected together. We insist that they all be of the same Abstract Type.
A Subcircuit Design might also, but also does not need to, include a description of what the outputs of an Instance of that Subcircuit would be, given the inputs (its Behavioral Description). This description might be a procedure, which is allowed to keep a state record, in some programming language.
A Subcircuit Design might also, but also does not need to, include a non-constructive Behavioral Description; one that can provide stimuli, observe the results, and approve or dissapprove. This description is called the Subcircuit Design's Test. It may also be a procedure in some programming language.
1.2 Simulation Structures
Forget the preceeding discussion. We will now discuss how a fairly general simulator might be built. Call it the Structural Simulator.
This simulator will not deal with hierarchy. It will have a single, flat, Structure. Furthermore, it will deal only with unidirectional devices. The Modules in such a structure will have outputs which are computable functions of the histories on their inputs.
A Simulation Structure will consist of Modules, connected up. The methodology for connecting is like that presented in section 1.1, but you've forgotten that, haven't you? Just to keep things clear, we will use different words.
Each Module will communicate via a Cedar RECORD. Each field will be either an input, an output, or both. Each Module will have an Evaluation PROCEDURE, which examines the input fields, does some computation, and assigns into some output fields. Each Module will have a REF ANY slot in which to store arbitrary state information from one invocation to the next. Each of the output fields has associated with it a Distribution List of input fields of other Modules. After a Module's Evaluation PROCEDURE has been run, for each output field that has changed, the bits in that field are copied into all of the fields on its Distribution List.
A Simulation Structure will also have a FIFO, called its Schedule. The Schedule contains Modules whose inputs have changed since their Evaluation PROCEDUREs were last run. Modules are added to the Schedule at the time their inputs change. The main loop of the simulator is to take the first Module out of the Schedule, run its Evaluation PROCEDURE, and take care of all the grubby little details, terminating when (and if!) the Schedule empties. If you start with a quiescent Structure, and make a small change, this makes for a breadth first exploration of the consequences of that change.
1.3 Rosemary
OK, now you can stop forgetting section 1.1. Rosemary has a Cedar data structure that represents concepts from both Circuit Designs and Simulation Structures. Rosemary simulates, by virtue of the efforts of possibly more than one Simulation Structure, and even other simulators, the operation of an Instance of a Circuit Design (that is, an Instance of a certain distinguished Subcircuit: its Root).
In Rosemary, Cells are used to represent Instances of Subcircuit Designs. For every Instance there is exactly one Cell. Furthermore, there are no Cells that do not represent Instances.
Rosemary includes an implementation of the simulator discussed in section 1.2. Its Modules are also represented by Cells, although it is not the case that all Cells must represent Modules.
Rosemary has another TYPE of object, Node, that is used to represent both the Abstract Networks of Subcircuit Designs, and the Distribution Lists of Simulation Structures.
When Instantiating a Subcircuit Design for simulation, either its Structural Description or its Behavioral Description could be used (assuming, of course, they are both present). When creating the data structure for a Rosemary simulation, a Subcircuit Design is always Instantiated in the context of some Simulation Structure. If the Subcircuit's Behavioral Description is to be used, a Module is introduced into that Simulation Structure. The Evaluation PROCEDURE of that Module is the Subcircuit's Behavioral Description.
If, on the other hand, the Subcircuit Design's Structural Description is to be used, there is a choice of how to use it. One alternative, Nested, also introduces a new Module into the Simulation Structure. It then introduces a new Simulation Structure, "inside" the Module, to implement that Subcircuit in terms of its components. The Evaluation PROCEDURE of the Module is another instance of the main loop of the Structural Simulator, directed at the inner Simulation Structure.
When the Nested alternative is used, new Nodes are created, in the inner Simulation Structure, corresponding to the Nodes in the outer Simulation Structure that are on the Interface of the Cell. That is, there are two sets of interface Nodes for such a Cell: one seen from the outside, and one seen from the inside. The ones seen from the outside are the ones entered in the interfaceNodes field in the Cell. The ones seen from the inside are put in the internalNodes SymbolTable.
The other alternative, Inline, does not introduce a new Module, nor a new Simulation Structure. It causes the components to be Instantiated in the same Simulation Structure.
The practical import of choosing one or the other is in the ordering of evaluations. In the Nested choice, when the nested Module is evaluated, it is run to completion before anything on the outside world may continue. In the Inline choice, there is no distinction between inside and outside; they mix freely. Inline is probably the one you want. The real reason for having Nested around it to start to debug ideas about plugging different simulators together.
Here are some highlights from Rosemary.Mesa, a DEFINITIONS file that has most of the relevant definitions in it:
Cell: TYPE = REF CellRep;
CellRep: TYPE = RECORD [
name: ROPE,
class: CellClass,
nextInstance: Cell,
parent, leftChild, rightSibling: Cell,
firstInternalNode: Node,
internalNodes, components: SymbolTable,
interfaceNodes: NodeS,
other: AList,
type: CellType,
expansion: ExpandDecision,
realCellStuff: RealCellStuff -- non-NIL only for Real Cells
];
CellType: TYPE = {Real, Shadow};
RealCellStuff: TYPE = REF RealCellStuffRep;
RealCellStuffRep: TYPE = RECORD [
schedNext: Cell,
newIO, oldIO: REF ANY,
newIOAsWP, oldIOAsWP: WordPtr,
locked: BOOLEANFALSE,
state: REF ANY,
eval: EvalProc,
schedWatchers, evalWatchers: CellWatcherList ← NIL];
NodeS: TYPE = REF NodeSR;
NodeSR: TYPE = RECORD [nodes: SEQUENCE length: CARDINAL OF Node];
The type of a Cell distinguishes those that represent Modules from those that do not; Real Cells represent Modules, and Shadow Cells represent Instances of Subcircuit Designs that have no Module (i.e., are Inlines). A CellClass represents a Subcircuit Design. The internalNodes SymbolTable of a Cell holds the Nodes that are used in connecting up the components of the Cell. The components SymbolTable holds the Subcircuit Design Instances from which that Cell is composed.
The interfaceNodes field holds the association between Interface Items of the Subcircuit Design and the Abstract Networks they are associated with. For I in [0 .. class.ports.length), interfaceNodes[I] represents the Abstract Network associated with the Interface Item represented by class.ports[I].
For Real Cells (that is, ones that also represent Modules in a Simulation Structure) there is an additional record that holds additional information: the realCellStuff. The Schedule of the Simulation Structure is a linked list, and the links are the schedNext fields. The newIO field holds a REF to the RECORD used by the Evaluation PROCEDURE. For the benefit of the simulator, it is duplicated as a LONG POINTER TO CARDINAL in newIOAsWP. The oldIO is used for detecting changes in newIO. The eval field holds the Module's Evaluation PROCEDURE, and the state field is for whatever use the Evaluation PROCEDURE wants to put it to.
Node: TYPE = REF NodeRep;
NodeRep: TYPE = RECORD [
name: ROPE,
type: SignalType ← NIL,
visible: Socket ← [NIL, LAST[CARDINAL]],
unwriteability: INTEGER ← 0,
readers: SocketList ← NIL,
watchers: ARRAY Priority OF NodeWatcherList ← ALL[NIL],
next: Node ← NIL,
other: AList ← NIL];
SocketList: TYPE = LIST OF Socket;
Socket: TYPE = RECORD [cell: Cell, index: CARDINAL];
Nodes hold the Distribution Lists of the Structural Simulator. A Distribution List is represented by a SocketList. The index in a Socket is into a table stored with the Class of the Cell referred to, which tells the simulator where to stuff the bits.
As was mentioned earlier, all of the Interface Items associated with a given Abstract Network must be of the same Abstract Type. That Type is stored in the Node. SignalTypes are used to represent Abstract Types.
SignalType: TYPE = REF SignalTypeRep;
SignalTypeRep: TYPE = RECORD [
toRope: ToRopeProc,
fromRope: FromRopeProc,
init: TypeInitProc,
maxWidth: MaxWidthProc,
parseTest: TestParseProc,
unParseTest: TestUnParseProc,
typeData: REF ANY];
Although Abstract Types have nothing but an identity, SignalTypes have more. But what they have is (mostly) just for constructing user interface; as far as most of Rosemary is concerned, only their identity is important. The ToRopeProc, FromRopeProc, MaxWidthProc, TestParseProc, and TestUnParseProc are for formatting and parsing Tests and Values (see discussion of mode in section 3.3). The TypeInitProc is used to provide a default initial value for fields in newIO.
SignalTypes are usually gotten by calling some peripheral procedure that creates them. "IntTypes.Mesa" is a file containing an interface that provides such a procedure; it can be found in the example. "Mnemonics.Mesa" is another.
CellClass: TYPE = REF CellClassRep;
CellClassRep: TYPE = RECORD [
name: ROPE,
expand: ExpandProc,
ioCreator: IOCreator,
initializer: Initializer,
eval: EvalProc,
test: EvalProc,
ports: Ports,
ioWordCount: CARDINAL,
ioTemplate: REF ANY,
firstInstance: Cell];
ExpandProc: TYPE = PROCEDURE [thisCell: Cell, initData: REF ANY];
CreateNode: PROCEDURE [within: Cell, name: ROPE, type: SignalType] RETURNS [node: Node];
CreateCell: PROCEDURE [within: Cell, instanceName, className, interfaceNodes: ROPE, initData: REF ANYNIL] RETURNS [cell: Cell];
IOCreator: TYPE = PROC [cell: Cell, initData: REF ANY];
Initializer: TYPE = PROCEDURE [cell: Cell, initData: REF ANY, leafily: BOOLEAN];
EvalProc: TYPE = PROCEDURE [cell: Cell];
Ports: TYPE = REF PortsRep;
PortsRep: TYPE = RECORD [
ports: SEQUENCE length: CARDINAL OF Port];
Port: TYPE = RECORD [
firstWord, wordCount: CARDINAL,
name: ROPE,
type: SignalType,
input, output: BOOLEANFALSE];
A CellClass represents a Subcircuit Design. The ExpandProc holds its Structural Description. It is a procedure, which, when executed, calls certain other procedures (CreateNode and CreateCell); these calls describe to Rosemary how an Instance of this Subcircuit Design is constructed out of Instances of others.
In CreateNode and CreateCell, the within parameter identifies the Instance being elaborated.
When calling CreateCell, the association between the Interface Items of the Instance being created and Abstract Networks is specified in the interfaceNodes parameter. It is of the format <id> ":" <id> ( "," <id> ":" <id> ) * . In each pair, the first <id> identifies the Interface Item (by the name of a Port), and the second identifies the Abstract Network (by the name of a Node). An alternative format elides the first <id> and colon of all the pairs; the association is then positional.
The IOCreator is called when the Class is Instantiated using its Behavioral Description, or using its Structural Description in the Nested fashion. The sole purpose of the IOCreator is to allocate RECORDS of the appropriate TYPE and put REFS to them in newIO and oldIO.
The Initializer is called under the same circumstances as the IOCreator. The reason for splitting them is to allow the fields of the IO RECORDS to be initialized according to the whims of their SignalTypes. The Initializer can then override those initializations, if it is so desired. The Initializer is passed a further flag, leafily, which distinguishes the two cases in which it might be called. It is TRUE when the Behavioral Description is being used. In this case, the Initialzer is also responsible for allocating the state RECORD that the Behavioral Description will use, and putting a REF to it in the state field of the Cell.
The ExpandProc, the IOCreator, and the Initializer all take a parameter, initData, which is for whatever use they choose to put it to. The initData handed to CreateCell is what will be given to the ExpandProc, IOCreator, and Initializer of the Class of Cell being created.
The eval EvalProc holds the Behavioral Description of the Subcircuit Design. It is a procedure which computes from the input fields of newIO the new values for the output fields of newIO. The way changes in the output fields are detected is as follows. Before doing anything else, the EvalProc must copy all the ouptut fields of newIO into the output fields of oldIO. Then it computes, and updates the output fields of newIO. The simulator then compares the bits in the output fields of newIO with those of oldIO. Note that the simulator treats these simply as a collection of bits. Thus, putting pointers there probably won't work "right" (and putting REFs there is almost certain to confuse the garbage collector). The Structural Simulator uses the information in the ports sequence of the Class of the Cell to determine where each field begins and ends (note that the fields must be aligned on word boundaries -- where necessary, pad them out with fixed bits).
The test EvalProc hold the Test of the Subcircuit Design. It is a procedure which repeatedly: sets some inputs in the Cell's newIO, calls a procedure (Rosemary.Eval) to run the Cell, and compares the results in newIO with what it expected. Note that since communication is only through the Cell's newIO, this Test can be applied to both the Behavioral Description and the behavior engendered by the Structural Description (when expanded Nested).
The ports of a Class represent the Interface of the Subcircuit Design; each Port represents an Interface Item.
RegisterCellClass: PROCEDURE [
className: ROPE,
expandProc: ExpandProc ← NIL,
ioCreator: IOCreator ← NIL,
initializer: Initializer ← NIL,
evalProc, testProc: EvalProc,
ports: Ports,
ioTemplate: REF ANY ← Unspecified];
Clients of Rosemary make CellClasses known to Rosemary via calls on RegisterCellClass.
The ioTemplate is left over from the bad old days; ignore it.
CreateTopCell: PROC [instanceName, className: ROPE, initData: REF ANYNIL, decider: ExpandDeciderClosure] RETURNS [cell: Cell];
ExpandDeciderClosure: TYPE = REF ExpandDeciderClosureRep;
ExpandDeciderClosureRep: TYPE = RECORD [
Decide: ExpandDecider, otherData: REF ANY];
ExpandDecider: TYPE = PROC [cell: Cell, otherData: REF ANY] RETURNS [ExpandDecision];
ExpandDecision: TYPE = {Leaf, Inline, Nested};
This is how you get started. CreateTopCell is used to Instantiate the Root Subcircuit of a Circuit Design. That Subcircuit must have an empty Interface.
The ExpandDeciderClosure is the vehicle that communicates the user's decisions, for each Instance, about whether to use the Behavioral Description or the Structural one (and in what fashion). The DEFINITIONS module RoseHelp.Mesa provides two ways of making those decisions:
ask: ExpandDeciderClosure;
DecideFromFile: PROC [fileName: ROPE] RETURNS [ExpandDeciderClosure];
The first, ask, uses a button-pushing screen interface. When RoseHelpImpl.bcd is loaded and started, it creates a Viewer. The Viewer has slots for displaying the instanceName and className of the Instantiation under question. It has a slot for the decision. It starts out with a possible suggestion, which then may be edited. When a decision is being requested, a Button appears, which, when pushed, causes the decision currently being displayed to be used.
The second, DecideFromFile, reads the decisions from a file. The file should be a sentance of the language defined by the following grammar (with start symbol <cell>):
<cell> => "(" <instance name> [ <decision> <cell>* ] ")"
<decision> => "I" | "N" | "L"
<instance name> => a sequence of letters and numbers (starting with a letter), or something enclosed in double quotes.
If the <decision> for a <cell> is elided, it is taken to be "L" (Leaf -- use the Behavioral Description).
2. The Translator
The Translator aids in producing a CellClass. It takes a description that is more or less in terms of a Subcircuit Design, and produces a .Mesa file that includes a call on RegisterCellClass, with all the right stuff filled in.
2.1 Syntax
The input to the Translator is a file whose extension is "Rose". It should contain a sentance in the language defined by the following grammar:
<start> => <main statement> ( ";" <main statement> ) *
<main statement> => <library> | <imports> | <open> | <class> | <cedar>
<library> => "LIBRARY" <id list>
<imports> => "IMPORTS" <id list>
<open> => "OPEN" <id list>
<class> => <id> ":" "CELL" <interface> <class part>* "ENDCELL"
<cedar> => "CEDAR" <StatementSeries (from Mesa syntax)>
<interface> => "NULL" | "[" [ <item> ( "," <item> ) * ] "]"
<item> => <id list> <direction> [<signal type constructor>]
<direction> => "<" | ">" | "="
<signal type constructor> => <id>
 [ "[" [ (<binding list> | <arg list>) ] "]" ]
 [ "~" <rope literal> ]
<binding list> => <binding> ( "," <binding> ) *
<binding> => <id> ":" <literal>
<arg list> => <literal> ( "," <literal> ) *
<literal> => <rope literal> | <int literal>
<class part> => <init data> | <default init data> | <default init expr> |
 <state record> | <initial valued state> | <initializer> | <eval proc> |
 <test proc> | <expand>
<init data> => "InitData" <NamedFieldList (from Mesa syntax)>
<default init data> => "DefaultInitData" <ComponentList (from Mesa syntax)>
<default init expr> => "DefaultInitExpr" <expression (from Mesa syntax)> "|"
<state record> => "State" <NamedFieldList (from Mesa syntax)>
<initial valued state> => "InitState" <NamedFieldList (from Mesa syntax)>
<initializer> => "Initializer" <block>
<eval proc> => "Eval" <block>
<test proc> => "Test" <block>
<expand> => "Expand" <expand statement> (";" <expand statement>) *
<block> => <EnableClause (from Mesa)> <DeclarationSeries (from Mesa)>
 <StatementSeries (from Mesa)> <ExitsClause (from Mesa)>
<expand statement> => <node instantiation> | <cell instantiation> | <cedar>
<node instantiation> => <id list> ":" <signal type constructor>
<cell instantiation> => <id> ":" <id>
 "[" [ <connection> ( "," <connection> ) * ] "]"
 [ <init data constructor> ]
<connection> => <id> ":" <id>
<init data constructor> => "init" <expression (from Mesa)> "|"
<id list> => <id> ( "," <id> ) *
<id>s begin with a letter, and continue with letters and digits. Case is insignificant for keywords. <rope literal>s are enclosed in double quotes. <int literal>s consist of a string of digits. White space is insignificant, except that it it seperates tokens. Mesa-style comments are ignored, as well as text from Tioga nodes whose "Comment" property is TRUE.
Actually, the above grammar is a bit of a lie, in a couple of ways. First, the stuff from Mesa is treated a little oddly. It was decided not to try to actually parse Mesa. There are three ways of delimiting Mesa. In one, used by <default init expr> and <init data constructor>, a certain character (vertical bar) is used to mark the end of the Mesa source. That character can be included in the Mesa part by doubling it.
Another method for delimiting Mesa source uses Tioga's document structure. When one of the keywords that uses this style is encountered, the Mesa is taken to be the contents of all the children of the node containing the keyword. Also, the rest of that node (after the keyword) is ignored.
Finally, <signal type constructor> uses a very simple method: the Mesa is put in a <rope literal>.
The Translator actually parses this language by first using operator-precedance, then applying some further understanding to the resultant parse tree.
2.2 Semantics
The translator produces from a ".Rose" file a ".Mesa" file (and some others). The ".Rose" file can contain descriptions of many CellClasses, and auxiallary PROCEDURES, TYPES, and so on. The ".Mesa" file will include calls on RegisterCellClass for all of the Classes from the ".Rose" file. The ".Mesa" file will also include ExpandProcs, IOCreators, Initializers, EvalProcs, and Ports's, constructed from the description in the ".Rose" file. The ".Mesa" file will include declarations for the TYPES of the state RECORD, and the initData RECORD. Actually, not all of these things are relevant for all Classes, and the Translator will not produce irrelevancies.
The <library> clause indicates uses of other CellClasses. Any CellClass used by a ".Rose" file, and defined outside that file, must be listed in a <library> clause. When a <cell instantiation> is processed, type checking is done. The <library> clauses tell where to look to get the information about those Classes necessary to do the checking.
The <imports> and <open> are there to allow for tweaking the Mesa that is produced; they add to the corresponding clauses in the resultant ".Mesa" file. Names mentioned in an <imports> or <open> clause are automatically added to the DIRECTORY clause of the Mesa, if necessary. The Translator starts out IMPORTing and OPENing Rosemary and IntTypes.
All three, <library>, <imports>, and <open> are additive and idempotent.
A <cedar> as a <main statement> introduces Cedar code into the output. A <cedar> that occurs before a <class> must contain only declarations. A <cedar> that occurs after all <class>es can contain declarations followed by statements.
A <class> is a description of a CellClass. The <interface> is the Interface of the Subcircuit Design. The Direction is encoded as follows: "<" means In, ">" means Out, and "=" means Both.
<signal type constructor>s work as follows. There is a Mesa interface (RoseTranslateTypes) through which one can associate with an <id> a SignalTypeConstructor. A SignalTypeConstructor is a procedure, which, given a parse tree for the arguments in the <signal type constructor>, returns an "understanding" of a SignalType. This "understanding" knows things like how many bits to allocate in an IO RECORD, the Mesa TYPE to declare such a field to be, the Mesa to produce that will compile into code to actually produce the desired SignalType, and a few other details needed by the Translator. When a <signal type constructor> ends with a tilde and <rope literal>, this means overriding the understanding's decision about the Mesa TYPE to declare the field of the IO RECORD to be. The <rope literal> contains the Mesa TYPE to use.
Currently there are two SignalTypeConstructors that get registered. One goes by the <id> INT. It takes one parameter, an integer, which specifies a bit width. The parameter can be omitted; it defaults to 1. It produces an understanding of IntTypes.IntType[n], where n is the integer parameter.
The other, which goes by the <id> Mnemonic, takes a single argument: a ROPE. It produces an understanding of Mnemonics.Mnemonic[r], where r is the parameter.
The <class part>s can appear in any order, but each should appear at most once.
An <init data> gives the body of a RECORD TYPE constructor. This is used in constructing the TYPE the ExpandProc and Initializer will expect for initData (the IOCreator will ignore its initData). The TYPE constructed will be a REF to such a RECORD.
Both <default init data> and <default init expr> provide defaults for the initData that will be passed such a Cell. They should not both be present, and it is possible to have neither. The <default init data> gives the values for the fields of the RECORD. The <default init expr> is any old expression which yields the right kind of REF.
In a way like that of the <init data>, the <state record> provides for the construction of a state RECORD TYPE. <initial valued state> is just like <state record>, except in the following way. When constructing an Initializer, the Translator, if given <initial valued state>, will initialize the state RECORD at the time of allocation, with code like "NEW [StateRec ← []]" (an ordinary <state record> gets only "NEW [StateRec]"). In order for this to get past the compiler, the fields given to <initial valued state> must all be given default values (with " ← expr" at the end). At most one of <state record> and <initial valued state> should be given. It is possible to give neither; EvalProcs are not required to keep state.
An <initializer> gives, verbatim, code to be used for the Initializer. It is put inside a Mesa <block> that OPENs the newIO, the initData, and the state (all NARROWed to the appropriate TYPEs).
An <eval proc> gives, verbatim, code to be used for the eval EvalProc. The Translator takes care of producing the code to copy from newIO into oldIO. The given code is put inside a Mesa <block> that OPENs the newIO and the state (NARROWed to the appropriate TYPEs).
A <test proc> gives, verbatim, the code to be used for the test EvalProc. The given code is put inside a Mesa <block> that OPENs the newIO.
An <expand> is used to construct an ExpandProc from. The <expand statement>s are processed in the order given; each produces code in the ExpandProc. A <cedar> simply gives code to be copied verbatim.
A <node instantiation> produces a Mesa declaration that introduces a Node. This is done by declaring a Node, and initializing it to the result of a call on CreateNode.
A <cell instantiation> produces a Mesa statement that instantiates a CellClass. The first <id> is the name of the Instance; the second names the Class. The <connection>s give the association between Ports of the Class and Nodes: the first <id> names the Port, and the second names the Node. The Translator checks that the Node and the Port were both declared to be of equivalent SignalTypes.
The optional <init data constructor> on a <cell instantiation> gives a Mesa expression to be given to CreateCell as the initData parameter. If none is given, but the Class being Instantiated has a <default init data> or <default init expr>, it will be used.
2.3 Running the Translator
The translator registers two commands with the UserExec:
RoseTranslate <id>*
Does a translation for each <id>. The extension "Rose" is appended to the <id> to get the source file name; various things are appended to get the destination file names as well.
RoseUpdate <id>*
Endeavors to prepare a ".bcd" (and a few others) for each <id> that is "consistant" with the other stuff on the disk. It will do translations and compiles of the named files, and files they depend on, in order to achieve this.
Each translation produces: a ".Mesa" file, a ".RoseSymbols" file, a ".RoseDeps" file, and a ".RoseLoad" file. The ".Mesa" and ".RoseSymbols" have been discussed above. The ".RoseDeps" gives dependancies. It has two sections. The first duplicates the information from the "LIBRARY" clauses. The second lists all of the Mesa modules that a compilation of this module depends on. By recursively exploring these dependancies, and checking create dates of sources and outputs, it can be determined what translations and compilations need to be done.
The ".RoseLoad" file is used at simulate time, to cause the results of compilation to be loaded and started in the right order. Each ".RoseLoad" file first invokes those of the things it depends on, and then causes its own ".bcd" to be loaded and started, if it hasn't already.
2.4 Relation of the Translator to the absence of Translator
It is not necessary to use the Translator. Code can be produced by other means (including by hand) to implement CellClasses. Using the Translator, however, places some constraints on the Classes referred to from the ".Rose" source. Here is a summary of them:
Classes referred to in a ".Rose" source, but not defined there, must be made known to the Translator via a "LIBRARY" entry. For each <id> given there, there must be a file named "<id>.RoseSymbols". This file gives the information the Translator needs for those Classes. The format of the file should be:
( <id> <id> <int literal> <rope literal> <interface> "!!" ) *
The first <id> names a Class being described. The second is the name of the Mesa module that implements it. The <int literal> encodes a few random bits:
1: Is there any default for its initData ?
2: Does the Class have an Initializer ?
4: Does the Class have initData ?
The <rope literal> gives a default expression for the Class's initData. If there is none, the <rope literal> is NIL.
The <interface> is the same as in a ".Rose" source.
If a RoseUpdate is to be done, there must also be a file named "<id>.RoseDeps". Its format should be
<id> * [ ";" <id> * ]
Each <id> in the first list will be recursively looked at in the manner we are discussing. The second list (if present) is taken to be all of the Mesa modules in the DIRECTORY clause of "<id>.Mesa" (if it exists), that is, all of the Mesa modules that this one depends on. This list will be used to decide (by looking at create dates) when to compile "<id>.Mesa", if it exists.
Finally, the ".RoseLoad" produced will reference "<id>.RoseLoad". It should contain UserExec commands to cause to be loaded and started, if not already loaded and started, the implementations of the Classes found in "<id>.RoseSymbols".
For an example of something that did not use the Translator, see RoseClocks, in section 5.
3. The Simulation-Time User Interface
See the example in section 5. It would probably even be a good idea to bring up the example and poke at it.
3.1 Displays
On an Instantiated Circuit, you can bring up Displays. A Display shows Instantiated Subcircuits, i.e. Cells, and Nodes. Displays are manipulated via Control Panels and Browsers.
In a Display, a Cell is shown as its instance name, followed by a colon, followed by an outlined rectangle which includes the display of everything that is a descendant of that Cell and is being displayed. If that Cell is a Real Cell, when it is in its Schedule, its instance name is displayed in an unusual manner. If it is at the head of the Schedule, it is displayed in video reverse. If it is elsewhere in the Schedule, it is displayed on a light gray background.
A Node is shown as its name, followed by one or two special characters, followed by a textual representation of the bits last sent out on its Distribution List. If there is only one special character after the Node's name, its meaning is as follows:
":" The Node is internal to the immediately enclosing Cell.
"<" The Node is an input to the immediately enclosing Cell.
">" The Node is an output of the immediately enclosing Cell.
"=" The Node is both an input and an output.
If there are two special characters, the first will be a colon. The immediatly enclosing Cell has been Instantiated in the Nested fashion, and this Node is the internal version of one of the interface nodes. The second character indicates the direction.
Rosemary allows for a user to manually cause bits to be distrubuted from a Node. The characters in the Tioga Viewer to the right of the Node's name may be edited. When the signal is given, the new text may be parsed into bits and distributed. The signal can be given via a Control Panel, or by hitting return. For convenience, clicking the Node's name with the Left mouse button will select the text in pending delete mode.
3.2 Browsers
On any given Display, Browsers may be brought up. Browsers are used to control what is displayed. These browsers are built with a general Browser package. First a description of that package, and then a description of the Rosemary-dependant features of these Browsers.
3.2.1 The Browsers Package
Browsers operate on directed graphs with named edges. Not all of the nodes of the graph need to appear in a Browser at any given time; which nodes appear in the Browser is controllable. A Browser is "started" at some "root" node of the graph. At any given time, the Browser is displaying a path from the root node.
A Browser is layed out as follows. The Browser is divided vertically into a number of rectangular areas; one for each node on the current path. The area for the root is at the top, the next node is immediately below it, and so on. The rectangular area for a node shows the name of each edge leaving that node. The names of the edges on the current path are displayed video inversed; the others are displayed normally.
A certain mouse click on the name of an edge will force that edge to be in the current path. This may cause the path to be truncated to the node from which the edge leaves, and then extended to the node the edge goes to. A certain other mouse click will truncate the path to the node from which the edge leaves. Still other mouse clicks may be interpreted by the application.
3.2.2 Rosemary Browsers
The graph that Rosemary presents to a Browser is a tree; in particular, it is an elaboration of the instantiation tree of the circuit. The tree is as follows. From a Cell eminate at most four edges: "Components", "Interface Nodes", "Internal Nodes", and "cell's state" (not all will apply to all Cells). The "Components" node has a child for each of the components of that Cell. The "Interface Nodes" node has a child for each of the interface nodes of that Cell. The "Internal Nodes" node has a child for each of the internal nodes of that Cell. The "cell's state" node has no children. The graph nodes corresponding to Nodes also have no children.
The way to force an edge to be in the path is by clicking with the Left mouse button. The way to truncate before an edge is with Shift Left.
Clicking the Middle or Right mouse buttons without any Shift key causes things to be displayed. All of the descendants of the tree node clicked, including itself, are enumerated. Those that are for Cells or Nodes cause those things to appear in the Display, if the Middle key was clicked. The Right mouse button is for making Record Viewers on the state RECORDS of the Cells appear.
Clicking the Middle or Right mouse buttons with either Shift key held down removes things from the display. Again, the descendants are enumerated. Everything found in the enumeration is made to dissappear, if the Middle buttons was used. The Right button only affects the state RECORDS.
Here is the procedure that creates Rosemary Browsers:
RoseDisplayBrowsing.BrowseDisplay: PROC [display: Display, info: ViewerClasses.ViewerRec ← [], paint: BOOLEANTRUE] RETURNS [v: ViewerClasses.Viewer]
The info parameter is what the Viewers package needs to create a Viewer. Actually, it is only necessary to set a few of the many fields in the ViewerRec. Setting the name is often nice. And you probably want it not to start out iconic.
3.3 Control Panels
On any given Instance of a Circuit Design, Control Panels may be brought up. Actually, Control Panels and Displays come together. Here is the procedure that creates them:
RoseDisplayOps.NewDisplay: PROC [cell: Cell, info: ViewerClasses.ViewerRec ← [], paint: BOOLEANTRUE] RETURNS [display: Display]
The Cell given to NewDisplay must be the Root. Nothing is returned for the Control Panel, as there is nothing to do with it (it is on the screen). The Display is returned so that it may be given to BrowseDisplay.
Control panels deal with things like Scheduling and running the simulator, distributing bits manually through Nodes, setting conditional breakpoints, and so on. Control Panels are RecordViewers, constructed by ViewRec. ViewRec.doc should be broughtover by Rosemary.df, and contains a description of the user interface presented by RecordViewers. What follows is a description of the meanings of the fields and procedures in a Control Panel.
stopBefore:, stopAfter: BOOLEAN
These are for testing. When a Cell's Test is running, these can cause a pause before and/or after the evaluations of the Cell, so that you can see the stimuli being applied and the results being returned.
status: {Normal, Interrupted}
There are a number of ways that simulation may be temporarily suspended; hitting breakpoints, and pausing before or after test evaluations, are some examples. This variable indicates whether a simulation is suspended. When a simulation is suspended, you may not initiate more simulation (i.e. Run). You must first Proceed or Abort the suspended simulation.
incrementalDisplay: BOOLEAN
The Display can be made to track the state of the simulation with either of two degrees of faithfulness. In the most faithful, whenever something in the simulated circuit changes, its displays (if any) are updated. Alternatively, you can make the display update only when simulation activity subsides (suspends or terminates). Setting incrementalDisplay to TRUE selects the more faithful of these options.
Pack: PROCEDURE
Updates the layout of the Display associated with this Control Panel to take into account the latest changes to what is to be displayed, and the current width of the Viewer the Display is in.
NoticeEdits: PROCEDURE RETURNS [AOK: BOOLEAN]
Invoking this procedure is a way to signal that edited text associated with Nodes in the Display is to be parsed into bits and distributed. Some of the parses may fail. For the Nodes where this happens, the name of the Node will be displayed in video reverse, and there will be no distribution. The flag AOK indicates whether all of the parses succeeded.
NoticEditsAndRunIfOK: PROCEDURE RETURNS [AOK: BOOLEAN]
Does NoticeEdits, and, if AOK, proceeds to Run.
Run: PROCEDURE
Invokes the main loop of the simulator on the Simulation Structure in the Root (what if the Root is also a (and, necessarily, the) leaf? dunno!).
SingleStep: PROCEDURE
Goes just once around the main loop of the simulator: take the first Module off the Schedule, and run its Evaluation PROCEDURE. If the Schedule is empty, this PROCEDURE does nothing.
Test: PROCEDURE [cellPathName: ROPE]
Calls the Test of the named Cell.
Interrupt: PROCEDURE
Suspends the simulation.
Proceed: PROCEDURE
Resumes the simulation. Proceed and Abort will only work if the simulation was initiated from the same Control Panel.
Abort: PROCEDURE
Terminates the simulation.
ClearStack: PROCEDURE
Empties the conditionStack. The conditionStack is used in constructing Conditions.
ClearCondition: PROCEDURE
Sets condition to a trivially false Condition.
Or: PROCEDURE
Pops the conditionStack, and ORs that into the condition.
PostCondition: PROCEDURE [name: SELECTED ROPE]
This is one of the two ways of posting a Condition. The Condition posted is the one with the given name. The name is taken from the current Tioga Selection. When a Condition is posted in this manner, the letter "p" appears between the parentheses. Posting a Condition in this manner means that at the end of every clock cycle, this Condition will be evaluated. If it comes up TRUE, a SIGNAL will be raised, and caught by BugBane. The user can either Proceed or Abort.
RemoveCondition: PROCEDURE [name: SELECTED ROPE]
This un-posts the named Condition.
PostIncremental: PROCEDURE [name: SELECTD ROPE]
This is the other way of posting a Condition. Such posting is indicated by the letter "i". In this case, whenever one of the Nodes being Tested in this Condition gets a new Value, the Condition is re-evaluated. When it changes from FALSE to TRUE, the SIGNAL is raised.
RemoveIncremental: PROCEDURE [name: SELECTED ROPE]
This is the other way of un-posting.
AddNamedCondition: PROCEDURE [name: ROPE]
Adds the condition, with the given name, to the list of named conditions.
DeleteNamedCondition: PROCEDURE [name: ROPE]
Removes from the list of named conditions the one with the given name.
Save: PROCEDURE [fileName: ROPE]
Saves the state of the circuit in the named file. The state of the circuit is construed to be the bits in all the newIO (and oldIO, actually) RECORDs, and also the contents of the state RECORDs used by Behavioral Descriptions.
Restore: PROCEDURE [fileName: ROPE]
Restore the state of the circuit from the named file. This is even meant to be tolerant of small differences between the circuit saved from and the circuit restored to. The changes currently tolerated are additions of things (Nodes, Cells, fields in the state RECORD).
mode: {Value, Test}
The Display may be used for composing Tests, rather than showing the Value of a Node (i.e., the bits last distributed through it). This switch controls the use of the Display. When in the Test position, the Tioga Viewers for the Nodes in the Display hold textual encodings of Tests, according to the rules of the SignalTypes of the Nodes. The NoticeEdits PROCEDURE is still used to invoke the parsers. Actually, with each appearance of a Node in the Display there is always associated at most one Test, whether this switch causes it to be displayed or not (an absence of Test is displayed as "??", when mode = Test).
conditions: READONLY SymbolTable
Rosemary breakpoints are conditional. This field holds a list of named Conditions. A Condition is a Boolean combination of Tests (each SignalType has its own set of Tests that it will perform, and a way of converting to and from a textual representation of those tests). Each entry in this list is displayed as a name, followed by a pair of parentheses, followed by a textual representation of the Condition. There are two different ways of posting a Conditional breakpoint, and the presence or absence of certain characters between the parentheses indicates the ways in which this Condition is currently posted. This list is displayed in a Tioga Viewer all its own, and may be scrolled if it gets too long for the area allocated.
conditionStack: READONLY STACK OF Condition
This is also used for composing new Conditions. Clicking the Right mouse button on a Node's name in the Display begins a new term in the condition. First, the old term is ORed into the top of the conditionStack (if the conditionStack was empty, a trivially FALSE term is introduced for this purpose). Then the condition is set to a single factor. That factor is the same one that would have been used for the Middle mouse button (i.e. the (maybe negated) Test of the Node).
condition: READONLY Condition
This field holds a textual representation of a Condition. This field is used in composing new Conditions. When, in the Display, the Middle mouse button is clicked on a Node's name, a new factor is ANDed into this Condition. That factor is the Test of that Node appearance (note that some Nodes can appear more than once in a Display). If either shift key was held down, that factor is the negation of the Test.
3.4 Others
The Rosemary simulate-time user interface is Client-expandable. One case of this expansion has already been seen: the Viewer put up by RoseHelpImpl to ask for ExpandDecisions.
A more interesting place that expansion can occur is through the actions of CellClasses. A CellClass's Initializer may create a Viewer in which to interact with a user.
An example of this is the CellClass "ClockGen". The CellClass "ClockGen" is used for providing two phase clocking. It puts up a RecordViewer with the following fields:
sofar: READONLY CARDINAL
When Cycling, this indicates how many cycles have been completed.
state: READONLY [0..5]
This is used by implementation of clock generators to keep track of what to do next. States 0 - 3 are used for 4-step operation, and 4-5 for 2-step.
status: READONLY {Normal, Interrupted}
As in Control Panels.
Cycle: PROCEDURE [cycles: CARDINAL]
This runs the clock generator through the given number of cycles. Each cycle consists of either two or four steps (ph1:on&phi2:off then phi1:off&phi2:on or phi1:on&phi2:off then phi1:off&phi2:off then phi1:off&phi2:on then phi1:off&phi2:off). In each step, the two clocks are set to the appropriate Values, and then the circuit is Run.
Step: PROCEDURE
Does one step of clocking.
Interrupt, Proceed, Abort: PROCEDURE
As in Control Panels.
4.
There is no section 4.
5. Example
Here is an example, using a 4 bit wide, 4 stage long shift register.
Here is the log from the UserExec, showing a Bringover of everything, use of the Translator, and use of the Simulator.
&2 bringover /a [Indigo]<Rosemary>Release>Rosemary
Loaded and started: BringOver.Bcd
BringOver, Version Of 20-Jul-83 13:09:23 PDT.
[Indigo]<Rosemary>Release>Rosemary.DF!38 (18-Aug-83 21:19:30 PDT)
...
End of BringOver of Rosemary.DF
many files retrieved.
Total elapsed time for BringOver 00:10:13.
Now we will use the Translator. First, get it loaded and started:
&3 @RoseTranslator
>RunNew RoseTranslator
Loaded and started: RunNew.BCD
>RunNew IntTypesTranslation
>RunNew MnemonicsTranslation
We delete "ExamplePrimitives.RoseSymbols" (it happened to be lying around on the disk) so that the RoseUpdate algorithm will decide to translate everything:
&4 dele ExamplePrimitives.RoseSymbols
Deleted: ExamplePrimitives.RoseSymbols
Now we invoke the Translator:
&5 RoseUpdate Shifting
Loading Compiler.bcd...
Compiling: ExamplePrimitives/-g . . . . . . no errors
End of compilationCompiling: SRHC/-g . . . . . . no errors
End of compilationCompiling: Shifting/-g . . . . . . no errors
End of compilation
Following is are descriptions of some of the files involved; the action resumes a dozen or so pages ahead with &9 (&6, &7, and &8 seem to have been the compilations).
The Translator created a Viewer showing a log, whose contents became:
Translating ExamplePrimitives.Rose into ExamplePrimitives.Mesa, log on ExamplePrimitives.Log
0 errors, 0 warnings; source tokens: 45, time: 3.19168
Done.
Translating SRHC.Rose into SRHC.Mesa, log on SRHC.Log
Reading symbols from ExamplePrimitives.RoseSymbols...
Done reading symbols
0 errors, 0 warnings; source tokens: 71, time: 6.116832
Done.
Translating Shifting.Rose into Shifting.Mesa, log on Shifting.Log
Reading symbols from RoseClocks.RoseSymbols...
Done reading symbols
Reading symbols from SRHC.RoseSymbols...
Done reading symbols
0 errors, 0 warnings; source tokens: 227, time: 8.04496
Done.
See figures E, S, W, N, and R for the Circuit Design being simulated.
Here are the contents of ExamplePrimitives.Rose:
PassBlock: CELL [input < INT[4], gate < INT, output> INT[4]]
Eval
IF gate THEN output ← input;
ENDCELL;
InvertBlock: CELL [input< INT[4], output> INT[4]]
Eval
output ← IntNot[4, input];
ENDCELL
IntNot is a PROCEDURE from IntTypes, a DEFINITIONS that gets OPENED in every .Mesa file produced by the Translator. Here are the contents of IntTypes.Mesa:
DIRECTORY
Rosemary;
IntTypes: CEDAR DEFINITIONS =
BEGIN
SignalType: TYPE = Rosemary.SignalType;
Bit: SignalType; -- same as IntType[1]
IntType: PROCEDURE [bitWidth: CARDINAL] RETURNS [SignalType];
IntNot: PROCEDURE [bitWidth: [1..32], bits: LONG CARDINAL] RETURNS [LONG CARDINAL];
END.
IntTypes.IntType[n] returns a SignalType for an n-bit wide integer. IntNot[n, x] returns a y whose n least significant bits are the inverse of x's, and the rest of whose bits are 0.
Here are the contents of SRHC.Rose:
Library ExamplePrimitives;
SRHC: CELL [input<INT[4]~"[0..16)", clock<, output> INT[4]]
InitData
init: [0..15] ← 7
DefaultInitExpr NEW [SRHC.SRHCInitRec ← [13]] |
State
latched: [0..15] ← 0
Initializer
latched ← init
Expand
temp: INT[4];
Pass: PassBlock[input: input, gate: clock, output: temp];
CEDAR
--any old Cedar code may appear here
;
Inv: InvertBlock[input: temp, output: output]
Eval
IF clock THEN latched ← input;
output ← IntNot[4, latched];
ENDCELL
The Translator produced 4 files from SRHC.Rose: SRHC.Mesa, SRHC.RoseSymbols, SRHC.RoseDeps, and SRHC.RoseLoad.
Here is SRHC.RoseSymbols:
SRHC SRHC 7 "NEW [SRHC.SRHCInitRec ← [13]] " [input<INT[4], clock<, output>INT[4]] !!
Here is SRHC.RoseDeps:
ExamplePrimitives ; ExamplePrimitives IntTypes Rosemary
Here is SRHC.RoseLoad:
@ExamplePrimitives.roseLoad
runnew SRHC
Here is SRHC.Mesa, which is the Mesa code to implement the Shift Register Half Cell Class:
--SRHC.Mesa
--created by RoseTranslate from SRHC.Rose of 19-Mar-83 12:19:02 PST for Spreitzer.pa at 19-Mar-83 12:40:18 PST
DIRECTORY
Rosemary, IntTypes, ExamplePrimitives;
SRHC: CEDAR PROGRAM
IMPORTS Rosemary, IntTypes, ExamplePrimitives =
BEGIN OPEN
Rosemary, IntTypes;
--Signal Type decls
RegisterCells: PROC =
BEGIN
CreateSRHCPorts[];
RegisterCellClass[className: "SRHC",
expandProc: SRHCExpand,
ioCreator: CreateSRHCIO,initializer: InitializeSRHC,
evalProc: SRHCEval,testProc: NIL,
ioTemplate: NEW [SRHCIORec],
ports: SRHCPorts];
END;
CreatePorts: PROC =
BEGIN
SRHCPorts[0] ← [0, 1, "input", IntType[4], TRUE, FALSE];
SRHCPorts[1] ← [1, 1, "clock", IntType[1], TRUE, FALSE];
SRHCPorts[2] ← [2, 1, "output", IntType[4], FALSE, TRUE];
END;
SRHCIORef: TYPE = REF SRHCIORec;
SRHCIORec: TYPE = MACHINE DEPENDENT RECORD [
fill0(0:0..11): [0..4095],
input(0:12..15): [0..16),
fill1(1:0..14): [0..32767],
clock(1:15..15): BOOLEAN,
fill2(2:0..11): [0..4095],
output(2:12..15): [0..15]];
SRHCInitRef: TYPE = REF SRHCInitRec;
SRHCInitRec: PUBLIC TYPE = RECORD [
init: [0..15] ← 7
];
SRHCStateRef: TYPE = REF SRHCStateRec;
SRHCStateRec: TYPE = RECORD [
latched: [0..15] ← 0
];
SRHCExpand: ExpandProc = {
initRef: SRHCInitRef ← NARROW[initData];
BEGIN OPEN initRef;
temp: Node ← CreateNode[within: thisCell, name: "temp", type: IntType[4]];
[] ← CreateCell[within: thisCell, instanceName: "Pass", className: "PassBlock", interfaceNodes: "input:input, gate:clock, output:temp"];
--explicitly requested CEDAR:
--any old Cedar code may appear here
[] ← CreateCell[within: thisCell, instanceName: "Inv", className: "InvertBlock", interfaceNodes: "input:temp, output:output"];
END;
};
CreateSRHCIO: IOCreator = {
cell.realCellStuff.newIO ← NEW [SRHCIORec];
cell.realCellStuff.oldIO ← NEW [SRHCIORec];
};
InitializeSRHC: Initializer = {
IF leafily THEN
BEGIN
ioRec: SRHCIORef ← NARROW[cell.realCellStuff.newIO];
narrowedInitData: SRHCInitRef ← NARROW[initData];
state: SRHCStateRef ← NEW [SRHCStateRec];
cell.realCellStuff.state ← state;
BEGIN OPEN ioRec, narrowedInitData, state;
latched ← init
END;
END;
};
SRHCEval: EvalProc =
BEGIN
newIO: SRHCIORef ← NARROW[cell.realCellStuff.newIO];
oldIO: SRHCIORef ← NARROW[cell.realCellStuff.oldIO];
state: SRHCStateRef ← NARROW[cell.realCellStuff.state];
oldIO^ ← newIO^;
BEGIN OPEN newIO, state;
IF clock THEN latched ← input;
output ← IntNot[4, latched];
END;
END;
SRHCPorts: Ports ← NEW [PortsRep[3]];
RegisterCells[];
END.
Here are the contents of Shifting.Rose:
Imports IO, Mnemonics;
Open Mnemonics;
Library RoseClocks, SRHC;
SRWC: CELL [phi1, phi2<, input<INT[4], output>INT[4]]
Expand
middle: INT[4];
First: SRHC[input:input, clock:phi1, output:middle] init NEW [SRHC.SRHCInitRec ← [3]]|;
second: SRHC[input:middle, clock:phi2--, output: output--]
ENDCELL;
NBitSR: CELL [phi1, phi2<, input<INT[4], output>INT[4]]
InitData
n: CARDINAL
Expand
CEDAR
prev, next: ROPE;
next ← "input";
FOR i: CARDINAL IN [0..n) DO
prev ← next;
IF n # i+1 THEN
BEGIN
next ← IO.PutFR["node%g", IO.card[i+1]];
[] ← CreateNode[within: thisCell, name: next, type: IntType[4]];
END
ELSE next ← "output";
[] ← CreateCell[within: thisCell, instanceName: IO.PutFR["SRWC%g", IO.card[i]], className: "SRWC", interfaceNodes: IO.PutFR["input: %g, phi2: phi2, output: %g", IO.rope[prev], IO.rope[next]]];
ENDLOOP;
Test
phi1 ← TRUE;
phi2 ← TRUE;
FOR i: [0 .. 16) IN [0 .. 16) DO
input ← i;
Eval[cell];
IF output # i THEN SIGNAL Stop[IO.PutFR["Got %g from %g", IO.card[output], IO.card[input]]];
ENDLOOP;
ENDCELL;
Fooey: CELL [] ENDCELL;
CEDAR
InitFor: PROC [n: CARDINAL] RETURNS [NBitSRInitRef] =
{RETURN [NEW [NBitSRInitRec ← [n]]]};
;
Counter: CELL [phi1, phi2<, count>INT[4], report=Mnemonic["ShiftCounterOps"]]
State
next: [0..16) ← 5
Eval
IF phi1 THEN next ← (count + 1) MOD 16;
IF phi2 THEN count ← next;
report ← reports[phi1][phi2];
ENDCELL;
CEDAR
reports: ARRAY BOOLEAN OF ARRAY BOOLEAN OF ShiftCounterOps ←
[[BothOff, Storing], [Looking, BothOn]];
;
TopNBitSR: CELL NULL
Expand
front, back: INT[4];
PhaseA, clk2: INT;
sink: Mnemonic["ShiftCounterOps"];
clkGen: ClockGen[PhaseA: PhaseA, PhaseB: clk2];
cntr: Counter[phi1: PhaseA, phi2: clk2, count: front, report: sink];
shifter: NBitSR[input: front, output: back, phi1: PhaseA, phi2: clk2] init initData|
ENDCELL
And for those of you really into blood and guts, here are the contents of Shifting.Mesa:
--Shifting.Mesa
--created by RoseTranslate from Shifting.Rose of 26-Jul-83 10:14:23 PDT for Spreitzer.pa at 18-Aug-83 21:23:36 PDT
DIRECTORY
Rosemary, IntTypes, IO, Mnemonics, SRHC, RoseClocks;
Shifting: CEDAR PROGRAM
IMPORTS Rosemary, IntTypes, IO, Mnemonics, SRHC, RoseClocks =
BEGIN OPEN
Rosemary, IntTypes, Mnemonics;
--Signal Type decls
ShiftCounterOps: TYPE = {BothOff, BothOn, Looking, Storing};
RegisterCells: PROC =
BEGIN
CreateSRWCPorts[];
RegisterCellClass[className: "SRWC",
expandProc: SRWCExpand,
ioCreator: CreateSRWCIO,initializer: NIL,
evalProc: NIL,testProc: NIL,
ioTemplate: NEW [SRWCIORec],
ports: SRWCPorts];
CreateNBitSRPorts[];
RegisterCellClass[className: "NBitSR",
expandProc: NBitSRExpand,
ioCreator: CreateNBitSRIO,initializer: NIL,
evalProc: NIL,testProc: NBitSRTest,
ioTemplate: NEW [NBitSRIORec],
ports: NBitSRPorts];
RegisterCellClass[className: "Fooey",
expandProc: NIL,
ioCreator: NIL,initializer: NIL,
evalProc: NIL,testProc: NIL,
ioTemplate: NIL,
ports: FooeyPorts];
CreateCounterPorts[];
RegisterCellClass[className: "Counter",
expandProc: NIL,
ioCreator: CreateCounterIO,initializer: InitializeCounter,
evalProc: CounterEval,testProc: NIL,
ioTemplate: NEW [CounterIORec],
ports: CounterPorts];
RegisterCellClass[className: "TopNBitSR",
expandProc: TopNBitSRExpand,
ioCreator: NIL,initializer: NIL,
evalProc: NIL,testProc: NIL,
ioTemplate: NIL,
ports: TopNBitSRPorts];
END;
CreateSRWCPorts: PROC =
BEGIN
SRWCPorts[0] ← [0, 1, "phi1", IntType[1], TRUE, FALSE];
SRWCPorts[1] ← [1, 1, "phi2", IntType[1], TRUE, FALSE];
SRWCPorts[2] ← [2, 1, "input", IntType[4], TRUE, FALSE];
SRWCPorts[3] ← [3, 1, "output", IntType[4], FALSE, TRUE];
END;
SRWCIORef: TYPE = REF SRWCIORec;
SRWCIORec: TYPE = MACHINE DEPENDENT RECORD [
fill0(0:0..14): [0..32767],
phi1(0:15..15): BOOLEAN,
fill1(1:0..14): [0..32767],
phi2(1:15..15): BOOLEAN,
fill2(2:0..11): [0..4095],
input(2:12..15): [0..15],
fill3(3:0..11): [0..4095],
output(3:12..15): [0..15]];
SRWCExpand: ExpandProc = {
middle: Node ← CreateNode[within: thisCell, name: "middle", type: IntType[4]];
[] ← CreateCell[within: thisCell, instanceName: "First", className: "SRHC", interfaceNodes: "input:input, clock:phi1, output:middle", initData: NEW [SRHC.SRHCInitRec ← [3]]];
[] ← CreateCell[within: thisCell, instanceName: "second", className: "SRHC", interfaceNodes: "input:middle, clock:phi2", initData: NEW [SRHC.SRHCInitRec ← [13]] ];
};
CreateSRWCIO: IOCreator = {
cell.realCellStuff.newIO ← NEW [SRWCIORec];
cell.realCellStuff.oldIO ← NEW [SRWCIORec];
};
SRWCPorts: Ports ← NEW [PortsRep[4]];
CreateNBitSRPorts: PROC =
BEGIN
NBitSRPorts[0] ← [0, 1, "phi1", IntType[1], TRUE, FALSE];
NBitSRPorts[1] ← [1, 1, "phi2", IntType[1], TRUE, FALSE];
NBitSRPorts[2] ← [2, 1, "input", IntType[4], TRUE, FALSE];
NBitSRPorts[3] ← [3, 1, "output", IntType[4], FALSE, TRUE];
END;
NBitSRIORef: TYPE = REF NBitSRIORec;
NBitSRIORec: TYPE = MACHINE DEPENDENT RECORD [
fill0(0:0..14): [0..32767],
phi1(0:15..15): BOOLEAN,
fill1(1:0..14): [0..32767],
phi2(1:15..15): BOOLEAN,
fill2(2:0..11): [0..4095],
input(2:12..15): [0..15],
fill3(3:0..11): [0..4095],
output(3:12..15): [0..15]];
NBitSRInitRef: TYPE = REF NBitSRInitRec;
NBitSRInitRec: PUBLIC TYPE = RECORD [
n: CARDINAL
];
NBitSRExpand: ExpandProc = {
initRef: NBitSRInitRef ← NARROW[initData];
BEGIN OPEN initRef;
--explicitly requested CEDAR:
prev, next: ROPE;
next ← "input";
FOR i: CARDINAL IN [0..n) DO
prev ← next;
IF n # i+1 THEN
BEGIN
next ← IO.PutFR["node%g", IO.card[i+1]];
[] ← CreateNode[within: thisCell, name: next, type: IntType[4]];
END
ELSE next ← "output";
[] ← CreateCell[within: thisCell, instanceName: IO.PutFR["SRWC%g", IO.card[i]], className: "SRWC", interfaceNodes: IO.PutFR["input: %g, phi2: phi2, output: %g", IO.rope[prev], IO.rope[next]]];
ENDLOOP;
END;
};
CreateNBitSRIO: IOCreator = {
cell.realCellStuff.newIO ← NEW [NBitSRIORec];
cell.realCellStuff.oldIO ← NEW [NBitSRIORec];
};
NBitSRTest: EvalProc =
BEGIN
ioRec: NBitSRIORef ← NARROW[cell.realCellStuff.newIO];
BEGIN OPEN ioRec;
phi1 ← TRUE;
phi2 ← TRUE;
FOR i: [0 .. 16) IN [0 .. 16) DO
input ← i;
Eval[cell];
IF output # i THEN SIGNAL Stop[IO.PutFR["Got %g from %g", IO.card[output], IO.card[input]]];
ENDLOOP;
END;
END;
NBitSRPorts: Ports ← NEW [PortsRep[4]];
FooeyPorts: Ports ← NEW [PortsRep[0]];
--explicitly requested CEDAR:
InitFor: PROC [n: CARDINAL] RETURNS [NBitSRInitRef] =
{RETURN [NEW [NBitSRInitRec ← [n]]]};
CreateCounterPorts: PROC =
BEGIN
CounterPorts[0] ← [0, 1, "phi1", IntType[1], TRUE, FALSE];
CounterPorts[1] ← [1, 1, "phi2", IntType[1], TRUE, FALSE];
CounterPorts[2] ← [2, 1, "count", IntType[4], FALSE, TRUE];
CounterPorts[3] ← [3, 1, "report", Mnemonic["ShiftCounterOps"], TRUE, TRUE];
END;
CounterIORef: TYPE = REF CounterIORec;
CounterIORec: TYPE = MACHINE DEPENDENT RECORD [
fill0(0:0..14): [0..32767],
phi1(0:15..15): BOOLEAN,
fill1(1:0..14): [0..32767],
phi2(1:15..15): BOOLEAN,
fill2(2:0..11): [0..4095],
count(2:12..15): [0..15],
fill3(3:0..13): [0..16383],
report(3:14..15): ShiftCounterOps];
CounterStateRef: TYPE = REF CounterStateRec;
CounterStateRec: TYPE = RECORD [
next: [0..16) ← 5
];
CreateCounterIO: IOCreator = {
cell.realCellStuff.newIO ← NEW [CounterIORec];
cell.realCellStuff.oldIO ← NEW [CounterIORec];
};
InitializeCounter: Initializer = {
IF leafily THEN
BEGIN
state: CounterStateRef ← NEW [CounterStateRec];
cell.realCellStuff.state ← state;
END;
};
CounterEval: EvalProc =
BEGIN
newIO: CounterIORef ← NARROW[cell.realCellStuff.newIO];
oldIO: CounterIORef ← NARROW[cell.realCellStuff.oldIO];
state: CounterStateRef ← NARROW[cell.realCellStuff.state];
oldIO^ ← newIO^;
BEGIN OPEN newIO, state;
IF phi1 THEN next ← (count + 1) MOD 16;
IF phi2 THEN count ← next;
report ← reports[phi1][phi2];
END;
END;
CounterPorts: Ports ← NEW [PortsRep[4]];
--explicitly requested CEDAR:
reports: ARRAY BOOLEAN OF ARRAY BOOLEAN OF ShiftCounterOps ←
[[BothOff, Storing], [Looking, BothOn]];
TopNBitSRExpand: ExpandProc = {
front: Node ← CreateNode[within: thisCell, name: "front", type: IntType[4]];
back: Node ← CreateNode[within: thisCell, name: "back", type: IntType[4]];
PhaseA: Node ← CreateNode[within: thisCell, name: "PhaseA", type: IntType[1]];
clk2: Node ← CreateNode[within: thisCell, name: "clk2", type: IntType[1]];
sink: Node ← CreateNode[within: thisCell, name: "sink", type: Mnemonic["ShiftCounterOps"]];
[] ← CreateCell[within: thisCell, instanceName: "clkGen", className: "ClockGen", interfaceNodes: "PhaseA:PhaseA, PhaseB:clk2", initData: RoseClocks.Init[]];
[] ← CreateCell[within: thisCell, instanceName: "cntr", className: "Counter", interfaceNodes: "phi1:PhaseA, phi2:clk2, count:front, report:sink"];
[] ← CreateCell[within: thisCell, instanceName: "shifter", className: "NBitSR", interfaceNodes: "input:front, output:back, phi1:PhaseA, phi2:clk2", initData: initData];
};
TopNBitSRPorts: Ports ← NEW [PortsRep[0]];
RegisterCells[];
END.
Shifting LIBRARY'd RoseClocks, but RoseClocks was not produced by the Translator. There is a "RoseClocks.Mesa" however; it is a DEFINTIONS file that Shifting made use of:
RoseClocks.Mesa
Last Edited by: Spreitzer, March 16, 1983 6:58 pm
Implements class: ClockGen
ClockGen posts event $EndOfClockCycle on the root.
DIRECTORY
Rosemary;
RoseClocks: CEDAR DEFINITIONS =
BEGIN OPEN Rosemary;
ClockInitData: TYPE = REF ClockInitDataRec;
ClockInitDataRec: TYPE;
Init: PROC [sense: Sense ← ActiveHigh, style: Style ← TwoStep] RETURNS [id: ClockInitData];
Sense: TYPE = {ActiveHigh, ActiveLow};
Style: TYPE = {TwoStep, FourStep};
Cycle: PROC [cell: Rosemary.Cell, cycles: CARDINAL];
Step: PROC [cell: Rosemary.Cell];
END.
For the benefit of the Translator, "RoseClocks.RoseSymbols" was produced by hand:
RoseClocks.RoseSymbols
Last Edited by: Spreitzer, March 16, 1983 7:03 pm
ClockGen RoseClocks 7 "RoseClocks.Init[]" [PhaseA, PhaseB>INT] !!
The file "RoseClocks.RoseDeps" was also produced by hand; it contains nothing, so that the Translator doesn't worry itself about the care and feeding of RoseClocks.
Finally, the file "RoseClocks.RoseLoad" was again hand coded; it contains:
RunNew RoseClocksImpl
Now we use the simulator. First, get it loaded and started:
&9 @RoseSimulate
>RunNew ViewRecImpl
>RunNew RoseSimulate
>RunNew IntTypesImpl
>RunNew MnemonicsImpl
>RunNew AddREAL
>RunNew Procedures
Now run the implementations of the various CellClasses used:
&10 @Shifting.roseLoad
>@RoseClocks.roseLoad
>runnew RoseClocksImpl
>@SRHC.roseLoad
>@ExamplePrimitives.roseLoad
>runnew ExamplePrimitives
>runnew SRHC
>runnew Shifting
Next, instantiate the circuit:
&11 ← &cell ← Rosemary.CreateTopCell["shi4top", "TopNBitSR", Shifting.InitFor[4], RoseHelp.DecideFromFile["shi4top.altexpand"]]
^[name: "shi4top", class: 5167402B^, nextInstance: NIL, parent: NIL, leftChild: 5173650B^, rightSibling: NIL, firstInternalNode: 10740174B^, internalNodes: 10472524B^, components: 10472362B^, interfaceNodes: 5154170B^, other: 5154116B^, type: Real, expansion: Nested, realCellStuff: 10740044B^]
Finally, bring up a Display and Control Panel on that circuit, then a Browser on the Display:
&12 ← &disp ← RoseDisplayOps.NewDisplay[cell:&cell, info: [iconic: FALSE, name: "shi4top"]]
^[rootCell: 5173744B^, rootDisplay: 5256310B^, rv: 5244360B^, ctlPanel: 5271676B^, conditionHandle: 5270574B^, conditionsHandle: 5270700B^, notice: [timeout: 175B (125), 0], stopResponse: Abort, parms: 5311760B^]
&13 ← &bv ← RoseDisplayBrowsing.BrowseDisplay[display:&disp, info: [iconic: FALSE, name: "shi4top.browser"]]
{Viewer - class: MJSContainer, name: shi4top.browser}
At this point, the Browser (created in &13) was used to display some Cells and Nodes in the Display (created in &12), and a snapshot of the screen was taken. It can be found in [Indigo]<Rosemary>Screen.press, and can not be printed on Dovers. Use a full PRESS printer (Stinger, for instance) (SORRY -- that file is out of date).