LichenPrimitiveTransforms:
CEDAR
PROGRAM
IMPORTS IO, LichenDataStructure, LichenOps, LichenTransforms, LichenTransformsPrivate, List, RedBlackTree, RefTab, Rope
EXPORTS LichenOps, LichenTransforms, LichenTransformsPrivate =
BEGIN OPEN LichenDataStructure, LichenTransforms, LichenOps, LichenTransformsPrivate;
--Not YET implemented-- nyet: PUBLIC ERROR = CODE;
Error: PUBLIC ERROR [format: ROPE, v1, v2, v3, v4, v5: IO.Value ← [null[]]] = CODE;
Differentiate:
PUBLIC
PROC [design: Design, newNames: Names, instances:
REF
ANY]
RETURNS [newCT: CellType] =
BEGIN
oldCT: CellType ← NIL;
vl: LORA ← NIL;
ConsumeInstance:
PROC [v: Vertex] = {
SELECT v.class
FROM
cell => NULL;
net => Err[[], "%g is a net, not a cell", IO.rope[GlobalVertexName[v]]];
ENDCASE => ERROR;
IF oldCT = NIL THEN oldCT ← v.type ELSE IF oldCT # v.type THEN Err[[], "%g of type %g, not %g", IO.rope[PickAName[v.names]], IO.rope[PickAName[v.type.names]], IO.rope[PickAName[oldCT.names]]];
vl ← CONS[v, vl]};
EnumerateVertices[design, instances, ConsumeInstance];
newCT ← NEW [CellTypeRep ← [design: design, names: newNames, file: NIL, publicKnown: TRUE, privateKnown: TRUE, ports: CopyPorts[oldCT.ports], parts: NIL]];
CopyParts[newCT, oldCT];
FOR vl ← vl, vl.rest
WHILE vl #
NIL
DO
ChangeType[v: NARROW[vl.first], from: oldCT, to: newCT];
ENDLOOP;
END;
Undifferentiate:
PUBLIC
PROC [design: Design, toTypeA, fromTypes:
REF
ANY]
RETURNS [changed: VertexList] =
BEGIN
toType: CellType ← ToType[design, toTypeA];
oldTypes: LIST OF CellType ← NIL;
oldCount: NAT ← 0;
ConsumeType:
PROC [ct: CellType] = {
oldTypes ← CONS[ct, oldTypes];
oldCount ← oldCount + 1};
EnumerateCellTypes[design, fromTypes, ConsumeType];
FOR oldTypes ← oldTypes, oldTypes.rest
WHILE oldTypes #
NIL
DO
WHILE oldTypes.first.firstInstance #
NIL
DO
v: Vertex ← oldTypes.first.firstInstance;
IF IsMirror[v] THEN ERROR; --AM2
ChangeType[v: v, from: oldTypes.first, to: toType];
changed ← CONS[v, changed];
ENDLOOP;
DeleteType[design, oldTypes.first];
ENDLOOP;
END;
NewEmptyCellType:
PUBLIC
PROC [design: Design, names: Names]
RETURNS [cellType: CellType] =
BEGIN
cellType ←
NEW [CellTypeRep ← [
design: design,
names: names,
file: NIL,
publicKnown: TRUE,
privateKnown: TRUE,
ports: NEW [PortSeq[0]],
parts: RedBlackTree.Create[GetAliasKey, CompareAliases],
mirror: NIL]];
AddWorld[cellType];
Insert[design.cellTypesByName, names, cellType];
design.cellTypesByAddress.Insert[cellType, cellType];
END;
CreateEmpty:
PUBLIC
PROC [design: Design, childNames: Names, childType, parentType: CellType]
RETURNS [child: Vertex] =
BEGIN
child ← NEW [VertexRep ← [names: childNames, type: childType, parent: parentType, class: cell]];
IF NOT IsEmpty[childType] THEN Err[[], "Asked to create empty child %g of non-empty type %g in %g", IO.refAny[PickAName[childNames]], IO.refAny[PickAName[childType.names]], IO.refAny[PickAName[parentType.names]]];
LinkInstance[child];
AddVertex[child];
NoteChange[child.parent];
END;
DeleteEmpty:
PUBLIC
PROC [design: Design, child: Vertex]
RETURNS [parentType: CellType] =
BEGIN
parentType ← child.parent;
IF NOT IsEmpty[child.type] THEN Err[[], "Child %g in %g is of a non-empty type (%g)", IO.rope[PickAName[child.names]], IO.rope[PickAName[child.parent.names]], IO.rope[PickAName[child.type.names]]];
IF (child.firstEdge # NIL) # (child.lastEdge # NIL) THEN ERROR;
IF child.firstEdge # NIL THEN ERROR;
NoteChange[child.parent];
DeleteVertex[child];
END;
RenameVertices:
PUBLIC
PROC [design: Design, parentA, vertices:
REF
ANY, renamer: Renamer] = {
parentType: CellType ← ToType[design, parentA];
changed: BOOL ← FALSE;
PerVertex:
PROC [v: Vertex] = {
newNames: Names ← renamer.Rename[renamer.data, v.names, implicitClass].newNames;
IF v.parent # parentType THEN ERROR;
IF newNames # v.names
THEN {
changed ← TRUE;
Delete[v.parent.parts, v.names, v];
v.names ← newNames;
Insert[v.parent.parts, v.names, v];
};
};
EnumerateVertices[parentType, vertices, PerVertex];
IF changed THEN NoteChange[parentType];
};
RenamePorts:
PUBLIC
PROC [design: Design, typeA:
REF
ANY, renamer: Renamer] = {
parentType: CellType ← ToType[design, typeA];
changed: BOOL ← FALSE;
FOR portIndex: PortIndex
IN [0 .. parentType.ports.length)
DO
newNames: Names;
newEquiv: EquivClass;
[newNames, newEquiv] ← renamer.Rename[renamer.data, parentType.ports[portIndex].names, parentType.ports[portIndex].equivClass];
IF newNames # parentType.ports[portIndex].names
OR newEquiv # parentType.ports[portIndex].equivClass
THEN {
changed ← TRUE;
parentType.ports[portIndex].names ← newNames;
parentType.ports[portIndex].equivClass ← newEquiv};
ENDLOOP;
IF changed THEN NoteChange[parentType];
};
RenameCellType:
PUBLIC
PROC [design: Design, typeA:
REF
ANY, renamer: Renamer] = {
ct: CellType ← ToType[design, typeA];
newNames: Names;
newEquiv: EquivClass;
[newNames, newEquiv] ← renamer.Rename[renamer.data, ct.names, ct.equivClass];
IF newNames # ct.names
OR newEquiv # ct.equivClass
THEN {
NoteChange[ct];
Delete[design.cellTypesByName, ct.names, ct];
ct.names ← newNames;
ct.equivClass ← newEquiv;
Insert[design.cellTypesByName, ct.names, ct];
};
};
RenameTypes:
PUBLIC
PROC [design: Design, typesA:
REF
ANY, renamer: Renamer] = {
PerType:
PROC [ct: CellType] = {
newNames: Names;
newEquiv: EquivClass;
[newNames, newEquiv] ← renamer.Rename[renamer.data, ct.names, ct.equivClass];
IF newNames # ct.names
OR newEquiv # ct.equivClass
THEN {
NoteChange[ct];
Delete[design.cellTypesByName, ct.names, ct];
ct.names ← newNames;
ct.equivClass ← newEquiv;
Insert[design.cellTypesByName, ct.names, ct];
};
};
EnumerateCellTypes[design, typesA, PerType];
};
RenameAll:
PUBLIC
PROC [design: Design, renamer: Renamer] = {
FOR ct: CellType ← FirstCellType[design], NextCellType[ct]
WHILE ct #
NIL
DO
EnsureParts[ct];
RenameCellType[design, ct, renamer];
RenamePorts[design, ct, renamer];
IF ExpansionKnown[ct] THEN RenameVertices[design, ct, all, renamer];
ENDLOOP;
};
ToNamesS:
PUBLIC
PROC [ra:
REF
ANY]
RETURNS [ns: NamesS] = {
WITH ra
SELECT
FROM
x: NamesS => ns ← x;
x: NamesList => ns ← NamesListToSeq[x];
ENDCASE => ERROR};
NamesListToSeq:
PUBLIC
PROC [l: NamesList]
RETURNS [s: NamesS] = {
size: CARDINAL ← 0;
FOR m: NamesList ← l, m.rest WHILE m # NIL DO size ← size+1 ENDLOOP;
s ← NEW [NamesSeq[size]];
FOR i:
NAT
IN [0 .. s.length)
DO
s[i] ← l.first;
l ← l.rest;
ENDLOOP;
};
ListNames:
PUBLIC
PROC [vertexs: VertexS]
RETURNS [nl: NamesList] = {
tail: NamesList ← nl ← NIL;
FOR i:
NAT
IN [0 .. vertexs.length)
DO
last: NamesList ← LIST[vertexs[i].names];
IF tail = NIL THEN nl ← last ELSE tail.rest ← last;
tail ← last;
ENDLOOP;
};
ToType:
PUBLIC
PROC [design: Design, ra:
REF
ANY]
RETURNS [type: CellType] = {
WITH ra
SELECT
FROM
r: ROPE => type ← NARROW[Lookup[design.cellTypesByName, r]];
ct: CellType => type ← ct;
ENDCASE => ERROR};
ToRope: PUBLIC PROC [ra: REF ANY] RETURNS [rope: ROPE] = {rope ← NARROW[ra]};
ToVertex:
PUBLIC
PROC [context, ra:
REF
ANY]
RETURNS [v: Vertex] = {
WITH ra
SELECT
FROM
vertex: Vertex => v ← vertex;
rope:
ROPE => {
ct: CellType ← NARROW[context];
EnsureParts[ct];
v ← NARROW[Lookup[ct.parts, rope]]};
lora:
LORA => {
design: Design ← NARROW[context];
ct: CellType ← ToType[design, lora.first];
name: ROPE ← NARROW[lora.rest.first];
EnsureParts[ct];
v ← NARROW[Lookup[ct.parts, name]]};
ENDCASE => ERROR};
ToVertexS:
PUBLIC
PROC [context, ra:
REF
ANY]
RETURNS [vs: VertexS] = {
WITH ra
SELECT
FROM
s: VertexS => vs ← s;
lora:
LORA => {
vs ← NEW [VertexSeq[List.Length[lora]]];
FOR i:
NAT
IN [0 .. vs.length)
DO
vs[i] ← ToVertex[context, lora.first];
lora ← lora.rest;
ENDLOOP;
IF lora # NIL THEN ERROR};
bag: Bag => {
vl: VertexList ← NIL;
count: INT ← 0;
PerElement:
PROC [e:
REF
ANY] = {
v: Vertex ← NARROW[e];
vl ← CONS[v, vl];
count ← count +1};
bag.Enumerate[context: context, data: bag.data, to: PerElement];
vs ← NEW [VertexSeq[count]];
FOR vl ← vl, vl.rest
WHILE vl #
NIL
DO
count ← count - 1;
vs[count] ← vl.first;
ENDLOOP;
IF count # 0 THEN ERROR;
};
ENDCASE => ERROR};
VVMapFromTIINames: PROC [design: Design, l: TIINamesList] RETURNS [m: Mapper] = {
rtm: RefTabMapper ← NEW [RefTabMapperRep ← [NIL, RefTab.Create[]]];
rtm.asMapper ← m ← NEW [MapperRep ← [RefTabMap, rtm]];
FOR tiil: TIINamesList ← l, tiil.rest WHILE tiil # NIL DO
tiin: TIINames ← tiil.first;
ct: CellType ← NARROW[Lookup[design.cellTypesByName, tiin.typeName]];
v1: Vertex ← NARROW[Lookup[ct.parts, tiin.v1Name]];
v2: Vertex ← NARROW[Lookup[ct.parts, tiin.v2Name]];
[] ← rtm.refTab.Store[v1, v2];
ENDLOOP;
};
VVSMapFromTIIlNames:
PUBLIC
PROC [design: Design, l: TIIlNamesList]
RETURNS [m: Mapper] = {
rtm: RefTabMapper ← NEW [RefTabMapperRep ← [NIL, RefTab.Create[]]];
rtm.asMapper ← m ← NEW [MapperRep ← [RefTabMap, rtm]];
FOR tiill: TIIlNamesList ← l, tiill.rest
WHILE tiill #
NIL
DO
tiiln: TIIlNames ← tiill.first;
ct: CellType ← NARROW[Lookup[design.cellTypesByName, tiiln.typeName]];
v1: Vertex ← NARROW[Lookup[ct.parts, tiiln.v1Name]];
v2s: VertexS ← ToVertexS[ct, tiiln.v2Names];
[] ← rtm.refTab.Store[v1, v2s];
ENDLOOP;
};
RefTabMapper: TYPE = REF RefTabMapperRep;
RefTabMapperRep:
TYPE =
RECORD [
asMapper: Mapper,
refTab: RefTab.Ref
];
RefTabMap:
PROC [data, domain:
REF
ANY]
RETURNS [range:
REF
ANY] = {
rtm: RefTabMapper ← NARROW[data];
range ← rtm.refTab.Fetch[domain].val};
OneMap:
PUBLIC
PROC [from, to:
REF
ANY]
RETURNS [mapper: Mapper] = {
om: OneMapper ← NEW [OneMapperRep ← [from, to]];
mapper ← NEW [MapperRep ← [MapOne, om]]};
OneMapper: TYPE = REF OneMapperRep;
OneMapperRep: TYPE = RECORD [from, to: REF ANY];
MapOne:
PROC [data, domain:
REF
ANY]
RETURNS [range:
REF
ANY] = {
om: OneMapper ← NARROW[data];
range ← IF domain = om.from THEN om.to ELSE NIL};
GenName:
PROC
RETURNS [name:
ROPE] =
{name ← IO.PutFR[" gen%g", IO.card[genCount ← genCount + 1]]};
genCount: NAT ← 0;
JoinNames:
PUBLIC
PROC [parent, child: Names, dot:
BOOL ←
TRUE]
RETURNS [joined: Names] =
{joined ← [progged: LIST[PickAName[parent].Cat[IF dot THEN "." ELSE NIL, PickAName[child]]]]};
QualifyEquivClass:
PUBLIC
PROC [qual: Names, equivClass: EquivClass, dot:
BOOL ←
TRUE]
RETURNS [quald: EquivClass] =
{quald ← IF equivClass # implicitClass THEN PickAName[qual].Cat[IF dot THEN "." ELSE NIL, equivClass] ELSE implicitClass};
IsEmpty:
PROC [type: CellType]
RETURNS [isEmpty:
BOOL] = {
EnsureParts[type];
EnsurePorts[type];
isEmpty ← type.ports.length = 0 AND type.cellCount = 0};
CopyPorts:
PROC [p: PortS]
RETURNS [q: PortS] = {
q ← NEW [PortSeq[p.length]];
FOR pi: NAT IN [0 .. q.length) DO q[pi] ← p[pi] ENDLOOP;
};
CopyParts:
PROC [newCT, oldCT: CellType] = {
oldParts: SymbolTable ← oldCT.parts;
newParts: SymbolTable;
Copy:
PROC [ra:
REF
ANY]
RETURNS [stop:
BOOL] = {
oldV: Vertex ←
NARROW[AntiAlias[ra]];
AM1 says this can't be the mirror.
newV: Vertex;
stop ← FALSE;
newV ← CopyWork[oldV]};
CopyWork:
PROC [oldV: Vertex]
RETURNS [newV: Vertex] = {
newV ← NARROW[Lookup[newParts, PickAName[oldV.names]]];
IF newV # NIL THEN RETURN;
newV ← NEW [VertexRep ← [names: oldV.names, type: oldV.type, parent: newCT, class: oldV.class]];
AddVertex[newV];
IF newV.class = net THEN RETURN;
LinkInstance[newV];
FOR oldE: Edge ← oldV.firstEdge, oldE.sides[cell].next
WHILE oldE #
NIL
DO
newNet: Vertex ← CopyWork[oldE.sides[net].v];
IF oldE.sides[cell].v # oldV THEN ERROR;
AddEdge[newV, newNet];
ENDLOOP;
};
IF oldCT.parts = NIL OR newCT.parts # NIL THEN ERROR;
IF newCT.mirror # NIL THEN ERROR;
newCT.parts ← newParts ← RedBlackTree.Create[GetAliasKey, CompareAliases];
oldParts.EnumerateIncreasing[Copy];
AddWorld[newCT];
};
DeleteType:
PROC [design: Design, type: CellType] = {
IF (type.firstInstance = NIL) # (type.lastInstance = NIL) THEN ERROR;
IF (type.firstInstance # NIL) OR (type.lastInstance # NIL) THEN ERROR; --AM2
Delete[design.cellTypesByName, type.names, type];
IF design.cellTypesByAddress.Delete[type].data # type THEN ERROR;
};
ChangeType:
PROC [v: Vertex, from, to: CellType] = {
IF v.type # from THEN ERROR;
NoteChange[v.parent];
UnlinkInstance[v];
v.type ← to;
LinkInstance[v]};
AddEdge:
PUBLIC
PROC [cv, nv: Vertex] = {
pi: NAT = IF cv.lastEdge # NIL THEN cv.lastEdge.portIndex+1 ELSE 0;
e: Edge ← NEW [EdgeRep ← [sides: [cell: [v: cv, next: NIL, prev: cv.lastEdge], net: [v: nv, next: NIL, prev: nv.lastEdge]], color: noColor, portIndex: pi]];
IF cv.class # cell OR nv.class # net THEN ERROR;
IF e.sides[cell].prev # NIL THEN e.sides[cell].prev.sides[cell].next ← e ELSE cv.firstEdge ← e;
IF e.sides[net].prev # NIL THEN e.sides[net].prev.sides[net].next ← e ELSE nv.firstEdge ← e;
cv.lastEdge ← nv.lastEdge ← e;
};
END.