[Indigo]<Rosemary>®>Rosemary.DF=>SwitchTypesImpl.Mesa
Last Edited by: Spreitzer, May 1, 1985 8:24:44 pm PDT
Last Edited by: Barth, April 23, 1984 5:37:27 pm PST
Last Edited by: Gasbarro, August 16, 1984 4:22:48 pm PDT
DIRECTORY Atom, Basics, IO, List, NumTypes, Rope, RoseRun, RoseTranslateTypes, RoseTypes, SignalTypeRegistration, SwitchNumConvert, SwitchTypes, VFonts;
SwitchTypesImpl: 
CEDAR 
PROGRAM
IMPORTS Atom, IO, NumTypes, Rope, RoseRun, RoseTranslateTypes, SignalTypeRegistration, SwitchNumConvert, VFonts
EXPORTS SwitchTypes =
 
BEGIN OPEN RoseTypes, SwitchTypes;
refInput:  PUBLIC REF Strength ← NEW [Strength ← input];
refDriveStrong: PUBLIC REF Strength ← NEW [Strength ← driveStrong];
refDrive:  PUBLIC REF Strength ← NEW [Strength ← drive];
refDriveWeak: PUBLIC REF Strength ← NEW [Strength ← driveWeak];
refChargeStrong: PUBLIC REF Strength ← NEW [Strength ← chargeStrong];
refCharge: PUBLIC REF Strength ← NEW [Strength ← charge];
refChargeWeak: PUBLIC REF Strength ← NEW [Strength ← chargeWeak];
refNone:  PUBLIC REF Strength ← NEW [Strength ← none];
bitProcs: NodeProcs ← 
NEW [NodeProcsRep ← [
UserDescription: BitUserDescription,
ListFormats: BitListFormats,
GetFormat: BitGetFormat,
MesaForSelf: BitMesaForSelf,
SelectorOffset: BitSelectorOffset,
SubType: BitSubType,
Bits: BitBits,
MesaRepresentation: BitMesaRepresentation,
Equivalent: BitEquivalent,
SimpleEquivalent: BitSimpleEquivalent,
Transduce: SwitchNumConvert.Transduce,
InitPort: BitInitPort,
InitQ: BitInitQ,
InitUD: BitInitUD,
NewVal: BitNewVal,
CopyVal: BitCopyVal,
NewQ: BitNewQ,
NewUD: BitNewUD,
QFromNode: BitQFromNode,
UDFromNode: BitUDFromNode,
ValFromNode: BitValFromNode,
SetNode: BitSetNode,
CompareUD: BitCompareUD
]];
bitType: 
PUBLIC NodeType ← 
NEW [NodeTypeRep[atom] ← [
procs: bitProcs,
typeData: NIL,
simple: FALSE,
structure: atom[$DigitalWire]]];
shortBitFormat: Format ← 
NEW [FormatRep ← [
FormatValue: BitFormatValue,
ParseValue: BitParseValue,
FormatTest: BitFormatTest,
ParseTest: BitParseTest,
MaxWidth: BitMaxWidth,
key: "short"]];
longBitFormat: Format ← 
NEW [FormatRep ← [
FormatValue: LBitFormatValue,
ParseValue: LBitParseValue,
FormatTest: BitFormatTest,
ParseTest: BitParseTest,
MaxWidth: LBitMaxWidth,
key: "long"]];
initBitFormat: Format ← 
NEW [FormatRep ← [
ParseValue: InitialBitParse,
key: "init"]];
Int: TYPE = RoseTranslateTypes.Int;
one: Int ← NEW [RoseTranslateTypes.IntRep ← [RoseTranslateTypes.nullSR, 1]];
Holder: TYPE = LONG POINTER TO SwitchValHolder;
ConstructBitType: 
PROC [parms: 
REF 
ANY 
--UNION [BindingList, Args]--] 
RETURNS [type: NodeType] 
--RoseTranslateTypes.NodeTypeConstructor-- =
BEGIN
type ← bitType;
END;
 
BitUserDescription: PROC [NodeType] RETURNS [r: ROPE] = {r ← "Switch"};
BitListFormats: 
PROC [NodeType] 
RETURNS [l: RopeList] =
{l ← LIST ["short", "long"]};
 
BitGetFormat: 
PROC [nt: NodeType, fmtKey: 
ROPE] 
RETURNS [Format] =
{RETURN [IF fmtKey.Equal["init"] THEN initBitFormat ELSE IF fmtKey.Equal["long", FALSE] OR fmtKey.Equal["QUD"] THEN longBitFormat ELSE shortBitFormat]};
 
BitMesaForSelf: 
PROC [NodeType] 
RETURNS [m: Mesa] =
{m ← [mesa: "SwitchTypes.bitType", imports: LIST["SwitchTypes"]]};
 
BitSelectorOffset: 
PROC [nt: NodeType, s: Selector] 
RETURNS [o: 
NAT] = {
o ← 
WITH s 
SELECT 
FROM
whole => 0,
number, range => ERROR,
ENDCASE => ERROR};
 
BitSubType: 
PROC [nt: NodeType, s: Selector] 
RETURNS [snt: NodeType] = {
snt ← 
WITH s 
SELECT 
FROM
whole => nt,
number, range => ERROR,
ENDCASE => ERROR};
 
BitBits: PROC [NodeType] RETURNS [container, data, leftPad: INT] = {RETURN [bpw, bitsPerSwitchVal, bpw-bitsPerSwitchVal]};
BitMesaRepresentation: 
PROC [NodeType] 
RETURNS [m: Mesa] =
{m ← [mesa: "SwitchTypes.SwitchVal", directory: LIST["SwitchTypes"]]};
 
BitEquivalent: 
PROC [self, other: NodeType] 
RETURNS [eqv: 
BOOL] = {
IF self # bitType THEN ERROR;
eqv ← other = bitType OR other = oneBitSwitches};
 
BitSimpleEquivalent: 
PROC [NodeType] 
RETURNS [NodeType] =
{RETURN [NumTypes.boolType]};
 
BitInitPort: 
PROC [n: Node, p: Ptr] = 
TRUSTED {
nh: Holder ← PtrToHolder[n.valPtr];
ph: Holder ← PtrToHolder[p];
ph.held ← nh.held};
 
PtrToHolder: 
PROC [p: Ptr] 
RETURNS [h: Holder] = {
IF p.bit # 0 THEN ERROR;
TRUSTED {h ← LOOPHOLE[p.word]};
};
 
BitInitQ: 
PROC [n: Node] = {
nh: Holder ← PtrToHolder[n.valPtr];
TRUSTED {nh.held.s[q] ← n.strength}};
 
BitInitUD: 
PROC [n: Node] = 
TRUSTED {
nh: Holder ← PtrToHolder[n.valPtr];
u, d: Strength;
[u, d] ← Parts[nh.held.val, n.strength];
nh.held.s[u] ← Block[u, nh.held.s[q]];
nh.held.s[d] ← Block[d, nh.held.s[q]];
n.isInput ← nh.held.s[q] = input};
 
BitNewVal: 
PROC [n: Node] 
RETURNS [delay: 
BOOL] = 
TRUSTED {
nh: Holder ← PtrToHolder[n.valPtr];
temp: Level ←
IF nh.held.s[u] = none AND nh.held.s[d] > none THEN L ELSE
IF nh.held.s[d] = none AND nh.held.s[u] > none THEN H ELSE
X;
delay ← FALSE;
IF n.XPhobic AND temp = X THEN delay ← TRUE ELSE nh.held.val ← temp;
};
 
BitCopyVal: 
PROC [nt: NodeType, from, to: Ptr] = 
TRUSTED {
hFrom: Holder ← PtrToHolder[from];
hTo: Holder ← PtrToHolder[to];
hTo.held.val ← hFrom.held.val};
 
BitNewQ: 
PROC [n: Node, p: Ptr] 
RETURNS [b: 
BOOLEAN] = 
TRUSTED {
h: Holder ← PtrToHolder[p];
nh: Holder ← PtrToHolder[n.valPtr];
IF b ← h.held.s[q] > nh.held.s[q] THEN nh.held.s[q] ← h.held.s[q]};
 
BitNewUD: 
PROC [n: Node, p: Ptr] 
RETURNS [b: 
BOOLEAN] = 
TRUSTED {
h: Holder ← PtrToHolder[p];
nh: Holder ← PtrToHolder[n.valPtr];
u: Strength ← Block[h.held.s[u], nh.held.s[q]];
d: Strength ← Block[h.held.s[d], nh.held.s[q]];
b ← FALSE;
IF u > nh.held.s[u] THEN {b ← TRUE; nh.held.s[u] ← u};
IF d > nh.held.s[d] THEN {b ← TRUE; nh.held.s[d] ← d}};
 
BitQFromNode: 
PROC [n: Node, to: Ptr] = 
TRUSTED {
h: Holder ← PtrToHolder[to];
nh: Holder ← PtrToHolder[n.valPtr];
h.held.s[q] ← nh.held.s[q]};
 
BitUDFromNode: 
PROC [n: Node, to: Ptr] = 
TRUSTED {
h: Holder ← PtrToHolder[to];
nh: Holder ← PtrToHolder[n.valPtr];
h.held.s[u] ← nh.held.s[u];
h.held.s[d] ← nh.held.s[d]};
 
BitValFromNode: 
PROC [n: Node, to: Ptr] = 
TRUSTED {
h: Holder ← PtrToHolder[to];
nh: Holder ← PtrToHolder[n.valPtr];
h.held.val ← nh.held.val};
 
BitSetNode: 
PROC [n: Node, to: Ptr] = 
TRUSTED {
h: Holder ← PtrToHolder[to];
nh: Holder ← PtrToHolder[n.valPtr];
nh.held ← h.held};
 
BitCompareUD: 
PROC [nt: NodeType, p1, p2: Ptr] 
RETURNS [diff: 
BOOL] = 
TRUSTED {
h1: Holder ← PtrToHolder[p1];
h2: Holder ← PtrToHolder[p2];
diff ← h1.held.s[u] # h2.held.s[u] OR h1.held.s[d] # h2.held.s[d]};
 
Block: 
PUBLIC 
PROC [a, b: Strength] 
RETURNS [c: Strength] =
{c ← IF a < b THEN none ELSE a};
 
Parts: 
PROC [l: Level, s: Strength] 
RETURNS [u, d: Strength] = {
RETURN [
SELECT l 
FROM
L => none,
H, X => s,
ENDCASE => ERROR,
 
SELECT l 
FROM
H => none,
L, X => s,
ENDCASE => ERROR]};
 
 
 
BitFormatValue: 
PROC [node: Node, fmt: Format, p: Ptr] 
RETURNS [r: 
ROPE] = {
h: Holder ← PtrToHolder[p];
TRUSTED {r ← levelToRope[h.held.val]}};
 
BitParseValue: 
PROC [node: Node, fmt: Format, p: Ptr, s: 
STREAM] 
RETURNS [success: 
BOOLEAN] = {
h: Holder ← PtrToHolder[p];
ans: Level;
success ← TRUE;
ans ← GetLevel[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
TRUSTED {h.held.val ← ans};
};
 
InitialBitParse: 
PROC [node: Node, fmt: Format, p: Ptr, s: 
STREAM] 
RETURNS [success: 
BOOLEAN] = {
h: Holder ← PtrToHolder[p];
ans: Level;
val: ATOM ← Atom.MakeAtom[s.GetID[]];
success ← TRUE;
SELECT val 
FROM
$steady => ans ← L;
$initial => ans ← X;
$vdd => ans ← H;
$gnd => ans ← L;
ENDCASE => success ← FALSE;
 
IF NOT success THEN RETURN;
TRUSTED {h.held.val ← ans};
};
 
LBitFormatValue: 
PROC [node: Node, fmt: Format, p: Ptr] 
RETURNS [r: 
ROPE] = 
TRUSTED {
h: Holder ← PtrToHolder[p];
r ← Rope.Cat[
strengthToRope[h.held.s[q]],
strengthToRope[h.held.s[u]],
strengthToRope[h.held.s[d]],
levelToRope[h.held.val],
strengthToRope[node.strength]]
.Cat[IF NOT node.XPhobic THEN "*" ELSE IF RoseRun.Delayed[node] THEN "+" ELSE "-"]};
 
LBitParseValue: 
PROC [node: Node, fmt: Format, p: Ptr, s: 
STREAM] 
RETURNS [success: 
BOOLEAN] = 
TRUSTED {
h: Holder ← PtrToHolder[p];
newStrength: Strength;
newSV: SwitchVal ← [];
success ← TRUE;
newSV.s[q] ← GetStrength[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
newSV.s[u] ← GetStrength[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
newSV.s[d] ← GetStrength[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
newSV.val ← GetLevel[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
newStrength ← GetStrength[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
IF p = node.valPtr THEN node.strength ← newStrength;
h.held ← newSV;
};
 
GetLevel: 
PROC [s: 
STREAM] 
RETURNS [l: Level] =
BEGIN
char: CHARACTER;
[] ← s.SkipWhitespace[];
IF s.EndOf[] THEN ERROR IO.EndOfStream[stream: s];
char ← s.GetChar[];
SELECT char 
FROM
'L => l ← L;
'H => l ← H;
'X => l ← X;
ENDCASE => ERROR IO.Error[stream: s, ec: SyntaxError];
 
END;
 
GetStrength: 
PROC [s: 
STREAM] 
RETURNS [strength: Strength] =
BEGIN
char: CHARACTER;
asRope: ROPE;
[] ← s.SkipWhitespace[];
IF s.EndOf[] THEN ERROR IO.EndOfStream[stream: s];
char ← s.GetChar[];
asRope ← Rope.FromChar[char];
FOR strength 
IN Strength 
DO
IF strengthToRope[strength].Equal[asRope, FALSE] THEN RETURN;
ENDLOOP;
 
ERROR IO.Error[stream: s, ec: SyntaxError];
END;
 
BitFormatTest: 
PROC [nt: NodeType, fmt: Format, test: NodeTest] 
RETURNS [r: 
ROPE] =
BEGIN
r ← SELECT test.data FROM $L => "L", $H => "H", $X => "X", ENDCASE => "??";
END;
 
BitParseTest: 
PROC [nt: NodeType, fmt: Format, s: 
STREAM] 
RETURNS [success: 
BOOLEAN, test: NodeTest] =
BEGIN
ans: Level;
success ← TRUE;
ans ← GetLevel[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
test.proc ← BitTest;
test.data ← SELECT ans FROM L => $L, H => $H, X => $X, ENDCASE => ERROR;
END;
 
BitTest: 
PROC [where: Ptr, testData: 
REF 
ANY, nodeType: NodeType] 
RETURNS [passes: 
BOOLEAN] 
--NodeTestProc-- =
BEGIN
l: Level ← SELECT testData FROM $L => L, $H => H, $X => X, ENDCASE => ERROR;
TRUSTED {passes ← PtrToHolder[where].held.val = l};
END;
 
BitMaxWidth: 
PROC [nt: NodeType, fmt: Format, font: VFonts.Font] 
RETURNS [
INT] =
{RETURN [VFonts.StringWidth["H", font]]};
 
LBitMaxWidth: 
PROC [nt: NodeType, fmt: Format, font: VFonts.Font] 
RETURNS [
INT] =
{RETURN [VFonts.StringWidth["555H55+", font]]};
 
NodeTypeList: TYPE = LIST OF ArrayNodeType;
switchTypes: NodeTypeList ← NIL;
Bundle: 
PUBLIC 
PROC [bits: 
CARDINAL] 
RETURNS [nt: NodeType] =
BEGIN
FOR it: NodeTypeList ← switchTypes, it.rest 
WHILE it # 
NIL 
DO
IF it.first.length = bits THEN RETURN [it.first];
ENDLOOP;
 
switchTypes ← CONS[nt ← MakeSwitchOfWidth[bits], switchTypes];
END;
 
MakeSwitchOfWidth: 
PROC [bits: 
CARDINAL] 
RETURNS [nt: ArrayNodeType] =
BEGIN
nt ← 
NEW [NodeTypeRep[array] ← [
procs: switchProcs,
typeData: NIL,
simple: FALSE,
structure: array[bits, NARROW[bitType]]]];
END;
 
switchProcs: NodeProcs ← 
NEW [NodeProcsRep ← [
UserDescription: SwitchUserDescription,
ListFormats: SwitchListFormats,
GetFormat: SwitchGetFormat,
MesaForSelf: SwitchMesaForSelf,
SelectorOffset: SwitchSelectorOffset,
SubType: SwitchSubType,
Bits: SwitchBits,
MesaRepresentation: SwitchMesaRepresentation,
Equivalent: SwitchEquivalent,
SimpleEquivalent: SwitchSimpleEquivalent,
Transduce: SwitchNumConvert.Transduce,
InitPort: SwitchesInitPort,
InitQ: SwitchesInitQ,
InitUD: SwitchesInitUD,
NewVal: SwitchesNewVal,
CopyVal: SwitchesCopyVal,
NewQ: SwitchesNewQ,
NewUD: SwitchesNewUD,
QFromNode: SwitchesQFromNode,
UDFromNode: SwitchesUDFromNode,
ValFromNode: SwitchesValFromNode,
SetNode: SwitchesSetNode,
CompareUD: SwitchesCompareUD
]];
ConstructSwitchType: RoseTranslateTypes.NodeTypeConstructor
--PROC [parms: REF ANY - -UNION [BindingList, Args]- -] RETURNS [type: SwitchType]-- =
BEGIN
bits: Int ← NARROW[RoseTranslateTypes.GetParm[n: 1, name: "bits", parms: parms, default: one]];
type ← Bundle[bits.i];
END;
 
bpw: NAT = Basics.bitsPerWord;
SwitchUserDescription: 
PROC [nt: NodeType] 
RETURNS [ud: 
ROPE] = {
ant: ArrayNodeType ← NARROW[nt];
ud ← IO.PutFR["Switch[%g]", IO.int[ant.length]]};
 
SwitchListFormats: PROC [NodeType] RETURNS [l: RopeList] = {l ← sfl};
SwitchGetFormat: 
PROC [nt: NodeType, key: 
ROPE] 
RETURNS [fmt: Format] = {
atom: ATOM ← Atom.MakeAtom[key];
fmt ← NARROW[Atom.GetProp[atom: atom, prop: switchFmtKey]];
};
 
SwitchMesaForSelf: 
PROC [nt: NodeType] 
RETURNS [m: Mesa] = {
ant: ArrayNodeType ← NARROW[nt];
m ← [
mesa: IO.PutFR["SwitchTypes.Bundle[%g]", IO.int[ant.length]],
imports: LIST["SwitchTypes"]]};
 
SwitchSelectorOffset: 
PROC [nt: NodeType, s: Selector] 
RETURNS [o: 
NAT] = {
o ← 
WITH s 
SELECT 
FROM
number => index*bpw,
whole => 0,
range => bpw*(IF up THEN first ELSE first+1-count),
ENDCASE => ERROR;
};
 
SwitchSubType: 
PROC [nt: NodeType, s: Selector] 
RETURNS [snt: NodeType] = {
snt ← 
WITH s 
SELECT 
FROM
whole => nt,
number => bitType,
range => Bundle[count],
ENDCASE => ERROR;
};
 
SwitchBits: 
PROC [nt: NodeType] 
RETURNS [container, data, leftPad: 
INT] = {
ant: ArrayNodeType ← NARROW[nt];
container ← bpw*((ant.length + switchValsPerWord -1)/switchValsPerWord);
data ← container;
leftPad ← 0;
};
 
SwitchMesaRepresentation: 
PROC [nt: NodeType] 
RETURNS [m: Mesa] = {
ant: ArrayNodeType ← NARROW[nt];
m ← [
mesa: IO.PutFR["PACKED ARRAY [0 .. %g) OF SwitchTypes.SwitchVal", IO.int[ant.length]],
directory: LIST["SwitchTypes"]]};
 
sfl: RopeList ← LIST["short", "long"];
switchFmtKey: REF ROPE ← NEW [ROPE ← "Switch Format Key"];
shortSwitchesFormat: Format ← 
NEW [FormatRep ← [
FormatValue: SwitchesFormatValue,
ParseValue: SwitchesParseValue,
FormatTest: NIL,
ParseTest: NIL,
MaxWidth: SwitchesMaxWidth,
key: "switches"]];
longSwitchesFormat: Format ← 
NEW [FormatRep ← [
FormatValue: SwitchesLongFormatValue,
ParseValue: SwitchesLongParseValue,
FormatTest: NIL,
ParseTest: NIL,
MaxWidth: SwitchesLongMaxWidth,
key: "long"]];
initSwitchesFormat: Format ← 
NEW [FormatRep ← [
ParseValue: InitialSwitchesParse,
key: "init"]];
Switches: TYPE = LONG POINTER TO PACKED ARRAY NAT OF SwitchVal;
PtrToSwitches: 
PROC [p: Ptr] 
RETURNS [ss: Switches] = {
IF p.bit # 0 THEN ERROR;
TRUSTED {ss ← LOOPHOLE[p.word]}};
 
SwitchEquivalent: 
PROC [self, other: NodeType] 
RETURNS [eqv: 
BOOL] = {
ant: ArrayNodeType ← NARROW[self];
IF ant.element # bitType THEN ERROR;
eqv ← other = self OR (other = bitType AND ant.length=1);
};
 
SwitchSimpleEquivalent: 
PROC [self: NodeType] 
RETURNS [NodeType] = {
ant: ArrayNodeType ← NARROW[self];
RETURN [NumTypes.NumType[ant.length]]};
 
SwitchesInitPort: 
PROC [n: Node, p: Ptr] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[n.type];
ns: Switches ← PtrToSwitches[n.valPtr];
s: Switches ← PtrToSwitches[p];
FOR i: 
CARDINAL 
IN [0 .. ant.length) 
DO
s[i] ← ns[i];
ENDLOOP};
 
 
SwitchesInitQ: 
PROC [n: Node] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[n.type];
ns: Switches ← PtrToSwitches[n.valPtr];
FOR i: CARDINAL IN [0 .. ant.length) DO ns[i].s[q] ← n.strength ENDLOOP};
 
SwitchesInitUD: 
PROC [n: Node] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[n.type];
ns: Switches ← PtrToSwitches[n.valPtr];
n.isInput ← TRUE;
FOR i: 
CARDINAL 
IN [0 .. ant.length) 
DO
u, d: Strength;
[u, d] ← Parts[ns[i].val, n.strength];
ns[i].s[u] ← Block[u, ns[i].s[q]];
ns[i].s[d] ← Block[d, ns[i].s[q]];
n.isInput ← n.isInput AND ns[i].s[q] = input;
ENDLOOP};
 
 
SwitchesNewVal: 
PROC [n: Node] 
RETURNS [delay: 
BOOL] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[n.type];
ns: Switches ← PtrToSwitches[n.valPtr];
delay ← FALSE;
FOR i: 
CARDINAL 
IN [0 .. ant.length) 
DO
temp: Level ←
IF ns[i].s[u] = none AND ns[i].s[d] > none THEN L ELSE
IF ns[i].s[d] = none AND ns[i].s[u] > none THEN H ELSE
X;
IF n.XPhobic AND temp = X THEN delay ← TRUE ELSE ns[i].val ← temp;
ENDLOOP;
 
};
 
SwitchesCopyVal: 
PROC [nt: NodeType, from, to: Ptr] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[nt];
sFrom: Switches ← PtrToSwitches[from];
sTo: Switches ← PtrToSwitches[to];
FOR i: 
INTEGER 
IN [0 .. ant.length) 
DO
sTo[i].val ← sFrom[i].val;
ENDLOOP};
 
 
SwitchesNewQ: 
PROC [n: Node, p: Ptr] 
RETURNS [b: 
BOOLEAN] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[n.type];
ns: Switches ← PtrToSwitches[n.valPtr];
s: Switches ← PtrToSwitches[p];
b ← FALSE;
FOR i: 
CARDINAL 
IN [0 .. ant.length) 
DO
IF s[i].s[q]>ns[i].s[q] THEN {ns[i].s[q] ← s[i].s[q]; b ← TRUE};
ENDLOOP};
 
 
SwitchesNewUD: 
PROC [n: Node, p: Ptr] 
RETURNS [b:
 BOOLEAN] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[n.type];
ns: Switches ← PtrToSwitches[n.valPtr];
s: Switches ← PtrToSwitches[p];
b ← FALSE;
FOR i: 
CARDINAL 
IN [0 .. ant.length) 
DO
u: Strength ← Block[s[i].s[u], ns[i].s[q]];
d: Strength ← Block[s[i].s[d], ns[i].s[q]];
IF u > ns[i].s[u] THEN {ns[i].s[u] ← u; b ← TRUE};
IF d > ns[i].s[d] THEN {ns[i].s[d] ← d; b ← TRUE};
ENDLOOP};
 
 
SwitchesQFromNode: 
PROC [n: Node, to: Ptr] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[n.type];
ns: Switches ← PtrToSwitches[n.valPtr];
s: Switches ← PtrToSwitches[to];
FOR i: CARDINAL IN [0 .. ant.length) DO s[i].s[q] ← ns[i].s[q] ENDLOOP};
 
SwitchesUDFromNode: 
PROC [n: Node, to: Ptr] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[n.type];
ns: Switches ← PtrToSwitches[n.valPtr];
s: Switches ← PtrToSwitches[to];
FOR i: 
CARDINAL 
IN [0 .. ant.length) 
DO
s[i].s[u] ← ns[i].s[u];
s[i].s[d] ← ns[i].s[d];
ENDLOOP};
 
 
SwitchesValFromNode: 
PROC [n: Node, to: Ptr] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[n.type];
ns: Switches ← PtrToSwitches[n.valPtr];
s: Switches ← PtrToSwitches[to];
FOR i: CARDINAL IN [0 .. ant.length) DO s[i].val ← ns[i].val ENDLOOP};
 
SwitchesSetNode: 
PROC [n: Node, to: Ptr] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[n.type];
ns: Switches ← PtrToSwitches[n.valPtr];
s: Switches ← PtrToSwitches[to];
FOR i: CARDINAL IN [0 .. ant.length) DO ns[i] ← s[i] ENDLOOP};
 
SwitchesCompareUD: 
PROC [nt: NodeType, p1, p2: Ptr] 
RETURNS [diff: 
BOOL] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[nt];
s1: Switches ← PtrToSwitches[p1];
s2: Switches ← PtrToSwitches[p2];
FOR i: 
NAT 
IN [0 .. ant.length) 
DO
IF s1[i].s[u] # s2[i].s[u] OR s1[i].s[d] # s2[i].s[d] THEN RETURN [TRUE];
ENDLOOP;
 
diff ← FALSE};
 
SwitchesLongFormatValue: 
PROC [node: Node, fmt: Format, p: Ptr] 
RETURNS [rope: 
ROPE] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[node.type];
s: Switches ← PtrToSwitches[p];
rope ← "";
FOR i: 
INTEGER 
IN [0 .. ant.length) 
DO
rope ← rope.Cat[
strengthToRope[s[i].s[q]],
strengthToRope[s[i].s[u]],
strengthToRope[s[i].s[d]],
levelToRope[s[i].val]];
ENDLOOP;
 
rope ← rope.Cat[
strengthToRope[node.strength],
IF NOT node.XPhobic THEN "*" ELSE IF RoseRun.Delayed[node] THEN "+" ELSE "-"];
};
 
SwitchSeq: TYPE = RECORD [switches: PACKED SEQUENCE length: NAT OF SwitchVal];
SwitchesLongParseValue: 
PROC [node: Node, fmt: Format, p: Ptr, s: 
STREAM] 
RETURNS [success: 
BOOLEAN] = 
TRUSTED {
ant: ArrayNodeType ← NARROW[node.type];
ss: Switches ← PtrToSwitches[p];
bits: INTEGER ← ant.length;
newStrength: Strength;
ts: REF SwitchSeq ← NEW [SwitchSeq[bits]];
success ← TRUE;
FOR i: 
INTEGER 
IN [0 .. bits) 
DO
ts[i].s[q] ← GetStrength[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
ts[i].s[u] ← GetStrength[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
ts[i].s[d] ← GetStrength[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
ts[i].val ← GetLevel[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
ENDLOOP;
 
newStrength ← GetStrength[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
FOR i: INTEGER IN [0 .. bits) DO ss[i] ← ts[i] ENDLOOP;
IF p = node.valPtr THEN {node.strength ← newStrength};
};
 
SwitchesLongMaxWidth: 
PROC [nt: NodeType, fmt: Format, font: VFonts.Font] 
RETURNS [
INT] =
BEGIN
ant: ArrayNodeType ← NARROW[nt];
bits: INTEGER ← ant.length;
RETURN [VFonts.StringWidth["555H", font]*bits + VFonts.StringWidth["55+", font]]
END;
 
InitialSwitchesParse: 
PROC [node: Node, fmt: Format, p: Ptr, s: 
STREAM] 
RETURNS [success: 
BOOLEAN] =
BEGIN
ant: ArrayNodeType ← NARROW[node.type];
ss: Switches ← PtrToSwitches[p];
bits: INTEGER ← ant.length;
atom: ATOM ← Atom.MakeAtom[s.GetID[]];
val: Level;
success ← TRUE;
SELECT atom 
FROM
$initial => val ← X;
$steady => val ← L;
$vdd => val ← H;
$gnd => val ← L;
ENDCASE => success ← FALSE;
 
IF NOT success THEN RETURN;
FOR i: 
INTEGER 
IN [0 .. bits) 
DO
TRUSTED {ss[i].val ← val};
ENDLOOP;
 
END;
 
SwitchesFormatValue: 
PROC [node: Node, fmt: Format, p: Ptr] 
RETURNS [rope: 
ROPE] = {
ant: ArrayNodeType ← NARROW[node.type];
ss: Switches ← PtrToSwitches[p];
bits: INTEGER ← ant.length;
rope ← "";
FOR i: 
INTEGER 
IN [0 .. bits) 
DO
TRUSTED {rope ← rope.Cat[levelToRope[ss[i].val]]};
ENDLOOP;
 
};
 
levelToRope: ARRAY Level OF ROPE ← ["L", "H", "X"];
strengthToRope: ARRAY Strength OF ROPE ← ["2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
SwitchesParseValue: 
PROC [node: Node, fmt: Format, p: Ptr, s: 
STREAM] 
RETURNS [success: 
BOOLEAN] =
BEGIN
ant: ArrayNodeType ← NARROW[node.type];
ss: Switches ← PtrToSwitches[p];
bits: INTEGER ← ant.length;
success ← TRUE;
FOR i: 
INTEGER 
IN [0 .. bits) 
DO
l: Level;
l ← GetLevel[s !IO.EndOfStream, IO.Error => {success ← FALSE; CONTINUE}];
IF NOT success THEN RETURN;
TRUSTED {ss[i].val ← l};
ENDLOOP;
 
END;
 
SwitchesMaxWidth: 
PROC [nt: NodeType, fmt: Format, font: VFonts.Font] 
RETURNS [
INT] =
BEGIN
ant: ArrayNodeType ← NARROW[nt];
bits: INTEGER ← ant.length;
RETURN [VFonts.StringWidth["H", font]*bits]
END;
 
BSwitchFormatValue: 
PROC [node: Node, fmt: Format, p: Ptr] 
RETURNS [rope: 
ROPE] =
BEGIN
ant: ArrayNodeType ← NARROW[node.type];
ss: Switches ← PtrToSwitches[p];
bits: INTEGER ← ant.length;
base: CARDINAL ← NARROW[fmt.formatData, REF CARDINAL]^;
bitsPerDigit: CARDINAL ← bitsPerBase[base];
digits: INTEGER ← (bits + bitsPerDigit - 1) / bitsPerDigit;
rope ← baseKeys[base];
FOR d: 
INTEGER 
IN [0 .. digits) 
DO
r: INTEGER ← bits - d * bitsPerDigit;
n: CARDINAL ← 0;
xless: BOOL ← TRUE;
FOR i: 
INTEGER 
IN [
MAX[r - bitsPerDigit, 0] .. r) 
DO
n ← n + n;
TRUSTED {
SELECT ss[i].val 
FROM
L => NULL;
X => xless ← FALSE;
H => n ← n + 1;
ENDCASE => ERROR};
 
ENDLOOP;
 
rope ← (IF xless THEN encode[n] ELSE "?").Concat[rope];
ENDLOOP;
 
END;
 
baseKeys: ARRAY [2 .. 16] OF ROPE = ["B", "R3", "R4", "R5", "R6", "R7", "O", "R9", "D", "R11", "R12", "R13", "R14", "R15", "H"];
numToLevel: ARRAY [0 .. 1] OF Level = [L, H];
bitsPerBase: ARRAY [2 .. 16] OF CARDINAL = [1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4];
decode: ARRAY CHARACTER OF [0..16] ← ALL[16];
encode: ARRAY [0..16) OF ROPE = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
BSwitchParseValue: 
PROC [node: Node, fmt: Format, p: Ptr, s: 
STREAM] 
RETURNS [success: 
BOOLEAN] =
BEGIN
ant: ArrayNodeType ← NARROW[node.type];
ss: Switches ← PtrToSwitches[p];
bits: INTEGER ← ant.length;
rope: ROPE ← s.GetTokenRope[IO.IDProc].token;
rlen, rend: INTEGER ← rope.Length[];
base: CARDINAL ← 0;
fb: REF CARDINAL ← NARROW[fmt.formatData];
bitsPerDigit: CARDINAL;
IF rlen < 1 THEN RETURN [FALSE];
SELECT rope.Fetch[rlen - 1] 
FROM
'b, 'B => {base ← 2; rend ← rlen - 1};
'o, 'O => {base ← 8; rend ← rlen - 1};
'h, 'H => {base ← 16; rend ← rlen - 1};
'a, 'A, 'c, 'C, 'd, 'D, 'e, 'E, 'f, 'F => {base ← 16};
ENDCASE => {base ← fb^};
 
bitsPerDigit ← bitsPerBase[base];
FOR d: 
INT 
IN [1 .. rend] 
DO
c: CHAR ← rope.Fetch[rend - d];
digit: [0 .. 16] ← decode[c];
x: BOOL ← c = 'x OR c = 'X;
IF (digit > base) AND (NOT x) THEN RETURN [FALSE];
ENDLOOP;
 
FOR d: 
INT 
IN [1 .. rend] 
DO
c: CHAR ← rope.Fetch[rend - d];
digit: [0 .. 16] ← decode[c];
x: BOOL ← c = 'x OR c = 'X;
FOR b: 
CARDINAL 
IN [1 .. bitsPerDigit] 
DO
l: Level ← IF x THEN X ELSE numToLevel[digit MOD 2];
i: INTEGER ← bits - (d-1)*bitsPerDigit - b;
next: [0 .. 16] ← digit / 2;
IF i >= 0 THEN TRUSTED {ss[i].val ← l};
digit ← next;
ENDLOOP;
 
ENDLOOP;
 
success ← TRUE;
END;
 
BSwitchMaxWidth: 
PROC [nt: NodeType, fmt: Format, font: VFonts.Font] 
RETURNS [
INT] =
BEGIN
ant: ArrayNodeType ← NARROW[nt];
bits: INTEGER ← ant.length;
base: REF CARDINAL ← NARROW[fmt.formatData];
bitsPerDigit: CARDINAL ← bitsPerBase[base^];
digits: INTEGER ← (bits + bitsPerDigit - 1) / bitsPerDigit;
RETURN [VFonts.StringWidth["H", font]*(digits+1)]
END;
 
AddFormat: 
PROC [key: 
ROPE, base: 
CARDINAL] 
RETURNS [fmt: Format] =
BEGIN
atom: ATOM ← Atom.MakeAtom[key];
fmt ← 
NEW [FormatRep ← [
FormatValue: BSwitchFormatValue,
ParseValue: BSwitchParseValue,
FormatTest: NIL,
ParseTest: NIL,
MaxWidth: BSwitchMaxWidth,
formatData: NEW [CARDINAL ← base],
key: key]];
Atom.PutProp[atom: atom, prop: switchFmtKey, val: fmt];
sfl ← CONS[key, sfl];
END;
 
IsSwitchType: 
PUBLIC 
PROC [nt: NodeType] 
RETURNS [switchy: 
BOOLEAN] = {
WITH nt 
SELECT 
FROM
ant: ArrayNodeType => switchy ← IsSwitchType[ant.element];
ant: AtomNodeType => switchy ← ant = bitType;
ENDCASE => ERROR};
 
 
defaultSwitchesFormat: Format ← NIL;
oneBitSwitches: ArrayNodeType ← NARROW[Bundle[1]];
Start: 
PROC = 
BEGIN
FOR c: 
CARDINAL 
IN [0..9] 
DO
decode['0 + c] ← c;
ENDLOOP;
 
FOR c: 
CARDINAL 
IN [0..5] 
DO
decode['A + c] ← 10 + c;
decode['a + c] ← 10 + c;
ENDLOOP;
 
Atom.PutProp[atom: $short, prop: switchFmtKey, val: shortSwitchesFormat];
Atom.PutProp[atom: $long, prop: switchFmtKey, val: longSwitchesFormat];
Atom.PutProp[atom: $QUD, prop: switchFmtKey, val: longSwitchesFormat];
Atom.PutProp[atom: $init, prop: switchFmtKey, val: initSwitchesFormat];
[] ← AddFormat["2", 2];
[] ← AddFormat["8", 8];
[] ← AddFormat["16", 16];
defaultSwitchesFormat ← AddFormat["", 16];
SignalTypeRegistration.RegisterNodeTypeConstructor["SWITCH", ConstructSwitchType];
SignalTypeRegistration.RegisterNodeTypeConstructor["BIT", ConstructBitType];
END;
 
Start[];
END.