LichenDataImpl.Mesa
Last tweaked by Mike Spreitzer on February 2, 1988 1:40:55 pm PST
DIRECTORY AbSets, AMBridge, Asserting, Basics, BiRels, Convert, InterpreterOps, IntStuff, IO, LichenArrayStuff, LichenDataOps, LichenDataStructure, LichenPrinting, List, Rope, RopeHash, SetBasics, StructuredStreams, SymTab, UnparserBuffer, ViewerIO;
LichenDataImpl:
CEDAR
PROGRAM
IMPORTS AbSets, Asserting, Basics, BiRels, IntStuff, IO, LichenArrayStuff, LichenDataOps, LichenDataStructure, LichenPrinting, List, Rope, RopeHash, SetBasics, StructuredStreams, UnparserBuffer, ViewerIO
EXPORTS LichenDataStructure, LichenDataOps
=
BEGIN OPEN LichenDataOps, LichenDataStructure, LichenArrayStuff, Sets:AbSets, SS:StructuredStreams, UB:UnparserBuffer;
nyet: PUBLIC ERROR = CODE;
Warning: PUBLIC SIGNAL [msg: ROPE ← NIL, v1, v2, v3, v4, v5: REF ANY ← NIL] = CODE;
Error: PUBLIC ERROR [msg: ROPE, v1, v2, v3, v4, v5: REF ANY ← NIL] = CODE;
nameReln: PUBLIC ATOM ← $LichenName;
partsByNameKey: PUBLIC ATOM ← $LichenNameToPart;
Escape: ERROR = CODE;
CopyTil:
PUBLIC
PROC [old: TList]
RETURNS [new: TList ← []] ~ {
FOR cur:
LORA ← old.head, cur.rest
WHILE cur#old.tail
DO
this: LORA ~ LIST[cur.first];
IF new.tail=NIL THEN new.head ← this ELSE new.tail.rest ← this;
new.tail ← this;
ENDLOOP;
RETURN};
nameStepSpace:
PUBLIC SetBasics.Space ←
NEW [SetBasics.SpacePrivate ← [
Contains: StepContains,
Equal: StepEqual,
Hash: StepHash,
Compare: StepCompare,
name: "name steps"
]];
StepContains:
PROC [data:
REF
ANY, v: Sets.Value]
RETURNS [
BOOL] ~ {
RETURN [
WITH v.ra
SELECT
FROM
y: ROPE => TRUE,
y: REF INT => TRUE,
ENDCASE => FALSE]};
StepEqual:
PROC [data:
REF
ANY, v1, v2: Sets.Value]
RETURNS [
BOOL] ~ {
WITH v1.
VA
SELECT
FROM
x:
REF
INT =>
WITH v2.
VA
SELECT
FROM
y: REF INT => RETURN [x^ = y^];
y: ROPE => RETURN [FALSE];
ENDCASE => ERROR;
x:
ROPE =>
WITH v2.
VA
SELECT
FROM
y: REF INT => RETURN [FALSE];
y: ROPE => RETURN [x.Equal[y]];
ENDCASE => ERROR;
ENDCASE => ERROR;
};
StepHash:
PROC [data:
REF
ANY, v: Sets.Value]
RETURNS [
CARDINAL] ~ {
WITH v.
VA
SELECT
FROM
x: REF INT => RETURN SetBasics.HashIntI[x^];
x: ROPE => RETURN [RopeHash.FromRope[rope: x]];
ENDCASE => ERROR;
};
StepCompare:
PROC [data:
REF
ANY, v1, v2: Sets.Value]
RETURNS [Basics.Comparison] ~ {
WITH v1.
VA
SELECT
FROM
x:
REF
INT =>
WITH v2.
VA
SELECT
FROM
y: REF INT => RETURN [SetBasics.CompareIntI[x^, y^]];
y: ROPE => RETURN [less];
ENDCASE => ERROR;
x:
ROPE =>
WITH v2.
VA
SELECT
FROM
y: REF INT => RETURN [greater];
y: ROPE => RETURN [x.Compare[y]];
ENDCASE => ERROR;
ENDCASE => ERROR;
};
steppyNameSpace:
PUBLIC SetBasics.Space ←
NEW [SetBasics.SpacePrivate ← [
Contains: SteppyNamesContains,
Equal: EqualSteppyNames,
Hash: HashSteppyName,
Compare: CompareSteppyNames,
name: "steppy names"
]];
SteppyNamesContains:
PROC [data:
REF
ANY, v: Sets.Value]
RETURNS [
BOOL] ~ {
RETURN [
WITH v.ra
SELECT
FROM
x: NameStepList => TRUE,
ENDCASE => FALSE]};
EqualSteppyNames:
PROC [data:
REF
ANY, v1, v2: Sets.Value]
RETURNS [
BOOL] ~ {
n1: SteppyName ~ VSn[v1];
n2: SteppyName ~ VSn[v2];
RETURN SteppyNameEqual[n1, n2]};
SteppyNameEqual:
PUBLIC
PROC [n1, n2: SteppyName, clip1, clip2: NameStepList ←
NIL]
RETURNS [
BOOL] ~ {
l1: NameStepList ← n1.steps;
l2: NameStepList ← n2.steps;
WHILE l1#clip1
AND l2#clip2
DO
WITH l1.first
SELECT
FROM
x:
ROPE =>
WITH l2.first
SELECT
FROM
y: ROPE => IF NOT x.Equal[y] THEN RETURN [FALSE];
y: REF INT => RETURN [FALSE];
ENDCASE => ERROR;
x:
REF
INT =>
WITH l2.first
SELECT
FROM
y: ROPE => RETURN [FALSE];
y: REF INT => IF x^#y^ THEN RETURN [FALSE];
ENDCASE => ERROR;
ENDCASE => ERROR;
l1 ← l1.rest;
l2 ← l2.rest;
ENDLOOP;
RETURN [(l1=clip1) = (l2=clip2)]};
HashSteppyName:
PROC [data:
REF
ANY, v: Sets.Value]
RETURNS [hash:
CARDINAL ← 0] ~ {
n: SteppyName ← VSn[v];
FOR steps: NameStepList ← n.steps, steps.rest
WHILE steps#
NIL
DO
hash ← hash + (
WITH steps.first
SELECT
FROM
x: ROPE => RopeHash.FromRope[x],
x: REF INT => SetBasics.HashIntI[x^],
ENDCASE => ERROR);
ENDLOOP;
RETURN};
CompareSteppyNames:
PROC [data:
REF
ANY, v1, v2: Sets.Value]
RETURNS [c: Basics.Comparison] ~ {
n1: SteppyName ~ VSn[v1];
n2: SteppyName ~ VSn[v2];
IF (c ← SteppyNameGradeCompare[n1.grade, n2.grade])#equal THEN RETURN;
c ← SteppyNamePartsCompare[n1.steps, n2.steps];
RETURN};
SteppyNameGradeCompare:
PUBLIC
PROC [g1, g2: SteppyNameGrade]
RETURNS [Basics.Comparison] ~ {
IF g1 = g2 THEN RETURN [equal];
RETURN [
SELECT
TRUE
FROM
g1.global<g2.global => greater,
g1.global>g2.global => less,
g1.gend<g2.gend => less,
g1.gend>g2.gend => greater,
g1.nonsubs<g2.nonsubs => less,
g1.nonsubs>g2.nonsubs => greater,
g1.subs<g2.subs => less,
g1.subs>g2.subs => greater,
ENDCASE => ERROR--they were equal!--];
};
SteppyNamePartsCompare:
PUBLIC
PROC [l1, l2: NameStepList]
RETURNS [c: Basics.Comparison] ~ {
WHILE l1#l2
DO
WITH l1.first
SELECT
FROM
x1:
REF
INT =>
WITH l2.first
SELECT
FROM
x2: REF INT => IF (c ← Basics.CompareInt[x1^, x2^]) # equal THEN RETURN;
x2: ROPE => RETURN [greater];
ENDCASE => ERROR;
x1:
ROPE =>
WITH l2.first
SELECT
FROM
x2: ROPE => IF (c ← x1.Compare[x2]) # equal THEN RETURN;
x2: REF INT => RETURN [less];
ENDCASE => ERROR;
ENDCASE => ERROR;
l1 ← l1.rest;
l2 ← l2.rest;
ENDLOOP;
RETURN [equal]};
SNCat:
PUBLIC
PROC [a, b: SteppyName]
RETURNS [SteppyName] ~ {
IF b=noName THEN RETURN [a];
IF a=noName THEN RETURN [b];
IF b.grade.nonsubs>0
THEN
RETURN [[
steps: List.Append[a.steps, b.steps],
grade: [
global: b.grade.global,
nonsubs: a.grade.nonsubs + b.grade.nonsubs,
gend: b.grade.gend,
subs: a.grade.subs + b.grade.subs]
]];
RETURN [[
steps: List.Append[a.steps, b.steps],
grade: [
global: a.grade.global,
nonsubs: a.grade.nonsubs,
gend: a.grade.gend,
subs: a.grade.subs + b.grade.subs]
]]};
SNPrepend:
PUBLIC
PROC [ns: NameStep, sn: SteppyName]
RETURNS [SteppyName] ~ {
ans: SteppyName ← [steps: CONS[ns, sn.steps], grade: sn.grade];
WITH ns
SELECT
FROM
x: ROPE => IF (ans.grade.nonsubs ← ans.grade.nonsubs+1) = 1 THEN [ans.grade.global, ans.grade.gend] ← Analast[x];
x: REF INT => ans.grade.subs ← ans.grade.subs+1;
ENDCASE => ERROR;
RETURN [ans]};
SNAppend:
PUBLIC
PROC [sn: SteppyName, ns: NameStep]
RETURNS [SteppyName] ~ {
ans: SteppyName ← [steps: List.Append[sn.steps, LIST[ns]], grade: sn.grade];
WITH ns
SELECT
FROM
x:
ROPE => {
ans.grade.nonsubs ← ans.grade.nonsubs+1;
[ans.grade.global, ans.grade.gend] ← Analast[x]};
x: REF INT => ans.grade.subs ← ans.grade.subs+1;
ENDCASE => ERROR;
RETURN [ans]};
LSn:
PUBLIC
PROC [l: NameStepList]
RETURNS [SteppyName]
~ {RETURN [[l, Grade[l]]]};
Grade:
PROC [steps: NameStepList]
RETURNS [grade: SteppyNameGrade ← [
FALSE, 0,
FALSE, 0]] ~ {
last: ROPE ← NIL;
FOR steps ← steps, steps.rest
WHILE steps#
NIL
DO
WITH steps.first
SELECT
FROM
x: ROPE => {grade.nonsubs ← grade.nonsubs+1; last ← x};
x: REF INT => grade.subs ← grade.subs+1;
ENDCASE => ERROR;
ENDLOOP;
IF last#NIL THEN [grade.global, grade.gend] ← Analast[last];
RETURN};
Analast:
PROC [last:
ROPE]
RETURNS [global, gend:
BOOL ←
FALSE] ~ {
xLen: INT ~ last.Length;
IF
NOT (global ← last.InlineFetch[xLen-1]='!)
THEN {
FOR i:
INT
DECREASING
IN [0 .. xLen)
DO
SELECT last.InlineFetch[i]
FROM
'#, '& => {gend ← TRUE; EXIT};
ENDCASE => NULL;
ENDLOOP;
};
RETURN};
listClass: PUBLIC Sets.SetClass ← Sets.CreateList[vals: NIL, space: steppyNameSpace, order: fwd].class;
CreateSteppyNames:
PUBLIC
PROC [names: SteppyNameList ←
NIL]
RETURNS [ListData] ~ {
set: Set ~ Sets.CreateList[vals: NIL, space: steppyNameSpace, order: fwd];
IF set.class#listClass THEN ERROR;
FOR names ← names, names.rest WHILE names#NIL DO [] ← set.AddElt[SnV[names.first]] ENDLOOP;
RETURN [[set.data.VA]]};
endOfQ: PUBLIC Vertex ← NEW [VertexPrivate.intermediate];
WireIndex:
PUBLIC
PROC [parent, child: Wire]
RETURNS [index:
INT] = {
index ← 0;
FOR x: Wire ← parent.firstChild, x.next WHILE x # child DO index ← index + 1 ENDLOOP;
RETURN};
SubWire:
PUBLIC
PROC [parent: Wire, index:
INT]
RETURNS [child: Wire] = {
FOR child ← parent.firstChild, child.next WHILE index > 0 DO index ← index - 1 ENDLOOP;
RETURN};
PortCCT:
PUBLIC
PROC [port: Port]
RETURNS [containingCT: CellType] = {
DO
WITH port.parent
SELECT
FROM
ct: CellType => RETURN [ct];
p: Port => port ← p;
ENDCASE => ERROR;
ENDLOOP;
};
PortIndex:
PUBLIC
PROC [child: Port]
RETURNS [index:
INT] = {
index ← 0;
FOR x: Port ← NARROW[child.parent, Port].firstChild, x.next WHILE x # child DO index ← index + 1 ENDLOOP;
RETURN};
SubPort:
PUBLIC
PROC [parent: Port, index:
INT]
RETURNS [child: Port] = {
FOR child ← parent.firstChild, child.next WHILE index > 0 DO index ← index - 1 ENDLOOP;
RETURN};
portToInternalWire: PUBLIC UWFunction ~ BiRels.FnFromProc[MapPortToInternalWire].AsUW;
MapPortToInternalWire:
PROC [data:
REF
ANY, v: Sets.Value]
RETURNS [Sets.MaybeValue] ~ {
port: Port ~ NARROW[v.VA];
RETURN [[port.wire#NIL, AV[port.wire]]];
};
EnsureAllIn:
PUBLIC
PROC [design: Design] = {
IF design.allKnown THEN RETURN;
design.allKnown ← TRUE;
EnumerateCellTypes[design, EnsurePrivate];
};
EnsurePublic:
PUBLIC
PROC [ct: CellType] = {
IF NOT ct.publicKnown THEN ERROR Error["Broken: Found cell type with undefined interface"];
IF ct.port = NIL THEN ERROR;
};
EnsurePrivate:
PUBLIC
PROC [ct: CellType] = {
IF
NOT ct.privateKnown
THEN {
ct.class.DefinePrivates[ct];
IF NOT ct.privateKnown THEN ERROR;
};
};
ExpansionKnown:
PUBLIC
PROC [ct: CellType]
RETURNS [known:
BOOL] = {
known ← ct.asUnorganized # NIL OR ct.asArray # NIL;
};
NoteChange:
PUBLIC
PROC [cellType: CellType] = {
NULL--er, we haven't yet figured out just what to do about the fact that cell types can change--;
};
AddPort:
PUBLIC
PROC [p: PortPrivate ← []]
RETURNS [port: Port] = {
port ← NEW [PortPrivate ← p];
WITH p.parent
SELECT
FROM
pp: Port => {
port.next ← NIL;
port.prev ← pp.lastChild;
pp.lastChild ← port;
IF port.prev # NIL THEN port.prev.next ← port ELSE pp.firstChild ← port;
IF port.PortCCT.inheritNames AND (port.names=NIL OR port.PortNames.Empty) AND port.wire#NIL THEN port.names ← [port.wire.VertexNames.Copy.data.VA];
};
ct: CellType => {
IF ct.port # NIL THEN ERROR;
ct.port ← port;
port.next ← port.prev ← NIL;
IF port.names=NIL THEN port.names ← CreateSteppyNames[];
[] ← KnowPortName[port, LSn[LIST[BeRope["PORTS"]]]];
};
ENDCASE => ERROR;
RETURN};
ActualName:
PROC [instanceName, portName: SteppyName]
RETURNS [actualName: SteppyName] ~ {
IF portName.grade.global THEN RETURN [portName];
actualName ← SNCat[instanceName, portName];
RETURN};
FullyAddPort:
PUBLIC
PROC [p: PortPrivate ← [], andReportConnectionTo: CellInstance ←
NIL]
RETURNS [port: Port, connection: Wire ←
NIL] = {
ct: CellType = PortCCT[port ← AddPort[p]];
portName: SteppyName ← noName;
FixInstance:
PROC [ci: CellInstance] = {
names: ListData ← noListData;
IF ci.containingCT.inheritNames
THEN {
IF portName=noName THEN portName ← SteppyDescribe[port, ct.port];
names ← CreateSteppyNames[LIST[ActualName[SteppyDescribe[ci, ci.containingCT], portName]]]};
{w: Wire = CreateWire[ci.containingCT, NIL, names];
AddEdge[[cellward: ci, wireward: w], port];
IF andReportConnectionTo = ci THEN connection ← w;
RETURN}};
FixArray: PROC [act: CellType] ~ {NoteNewEltPort[act.asArray, port]};
IF ct.asUnorganized #
NIL
THEN {
IF ct.asUnorganized.mirror = NIL THEN ERROR;
IF p.wire = NIL THEN ERROR;
AddEdge[[cellward: ct.asUnorganized.mirror, wireward: port.wire], port];
};
IF ct.asArray #
NIL
THEN {
NULL--we don't need to do anything--;
};
EnumerateInstances[ct, FixInstance, FALSE];
EnumerateArrays[ct, FixArray];
RETURN};
RemovePort:
PUBLIC
PROC [port: Port] = {
WITH port.parent
SELECT
FROM
pp: Port => {
IF port.next = NIL THEN pp.lastChild ← port.prev ELSE port.next.prev ← port.prev;
IF port.prev = NIL THEN pp.firstChild ← port.next ELSE port.prev.next ← port.next;
};
ct: CellType => {
ERROR --I don't think we ever really want to Remove the root port--;
};
ENDCASE => ERROR;
RETURN};
AddEdge:
PUBLIC
PROC [vs:
ARRAY GraphDirection
OF Vertex, port: Port] = {
e: Edge = NEW [EdgePrivate ← [port: port]];
FOR dir: GraphDirection IN GraphDirection DO e.sides[dir].v ← vs[dir] ENDLOOP;
FOR side: GraphDirection
IN GraphDirection
DO
LinkEdge[vs[side], e, side];
port ← port;
ENDLOOP;
RETURN};
LinkEdge:
PROC [v: Vertex, e: Edge, side: GraphDirection] = {
prev, next: Edge;
prevSide: GraphDirection;
SELECT side
FROM
--we have to choose position carefully to satisfy AI1
cellward => {
IF e.port.prev #
NIL
THEN {
prev ← FindImmediateEdge[v, e.port.prev, backward].e;
IF prev=NIL THEN ERROR--we only implement AddEdge in increasing port order--;
IF prev.sides[prevSide ← cellward].v#v THEN ERROR Error["Broken"];
}
ELSE IF v.firstEdge=NIL OR v.firstEdge.sides[cellward].v=v THEN prev ← NIL
ELSE {
FOR prev ← v.lastEdge, prev.sides[cellward].prev
UNTIL prev.sides[wireward].v=v
DO
IF prev.sides[cellward].v#v THEN ERROR Error["Broken"];
ENDLOOP;
prevSide ← wireward};
};
wireward => prev ← NIL;
ENDCASE => ERROR;
e.sides[side].next ← next ← IF prev # NIL THEN prev.sides[prevSide].next ELSE v.firstEdge;
e.sides[side].prev ← prev;
IF prev=NIL THEN v.firstEdge ← e ELSE prev.sides[prevSide].next ← e;
IF next=NIL THEN v.lastEdge ← e ELSE next.sides[next.SideFor[v]].prev ← e;
RETURN};
AddEdges:
PUBLIC
PROC [vs:
ARRAY GraphDirection
OF Vertex, port: Port] = {
rootPort: Port =
WITH vs[cellward]
SELECT
FROM
ci: CellInstance => ci.type.port,
im: Intermediary => im.port,
w: Wire => ERROR Error["Broken"],
ENDCASE => ERROR;
FindVertex:
PROC [port: Port]
RETURNS [v: Vertex] = {
cellward: Vertex;
IF port = rootPort THEN RETURN [vs[cellward]];
cellward ← FindVertex[NARROW[port.parent]];
v ← FindImmediateConnection[cellward, port];
IF v # NIL THEN RETURN;
{ccct: CellType ~ cellward.containingCT;
v ← CreateIntermediary[cellward, wireward, ccct, port, [IF ccct.inheritNames THEN port.PortNames.Copy.data.VA ELSE NIL]];
RETURN}};
immediatelyCellward: Vertex = FindVertex[NARROW[port.parent]];
AddEdge[[cellward: immediatelyCellward, wireward: vs[wireward]], port];
RETURN};
RemoveEdge:
PUBLIC
PROC [e: Edge] = {
e ← e;
FOR dir: GraphDirection
IN GraphDirection
DO
next: Edge ~ e.sides[dir].next;
prev: Edge ~ e.sides[dir].prev;
v: Vertex ~ e.sides[dir].v;
IF next#NIL THEN next.sides[SideFor[next, v]].prev ← prev ELSE v.lastEdge ← prev;
IF prev#NIL THEN prev.sides[SideFor[prev, v]].next ← next ELSE v.firstEdge ← next;
ENDLOOP;
RETURN};
RemoveEdges:
PUBLIC
PROC [e: Edge] = {
cellward: Vertex = e.sides[cellward].v;
RemoveEdge[e];
IF ISTYPE[cellward, Intermediary] AND (cellward.lastEdge = NIL OR cellward.lastEdge.sides[wireward].v = cellward--AI1 used here--) THEN DeleteVertex[cellward];
RETURN};
UnlinkPort:
PUBLIC
PROC [ci: CellInstance, port: Port] = {
RemoveEdge[FindImmediateEdge[ci, port].e]; RETURN};
UnlinkPorts:
PUBLIC
PROC [ci: CellInstance, ports: ConstSet
--of Port--] ~ {
n: NATURAL ~ ports.Size[].EN;
i: NATURAL ← 0;
Work:
PROC [port: Port, v: Vertex, e: Edge] ~ {
IF port=NIL THEN ERROR;
IF ports.HasMemA[port]
THEN {
RemoveEdges[e];
i ← i + 1;
IF i=n THEN Escape;
}
ELSE
SELECT v.class
FROM
cell => ERROR;
intermediate => EnumerateImmediateEdges[v, Work, [cellward: FALSE, wireward: TRUE]];
wire => NULL;
ENDCASE => ERROR;
RETURN};
EnumerateImmediateEdges[ci, Work !Escape => CONTINUE];
IF i#n THEN ERROR;
RETURN};
Instantiate:
PUBLIC
PROC [type, containingCT: CellType, names: ListData ← noListData, other: Assertions ←
NIL]
RETURNS [ci: CellInstance] = {
IF names=NIL THEN names ← CreateSteppyNames[];
ci ←
NEW [VertexPrivate.cell ← [
containingCT: containingCT,
names: names,
other: other,
variant: cell[
type: type,
nextInstance: NIL,
prevInstance: type.lastInstance]]];
type.lastInstance ← ci;
IF ci.prevInstance # NIL THEN ci.prevInstance.nextInstance ← ci ELSE ci.type.firstInstance ← ci;
type.useCount ← type.useCount + 1;
[] ← containingCT.asUnorganized.containedInstances.AddA[ci];
IndexVertexNames[ci];
RETURN};
PortForWire:
PUBLIC
PROC [ct: CellType, internal: Wire, ci: CellInstance, mayAdd:
BOOL]
RETURNS [port: Port, external: Wire] = {
See:
PROC [p: Port, v: Vertex] = {
IF IsMirror[NARROW[v]] THEN port ← p;
RETURN};
IF internal.containingCT # ct THEN ERROR;
internal.EnumerateTransitiveConnections[See];
IF port =
NIL
THEN {
IF mayAdd
THEN {
[port, external] ← FullyAddPort[
[parent: ct.port, wire: internal, names: CreateSteppyNames[IF ct.inheritNames THEN LIST[SteppyDescribe[internal, ct.asUnorganized.internalWire]] ELSE NIL]],
ci
];
};
}
ELSE IF ci # NIL THEN external ← NARROW[FindCellConnection[ci, port]];
RETURN};
FullyInstantiate:
PUBLIC
PROC [type, containingCT: CellType, names: ListData ← noListData, other: Assertions ←
NIL]
RETURNS [ci: CellInstance] ~ {
ci ← Instantiate[type, containingCT, names, other];
{instanceName: SteppyName ~ IF containingCT.inheritNames THEN SteppyDescribe[ci, ci.containingCT] ELSE noName;
FOR port: Port ← type.port.FirstChildPort[], port.NextChildPort[]
WHILE port #
NIL
DO
w: Wire = CreateWire[ci.containingCT, NIL, CreateSteppyNames[IF containingCT.inheritNames THEN LIST[ActualName[instanceName, SteppyDescribe[port, type.port]]] ELSE NIL]];
AddEdge[[cellward: ci, wireward: w], port];
ENDLOOP;
ci ← ci;
RETURN}};
CreateWire:
PUBLIC
PROC [containingCT: CellType, containingWire: Wire ←
NIL, names: ListData ← noListData, other: Assertions ←
NIL, copy: Wire ←
NIL]
RETURNS [w: Wire] = {
IF containingWire=NIL THEN containingWire ← containingCT.asUnorganized.internalWire;
IF names=NIL THEN names ← CreateSteppyNames[];
w ←
NEW [VertexPrivate.wire ← [
containingCT: containingCT,
names: names,
other: other,
variant: wire[
containingWire: containingWire,
next: NIL,
prev: IF containingWire#NIL THEN containingWire.lastChild ELSE NIL
]]];
IF w.containingWire=NIL THEN [] ← w.VertexNames.AddA[LIST[internalWireName]];
IF w.prev # NIL THEN w.prev.next ← w ELSE IF containingWire#NIL THEN containingWire.firstChild ← w;
IF containingWire#NIL THEN containingWire.lastChild ← w ELSE containingCT.asUnorganized.internalWire ← w;
IF copy # NIL THEN WireCopy[copy, w];
IndexVertexNames[w];
RETURN};
internalWireName: ROPE ~ "INTERNAL";
WireCopy:
PROC [from, to: Wire] = {
IF to.VertexNames.Empty THEN to.names ← [from.VertexNames.Copy.data.VA];
FOR child: Wire ← from.FirstChildWire[], child.NextChildWire[]
WHILE child #
NIL
DO
[] ← CreateWire[containingCT: to.containingCT, containingWire: to, copy: child];
ENDLOOP;
RETURN};
CreateIntermediary:
PUBLIC
PROC [from: Vertex, go: GraphDirection, containingCT: CellType, port: Port, names: ListData ← noListData, other: Assertions ←
NIL]
RETURNS [im: Intermediary] = {
vs: ARRAY GraphDirection OF Vertex ← ALL[from];
IF names=NIL THEN names ← CreateSteppyNames[];
vs[go] ← im ←
NEW [VertexPrivate.intermediate ← [
containingCT: containingCT,
names: names,
other: other,
variant: intermediate[port]]];
AddEdge[vs, port];
IndexVertexNames[im];
RETURN};
CreateCellType:
PUBLIC
PROC [design: Design, cellTypeName:
ROPE, class: CellClass, inheritNames, internals:
BOOL, otherPublic, otherPrivate: Assertions ←
NIL]
RETURNS [ct: CellType] = {
pbn: VarFunction = BiRels.CreateHashFn[[steppyNameSpace, SetBasics.refs]];
ct ←
NEW [CellTypePrivate ← [
class: class,
designs: Sets.CreateHashSet[],
inheritNames: inheritNames,
publicKnown: TRUE,
privateKnown: TRUE,
otherPublic: otherPublic,
otherPrivate: otherPrivate
]];
IF cellTypeName#NIL THEN ct.otherPublic ← Asserting.Assert1[nameReln, cellTypeName, ct.otherPublic];
[] ← AddPort[[parent: ct]];
IF internals
THEN {
iw: Wire;
ct.otherPrivate ← Asserting.AssertFn1[partsByNameKey, pbn.Refify, ct.otherPrivate];
ct.asUnorganized ←
NEW [UnorganizedPrivate ← [
containedInstances: Sets.CreateHashSet[]
]];
iw ← CreateWire[ct];
IF ct.asUnorganized.internalWire # iw THEN ERROR;
AddMirror[ct];
};
[] ← design.cellTypes.AddA[ct];
[] ← ct.designs.AddA[design];
RETURN};
CreateArray:
PUBLIC
PROC [design: Design, cellTypeName:
ROPE, class: CellClass, eltType: CellType, size2, basePeriod: Size2, inheritNames:
BOOL, otherPublic, otherPrivate: Assertions ←
NIL]
RETURNS [ct: CellType] = {
a: Array ~ CreateArrayRep[eltType, size2, basePeriod];
ct ← CreateCellType[design, cellTypeName, class, inheritNames, FALSE, otherPublic, otherPrivate];
ct.asArray ← a;
a.prevArray ← eltType.lastArray;
IF a.prevArray # NIL THEN a.prevArray.asArray.nextArray ← ct ELSE eltType.firstArray ← ct;
eltType.lastArray ← ct;
eltType.useCount ← eltType.useCount + 1;
};
DeleteVertex:
PUBLIC
PROC [v: Vertex] = {
ct: CellType = v.containingCT;
Killit:
PROC [p: Port, w: Vertex, e: Edge] = {
dir: GraphDirection ~ e.SideFor[w];
IF dir=cellward THEN RemoveEdges[e] ELSE RemoveEdge[e];
WITH w
SELECT
FROM
ci: CellInstance => NULL;
im: Intermediary => IF dir=wireward THEN DeleteVertex[w];
wire: Wire => NULL;
ENDCASE => ERROR;
};
UnindexVertexNames[v];
EnumerateImmediateEdges[v, Killit];
WITH v
SELECT
FROM
ci: CellInstance => {
IF ci.nextInstance # NIL THEN ci.nextInstance.prevInstance ← ci.prevInstance ELSE ci.type.lastInstance ← ci.prevInstance;
IF ci.prevInstance # NIL THEN ci.prevInstance.nextInstance ← ci.nextInstance ELSE ci.type.firstInstance ← ci.nextInstance;
IF NOT v.containingCT.asUnorganized.containedInstances.RemA[ci] THEN ERROR;
ci.type.useCount ← ci.type.useCount - 1;
};
im: Intermediary => NULL;
w: Wire => {
IF w.next # NIL THEN w.next.prev ← w.prev ELSE w.containingWire.lastChild ← w.prev;
IF w.prev # NIL THEN w.prev.next ← w.next ELSE w.containingWire.firstChild ← w.next;
};
ENDCASE => ERROR;
RETURN};
IsMirror:
PUBLIC
PROC [v: CellInstance]
RETURNS [isMirror:
BOOL] = {
isMirror ← v.type = v.containingCT;
};
AddMirror:
PUBLIC
PROC [lct: CellType] = {
CreateMirrorBinding:
PROC [port: Port, cellward: Vertex] = {
FOR subPort: Port ← port.firstChild, subPort.next
WHILE subPort #
NIL
DO
subVertex: Vertex;
IF subPort.wire #
NIL
THEN {
AddEdge[[cellward: cellward, wireward: subPort.wire], subPort]}
ELSE {
subVertex ← CreateIntermediary[cellward, wireward, lct, subPort, [IF lct.inheritNames THEN subPort.PortNames.Copy.data.VA ELSE NIL]];
CreateMirrorBinding[subPort, subVertex];
}
ENDLOOP;
};
v: CellInstance =
NEW [VertexPrivate.cell ← [
containingCT: lct,
names: CreateSteppyNames[LIST[LSn[LIST[BeRope["mirror"]]]]],
variant: cell[type: lct--AM2 says not to link it--]
]];
lct.asUnorganized.mirror ← v;
CreateMirrorBinding[lct.port, v];
};
VarRefSeqAppend:
PUBLIC
PROC [vrs: VarRefSeq, value:
REF
ANY] = {
IF vrs.length = vrs.refs.length
THEN {
oldRefs: RefSeq = vrs.refs;
vrs.refs ← CreateRefSeq[MAX[oldRefs.length*2, 1]];
FOR i:
INT
IN [0 .. oldRefs.length)
DO
vrs.refs[i] ← oldRefs[i];
ENDLOOP;
};
vrs.refs[vrs.length] ← value;
vrs.length ← vrs.length + 1;
};
Choose2:
PROC [n:
INT]
RETURNS [nChoose2:
INT] =
INLINE {
nChoose2 ← n*(n-1)/2};
PrintOnLog:
PUBLIC
PROC [ra:
REF
ANY] ~ {
OPEN LichenPrinting;
DO
ENABLE IO.Error => IF ec=StreamClosed THEN {log ← NIL; LOOP};
IF log = NIL THEN log ← ViewerIO.CreateViewerStreams["Lichen Debugging Log"].out;
{slog: IO.STREAM ~ SS.Create[UB.NewInittedHandle[[output: [stream[log]], margin: printWidth]]];
WITH ra
SELECT
FROM
x: Design => PrintDesign[slog, x];
x: CellType => PrintCellType[slog, x];
x: Port => PrintPort[slog, x];
x: Wire => PrintWire[slog, x];
x: CellInstance => PrintInstance[slog, x];
ENDCASE => ERROR;
slog.PutRope["\n"];
slog.Close[];
EXIT;
}ENDLOOP;
RETURN};
printWidth: INT ← 69;
Log:
PUBLIC
PROC [fmt:
ROPE, args:
LORA ←
NIL] = {
head, tail, this: LIST OF IO.Value ← NIL;
FOR args ← args, args.rest
WHILE args#
NIL
DO
this ←
WITH args.first
SELECT
FROM
x: Design => LIST[[rope[Describe[x]]]],
x: CellType => LIST[[rope[Describe[x]]]],
x: Vertex => LIST[[rope[Describe[x]]]],
x: Port => LIST[[rope[Describe[x]]]],
x: PortList => LIST[[rope[FmtPortList[x]]]],
x: ROPE => LIST[[rope[x]]],
x: StatEdge => LIST[[rope[FmtStatEdge[x]]]],
x: REF Time => LIST[[time[x^]]],
ENDCASE => LIST[[refAny[args.first]]];
IF tail=NIL THEN head ← this ELSE tail.rest ← this;
tail ← this;
ENDLOOP;
DO
ENABLE IO.Error => IF ec=StreamClosed THEN {log ← NIL; LOOP};
IF log = NIL THEN log ← ViewerIO.CreateViewerStreams["Lichen Debugging Log"].out;
log.PutFL[fmt, head];
EXIT;
ENDLOOP;
RETURN};
log: IO.STREAM ← NIL;
FmtPortList:
PROC [pl: PortList]
RETURNS [asRope:
ROPE] ~ {
asRope ← NIL;
FOR pl ← pl, pl.rest
WHILE pl#
NIL
DO
IF asRope#NIL THEN asRope ← asRope.Concat[", "];
asRope ← asRope.Concat[Describe[pl.first]];
ENDLOOP;
asRope ← Rope.Cat["{", asRope, "}"];
RETURN};
NewInt:
PUBLIC
PROC [i:
INT]
RETURNS [
REF
INT] ~ {
IF i IN [0 .. 64] THEN RETURN [intRefs[i]];
RETURN [NEW [INT ← i]]};
IntRefArray: TYPE ~ ARRAY [0 .. 64] OF REF INT;
intRefs: REF IntRefArray ~ NEW [IntRefArray ← ALL[NIL]];
Start:
PROC ~ {
FOR i: INT IN [0 .. 64] DO intRefs[i] ← NEW [INT ← i] ENDLOOP;
RETURN};
Start[];
END.