LichenDataImpl: 
CEDAR 
PROGRAM
IMPORTS AMBridge, Asserting, Convert, HashTable, InterpreterOps, IntHashTable, IO, LichenDataStructure, LichenSetTheory, Rope, StructuredStreams, UnparserBuffer, ViewerIO
EXPORTS LichenDataStructure, LichenDataOps =
BEGIN OPEN LichenSetTheory, LichenDataStructure, 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;
step: ROPE = ".";
partsByNameKey: PUBLIC ATOM ← $LichenNameToPart;
DimName: ARRAY Dim OF ROPE = [Foo: "Foo", Bar: "Bar"];
Describe: 
PUBLIC 
PROC [subject: 
REF 
ANY, relativeTo: 
REF 
ANY ← 
NIL, nameGen: NameGenerator ← 
NIL] 
RETURNS [name: 
ROPE] = {
GetShort: 
PROC [oldAssns: Assertions] 
RETURNS [newAssns: Assertions, name: 
ROPE] = {
name ← NARROW[Asserting.FnVal[nameReln, newAssns ← oldAssns]];
IF name = 
NIL 
THEN {
name ← nameGen.GenerateName[nameGen.data, subject];
newAssns ← Asserting.Assert[nameReln, LIST[name], newAssns];
};
 
};
 
IF nameGen = NIL THEN nameGen ← defaultNameGen;
IF subject = relativeTo 
THEN name ← 
NIL 
ELSE 
WITH subject 
SELECT 
FROM
d: Design => {
short: ROPE;
[d.other, short] ← GetShort[d.other];
name ← short;
};
ct: CellType => {
short: ROPE;
[ct.otherPublic, short] ← GetShort[ct.otherPublic];
name ← IF ct.designs.HasMember[relativeTo] OR ct.designs.Size[]=0 THEN short ELSE Describe[GetADesign[ct], relativeTo, nameGen].Cat[step, short];
};
v: Vertex => {
short: ROPE;
parent: REF ANY;
[v.other, short] ← GetShort[v.other];
WITH v 
SELECT 
FROM
ci: CellInstance => parent ← v.containingCT;
im: Intermediary => parent ← ImParent[im];
w: Wire => parent ← WireContainer[w];
ENDCASE => ERROR;
 
name ← IF relativeTo = parent OR parent = NIL THEN short ELSE Describe[parent, relativeTo, nameGen].Cat[step, short];
};
port: Port => {
short: ROPE;
parent: REF ANY = port.parent;
[port.other, short] ← GetShort[port.other];
name ← IF relativeTo = parent OR parent = NIL THEN short ELSE Describe[parent, relativeTo, nameGen].Cat[step, short];
};
ENDCASE => ERROR;
 
};
 
GetADesign: 
PROC [ct: CellType] 
RETURNS [d: Design] = {
See: PROC [ra: REF ANY] = {d ← NARROW[ra]};
IF ct.designs.Size[]  = 0 THEN RETURN [NIL];
ct.designs.Enumerate[See];
};
 
WireContainer: 
PROC [w: Wire] 
RETURNS [container: 
REF 
ANY] = {
container ← 
SELECT w.containingWire 
FROM
NIL => w.containingCT,
ENDCASE => w.containingWire;
};
 
defaultNameGen: NameGenerator = 
NEW [NameGeneratorPrivate ← [
GenerateBlandName,
NEW [NameCountsPrivate ← []]
]];
NameCounts: TYPE = REF NameCountsPrivate;
NameCountsPrivate: 
TYPE = 
RECORD [
design, cellType, port, vertex: INT ← 0
];
GenerateBlandName: 
PROC [data, subject: 
REF 
ANY] 
RETURNS [name: 
ROPE] = {
nc: NameCounts = NARROW[data];
name ← GenByCount[nc, subject];
};
 
TVNameGenerator: TYPE = REF TVNameGeneratorPrivate;
TVNameGeneratorPrivate: 
TYPE = 
RECORD [
nc: NameCounts,
symTab: SymTab.Ref
];
MakeTVNameGen: 
PROC [symTab: SymTab.Ref] 
RETURNS [ng: NameGenerator] = {
ng ← 
NEW [NameGeneratorPrivate ← [
GenerateTVName,
NEW [TVNameGeneratorPrivate ← [
nc: NEW [NameCountsPrivate ← []],
symTab: symTab
]]
 
]];
};
 
GenerateTVName: 
PROC [data, subject: 
REF 
ANY] 
RETURNS [name: 
ROPE] = {
tvng: TVNameGenerator = NARROW[data];
name ← Rope.Concat["&", GenByCount[tvng.nc, subject]];
TRUSTED {InterpreterOps.RegisterTV[
name: name,
tv: AMBridge.TVForReferent[
WITH subject 
SELECT 
FROM
d: Design => NEW [Design ← d],
ct: CellType => NEW [CellType ← ct],
p: Port => NEW [Port ← p],
v: Vertex => NEW [Vertex ← v],
ENDCASE => ERROR],
symTab: tvng.symTab]};
 
};
 
GenByCount: 
PROC [nc: NameCounts, subject: 
REF 
ANY] 
RETURNS [name: 
ROPE] = {
n: INT ← 0;
WITH subject 
SELECT 
FROM
d: Design => {n ← nc.design ← nc.design + 1; name ← "D"};
ct: CellType => {n ← nc.cellType ← nc.cellType + 1; name ← "CT"};
p: Port => {n ← nc.port ← nc.port + 1; name ← "P"};
v: Vertex => {n ← nc.vertex ← nc.vertex + 1; name ← "V"};
ENDCASE => ERROR;
 
name ← name.Concat[Convert.RopeFromInt[n]];
};
 
PrintObject: 
PROC [to: 
IO.
STREAM, united: 
BOOL, 
PrintIt: 
PROC] = {
SS.Bp[to, united, printStep];
SS.Begin[to];
PrintIt[!UNWIND => SS.End[to]];
SS.End[to];
};
 
printStep: INT ← 3;
PrintDesign: 
PROC [to: 
IO.
STREAM, design: Design, nameGen: NameGenerator] = {
CTPrint: 
PROC [ra: 
REF 
ANY] = {
ct: CellType = NARROW[ra];
Inner: PROC = {PrintCellType[to, ct, nameGen]};
PrintObject[to, TRUE, Inner];
};
 
IF NOT SS.IsAnSS[to] THEN to ← SS.Create[UB.NewHandle[[stream[to]], 60]];
to.PutF["%g: Design {", [rope[Describe[design, NIL, nameGen]]]];
design.cellTypes.Enumerate[CTPrint];
to.PutF["}"];
};
 
PrintCellType: 
PROC [to: 
IO.
STREAM, ct: CellType, nameGen: NameGenerator] = {
Main: 
PROC = {
to.PutF["%g: CellType[", [rope[Describe[ct, GetADesign[ct], nameGen]]]];
PrintObject[to, TRUE, PortPrint];
IF ct.asUnorganized # 
NIL 
THEN {
to.PutRope[", "]; PrintObject[to, TRUE, IWPrint];
to.PutRope[", "]; PrintObject[to, TRUE, CIPrint];
};
 
IF ct.asArray # 
NIL 
THEN {
to.PutRope[", "]; PrintObject[to, TRUE, AyPrint];
};
 
to.PutRope["]"];
};
 
PortPrint: 
PROC = {
to.PutF["port: "];
PrintPort[to, ct.port, nameGen];
};
 
IWPrint: 
PROC = {
to.PutF["internal wire: "];
PrintWire[to, ct.asUnorganized.internalWire, nameGen];
};
 
CIPrint: 
PROC = {
to.PutF["contained instances: "];
PrintInstances[to, ct.asUnorganized.containedInstances, ct.asUnorganized.mirror, nameGen];
};
 
AyPrint: 
PROC = {
to.PutRope["asArray: "];
PrintArray[to, ct, nameGen]
};
 
IF NOT SS.IsAnSS[to] THEN to ← SS.Create[UB.NewHandle[[stream[to]], 60]];
--PrintObject[to, TRUE, Main]--Main[];
};
 
PrintPort: 
PROC [to: 
IO.
STREAM, port: Port, nameGen: NameGenerator] = {
first: BOOL ← TRUE;
to.PutRope[Describe[port, port.parent, nameGen]];
IF port.FirstChildPort[] = NIL THEN RETURN;
to.PutRope["["];
FOR subPort: Port ← port.FirstChildPort[], subPort.NextChildPort[] 
WHILE subPort # 
NIL 
DO
PortPrint: PROC = {PrintPort[to, subPort, nameGen]};
IF first THEN first ← FALSE ELSE to.PutRope[", "];
PrintObject[to, FALSE, PortPrint];
ENDLOOP;
 
to.PutRope["]"];
};
 
PrintWire: 
PROC [to: 
IO.
STREAM, wire: Wire, nameGen: NameGenerator] = {
first: BOOL ← TRUE;
to.PutRope[Describe[wire, WireContainer[wire], nameGen]];
IF wire.FirstChildWire[] = NIL THEN RETURN;
to.PutRope["["];
FOR subWire: Wire ← wire.FirstChildWire[], subWire.NextChildWire[] 
WHILE subWire # 
NIL 
DO
WirePrint: PROC = {PrintWire[to, subWire, nameGen]};
IF first THEN first ← FALSE ELSE to.PutRope[", "];
PrintObject[to, FALSE, WirePrint];
ENDLOOP;
 
to.PutRope["]"];
};
 
PrintInstances: 
PROC [to: 
IO.
STREAM, set: Set
--OF CellInstance--, mirror: CellInstance, nameGen: NameGenerator] = {
first: BOOL ← TRUE;
PrintIt: 
PROC [ra: 
REF 
ANY] = {
ci: CellInstance = NARROW[ra];
IPrint: PROC = {PrintInstance[to, ci, nameGen]};
IF first THEN first ← FALSE ELSE to.PutRope[", "];
PrintObject[to, TRUE, IPrint];
};
 
to.PutRope["["];
set.Enumerate[PrintIt];
PrintIt[mirror];
to.PutRope["]"];
};
 
PrintInstance: 
PROC [to: 
IO.
STREAM, ci: CellInstance, nameGen: NameGenerator] = {
PrintConnections: 
PROC [v: Vertex] = {
first: BOOL ← TRUE;
PrintConnection: 
PROC [port: Port, w: Vertex] = {
CPrint: 
PROC = {
to.PutF["%g: ", [rope[Describe[port, port.parent, nameGen]]]];
WITH w 
SELECT 
FROM
im: Intermediary => {
PrintConnections[im];
};
wire: Wire => {
to.PutRope[Describe[wire, WireContainer[wire], nameGen]];
};
ci: CellInstance => ERROR;
ENDCASE => ERROR;
 
};
 
IF first THEN first ← FALSE ELSE to.PutRope[", "];
PrintObject[to, FALSE, CPrint];
};
 
to.PutRope["["];
EnumerateImmediateConnections[v, PrintConnection, [cellward: FALSE, wireward: TRUE]];
to.PutRope["]"];
};
 
to.PutF["%g: %g", [rope[Describe[ci, ci.containingCT, nameGen]]], [rope[Describe[ci.type, GetADesign[ci.type], nameGen]]] ];
PrintConnections[ci];
};
 
PrintArray: 
PROC [to: 
IO.
STREAM, ct: CellType, nameGen: NameGenerator] = {
a: Array = ct.asArray;
to.PutF["{%g BY %g OF %g (joints period is %g by %g)",
[integer[a.size[Foo]]], [integer[a.size[Bar]]],
[rope[Describe[a.eltType, GetADesign[ct], nameGen]]],
[integer[a.jointsPeriod[Foo]]], [integer[a.jointsPeriod[Bar]]]
];
FOR d: Dim 
IN Dim 
DO
PrintJoints: 
PROC = {
first: BOOL ← TRUE;
to.PutF[", joints[%g] = [", [rope[DimName[d]]]];
FOR 
f
f: 
INT 
IN [0 .. a.jointsPeriod[Foo]) 
DO
FOR 
f
b: 
INT 
IN [0 .. a.jointsPeriod[Bar]) 
DO
JPrint: 
PROC = {
to.PutF["[%g,%g]: ", [integer[ff]], [integer[fb]]];
PrintJoint[to, ct, GetArrayJoint[a, d, [ff, fb]], nameGen];
};
 
IF first THEN first ← FALSE ELSE to.PutRope[", "];
PrintObject[to, TRUE, JPrint];
ENDLOOP;
 
ENDLOOP;
 
to.PutRope["]"];
};
 
PrintObject[to, TRUE, PrintJoints];
ENDLOOP;
 
to.PutRope["}"];
};
 
PrintJoint: 
PROC [to: 
IO.
STREAM, act: CellType, j: Joint, nameGen: NameGenerator] = {
first: BOOL ← TRUE;
PerPair: 
PROC [key, value: 
REF 
ANY] 
RETURNS [stop: 
BOOL ← 
FALSE] 
--HashTable.EachPairAction-- = {
lowPort: Port = NARROW[key];
highPort: Port = NARROW[value];
PPrint: 
PROC = {
inc: Incompleteness = IF j.lowToIncompleteness # NIL THEN NARROW[j.lowToIncompleteness.Fetch[key].value] ELSE NIL;
to.PutRope[Describe[lowPort, act, nameGen]];
to.PutRope["—"];
to.PutRope[Describe[highPort, act, nameGen]];
IF inc # NIL THEN to.PutF["(%g/%g incomplete)", [integer[inc.nIncomplete]], [integer[inc.length]]];
};
 
IF first THEN first ← FALSE ELSE to.PutRope[", "];
PrintObject[to, TRUE, PPrint];
};
 
to.PutRope["["];
[] ← j.lowToHigh.Pairs[PerPair];
to.PutRope["]"];
};
 
EnumerateCellTypes: 
PUBLIC 
PROC [design: Design, 
Consume: 
PROC [CellType]] = {
PerCellType: PROC [elt: REF ANY] = {Consume[NARROW[elt]]};
design.cellTypes.Enumerate[PerCellType]};
 
endOfQ: PUBLIC Vertex ← NEW [VertexPrivate.intermediate];
EnumerateImmediateEdges: 
PUBLIC 
PROC [v: Vertex, 
Consume: 
PROC [Port, Vertex, Edge], filter: 
ARRAY GraphDirection 
OF 
BOOL ← 
ALL[
TRUE], order: Order ← any] = {
nextEdge: Edge ← 
SELECT order 
FROM 
--these depend on AI1
forward, any => v.firstEdge,
backward => v.lastEdge,
ENDCASE => ERROR;
FOR e: Edge ← nextEdge, nextEdge 
WHILE e # 
NIL 
DO
selfward: GraphDirection = 
SELECT v.class 
FROM
cell => cellward,
wire => wireward,
intermediate => 
SELECT v 
FROM
e.sides[wireward].v => wireward,
e.sides[cellward].v => cellward,
ENDCASE => ERROR,
ENDCASE => ERROR;
away: GraphDirection = OppositeDirection[selfward];
w: Vertex = e.sides[away].v;
IF v # e.sides[selfward].v THEN ERROR;
IF v.class # intermediate AND v.class = w.class THEN ERROR Error["Broken"];
nextEdge ← 
SELECT order 
FROM 
--these depend on AI1
forward, any => e.sides[selfward].next,
backward => e.sides[selfward].prev,
ENDCASE => ERROR;
IF filter[away] THEN Consume[e.port, w, e];
ENDLOOP;
 
};
 
EnumerateImmediateConnections: 
PUBLIC 
PROC [v: Vertex, 
Consume: 
PROC [Port, Vertex], filter: 
ARRAY GraphDirection 
OF 
BOOL ← 
ALL[
TRUE], order: Order ← any] = {
Filter: PROC [port: Port, w: Vertex, e: Edge] = {Consume[port, w]};
EnumerateImmediateEdges[v, Filter, filter, order];
};
 
EnumerateNeighboringVertices: 
PUBLIC 
PROC [v: Vertex, 
Consume: 
PROC [Vertex], filter: 
ARRAY GraphDirection 
OF 
BOOL ← 
ALL[
TRUE]] = {
Filter: PROC [port: Port, w: Vertex, e: Edge] = {Consume[w]};
EnumerateImmediateEdges[v, Filter, filter];
};
 
EnumerateTransitiveConnections: 
PUBLIC 
PROC [v: Vertex, 
Consume: 
PROC [Port, Vertex]] = {
WITH v 
SELECT 
FROM
wire: Wire => {
WireWork: 
PROC [wire: Wire, 
Consume: 
PROC [Port, Vertex]] = {
CellStart: 
PROC [port: Port, w: Vertex] = {
WITH w 
SELECT 
FROM
ci: CellInstance => Consume[port, ci];
im: Intermediary => {
CellFinish: 
PROC [parent: Port, u: Vertex] = {
WITH u 
SELECT 
FROM
ci: CellInstance => Consume[port, ci];
im: Intermediary => EnumerateImmediateConnections[im, CellFinish, [cellward: TRUE, wireward: FALSE]];
wire: Wire => ERROR;
ENDCASE => ERROR;
 
};
 
EnumerateImmediateConnections[im, CellFinish, [cellward: TRUE, wireward: FALSE]];
};
wire: Wire => ERROR;
ENDCASE => ERROR;
 
};
 
EnumerateImmediateConnections[wire, CellStart];
IF wire.containingWire # 
NIL 
THEN {
index: INT = WireIndex[wire.containingWire, wire];
Filter: 
PROC [parent: Port, w: Vertex] = {
port: Port = SubPort[parent, index];
Consume[port, w]};
 
WireWork[wire.containingWire, Filter];
};
 
};
 
WireWork[wire, Consume];
};
im: Intermediary => ERROR;
ci: CellInstance => {
Elaborate: PROC [port: Port, wire: Wire] = {EnumeratePortAndWire[port, wire, Consume]};
EnumerateTopConnections[ci, Elaborate];
};
ENDCASE => ERROR;
 
};
 
EnumerateTopEdges: 
PUBLIC 
PROC [ci: CellInstance, 
Consume: 
PROC [Port, Wire, Edge]]= {
Work: 
PROC [port: Port, v: Vertex, e: Edge] = {
WITH v 
SELECT 
FROM
wire: Wire => Consume[port, wire, e];
im: Intermediary => EnumerateImmediateEdges[im, Work, [cellward: FALSE, wireward: TRUE]];
ci: CellInstance => ERROR;
ENDCASE => ERROR;
 
};
 
EnumerateImmediateEdges[ci, Work];
};
 
EnumerateTopConnections: 
PUBLIC 
PROC [ci: CellInstance, 
Consume: 
PROC [Port, Wire]]= {
Filter: PROC [port: Port, w: Wire, e: Edge] = {Consume[port, w]};
EnumerateTopEdges[ci, Filter];
};
 
FindImmediateConnection: 
PUBLIC 
PROC [cellward: Vertex, port: Port, hint: Order ← any] 
RETURNS [w: Vertex] = {
w ← FindImmediateEdge[cellward, port, hint].w;
};
 
FindImmediateEdge: 
PUBLIC 
PROC [cellward: Vertex, port: Port, hint: Order ← any] 
RETURNS [w: Vertex, e: Edge] = {
ENABLE Escape => CONTINUE;
Consume: 
PROC [tp: Port, tw: Vertex, te: Edge] = {
IF tp = port THEN {w ← tw; e ← te; Escape};
};
 
EnumerateImmediateEdges[cellward, Consume, [cellward: FALSE, wireward: TRUE], hint];
ERROR--not found--;
};
Escape: ERROR = CODE;
 
FindTransitiveConnection: 
PUBLIC 
PROC [cellward: Vertex, port: Port] 
RETURNS [w: Wire] = {
ENABLE Escape => CONTINUE;
Tryit: 
PROC [p: Port, v: Vertex] = {
IF port = p THEN {w ← NARROW[v]; Escape};
};
 
EnumerateTransitiveConnections[cellward, Tryit];
ERROR--not found--;
};
 
ImParent: 
PUBLIC 
PROC [im: Intermediary] 
RETURNS [v: Vertex] = {
See: PROC [w: Vertex] = {v ← w};
EnumerateNeighboringVertices[im, See, [cellward: TRUE, wireward: FALSE]];
};
 
notPorted: PUBLIC Porting ← NEW [ROPE ← "not ported"];
unknownPorting: PUBLIC Porting ← NEW [ROPE ← "unknown porting"];
GetArrayPort: 
PUBLIC 
PROC [a: Array, index: ArrayIndex, ep: Port] 
RETURNS [arrayPort: Port] = {
Get: PROC [pp: PortPtr] = TRUSTED {arrayPort ← IF pp # NIL THEN pp^ ELSE NIL};
ForArrayPort[a, index, ep, Get, FALSE]};
 
SetArrayPort: 
PUBLIC 
PROC [a: Array, index: ArrayIndex, ep, ap: Port] = {
Set: PROC [pp: PortPtr] = TRUSTED {IF pp # NIL THEN pp^ ← ap ELSE ERROR};
wF: Where = WhereIs[index[Foo], [0, a.size[Foo]]];
wB: Where = WhereIs[index[Bar], [0, a.size[Bar]]];
apc: ArrayPortConnections ← NARROW[a.portConnections.Fetch[ap].value];
ForArrayPort[a, index, ep, Set, TRUE];
IF apc = 
NIL 
THEN {
apc ← NEW [ArrayPortConnectionsPrivate ← ALL[ALL[NIL]]];
FOR e: End 
IN End 
DO 
FOR d: Dim 
IN Dim 
DO
apc[e][d] ← CreateIntTable[];
ENDLOOP ENDLOOP;
 
[] ← a.portConnections.Store[ap, apc];
};
 
FOR d: Dim 
IN Dim 
DO
id: INT = index[d];
wd: Where = WhereIs[id, [0, a.size[d]]];
WITH e
d: wd 
SELECT 
FROM
end => [] ← apc[ed.end][d].Store[index[OtherDim[d]], ep];
center => NULL;
ENDCASE => ERROR;
 
ENDLOOP;
 
};
 
PortPtr: TYPE = LONG POINTER TO Port;
ForArrayPort: 
PROC [a: Array, index: ArrayIndex, ep: Port, 
Consume: 
PROC [pp: PortPtr], mayCreate: 
BOOL] = 
TRUSTED {
p: Porting = a.porting.Fetch[ep].value;
dp: DetailedPorting;
SELECT p 
FROM
notPorted => {
IF 
NOT mayCreate 
THEN {
Consume[NIL];
RETURN}
 
ELSE {
xyz: NAT = (MAX[a.size[Foo]-2, 0] + MAX[a.size[Bar]-2, 0]) * 2;
firstSlot: INT ← 0;
dp ← NEW [DetailedPortingRep[xyz]];
dp.corners ← ALL[ALL[NIL]];
FOR e: End 
IN End 
DO 
FOR d: Dim 
IN Dim 
DO
dp.sideIndices[e][d] ← [FALSE, firstSlot];
firstSlot ← firstSlot + MAX[a.size[OtherDim[d]]-2, 0];
ENDLOOP ENDLOOP;
 
FOR i: INT IN [0 .. dp.length) DO dp[i] ← NIL ENDLOOP;
[] ← a.porting.Store[ep, dp];
};
 
};
unknownPorting => ERROR;
ENDCASE => dp ← NARROW[p];
 
{
For: 
PROC [si: SideIndex, offset: 
NAT] = 
TRUSTED {
s: NAT ← si.firstSlot;
IF NOT si.same THEN s ← s + offset;
Consume[@dp.slots[s]]};
 
wF: Where = WhereIs[index[Foo], [0, a.size[Foo]]];
wB: Where = WhereIs[index[Bar], [0, a.size[Bar]]];
WITH f: wF 
SELECT 
FROM
end => 
WITH b: wB 
SELECT 
FROM
end => Consume[@dp.corners[f.end][b.end]];
center => For[dp.sideIndices[f.end][Bar], b.offset];
ENDCASE => ERROR;
center => 
WITH b: wB 
SELECT 
FROM
end => For[dp.sideIndices[b.end][Foo], f.offset];
center => ERROR;
ENDCASE => ERROR;
ENDCASE => ERROR;
 
};
};
 
Where: 
TYPE = 
RECORD [
variant: 
SELECT kind: * 
FROM
end => [end: End],
center => [offset: NAT],
ENDCASE];
WhereIs: 
PROC [i: 
INT, r: Range] 
RETURNS [w: Where] = {
i ← r.min + ((i - r.min) MOD (r.maxPlusOne - r.min));
SELECT 
TRUE 
FROM
i = r.min => RETURN [[end[low]]];
i+1 = r.maxPlusOne => RETURN [[end[high]]];
ENDCASE => RETURN [[center[i - (r.min+1)]]];
 
};
 
EnumeratePorts: 
PUBLIC 
PROC [cellType: CellType, 
Consume: 
PROC [Port]] = {
Work: 
PROC [port: Port, wire: Wire, wired: 
BOOL] = {
subPort: Port ← port.firstChild;
subWire: Wire ← IF wired THEN wire.firstChild ELSE NIL;
IF port.wire # wire THEN ERROR Error["Broken"];
Consume[port];
WHILE subPort # 
NIL 
DO
IF NOT wired THEN subWire ← subPort.wire ELSE IF subWire = NIL THEN ERROR Error["Broken"];
Work[subPort, subWire, subWire # NIL];
subPort ← subPort.next;
IF wired THEN subWire ← subWire.next;
ENDLOOP;
 
IF wired AND subWire # NIL THEN ERROR Error["Broken"];
};
 
Work[cellType.port, cellType.port.wire, cellType.port.wire # NIL];
IF cellType.port.next # NIL THEN ERROR Error["Broken"];
};
 
EnumerateInstances: 
PUBLIC 
PROC [cellType: CellType, 
Consume: 
PROC [CellInstance]] = {
FOR ci: CellInstance ← cellType.firstInstance, ci.nextInstance 
WHILE ci # 
NIL 
DO
Consume[ci];
ENDLOOP;
 
};
 
EnumerateArrays: 
PUBLIC 
PROC [cellType: CellType, 
Consume: 
PROC [CellType]] = {
FOR act: CellType ← cellType.firstArray, act.asArray.nextArray 
WHILE act # 
NIL 
DO
Consume[act];
ENDLOOP;
 
};
 
EnumeratePortAndWire: 
PUBLIC 
PROC [port: Port, wire: Wire, 
Consume: 
PROC [Port, Wire]] = {
Consume[port, wire];
port ← port.firstChild;
wire ← wire.firstChild;
WHILE port # 
NIL 
AND wire # 
NIL 
DO
EnumeratePortAndWire[port, wire, Consume];
port ← port.next;
wire ← wire.next;
ENDLOOP;
 
IF port # NIL OR wire # NIL THEN ERROR Error["Broken"];
};
 
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;
index ← index;
};
 
SubWire: 
PUBLIC 
PROC [parent: Wire, index: 
INT] 
RETURNS [child: Wire] = {
FOR child ← parent.firstChild, child.next WHILE index > 0 DO index ← index - 1 ENDLOOP;
};
 
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 [parent, child: Port] 
RETURNS [index: 
INT] = {
index ← 0;
FOR x: Port ← parent.firstChild, x.next WHILE x # child DO index ← index + 1 ENDLOOP;
index ← index;
};
 
SubPort: 
PUBLIC 
PROC [parent: Port, index: 
INT] 
RETURNS [child: Port] = {
FOR child ← parent.firstChild, child.next WHILE index > 0 DO index ← index - 1 ENDLOOP;
};
 
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;
};
ct: CellType => {
IF ct.port # NIL THEN ERROR;
ct.port ← port;
port.next ← port.prev ← NIL;
port.other ← Asserting.Assert[nameReln, LIST[R["PORTS"]], port.other];
};
ENDCASE => ERROR;
 
};
 
R: PROC [r: ROPE] RETURNS [r2: ROPE] = INLINE {r2 ← r}--stupid goddam anachronism--;
FullyAddPort: 
PUBLIC 
PROC [p: PortPrivate ← [], andReportConnectionTo: CellInstance ← 
NIL] 
RETURNS [port: Port, connection: Wire ← 
NIL] = {
ct: CellType = PortCCT[port ← AddPort[p]];
portName: ROPE = Describe[port, ct.port];
FixInstance: 
PROC [ci: CellInstance] = {
instanceName: ROPE = Describe[ci, ci.containingCT].Cat["/", portName];
w: Wire = CreateWire[ci.containingCT, NIL, Asserting.Assert[nameReln, LIST[instanceName], NIL]];
AddEdge[[cellward: ci, wireward: w], port];
IF andReportConnectionTo = ci THEN connection ← w;
};
 
FixArray: 
PROC [act: CellType] = {
a: Array = act.asArray;
[] ← a.porting.Store[port, notPorted];
};
 
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 {
apc: ArrayPortConnections = NEW [ArrayPortConnectionsPrivate];
FOR e: End 
IN End 
DO 
FOR d: Dim 
IN Dim 
DO
apc[e][d] ← CreateIntTable[];
ENDLOOP ENDLOOP;
 
[] ← ct.asArray.portConnections.Store[port, apc];
};
 
EnumerateInstances[ct, FixInstance];
EnumerateArrays[ct, FixArray];
};
 
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;
 
};
 
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];
ENDLOOP;
 
};
 
LinkEdge: 
PROC [v: Vertex, e: Edge, side: GraphDirection] = {
prev, next: Edge;
SELECT side 
FROM
cellward => {
prev ← IF e.port.prev # NIL THEN FindImmediateEdge[v, e.port.prev, backward].e ELSE v.lastEdge;
};
wireward => prev ← v.lastEdge;
ENDCASE => ERROR;
 
e.sides[side].next ← next ← IF prev # NIL THEN prev.sides[side].next ELSE NIL;
e.sides[side].prev ← prev;
IF prev = NIL THEN v.firstEdge ← e ELSE prev.sides[side].next ← e;
IF next = NIL THEN v.lastEdge ← e ELSE next.sides[side].prev ← e;
};
 
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;
v ← CreateIntermediary[cellward, wireward, cellward.containingCT, port];
};
 
immediatelyCellward: Vertex = FindVertex[NARROW[port.parent]];
AddEdge[[cellward: immediatelyCellward, wireward: vs[wireward]], port];
};
 
RemoveEdge: 
PUBLIC 
PROC [e: Edge] = {
FOR dir: GraphDirection 
IN GraphDirection 
DO
[e.sides[dir].v.firstEdge, e.sides[dir].v.lastEdge] ← UnlinkEdge[e.sides[dir].v.firstEdge, e.sides[dir].v.lastEdge, e, dir];
ENDLOOP;
 
};
 
UnlinkEdge: 
PROC [head, tail, e: Edge, dir: GraphDirection] 
RETURNS [newHead, newTail: Edge] = {
newHead ← head; newTail ← tail;
IF e.sides[dir].next # NIL THEN e.sides[dir].next.sides[dir].prev ← e.sides[dir].prev ELSE newTail ← e.sides[dir].prev;
IF e.sides[dir].prev # NIL THEN e.sides[dir].prev.sides[dir].next ← e.sides[dir].next ELSE newHead ← e.sides[dir].next;
};
 
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 RemoveEdges[cellward.firstEdge--AI1 used here--];
};
 
UnlinkPort: 
PUBLIC 
PROC [ci: CellInstance, port: Port] = {
RemoveEdge[FindImmediateEdge[ci, port].e]};
 
Instantiate: 
PUBLIC 
PROC [type, containingCT: CellType, other: Assertions ← 
NIL] 
RETURNS [ci: CellInstance] = {
ci ← 
NEW [VertexPrivate.cell ← [
containingCT: containingCT,
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.UnionSingleton[ci];
NoteNewPart[ci];
};
 
CreateWire: 
PUBLIC 
PROC [containingCT: CellType, containingWire: Wire ← 
NIL, other: Assertions ← 
NIL, copy: Wire ← 
NIL] 
RETURNS [w: Wire] = {
IF containingWire = NIL THEN containingWire ← containingCT.asUnorganized.internalWire;
w ← 
NEW [VertexPrivate.wire ← [
containingCT: containingCT,
other: other,
variant: wire[
containingWire: containingWire,
next: NIL,
prev: IF containingWire#NIL THEN containingWire.lastChild ELSE NIL
]]];
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];
NoteNewPart[w];
};
 
WireCopy: 
PROC [from, to: Wire] = {
FOR child: Wire ← from.FirstChildWire[], child.NextChildWire[] 
WHILE child # 
NIL 
DO
[] ← CreateWire[to.containingCT, to, NIL, child];
ENDLOOP;
 
};
 
CreateIntermediary: 
PUBLIC 
PROC [from: Vertex, go: GraphDirection, containingCT: CellType, port: Port, other: Assertions ← 
NIL] 
RETURNS [im: Intermediary] = {
vs: ARRAY GraphDirection OF Vertex ← ALL[from];
vs[go] ← im ← 
NEW [VertexPrivate.intermediate ← [
containingCT: containingCT,
other: other,
variant: intermediate[port]]];
AddEdge[vs, port];
NoteNewPart[im];
};
 
NoteNewPart: 
PROC [v: Vertex] = {
ct: CellType = v.containingCT;
pbn: Mapper = NARROW[Asserting.FnVal[partsByNameKey, ct.otherPrivate]];
PerName: 
PROC [assertion: Asserting.Assertion] = {
name: ROPE = NARROW[Asserting.TermsOf[assertion].first];
SELECT pbn.Map[name] 
FROM
NIL => IF pbn.SetMapping[name, v] THEN ERROR;
v => NULL;
ENDCASE => ERROR;
 
};
 
IF pbn = NIL THEN RETURN;
Asserting.EnumerateAssertionsAbout[nameReln, v.other, PerName];
};
 
KnowVertexName: 
PUBLIC 
PROC [v: Vertex, name: 
ROPE] = {
ct: CellType = v.containingCT;
pbn: Mapper = NARROW[Asserting.FnVal[partsByNameKey, ct.otherPrivate]];
IF pbn # 
NIL 
THEN {
SELECT pbn.Map[name] 
FROM
v => NULL;
NIL => IF pbn.SetMapping[name, v] THEN ERROR;
ENDCASE => ERROR;
 
};
 
v.other ← Asserting.Assert[nameReln, LIST[name], v.other];
};
 
DeleteVertex: 
PUBLIC 
PROC [v: Vertex] = {
ct: CellType = v.containingCT;
pbn: Mapper = NARROW[Asserting.FnVal[partsByNameKey, ct.otherPrivate]];
PerName: 
PROC [assertion: Asserting.Assertion] = {
name: ROPE = NARROW[Asserting.TermsOf[assertion].first];
IF NOT pbn.SetMapping[name, NIL] THEN ERROR;
};
 
Killit: 
PROC [p: Port, w: Vertex, e: Edge] = {
RemoveEdge[e];
WITH w 
SELECT 
FROM
ci: CellInstance => NULL;
im: Intermediary => IF w = e.sides[wireward].v THEN DeleteVertex[w];
wire: Wire => NULL;
ENDCASE => ERROR;
 
};
 
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;
v.containingCT.asUnorganized.containedInstances.RemoveElt[ci];
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;
 
IF pbn # NIL THEN Asserting.EnumerateAssertionsAbout[nameReln, v.other, PerName];
};
 
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, Asserting.Filter[nameReln, subPort.other].about];
CreateMirrorBinding[subPort, subVertex];
}
 
ENDLOOP;
 
};
 
v: CellInstance = 
NEW [VertexPrivate.cell ← [
containingCT: lct,
other: Asserting.Assert[nameReln, LIST[R["mirror"]], NIL],
variant: cell[type: lct--AM2 says not to link it--]
]];
lct.asUnorganized.mirror ← v;
CreateMirrorBinding[lct.port, v];
};
 
MakeArrayConnection: 
PUBLIC 
PROC [ct: CellType, d: Dim, lowRange: Range2, lowPort, highPort: Port] = {
o: Dim = OtherDim[d];
a: Array = ct.asArray;
tf: INT = a.jointsPeriod[Foo];
tb: INT = a.jointsPeriod[Bar];
IF a = NIL THEN ERROR;
IF lowRange[d].min<0 OR lowRange[d].maxPlusOne>=a.size[d] THEN ERROR;
IF lowRange[o].min<0 OR lowRange[o].maxPlusOne>a.size[o] THEN ERROR;
IF a.jointsPeriod[d] > a.size[d] THEN ERROR;
FOR 
f
f: 
INT 
IN [0 .. 
t
f) 
DO
FOR 
f
b: 
INT 
IN [0 .. 
t
b) 
DO
phase2: ArrayIndex = [ff, fb];
j: Joint = GetArrayJoint[a, d, phase2];
jir: Range2 = [
Foo: [
min: CeilDiv[MAX[lowRange[Foo].min, ff] - ff, tf],
maxPlusOne: FloorDiv[lowRange[Foo].maxPlusOne-1 - ff, tf] + 1],
Bar: [
min: CeilDiv[MAX[lowRange[Bar].min, fb] - fb, tb],
maxPlusOne: FloorDiv[lowRange[Bar].maxPlusOne-1 - fb, tb] + 1]];
jsize: Range2 = [
Foo: [0, FloorDiv[a.size[Foo]-(IF d=Foo THEN 2 ELSE 1) - ff, tf]+1],
Bar: [0, FloorDiv[a.size[Bar]-(IF d=Bar THEN 2 ELSE 1) - fb, tb]+1]];
complete: BOOL = jsize = jir;
ncji: INT = jsize[Foo].maxPlusOne * jsize[Bar].maxPlusOne;
FixMapping: 
PROC [mapTable: RefTable, from, to: Port] = {
SELECT mapTable.Fetch[from].value 
FROM
NIL => [] ← mapTable.Store[from, to];
to => NULL;
ENDCASE => ERROR;
 
};
 
FixIncompleteness: 
PROC [oldToInc: RefTable, from: Port] 
RETURNS [newToInc: RefTable] = {
inc: Incompleteness;
newToInc ← oldToInc;
IF newToInc = 
NIL 
THEN {
IF complete THEN RETURN;
newToInc ← CreateRefTable[];
};
 
inc ← NARROW[newToInc.Fetch[from].value];
IF inc = 
NIL 
THEN {
IF complete THEN RETURN;
inc ← NEW [IncompletenessPrivate[ncji]];
inc.nIncomplete ← ncji - RangeArea[jir];
FOR i
f: 
INT 
IN [0 .. jsize[Foo].maxPlusOne) 
DO
inf: BOOL = if IN [jir[Foo].min .. jir[Foo].maxPlusOne);
FOR i
b: 
INT 
IN [0 .. jsize[Bar].maxPlusOne) 
DO
cji: INT = if * jsize[Bar].maxPlusOne + ib;
inc[cji] ← NOT (inf AND ib IN [jir[Bar].min .. jir[Bar].maxPlusOne));
ENDLOOP;
 
ENDLOOP;
 
[] ← newToInc.Store[from, inc];
}
 
ELSE {
FOR i
f: 
INT 
IN [jir[Foo].min .. jir[Foo].maxPlusOne) 
DO
FOR i
b: 
INT 
IN [jir[Bar].min .. jir[Bar].maxPlusOne) 
DO
cji: INT = if * jsize[Bar].maxPlusOne + ib;
IF inc[cji] THEN inc.nIncomplete ← inc.nIncomplete - 1;
inc[cji] ← FALSE;
ENDLOOP;
 
ENDLOOP;
 
};
 
IF inc.nIncomplete = 0 THEN [] ← newToInc.Store[from, NIL];
};
 
FixMapping[j.lowToHigh, lowPort, highPort];
FixMapping[j.highToLow, highPort, lowPort];
j.lowToIncompleteness ← FixIncompleteness[j.lowToIncompleteness, lowPort];
j.highToIncompleteness ← FixIncompleteness[j.highToIncompleteness, highPort];
ENDLOOP ENDLOOP;
 
 
};
 
RangeArea: 
PROC [r: Range2] 
RETURNS [area: 
INT] = {
area ← (r[Foo].maxPlusOne-r[Foo].min) * (r[Bar].maxPlusOne-r[Bar].min)};
 
FloorDiv: 
PROC [num, den: 
INT] 
RETURNS [quot: 
INT] = {
IF den <= 0 THEN ERROR;
IF num < 0 THEN num ← num - (den-1);
quot ← num/den;
};
 
CeilDiv: 
PROC [num, den: 
INT] 
RETURNS [quot: 
INT] = {
IF den <= 0 THEN ERROR;
IF num > 0 THEN num ← num + (den-1);
quot ← num/den;
};
 
Log: 
PUBLIC 
PROC [fmt: 
ROPE, v1, v2, v3, v4, v5: 
REF 
ANY ← 
NIL] = {
DO
IF log = NIL THEN log ← ViewerIO.CreateViewerStreams["Lichen Debugging Log"].out;
log.PutF[fmt, [refAny[v1]], [refAny[v2]], [refAny[v3]], [refAny[v4]], [refAny[v5]] !IO.Error => IF ec = StreamClosed THEN {log ← NIL; LOOP}];
EXIT;
ENDLOOP;
 
};
log: IO.STREAM ← NIL;
 
END.