LichenDataImpl:
CEDAR
PROGRAM
IMPORTS Asserting, Basics, GList, HashTable, IntHashTable, IO, LichenDataStructure, LichenSetTheory, Rope, ViewerIO
EXPORTS LichenDataStructure, LichenDataOps =
BEGIN OPEN LichenSetTheory, LichenDataStructure, SS:StructuredStreams, UB:UnparserBuffer;
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][Foo], b.offset];
ENDCASE => ERROR;
center =>
WITH b: wB
SELECT
FROM
end => For[dp.sideIndices[b.end][Bar], 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];
};
FullyInstantiate:
PUBLIC
PROC [type, containingCT: CellType, other: Assertions ←
NIL]
RETURNS [ci: CellInstance] = {
ci ← Instantiate[type, containingCT, other];
{instanceName: ROPE = Describe[ci, ci.containingCT];
FOR port: Port ← type.port.FirstChildPort[], port.NextChildPort[]
WHILE port #
NIL
DO
portName: ROPE = Describe[port, type.port];
wireName: ROPE = Rope.Cat[instanceName, "/", portName];
w: Wire = CreateWire[ci.containingCT, NIL, Asserting.Assert[nameReln, LIST[wireName], NIL]];
AddEdge[[cellward: ci, wireward: w], port];
ENDLOOP;
ci ← 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 => RETURN;
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, rp1, rp2: RoledPort] = {
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];
tie1: Tie = NARROW[j.toTie[rp1.side].Fetch[rp1.port].value];
tie2: Tie = NARROW[j.toTie[rp2.side].Fetch[rp2.port].value];
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]];
tie: Tie;
complete: BOOL ← jir = [Foo: [0, j.size2[Foo]], Bar: [0, j.size2[Bar]]] OR j.size = 0;
SELECT
TRUE
FROM
tie
1 =
NIL =>
SELECT
TRUE
FROM
tie
2 =
NIL => {
tie ← CreateTie[j, rp1, rp2, complete]};
ENDCASE => {
complete ← complete AND tie2.completion = NIL;
tie ← AddPortToTie[j, tie2, rp1, complete]};
tie
2 =
NIL => {
complete ← complete AND tie1.completion = NIL;
tie ← AddPortToTie[j, tie1, rp2, complete]};
tie
1 = tie
2 => {
complete ← (complete AND tie1.n = 2) OR tie1.completion = NIL;
tie ← tie1};
ENDCASE => {
complete ← complete AND tie1.completion = NIL AND tie2.completion = NIL;
tie ← JoinTies[j, tie1, tie2, complete]};
IF complete THEN SetCompletion[j, tie, TRUE]
ELSE {
rpd1: RoledPortData = NARROW[j.toRole[rp1.side].Fetch[rp1.port].value];
rpd2: RoledPortData = NARROW[j.toRole[rp2.side].Fetch[rp2.port].value];
FOR ji
f:
INT
IN [jir[Foo].min .. jir[Foo].maxPlusOne)
DO
FOR ji
b:
INT
IN [jir[Bar].min .. jir[Bar].maxPlusOne)
DO
cji: NAT = j.size2[Bar]*jif + jib;
r1: NAT = GetRoot[j, rpd1, cji];
r2: NAT = GetRoot[j, rpd2, cji];
IF r1 = r2 THEN LOOP;
IF tie.completion[cji] THEN ERROR;
IF r1 < r2 THEN SetRoot[j, r2, cji, r1] ELSE SetRoot[j, r1, cji, r2];
IF tie.completion[cji] ← ComputeComplete[j, tie, cji]
THEN {
IF (tie.completion.nIncomplete ← tie.completion.nIncomplete - 1) = 0 THEN {SetCompletion[j, tie, TRUE]; GOTO Completed};
};
ENDLOOP ENDLOOP;
EXITS Completed => tie ← tie;
};
ENDLOOP ENDLOOP;
};
SetCompletion:
PROC [j: Joint, tie: Tie, complete:
BOOL] = {
FOR rpl: RoledPortDataList ← tie.ports, rpl.rest
WHILE rpl #
NIL
DO
IF
SELECT rpl.first.index
FROM
=0 => rpl.first.links#NIL,
#0 => (rpl.first.links#NIL) # (tie.completion#NIL),
ENDCASE => ERROR
THEN ERROR;
ENDLOOP;
IF complete = (tie.completion = NIL) THEN RETURN;
IF complete
THEN {
tie.completion ← NIL;
FOR rpl: RoledPortDataList ← tie.ports, rpl.rest
WHILE rpl #
NIL
DO
rpl.first.links ← NIL;
ENDLOOP;
}
ELSE {
tie.completion ← NEW [CompletionPrivate[j.size]];
tie.completion.nIncomplete ← 0;
FOR rpl: RoledPortDataList ← tie.ports, rpl.rest
WHILE rpl #
NIL
DO
AddLink[j, rpl.first, tie.mindex];
ENDLOOP;
FOR cji:
INT
IN [0 .. tie.completion.length)
DO
tie.completion[cji] ← TRUE;
ENDLOOP;
};
};
FinishCompletion:
PROC [j: Joint, tie: Tie, complete:
BOOL] = {
IF complete
THEN {
tie.completion ← NIL;
FOR rpl: RoledPortDataList ← tie.ports, rpl.rest
WHILE rpl #
NIL
DO
rpl.first.links ← NIL;
ENDLOOP;
}
ELSE {
IF tie.completion = NIL THEN tie.completion ← NEW [CompletionPrivate[j.size]];
tie.completion.nIncomplete ← j.size;
FOR cji:
INT
IN [0 .. tie.completion.length)
DO
IF tie.completion[cji] ← ComputeComplete[j, tie, cji] THEN ERROR;
ENDLOOP;
};
};
CreateTie:
PROC [j: Joint, rp1, rp2: RoledPort, complete:
BOOL]
RETURNS [tie: Tie] = {
rpd1: RoledPortData = NewRoleData[j, rp1, complete];
rpd2: RoledPortData = NewRoleData[j, rp2, complete];
tie ←
NEW [TiePrivate ← [
ports: LIST[rpd1, rpd2],
n: 2,
mindex: MIN[rpd1.index, rpd2.index],
completion: NIL
]];
FinishCompletion[j, tie, complete];
[] ← j.ties.UnionSingleton[tie];
FOR rpl: RoledPortDataList ← tie.ports, rpl.rest
WHILE rpl #
NIL
DO
[] ← j.toTie[rpl.first.side].Store[rpl.first.port, tie];
ENDLOOP;
tie ← tie;
};
AddPortToTie:
PROC [j: Joint, tie: Tie, rp: RoledPort, complete:
BOOL]
RETURNS [same: Tie] = {
rpd: RoledPortData = NewRoleData[j, rp, complete];
tie.ports ← CONS[rpd, tie.ports];
tie.n ← tie.n + 1;
tie.mindex ← MIN[tie.mindex, rpd.index];
FinishCompletion[j, tie, complete];
[] ← j.toTie[rp.side].Store[rp.port, tie];
same ← tie;
};
JoinTies:
PROC [j: Joint, tie1, tie2: Tie, complete:
BOOL]
RETURNS [tie: Tie] = {
SetCompletion[j, tie1, FALSE];
SetCompletion[j, tie2, FALSE];
tie ←
NEW [TiePrivate ← [
ports: NARROW[GList.Append[tie1.ports, tie2.ports]],
n: tie1.n + tie2.n,
mindex: MIN[tie1.mindex, tie2.mindex],
completion: NIL
]];
FinishCompletion[j, tie, complete];
[] ← j.ties.UnionSingleton[tie];
[] ← j.ties.RemoveElt[tie1];
[] ← j.ties.RemoveElt[tie2];
FOR rpl: RoledPortDataList ← tie.ports, rpl.rest
WHILE rpl #
NIL
DO
[] ← j.toTie[rpl.first.side].Store[rpl.first.port, tie];
ENDLOOP;
tie ← tie;
};
AddLink:
PROC [j: Joint, rpd: RoledPortData, to:
NAT] = {
IF rpd.links # NIL THEN ERROR;
SELECT rpd.index
FROM
=0 => j ← j;
#0 => {
linkSize, wordsNeeded: NAT;
lgLinksPerWord: Sublg;
[linkSize, lgLinksPerWord] ← ChooseLinkSize[rpd.index+1];
wordsNeeded ← CeilDiv[linkSize * j.size, Basics.bitsPerWord];
rpd.links ← NEW [LinksPrivate[wordsNeeded]];
rpd.links.linkSize ← linkSize;
rpd.links.negLinkSize ← - linkSize;
rpd.links.negLgLinksPerWord ← - lgLinksPerWord;
rpd.links.lgLinksPerWord ← lgLinksPerWord;
FOR cji:
NAT
IN [0 ..
NAT[j.size])
DO
SetRoot[j, rpd.index, cji, rpd.index];
ENDLOOP;
j ← j;
};
ENDCASE => ERROR;
};
NewRoleData:
PROC [j: Joint, rp: RoledPort, complete:
BOOL]
RETURNS [rpd: RoledPortData] = {
rpd ← NARROW[j.toRole[rp.side].Fetch[rp.port].value];
IF rpd =
NIL
THEN {
rpd ←
NEW [RoledPortDataPrivate ← [
port: rp.port,
side: rp.side,
index: j.nrp,
links: NIL
]];
IF j.roles.length # rpd.index THEN ERROR;
VarRefSeqAppend[j.roles, rpd];
j.nrp ← j.nrp + 1;
IF NOT j.toRole[rp.side].Store[rp.port, rpd] THEN ERROR;
IF NOT complete THEN AddLink[j, rpd, rpd.index];
}
ELSE ERROR;
};
ChooseLinkSize:
PROC [nrp:
NAT]
RETURNS [linkSize:
NAT, lgLinksPerWord: Sublg] = {
SELECT nrp
FROM
<=1 => ERROR;
<=2 => RETURN [1, Basics.logBitsPerWord];
<=4 => RETURN [2, Basics.logBitsPerWord-1];
<=16 => RETURN [4, Basics.logBitsPerWord-2];
<=256 => RETURN [8, Basics.logBitsPerWord-3];
<=32767 => RETURN [16, Basics.logBitsPerWord-4];
ENDCASE => ERROR;
};
ComputeComplete:
PUBLIC
PROC [j: Joint, tie: Tie, cji:
NAT]
RETURNS [complete:
BOOL] = {
root: NAT = GetRoot[j, tie.ports.first, cji];
FOR rpl: RoledPortDataList ← tie.ports.rest, rpl.rest
WHILE rpl #
NIL
DO
r2: NAT = GetRoot[j, rpl.first, cji];
IF r2 # root THEN RETURN [FALSE];
ENDLOOP;
complete ← TRUE;
};
WordPtr: TYPE = LONG POINTER TO WORD;
GetNext:
PUBLIC
PROC [j: Joint, rp: RoledPortData, cji:
NAT]
RETURNS [next:
NAT] =
TRUSTED {
IF rp.index = 0 THEN RETURN [rp.index];
{ls: Links = rp.links;
wordPtr: WordPtr = @ls[Basics.BITSHIFT[cji, ls.negLgLinksPerWord]];
rightShift: INTEGER = ls.negLinkSize * INTEGER[Basics.BITAND[cji, last[ls.lgLinksPerWord]]];
mask: WORD = last[ls.linkSize];
next ← Basics.BITAND[Basics.BITSHIFT[wordPtr^, rightShift], mask];
}};
GetRoot:
PUBLIC
PROC [j: Joint, rp: RoledPortData, cji:
NAT]
RETURNS [root:
NAT] =
TRUSTED {
IF rp.index = 0 THEN RETURN [rp.index];
{ls: Links = rp.links;
wordPtr: WordPtr = @ls[Basics.BITSHIFT[cji, ls.negLgLinksPerWord]];
rightShift: INTEGER = ls.negLinkSize * INTEGER[Basics.BITAND[cji, last[ls.lgLinksPerWord]]];
mask: WORD = last[ls.linkSize];
next: NAT = Basics.BITAND[Basics.BITSHIFT[wordPtr^, rightShift], mask];
IF next = rp.index THEN RETURN [rp.index];
{rp2: RoledPortData = NARROW[j.roles.refs[next]];
IF next # rp2.index THEN ERROR;
root ← GetRoot[j, rp2, cji];
IF root # next
THEN {
leftShift: INTEGER = - rightShift;
shiftedMask: WORD = Basics.BITNOT[Basics.BITSHIFT[mask, leftShift]];
shiftedRoot: WORD = Basics.BITSHIFT[root, leftShift];
word: WORD = Basics.BITOR[shiftedRoot, Basics.BITAND[shiftedMask, wordPtr^]];
wordPtr^ ← word;
};
}}};
SetRoot:
PROC [j: Joint, oldRoot, cji, newRoot:
NAT] =
TRUSTED {
IF oldRoot = 0 THEN ERROR;
{rpd: RoledPortData = NARROW[j.roles.refs[oldRoot]];
ls: Links = rpd.links;
wordPtr: WordPtr = @ls[Basics.BITSHIFT[cji, ls.negLgLinksPerWord]];
leftShift: INTEGER = ls.linkSize * INTEGER[Basics.BITAND[cji, last[ls.lgLinksPerWord]]];
shiftedMask: WORD = Basics.BITNOT[Basics.BITSHIFT[last[ls.linkSize], leftShift]];
shiftedRoot: WORD = Basics.BITSHIFT[newRoot, leftShift];
word: WORD = Basics.BITOR[shiftedRoot, Basics.BITAND[shiftedMask, wordPtr^]];
IF Basics.BITAND[shiftedRoot, shiftedMask] # 0 THEN ERROR;
wordPtr^ ← word;
}};
last:
ARRAY [0 .. Basics.bitsPerWord]
OF
WORD = [
00000H,
00001H, 00003H, 00007H, 0000FH,
0001FH, 0003FH, 0007FH, 000FFH,
001FFH, 003FFH, 007FFH, 00FFFH,
01FFFH, 03FFFH, 07FFFH, 0FFFFH];
CrossATie:
PUBLIC
PROC [ct: CellType, d: Dim, fromP: Port, fromS: End]
RETURNS [toP: Port] = {
toS: End = OtherEnd[fromS];
a: Array = ct.asArray;
tf: INT = a.jointsPeriod[Foo];
tb: INT = a.jointsPeriod[Bar];
candidates: RoledPortDataList ← NIL;
{
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];
tie: Tie = NARROW[j.toTie[fromS].Fetch[fromP].value];
IF tie = NIL OR tie.completion # NIL THEN GOTO Dun;
IF phase2 = [0, 0]
THEN {
FOR rpl: RoledPortDataList ← tie.ports, rpl.rest
WHILE rpl #
NIL
DO
IF rpl.first.side = toS THEN candidates ← CONS[rpl.first, candidates];
ENDLOOP;
}
ELSE {
last: RoledPortDataList ← NIL;
FOR rpl: RoledPortDataList ← candidates, rpl.rest
WHILE rpl #
NIL
DO
IF j.toTie[rpl.first.side].Fetch[rpl.first.port].value = tie
THEN last ← rpl
ELSE {
IF last = NIL THEN candidates ← rpl.rest ELSE last.rest ← rpl.rest;
};
ENDLOOP;
};
ENDLOOP ENDLOOP;
EXITS Dun => candidates ← NIL};
toP ← IF candidates # NIL THEN candidates.first.port ELSE NIL;
};
RangeArea:
PROC [r: Range2]
RETURNS [area:
INT] = {
area ← (r[Foo].maxPlusOne-r[Foo].min) * (r[Bar].maxPlusOne-r[Bar].min)};
VarRefSeqAppend:
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;
};
FloorDiv:
PUBLIC
PROC [num, den:
INT]
RETURNS [quot:
INT] = {
IF den < 0 THEN {den ← -den; num ← -num};
IF num < 0 THEN num ← num - (den-1);
quot ← num/den;
};
CeilDiv:
PUBLIC
PROC [num, den:
INT]
RETURNS [quot:
INT] = {
IF den < 0 THEN {den ← -den; num ← -num};
IF num > 0 THEN num ← num + (den-1);
quot ← num/den;
};
Choose2:
PROC [n:
INT]
RETURNS [nChoose2:
INT] =
INLINE {
nChoose2 ← n*(n-1)/2};
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.