Ports.mesa
Barth, September 25, 1987 12:50:44 pm PDT
Gasbarro, January 23, 1986 11:32:11 am PST
Bertrand Serlet, January 27, 1986 4:01:32 pm PST
Louis Monier August 26, 1987 5:43:03 pm PDT
Jean-Marc Frailong December 24, 1987 6:19:11 pm PST
DIRECTORY BitOps, Core, CoreCreate, Rope;
Ports: CEDAR DEFINITIONS = BEGIN
Theory
A port is a DAG which is a subgraph of a Core.Wire DAG. A port requires that the leaves of the port DAG form a disjoint cover of the leaves of the Core.Wire DAG. This eliminates aliases of values.
A port is used for representing an interface to a Core.wire. A port defines an interface to a wire rather than the wire itself. Thus a port represents a current strength as well as a voltage level.
A voltage level in a port can be represented as a boolean value or as a member of the set L, H, or X. A leaf port can represent aggregates of either of these value sets. A current strength may be represented as an aggregate value or as a strength per voltage level.
Types
PortList: TYPE = LIST OF Port;
Port: TYPE = REF PortRec;
The comment definition of a port record captures the semantics. However it introduces a number of runtime checks and excess verbiage in the source. The uncommented definition is used to eliminate them. Unfortunately this reduces the amount of compile time checking which can be performed.
PortRec: TYPE = RECORD [
port: SELECT levelType: LevelType FROM
l => [d: Drive ← none, l: Level ← L],
b => [d: Drive ← none, b: BOOLFALSE],
ls => [ls: LevelSequence ← NIL, dt: SELECT driveType: DriveType FROM
aggregate => [d: Drive ← none],
separate => [ds: DriveSequence ← NIL],
ENDCASE],
bs => [bs: BoolSequence ← NIL, dt: SELECT driveType: DriveType FROM
aggregate => [d: Drive ← none],
separate => [ds: DriveSequence ← NIL],
ENDCASE],
c => [
fieldStart: [0..16),
c: CARDINAL ← 0,
dt: SELECT driveType: DriveType FROM
aggregate => [d: Drive ← none],
separate => [ds: DriveSequence ← NIL],
ENDCASE],
lc => [
fieldStart: [0..32),
lc: LONG CARDINAL ← 0,
dt: SELECT driveType: DriveType FROM
aggregate => [d: Drive ← none],
separate => [ds: DriveSequence ← NIL],
ENDCASE],
q => [
fieldStart: [0..64),
q: BitOps.BitQWord ← BitOps.BitQWordZero,
dt: SELECT driveType: DriveType FROM
aggregate => [d: Drive ← none],
separate => [ds: DriveSequence ← NIL],
ENDCASE],
composite => [composite: SEQUENCE size: NAT OF Port],
ENDCASE];
PortRec: TYPE = RECORD [
levelType: LevelType ← composite,
driveType: DriveType ← aggregate,
d: Drive ← none,
l: Level ← L,
b: BOOLFALSE,
ds: DriveSequence ← NIL,
ls: LevelSequence ← NIL,
bs: BoolSequence ← NIL,
fieldStart: [0..64) ← 0,
c: BitOps.BitWord ← BitOps.BitWordZero,
lc: BitOps.BitDWord ← BitOps.BitDWordZero,
q: BitOps.BitQWord ← BitOps.BitQWordZero,
composite: SEQUENCE size: NAT OF Port];
LevelType: TYPE = {l, ls, b, bs, c, lc, q, composite};
DriveType: TYPE = {aggregate, separate};
Drive: TYPE = {
inspect, -- allows test port to receive value
expect, -- allows test port to specify expected value
none, --in a test port it means neither driven nor checked; in an eval port it means no strength at all
chargeWeak, chargeMediumWeak,
charge,
chargeMediumStrong, chargeStrong,
force, -- weakest drive level, allows test procs to check if device has tristated
driveWeak, driveMediumWeak,
drive,
driveMediumStrong, driveStrong,
infinite -- drive for nodes which have infinite current sources
};
Level: TYPE = {L, H, X};
DriveSequence: TYPE = REF DriveSequenceRec;
DriveSequenceRec: TYPE = RECORD [drives: PACKED SEQUENCE size: NAT OF Drive];
LevelSequence: TYPE = REF LevelSequenceRec;
LevelSequenceRec: TYPE = RECORD [levels: PACKED SEQUENCE size: NAT OF Level];
BoolSequence: TYPE = REF BoolSequenceRec;
BoolSequenceRec: TYPE = RECORD [bools: PACKED SEQUENCE size: NAT OF BOOL];
PortData: TYPE = REF PortDataRec;
PortDataRec: TYPE = RECORD [
levelType: LevelType,
driveType: DriveType,
drive: Drive,
drives: DriveSequence];
levelTypeNames: ARRAY LevelType OF Rope.ROPE;
levelNames: ARRAY Level OF Rope.ROPE;
driveTypeNames: ARRAY DriveType OF Rope.ROPE;
driveNames: ARRAY Drive OF Rope.ROPE;
Operations
FindLevelType: PROC [levelTypeID: Rope.ROPE] RETURNS [levelType: LevelType];
FindLevel: PROC [levelID: Rope.ROPE] RETURNS [level: Level];
FindDriveType: PROC [driveTypeID: Rope.ROPE] RETURNS [driveType: DriveType];
FindDrive: PROC [driveID: Rope.ROPE] RETURNS [drive: Drive];
CreatePort: PROC [cellType: Core.CellType, testerPort: BOOLFALSE] RETURNS [port: Port];
Uses inheritance to find properties that guide port creation.
RenewPort: PROC [cellType: Core.CellType, port: Port, testerPort: BOOLFALSE];
WirePortType: PROC [cellType: Core.CellType, wire: Core.Wire] RETURNS [levelType: LevelType, driveType: DriveType];
PortLeaves: PROC [port: Port] RETURNS [leaves: CARDINAL];
CopyPortValue: PROC [from: Port, to: Port];
Raises an error if the ports are not isomorphic.
CheckPortValue: PROC [root: Core.Wire, truth: Port, question: Port];
Raises an error if the ports are not isomorphic or the question port does not match the requirements of the truth port. Uses wire to generate a sensible error message; it should be the wire which was the argument to CreatePort.
CheckError: SIGNAL [msg: Rope.ROPE];
Old Port Initialization and Binding Procedures
InitPort: PROC [wire: Core.Wire, levelType: LevelType ← b, driveType: DriveType ← aggregate, initDrive: Drive ← none, initDrives: DriveSequence ← NIL] RETURNS [sameWire: Core.Wire];
InitPorts: PROC [ct: Core.CellType, initType: LevelType ← l, initDrive: Drive ← none, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10: CoreCreate.WRNIL];
InitPortList: PROC [ct: Core.CellType, initType: LevelType ← l, initDrive: Drive ← none, ports: LIST OF CoreCreate.WR];
InitTesterDrive: PROC [wire: Core.Wire, initDrive: Drive ← none, initDrives: DriveSequence ← NIL];
If initdrives#NIL then the port created with testerPort=TRUE will have driveType=separate.
InitTesterDrives: PROC [ct: Core.CellType, initDrive: Drive ← none, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10: CoreCreate.WRNIL];
InitTesterDriveList: PROC [ct: Core.CellType, initDrive: Drive ← none, ports: LIST OF CoreCreate.WR];
ITDList: PROC [public: Core.Wire, indicies: LIST OF NAT, initDrive: Drive];
IPList: PROC [public: Core.Wire, indicies: LIST OF NAT, levelType: LevelType, initDrive: Drive ← none];
PortIndex: PROC [wire: Core.Wire, name: Rope.ROPE] RETURNS [NAT];
PortIndexes: PROC [wire: Core.Wire, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11: Rope.ROPE ← NIL] RETURNS [i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11: NATLAST[NAT]];
New Port Initialization Procedures
The following set of procedures allows each of the characteristics of a port to be set independently. These procedures are needed so that independent graphical icons can be used for each characteristic. A coercion procedure is provided to transform these individual settings into the collective setting for backwards compatibility reasons. In the glorious future all this will go away but for now this is a better way of determining the port structure.
SetPortLevelType: PROC [wire: Core.Wire, levelType: LevelType ← b] RETURNS [sameWire: Core.Wire];
SetPortDriveType: PROC [wire: Core.Wire, driveType: DriveType ← aggregate] RETURNS [sameWire: Core.Wire];
SetPortTesterDriveType: PROC [wire: Core.Wire, driveType: DriveType ← aggregate] RETURNS [sameWire: Core.Wire];
SetInitialPortDrive: PROC [wire: Core.Wire, initDrive: Drive ← none, initDrives: DriveSequence ← NIL] RETURNS [sameWire: Core.Wire];
SetInitialPortTesterDrive: PROC [wire: Core.Wire, initDrive: Drive ← none, initDrives: DriveSequence ← NIL] RETURNS [sameWire: Core.Wire];
SetPorts: PROC [r: Core.Wire, n: LIST OF Rope.ROPE, lt: LevelType ← b, cdt: DriveType ← aggregate, cd: Drive ← none, cds: DriveSequence ← NIL, tdt: DriveType ← aggregate, td: Drive ← none, tds: DriveSequence ← NIL];
Any defaulted parameters are not applied to the wire. Thus different characteristics can be set in different calls of this procedure.
r is the root wire.
n is a list of full wire names.
New Port Binding Procedures
This set of procedures and the following access procedures standardize procedural access to ports so that some day this horrible mess can be cleaned up. Clients should change to create pointers to their ports at the beginning of their test procedures or in the corresponding Init proc of Rosemary Eval procedures. Please flush all use of port access of the form port[index].leveltype.
BindPort: PROC [rootWire: Core.WireSeq, rootPort: Port, name: Rope.ROPE] RETURNS [p: Port];
Given a root public wire, root port, and a full name returns the corresponding port.
BindPorts: PROC [rootWire: Core.WireSeq, rootPort: Port, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11: Rope.ROPENIL] RETURNS [p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11: Port ← NIL];
New Port Access Procedures
The drive field in the PW, PDW, PQW procedures is applied to the aggregate value. If the driveType is aggregate for PLS or PBS then each put call changes the drive for the entire sequence, not just the indexed element. If the driveType is separate then only the indexed element's drive is changed. All of the following routines may be applied to a level sequence port in addition to port types compatible with the procedure. In the glorious future all the port initialization crud will go away. To be compatible with both the new and old worlds one should make all one's ports level sequence ports and set all the drives at the beginning of each test procedure and in each init procedure.
Drive
GetDrive, GD: PROC [p: Port] RETURNS [v: Drive];
PutDrive, PD: PROC [p: Port, v: Drive];
GetDriveSequence, GDS: PROC [p: Port, i: NAT] RETURNS [v: Drive];
PutDriveSequence, PDS: PROC [p: Port, i: NAT, v: Drive];
Value
GetLevel, GL: PROC [p: Port] RETURNS [v: Level];
PutLevel, PL: PROC [p: Port, v: Level, d: Drive ← drive];
GetLevelSequence, GLS: PROC [p: Port, i: NAT] RETURNS [v: Level];
PutLevelSequence, PLS: PROC [p: Port, i: NAT, v: Level, d: Drive ← drive];
GetBool, GB: PROC [p: Port] RETURNS [v: BOOL];
PutBool, PB: PROC [p: Port, v: BOOL, d: Drive ← drive];
GetBoolSequence, GBS: PROC [p: Port, i: NAT] RETURNS [v: BOOL];
PutBoolSequence, PBS: PROC [p: Port, i: NAT, v: BOOL, d: Drive ← drive];
GetWord, GW: PROC [p: Port] RETURNS [v: BitOps.BitWord];
PutWord, PW: PROC [p: Port, v: BitOps.BitWord, d: Drive ← drive];
GetDWord, GDW: PROC [p: Port] RETURNS [v: BitOps.BitDWord];
PutDWord, PDW: PROC [p: Port, v: BitOps.BitDWord, d: Drive ← drive];
GetQWord, GQW: PROC [p: Port] RETURNS [v: BitOps.BitQWord];
PutQWord, PQW: PROC [p: Port, v: BitOps.BitQWord, d: Drive ← drive];
Utilities
These procedures only apply to level sequence ports. They will continue to work in the glorious future as well.
Not: PROC [src, dst: Port];
Copy: PROC [src, dst: Port];
Set: PROC [p: Port, v: Level];
AnyX: PROC [p: Port] RETURNS [BOOL];
ToRope: PROC [p: Port, size: NAT ← 0, base: NAT ← 16] RETURNS [r: Rope.ROPE];
size is the number of high order bits in container to be converted.
Size: PROC [p: Port] RETURNS [size: NAT];
Enumerating Pairs
EachPortPairProc: TYPE = PROC [onePort: Port, anotherPort: Port] RETURNS [subElements: BOOLTRUE, quit: BOOLFALSE];
VisitPortPair: PROC [onePort: Port, anotherPort: Port, eachPortPair: EachPortPairProc] RETURNS [quit: BOOL];
TRUE is returned if some invocation of eachPortPair returns quit=TRUE or if the ports do not conform.
EachWirePortPairProc: TYPE = PROC [wire: Core.Wire, port: Port] RETURNS [subElements: BOOLTRUE, quit: BOOLFALSE];
VisitBinding: PROC [wire: Core.Wire, port: Port, eachWirePortPair: EachWirePortPairProc] RETURNS [quit: BOOL];
TRUE is returned if some invocation of eachWirePortPair returns quit=TRUE. Wire and port need not conform, but port must be a subgraph of wire. If the port is a strict subgraph of the wire then the EachWirePortPairProc will be called with port: NIL;
Logical Operations and Conversions
ConversionError: SIGNAL;
ToBool: PROC [a: Level] RETURNS [b: BOOL];
ConversionError if X.
ToLevel: PROC [a: BOOL] RETURNS [b: Level];
NotL: PROC [a: Level] RETURNS [b: Level];
AndL: PROC [a, b: Level] RETURNS [c: Level];
OrL: PROC [a, b: Level] RETURNS [c: Level];
XorL: PROC [a, b: Level] RETURNS [c: Level];
SumL: PROC [a, b, c: Level] RETURNS [carry, s: Level];
NotLS: PROC [a, b: LevelSequence];
CopyLS: PROC [from, to: LevelSequence];
SetLS: PROC [seq: LevelSequence, level: Level];
HasX: PROC [ls: Ports.LevelSequence] RETURNS [BOOLFALSE];
LSToRope, LevelSequenceToRope: PROC [container: LevelSequence, size: NAT ← 0, base: NAT ← 16] RETURNS [val: Rope.ROPE];
size is the number of high order bits in container to be converted.
LSToC: PROC [ls: LevelSequence] RETURNS [c: CARDINAL];
Raises ConversionError if some bit of the level sequence is an X or if the value is larger than LAST[CARDINAL].
CToLS: PROC [c: CARDINAL, ls: LevelSequence];
Raises ConversionError if the level sequence is too small to hold the value.
LSToLC: PROC [ls: LevelSequence] RETURNS [lc: LONG CARDINAL];
Raises ConversionError if some bit of the level sequence is an X or if the value is larger than LAST[CARDINAL].
LCToLS: PROC [lc: LONG CARDINAL, ls: LevelSequence];
Raises ConversionError if the level sequence is too small to hold the value.
LSToQ: PROC [ls: LevelSequence] RETURNS [q: BitOps.BitQWord];
Raises ConversionError if the value in the level sequence is larger than 64 bits or an X is in it.
QToLS: PROC [q: BitOps.BitQWord, ls: LevelSequence];
Raises ConversionError if the level sequence is too small to hold the value.
END.