CoreBlockImpl.mesa
Created by Don Curry, February 1, 1986 2:43:22 pm PST
Edited by Don Curry, October 27, 1986 12:47:39 pm PST
DIRECTORY CoreCreate, CD, CDOrient, Basics, Core, CoreBlock, CoreGeometry, CoreIOIFUProps, CoreOps, CoreClasses, CoreFrame, CoreInstCell, CoreName, CoreProperties, HashTable, IO, PWC, Rope;
CoreBlockImpl:
CEDAR
PROGRAM
IMPORTS CD, CDOrient, Basics, CoreBlock, CoreOps, CoreFrame, CoreGeometry, CoreInstCell, CoreIOIFUProps, CoreName, CoreProperties, HashTable, IO, PWC, Rope
EXPORTS CoreBlock =
BEGIN OPEN CoreBlock;
Wire: TYPE = Core.Wire;
CellType: TYPE = Core.CellType;
ROPE: TYPE = Core.ROPE;
SidesProp: PROC RETURNS[ATOM] = {RETURN[CoreIOIFUProps.sides]};
Signal: SIGNAL[] = CODE;
AddSide:
PUBLIC
PROC[new, old: Sides]
RETURNS[Sides] =
{RETURN[SidesFmWord[Basics.BITOR[SidesToWord[new], SidesToWord[old]]]]};
DelSide:
PUBLIC
PROC[new, old: Sides]
RETURNS[Sides] =
{RETURN[SidesFmWord[Basics.BITAND[Basics.BITNOT[SidesToWord[new]], SidesToWord[old]]]]};
OnSide:
PUBLIC
PROC[new, old: Sides]
RETURNS[
BOOL] =
{RETURN[(Basics.BITAND[SidesToWord[new], SidesToWord[old]])#0]};
OtherSide:
PUBLIC
PROC[side: Sides]
RETURNS[Sides] =
{RETURN[SELECT side FROM bottom=>top, top=>bottom, left=>right, right=>left,ENDCASE=>none]};
SidesToWord:
PUBLIC
PROC[side: Sides]
RETURNS[word:
WORD] =
{RETURN[LOOPHOLE[side]]};
SidesFmWord:
PUBLIC
PROC[word:
WORD]
RETURNS[side: Sides] =
{RETURN[LOOPHOLE[Basics.BITAND[word, SidesToWord[all] ] ] ] };
GetCellSide:
PUBLIC
PROC[cell: CellType]
RETURNS[side: Sides] = {
refSides: REF Sides;
IF cell=NIL THEN RETURN[none];
refSides ← NARROW[CoreProperties.GetCellTypeProp[cell, SidesProp[]]];
RETURN[IF refSides=NIL THEN none ELSE refSides^] };
PutCellSide:
PUBLIC
PROC[cell: CellType, side: Sides] =
{CoreProperties.PutCellTypeProp[cell, SidesProp[], NEW[CoreBlock.Sides ← side]]};
GetWireSide:
PUBLIC
PROC[wire: Wire]
RETURNS[side: Sides] = {
refSides: REF Sides;
IF wire=NIL THEN RETURN[none];
refSides ← NARROW[CoreProperties.GetWireProp[wire, SidesProp[]]];
RETURN[IF refSides=NIL THEN none ELSE refSides^]};
PutWireSide:
PUBLIC
PROC[wire: Wire, side: Sides] = {
refSides: REF Sides;
IF wire=NIL THEN RETURN;
refSides ← NARROW[CoreProperties.GetWireProp[wire, SidesProp[]]];
IF refSides=
NIL
THEN CoreProperties.PutWireProp[wire, SidesProp[], NEW[CoreBlock.Sides ← side]]
ELSE refSides^ ← side;
FOR i: NAT IN [0..wire.size) DO PutWireSide[wire[i], side] ENDLOOP};
AddWireSide:
PUBLIC
PROC[wire: Wire, side: Sides]
RETURNS[sameWire: Wire] = {
refSides: REF Sides;
IF wire=NIL THEN RETURN[NIL];
refSides ← NARROW[CoreProperties.GetWireProp[wire, SidesProp[]]];
IF refSides=NIL THEN refSides ← NEW[Sides ← none];
refSides^ ← AddSide[side, refSides^];
CoreProperties.PutWireProp[wire, SidesProp[], refSides];
FOR i: NAT IN [0..wire.size) DO wire[i] ← AddWireSide[wire[i], side] ENDLOOP;
RETURN[wire]};
DelWireSide:
PUBLIC
PROC[wire: Wire, side: Sides]
RETURNS[sameWire: Wire] = {
refSides: REF Sides;
IF wire=NIL THEN RETURN[NIL];
refSides ← NARROW[CoreProperties.GetWireProp[wire, SidesProp[]]];
IF refSides=NIL THEN refSides ← NEW[Sides ← none];
refSides^ ← DelSide[side, refSides^];
CoreProperties.PutWireProp[wire, SidesProp[], refSides];
FOR i: NAT IN [0..wire.size) DO wire[i] ← DelWireSide[wire[i], side] ENDLOOP;
RETURN[wire]};
MergeSides:
PUBLIC
PROC[cell: CellType] = {
first: Sides ← GetCellSide[cell];
last: Sides ← OtherSide[first];
hidden: Sides;
data: CoreClasses.RecordCellType ← NARROW[cell.data];
visit: CoreOps.EachWirePairProc ~ {
side: Sides ← GetWireSide[publicWire];
side ← DelSide[hidden, side];
[ ] ← AddWireSide[actualWire, side]};
IF data.size>1 AND first=none THEN Signal[];
FOR i:
NAT
IN [0..data.size)
DO
hidden ← IF i # 0 THEN first ELSE none;
hidden ← AddSide[ IF (i+1) < data.size THEN last ELSE none, hidden];
[ ] ← CoreOps.VisitBinding[data[i].actual, data[i].type.public, visit] ENDLOOP;
DeletePseudoPublics[cell]};
DeletePseudoPublics:
PUBLIC
PROC [cell: Core.CellType] = {
publics: Core.Wires ← NIL;
FOR i:
INT
DECREASING
IN [0..cell.public.size)
DO
IF GetWireSide[ cell.public[i] ]#none
THEN publics ← CONS[ cell.public[i], publics]
ELSE log.PutF["\nRemoving pseudo public: %g",
IO.rope[ CoreName.WireNm[cell.public[i]].n] ]; ENDLOOP;
cell.public ← CoreOps.CreateWire[publics]};
RevInstances:
PROC[list: CoreClasses.CellInstances]
RETURNS[rev: CoreClasses.CellInstances] = {
FOR list ← list, list.rest WHILE list#NIL DO rev ← CONS[list.first, rev] ENDLOOP};
AbutCellList:
PUBLIC
PROC[
name: ROPE,
first: Sides,
cellTypes:
LIST
OF CellType]
RETURNS[cellType: CellType] = {
temp: LIST OF CellType ← NIL;
cts: LIST OF CellType ← NIL;
data: CoreClasses.RecordCellType;
specificGeneric, other: BOOL ← FALSE;
FOR temp: LIST OF CellType ← cellTypes, temp.rest WHILE temp#NIL DO
SELECT temp.first.class FROM
CoreInstCell.specificGenericCellClass => specificGeneric ← TRUE;
ENDCASE => other ← TRUE ENDLOOP;
IF specificGeneric=other THEN Signal[];
FOR temp:
LIST
OF CellType ← cellTypes, temp.rest
WHILE temp#
NIL
DO
cts ←
CONS[(
IF temp.first.class=CoreInstCell.specificGenericCellClass
THEN NARROW[ temp.first.data, CellType]
ELSE temp.first ), cts];
ENDLOOP;
IF first=left
OR first=bottom
THEN {
temp: LIST OF CellType ← cts; cts ← NIL;
FOR temp ← temp, temp.rest WHILE temp#NIL DO cts ← CONS[temp.first, cts] ENDLOOP};
cellType ← PWC.AbutList[ cts, (first=left OR first=right)];
[ ] ← CoreName.CellNm[cellType, name];
CoreBlock.PutCellSide[cellType, (SELECT first FROM left, right => left, ENDCASE => bottom)];
CoreBlock.MergeSides[cellType];
IF first=top
OR first=right
THEN {
temp: LIST OF CellType ← cellTypes; cellTypes ← NIL;
FOR temp ← temp, temp.rest
WHILE temp#
NIL
DO cellTypes ← CONS[temp.first, cellTypes] ENDLOOP};
Rename wires. Names are wrong either because cells were specificGeneric's or because extraction does not propagate names if nodes are split.
data ← NARROW[cellType.data];
FOR index:
NAT
IN [0..data.size)
DO
Visit: CoreOps.EachWirePairProc ~ {
new: ROPE ← CoreName.WireNm[publicWire].n;
IF publicWire.size#actualWire.size THEN Signal[];
IF publicWire.size#0 THEN RETURN[TRUE, FALSE];
IF new.Length[]=0 THEN
{IF CoreName.WireNm[actualWire].n.Length[]#0 THEN Signal[]};
[ ] ← CoreName.WireNm[actualWire, new]};
refCell: CellType ←
IF specificGeneric THEN NARROW[cellTypes.first.data, CellType] ELSE cellTypes.first;
Imports don't understand this prop until recasted
IF GetCellSide[data[index].type]=none THEN Signal[];
IF data[index].type#refCell THEN Signal[];
IF cellTypes.first.public.size#0
THEN [ ] ← CoreOps.VisitBinding
[actual: data[index].actual, public: cellTypes.first.public, eachWirePair: Visit];
cellTypes ← cellTypes.rest ENDLOOP;
EnsureUniqueNames[cellType]};
MergeCell renames children actuals based on children publics then does EnsureUniqueNames.
MergeCell can't be used in AbutCellList because AbutCellList must deal with specificGeneric's.
MergeCell is useful for extracting pads by getting Gnd and Vdd to connect.
MergeCell:
PUBLIC PROC[cellType: CellType] = {
data: CoreClasses.RecordCellType ← NARROW[cellType.data];
FOR index:
NAT
IN [0..data.size)
DO
Visit: CoreOps.EachWirePairProc ~ {
new: ROPE ← CoreName.WireNm[publicWire].n;
IF publicWire.size#0 OR new.Length[]=0 THEN RETURN[TRUE, FALSE];
[ ] ← CoreName.WireNm[actualWire, new]};
IF data[index].type.public.size#0
THEN [ ] ← CoreOps.VisitBinding
[actual: data[index].actual, public: data[index].type.public, eachWirePair: Visit] ENDLOOP;
EnsureUniqueNames[cellType]};
phA: ROPE ← CoreName.RopeNm["PhA"];
phB: ROPE ← CoreName.RopeNm["PhB"];
GND: ROPE ← CoreName.RopeNm["GND"];
VDD: ROPE ← CoreName.RopeNm["VDD"];
VBB: ROPE ← CoreName.RopeNm["VBB"];
Public wires with the same name are merged.
InternalOnlys are given versions (ie !1)
EnsureUniqueNames:
PROC[cellType: CellType] = {
publics: CoreName.Context ← CoreName.NewContext[]; -- public name to wire
deletedPublics: HashTable.Table ← HashTable.Create[]; -- wires
internal: CoreName.Context ← CoreName.NewContext[]; -- internal name to wire
iVersion: HashTable.Table ← HashTable.Create[]; -- internal name to version
data: CoreClasses.RecordCellType ← NARROW[cellType.data];
ResolveNameConflicts:
PROC[root: Wire, mergeConflicts:
BOOL ←
FALSE] = {
CoreOps.FlushNameCaches[root];
FOR i:
INT
IN [0..root.size)
DO
IF root[i].size # 0
THEN ResolveNameConflicts[root[i], mergeConflicts]
ELSE {
old: Wire ← root[i];
wNm: ROPE ← CoreName.WireNm[old].n;
regPublic: Wire ← CoreName.CtxNameToWire[publics, wNm];
regInternal: Wire ← CoreName.CtxNameToWire[internal, wNm];
alreadyMerged: BOOL ← HashTable.Fetch[deletedPublics, old].found;
IF wNm.Length[]=0 THEN LOOP; -- no conflicts possible
IF regInternal=old THEN LOOP;
IF regPublic#
NIL
AND mergeConflicts
OR alreadyMerged
THEN {
root[i] ← regPublic;
IF alreadyMerged THEN LOOP;
[ ] ← HashTable.Store[deletedPublics, old, old];
[ ] ← AddWireSide[root[i], GetWireSide[old]];
CoreGeometry.AddIndirectLazyPins[PWC.extractMode.decoration, root[i], old];
LOOP};
SELECT wNm FROM phA, phB, GND, VDD, VBB => Signal[]; ENDCASE;
IF regInternal=
NIL
THEN {[ ] ← CoreName.CtxRegisterWire[internal, old]}
ELSE {
last: REF INT ← NARROW[HashTable.Fetch[iVersion, wNm].value];
IF last=
NIL
THEN
{[ ] ← HashTable.Store[iVersion, wNm, NEW[INT ← 0]]; LOOP};
last^ ← last^ +1;
[]𡤌oreName.WireNm[old, wNm.Cat[IO.PutFR["!%g",IO.int[last^]]]]}} ENDLOOP};
Visitor:
PROC [wire: Wire] = {
[ ] ← CoreName.CtxRegisterWire[publics, wire];
[ ] ← CoreName.CtxRegisterWire[internal, wire]};
log.PutF["\nEnsure unique wire names for: %g ", IO.rope[CoreName.CellNm[cellType].n]];
[ ] ← CoreOps.VisitRootAtomics[cellType.public, Visitor];
ResolveNameConflicts[root: cellType.public, mergeConflicts: TRUE];
FOR i:
INT
IN [0..data.size)
DO
ResolveNameConflicts[root: data[i].actual, mergeConflicts: FALSE] ENDLOOP;
ResolveNameConflicts[root: data.internal, mergeConflicts: FALSE];
cellType.public ← CoreName.WireFromCtx[publics]; -- flatten and reorder
data.internal ← CoreName.WireFromCtx[internal]; -- flatten and reorder
HashTable.Erase[iVersion];
HashTable.Erase[deletedPublics];
publics ← CoreName.KillContext[publics];
publics ← CoreName.KillContext[internal]};
MergeSplitPublicsRenameInternalConflicts: PROC[cellType: CellType] = {
index: INT;
publics: CoreName.Context ← CoreName.NewContext[];
deletedPublics: HashTable.Table; -- removed public wires
iOnlys: HashTable.Table; -- int onlys version #
name: ROPE ← CoreName.CellNm[cellType].n;
data: CoreClasses.RecordCellType ← NARROW[cellType.data];
SubstituteContextWires: PROC[root: Wire, trap: BOOL] = {
FOR i: INT IN [0..root.size) DO
IF root[i].size # 0
THEN SubstituteContextWires[root[i], trap]
ELSE {
old: Wire ← root[i];
wNm: ROPE ← CoreName.WireNm[old].n;
new: Wire ← CoreName.CtxNameToWire[publics, wNm];
IF new=NIL OR new=old THEN LOOP;
IF HashTable.Fetch[deletedPublics, old].found THEN {root[i] ← new; LOOP};
IF trap THEN {
IF HashTable.Fetch[iOnlys, wNm].found THEN {
last: REF INT ← NARROW[HashTable.Fetch[deletedPublics, old].value];
[]𡤌oreName.WireNm[old, wNm.Cat[IO.PutFR["!%g",IO.int[last^]]]];
last^ ← last^ +1;
LOOP}; -- add version # to additional iOnlys
IF index=-1
THEN Signal[] -- why was this not found in actuals
ELSE {
log.PutF["\nSIGNAL - Internal-Only with public name %g", IO.rope[wNm] ];
log.PutF["\n Parent: %g Index: %g Child: %g",
IO.rope[name], IO.int[index], IO.rope[CoreName.CellNm[data[index].type].n] ];
[]𡤌oreName.WireNm[old, wNm.Cat["!0"]];
[ ] ← HashTable.Store[iOnlys, wNm, NEW[INT ← 1]]; LOOP} };
root[i] ← new;
[ ] ← HashTable.Store[deletedPublics, old, old];
log.PutF["\n Joining split public %g", IO.rope[wNm]];
[ ] ← AddWireSide[root[i], GetWireSide[old]];
CoreGeometry.AddIndirectLazyPins[PWC.extractMode.decoration, root[i], old]};
ENDLOOP};
VisitPublics: PROC [wire: Wire] = {[ ] ← CoreName.CtxRegisterWire[publics, wire]};
log.PutF["\nCheck new public and internal of: %g ", IO.rope[name]];
[ ] ← CoreOps.VisitRootAtomics[cellType.public, VisitPublics];
deletedPublics ← HashTable.Create[]; -- removed public wires
iOnlys ← HashTable.Create[]; -- next version
SubstituteContextWires[cellType.public, FALSE];
cellType.public ← CoreName.WireFromCtx[publics];
FOR index IN [0..data.size) DO SubstituteContextWires[data[index].actual, TRUE] ENDLOOP;
index ← -1;
SubstituteContextWires[data.internal, TRUE];
HashTable.Erase[iOnlys];
HashTable.Erase[deletedPublics];
publics ← CoreName.KillContext[publics]};
AbutCellInstances: PUBLIC PROC[
name: ROPE,
first: Sides,
instances: CoreClasses.CellInstances]
RETURNS[cellType: CellType] = {
size: INT ← 0;
index: INT ← 0;
newPublicCtx: CoreName.Context ← CoreName.NewContext[];
newPublicWire: Wire;
newPublicWires: Core.Wires ← NIL;
noNamePublics: Core.Wires ← NIL;
ais: LIST OF PWC.AbutInstance ← NIL;
inX: BOOL ← SELECT first FROM left, right => TRUE, bottom, top => FALSE, ENDCASE => ERROR;
FOR list: CoreClasses.CellInstances ← instances, list.rest WHILE list#NIL DO
size ← size+1 ENDLOOP;
index ← 0;
FOR list: CoreClasses.CellInstances ← instances, list.rest WHILE list#NIL DO
eachWirePair: CoreOps.EachWirePairProc ~ {
aName: ROPE ← CoreName.WireNm[actualWire].n;
pName: ROPE ← CoreName.WireNm[publicWire].n;
sides: Sides ← GetWireSide[publicWire];
IF actualWire.size#0 THEN RETURN;
IF OnSide[sides, outSides] THEN {
parentPublic: Wire;
IF aName#NIL
THEN
parentPublic ← CoreName.CtxWire[newPublicCtx, aName] -- adds if new
ELSE {
Signal[];
parentPublic ← CoreOps.CreateWires[0]; -- Should Be Dead End Wire
noNamePublics ← CONS[parentPublic, noNamePublics]};
Must use rope here since Identity sub cell publics get copied when making the CellType to Layout to CellType round trip
pas ← CONS[ [pName, parentPublic], pas];
[ ] ← AddWireSide[parentPublic, DelSide[inSides, sides]] } };
pas: LIST OF CoreCreate.PA ← NIL;
outSides: Sides ← OutSides[index, size, first];
inSides: Sides ← DelSide[outSides, all];
IF checking AND GetCellSide[list.first.type]=none THEN Signal[];
[ ] ← CoreOps.VisitBinding
[actual: list.first.actual, public: list.first.type.public, eachWirePair: eachWirePair];
THEN Signal[];
ais ← CONS[[PWC.Layout[list.first.type], pas], ais];
index ← index+1;
ENDLOOP;
newPublicWires ← CoreName.WiresFromCtx[newPublicCtx];
FOR list: Core.Wires ← noNamePublics, list.rest WHILE list#NIL DO
newPublicWires ← CONS[ list.first, newPublicWires] ENDLOOP;
newPublicWire ← CoreOps.CreateWire[newPublicWires];
DelPAInternalOnlys[newPublicCtx, ais];
SELECT first FROM right, top => { }; ENDCASE => {
list: LIST OF PWC.AbutInstance ← ais; ais ← NIL;
FOR list ← list, list.rest WHILE list#NIL DO ais ← CONS[list.first, ais] ENDLOOP};
cellType ← PWC.AbutCell[
public: newPublicWire,
abutInstances: ais,
inX: inX,
shared: FALSE,
name: name,
props: NIL];
newPublicCtx ← CoreName.KillContext[newPublicCtx];
CoreBlock.PutCellSide [cellType, IF inX THEN left ELSE bottom]};
DelPAInternalOnlys:
PROC[context: CoreName.Context, ais:
LIST
OF
PWC.AbutInstance] = {
IsPublic:
PROC[wr: CoreCreate.
WR]
RETURNS[
BOOL] =
{name: ROPE ← NARROW[wr]; RETURN[CoreName.CtxNameToWire[context, name]#NIL]};
FOR ais ← ais, ais.rest
WHILE ais#
NIL
DO
-- two LOOPs to avoid CONSing
pas: LIST OF CoreCreate.PA;
DO
-- remove internal onlys from first of list
IF ais.first.pas=NIL THEN GOTO Exit;
IF IsPublic[ais.first.pas.first.actual] THEN EXIT;
ais.first.pas ← ais.first.pas.rest;
REPEAT Exit => LOOP; ENDLOOP;
pas ← ais.first.pas;
WHILE pas.rest#
NIL
DO
-- remove internal onlys from rest of list
IF IsPublic[pas.rest.first.actual]
THEN pas ← pas.rest
ELSE pas.rest ← pas.rest.rest ENDLOOP;
ENDLOOP};
checking: BOOL ← TRUE;
OutSides:
PROC[index, size:
INT, first: Sides]
RETURNS[ outSides: Sides ← all] = {
nextInSide, lastInSide: Sides;
SELECT first
FROM
left => {nextInSide ← right; lastInSide ← left};
bottom => {nextInSide ← top; lastInSide ← bottom};
right => {nextInSide ← left; lastInSide ← right};
top => {nextInSide ← bottom; lastInSide ← top};
ENDCASE => Signal[];
IF index#0 THEN outSides ← DelSide[lastInSide, outSides];
IF index+1#size THEN outSides ← DelSide[nextInSide, outSides]};
PWC.FromLayoutWithoutPublic of PW.Abut
Rename by visiting bindings
AbutCellInstances: PUBLIC PROC[
name: ROPE,
first: Sides,
instances: CoreClasses.CellInstances]
RETURNS[cellType: CellType,
] = {
RevObjs: PROC = {
temp: PW.ListOb ← objs; objs ← NIL;
FOR temp ← temp, temp.rest WHILE temp#NIL DO objs ← CONS[temp.first, objs] ENDLOOP};
publicSides: HashTable.Table ←
HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope];
newFirst: Sides;
objs: PW.ListOb ← NIL;
obj: CD.Object ← NIL;
data: CoreClasses.RecordCellType;
list: CoreClasses.CellInstances ← SELECT first FROM
left, bottom => RevInstances[instances], ENDCASE => instances;
FOR list ← list, list.rest WHILE list#NIL DO
objs ← CONS[PWC.Layout[list.first.type], objs] ENDLOOP;
SELECT first FROM
left, right => {obj ← PW.AbutListX[objs]; newFirst ← left};
bottom, top => {obj ← PW.AbutListY[objs]; newFirst ← bottom};
ENDCASE => ERROR;
cellType ← PWC.FromLayoutWithoutPublic[obj];
[ ] ← CoreName.CellNm[cellType, name];
data ← NARROW[cellType.data];
IF data.size>1 AND first=none THEN Signal[];
list ← SELECT first FROM
right, top => RevInstances[instances], ENDCASE => instances;
FOR index: NAT IN [0..data.size) DO
Visit: CoreOps.EachWirePairProc ~ {
name: ROPE ← CoreName.WireNm[publicWire].n;
[ ] ← CoreName.WireNm[actualWire, name]};
IF GetCellSide[data[index].type]=none THEN Signal[];
IF list.first.type#data[index].type THEN Signal[]; -- PWC should have cached
[ ] ← CoreOps.VisitBinding
[actual: data[index].actual, public: list.first.actual, eachWirePair: Visit];
list ← list.rest ENDLOOP;
CoreOps.FlushNameCaches[cellType.public];
CoreOps.FlushNameCaches[data.internal];
CoreBlock.PutCellSide [cellType, newFirst];
CoreBlock.MergeSides [cellType];
SELECT newFirst FROM
left => PWC.SetAbutX[cellType];
bottom => PWC.SetAbutY[cellType];
ENDCASE => Signal[] };
PWC.FromLayoutWithoutPublic of PW.Abut
Rename by visiting bindings
AbutCellInstances: PUBLIC PROC[
name: ROPE,
first: Sides,
instances: CoreClasses.CellInstances]
RETURNS[cellType: CellType,
] = {
ApplySidesToPublic: PROC [wire: Wire] ~ {
name: ROPE ← CoreName.WireNm[wire].n;
refSides: REF Sides ← NARROW[HashTable.Fetch[publicSides, name].value];
IF refSides=NIL THEN Signal[];
IF refSides^=none THEN Signal[];
IF CoreProperties.GetWireProp[wire, SidesProp[]]#NIL THEN Signal[];
CoreProperties.PutWireProp[wire, SidesProp[], refSides]};
RevObjs: PROC = {
temp: PW.ListOb ← objs; objs ← NIL;
FOR temp ← temp, temp.rest WHILE temp#NIL DO objs ← CONS[temp.first, objs] ENDLOOP};
publicSides: HashTable.Table ←
HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope];
hidden: Sides;
newFirst: Sides;
newLast: Sides;
objs: PW.ListOb ← NIL;
obj: CD.Object ← NIL;
data: CoreClasses.RecordCellType;
list: CoreClasses.CellInstances ← SELECT first FROM
left, bottom => RevInstances[instances], ENDCASE => instances;
FOR list ← list, list.rest WHILE list#NIL DO
objs ← CONS[PWC.Layout[list.first.type], objs] ENDLOOP;
SELECT first FROM
left, right => {obj ← PW.AbutListX[objs]; newFirst ← left};
bottom, top => {obj ← PW.AbutListY[objs]; newFirst ← bottom};
ENDCASE => ERROR;
newLast ← OtherSide[newFirst];
cellType ← PWC.FromLayoutWithoutPublic[obj];
[ ] ← CoreName.CellNm[cellType, name];
data ← NARROW[cellType.data];
IF data.size>1 AND first=none THEN Signal[];
list ← SELECT first FROM
right, top => RevInstances[instances], ENDCASE => instances;
FOR index: NAT IN [0..data.size) DO
Visit: CoreOps.EachWirePairProc ~ {
name: ROPE ← CoreName.WireNm[publicWire].n;
side: Sides ← GetWireSide[actualWire];
pubs: REF Sides ← NARROW[HashTable.Fetch[publicSides, name].value];
side ← DelSide[hidden, side];
IF pubs=NIL THEN pubs ← NEW[Sides ← none];
pubs^ ← AddSide[pubs^, side];
[ ] ← HashTable.Store[publicSides, name, pubs];
[ ] ← CoreName.WireNm[actualWire, name]};
IF GetCellSide[data[index].type]=none THEN Signal[];
hidden ← IF index # 0 THEN newFirst ELSE none;
hidden ← AddSide[ IF (index+1) < data.size THEN newLast ELSE none, hidden];
IF list.first.type#data[index].type THEN Signal[]; -- PWC should have cached
[ ] ← CoreOps.VisitBinding
[actual: data[index].actual, public: list.first.actual, eachWirePair: Visit];
list ← list.rest ENDLOOP;
CoreOps.VisitRootAtomics[wire: cellType.public, eachWire: ApplySidesToPublic];
CoreOps.FlushNameCaches[cellType.public];
CoreOps.FlushNameCaches[data.internal];
CoreBlock.PutCellSide [cellType, newFirst];
CoreBlock.MergeSides [cellType]; -- replaced by ApplySidesToPublic
SELECT newFirst FROM
left => PWC.SetAbutX[cellType];
bottom => PWC.SetAbutY[cellType];
ENDCASE => Signal[] };
PWC.CoreCreate.Cell
AbutCellList: PUBLIC PROC[
name: ROPE,
first: Sides,
cellTypes: LIST OF CellType,
]
RETURNS[cellType: CellType,
] = {
oIside, nIside, oOsides, nOsides: Sides;
public: CoreName.Context ← CoreName.NewContext[];
internal: CoreName.Context ← CoreName.NewContext[];
intOnly: CoreName.Context ← CoreName.NewContext[];
intances: CoreClasses.CellInstances;
tempInsts: CoreClasses.CellInstances;
IF first=right OR first=top
THEN {
temp: LIST OF CellType,
← cellTypes; cellTypes ← NIL;
FOR temp ← temp, temp.rest WHILE temp#NIL DO
cellTypes ← CONS[temp.first, cellTypes] ENDLOOP;
IF first=right THEN first←left ELSE first𡤋ottom};
IF first=left
THEN {oIside ← right; nIside ← left}
ELSE {oIside ← top; nIside ← bottom};
oOsides ← DelSide[ oIside, all];
nOsides ← DelSide[ nIside, all];
FOR kids: LIST OF CellType,
← cellTypes, kids.rest WHILE kids#NIL DO
nPubSides: Sides ← all;
IF kids#cellTypes THEN nPubSides ← DelSide[nIside, nPubSides];
IF kids.rest#NIL THEN nPubSides ← DelSide[oIside, nPubSides];
FOR index: INT IN [0..kids.first.public.size) DO
newWire: Wire ← kids.first.public[index];
aName: ROPE ← CoreName.WireNm[newWire ].n;
oldWire: Wire ← CoreName.CtxWire[internal, aName]; -- adds if not present
check: Wire ← CoreName.CtxNameToWire[intOnly, aName];
oldSides: Sides ← CoreBlock.GetWireSide[oldWire];
newSides: Sides ← CoreBlock.GetWireSide[newWire];
oldExternal: BOOL ← CoreBlock.OnSide[oldSides, oOsides];
oldConn: BOOL ← CoreBlock.OnSide[oldSides, oIside];
newExternal: BOOL ← CoreBlock.OnSide[newSides, nOsides];
newConn: BOOL ← CoreBlock.OnSide[newSides, nIside];
newPublic: BOOL ← CoreBlock.OnSide[newSides, nPubSides];
IF check#NIL THEN Signal[];
IF kids#cellTypes THEN {
IF oldConn # newConn THEN {
log.PutF["\n Wire ending at cell boundry."];
log.PutF[" Parent: %g; Neglected child: %g; Wire: %g",
IO.rope[name], IO.rope[CoreName.CellNm[kids.first].n], IO.rope[aName]]};
IF ~(oldExternal OR newExternal) THEN [] ← CoreName.CtxWire[intOnly, aName]};
IF oldExternal OR newPublic THEN [ ] ← CoreName.CtxRegisterWire[public, oldWire];
PutWireSide[oldWire, AddSide[DelSide[ oIside, oldSides], DelSide[ nIside, newSides]]];
ENDLOOP;
intances ← CONS[CoreCreate.Instance[ kids.first ], intances];
ENDLOOP;
tempInsts ← intances; intances ← NIL;
FOR tempInsts ← tempInsts, tempInsts.rest WHILE tempInsts#NIL DO
intances ← CONS[tempInsts.first, intances] ENDLOOP;
IF HashTable.GetSize[internal] # (HashTable.GetSize[public] + HashTable.GetSize[intOnly])
THEN log.PutF["\n CoreBlockImpl.AbutCellList internal#public+intOnly anomaly"];
THEN Signal;
cellType ← CoreCreate.Cell[
public: CoreName.WireFromCtx[public],
internal: CoreName.WireFromCtx[internal],
instances: intances,
name: name ];
public ← CoreName.KillContext[public];
internal ← CoreName.KillContext[internal];
intOnly ← CoreName.KillContext[intOnly];
CoreBlock.PutCellSide [cellType, first];
CoreBlock.MergeSides [cellType];
SELECT first FROM
left => PWC.SetAbutX[cellType];
bottom => PWC.SetAbutY[cellType];
ENDCASE => Signal[] };
MarkSides:
PUBLIC
PROC[cell: CellType, cap: Sides ← none] = {
eachWireProc:
PROC [wire: Wire] =
{[ ] ← CoreBlock.PutWireSide[wire, DelSide[cap, GetWireLayoutSides[cell, wire] ] ]};
IF GetCellSide[cell]#none THEN RETURN; -- already done (ie. cached blank)
[] ← CoreOps.VisitRootAtomics[cell.public, eachWireProc];
PutCellSide[cell, all]};
MySides:
PROC[hisSides: CoreGeometry.Sides]
RETURNS[mySides: Sides ← none] = {
IF hisSides[left] THEN mySides ← CoreBlock.AddSide[mySides, left];
IF hisSides[right] THEN mySides ← CoreBlock.AddSide[mySides, right];
IF hisSides[top] THEN mySides ← CoreBlock.AddSide[mySides, top];
IF hisSides[bottom] THEN mySides ← CoreBlock.AddSide[mySides, bottom]};
GetWireLayoutSides:
PUBLIC
PROC[cell: CellType, wire: Wire]
RETURNS[sides: Sides ← none] = {
ir: CD.Rect ← PWC.InterestRect[cell];
eachPinProc: CoreGeometry.EachInstanceProc =
{sides ← CoreBlock.AddSide[sides, MySides[CoreGeometry.GetSides[ir, instance]]]};
[] ← CoreGeometry.EnumeratePins[PWC.extractMode.decoration, wire, eachPinProc]};
GetInstSideLocSize:
PUBLIC
PROC
[ob: CD.Object, inst: CD.Instance] RETURNS [side: CoreBlock.Sides, loc, size: INT] = {
base: CD.Rect ← CD.InterestRect[ob];
rect: CD.Rect ← CDOrient.RectAt[inst.location, inst.ob.size, inst.orientation];
side ← none;
IF base.y1 = rect.y1 THEN side ← AddSide[bottom, side];
IF base.x2 = rect.x2 THEN side ← AddSide[right, side];
IF base.y2 = rect.y2 THEN side ← AddSide[top, side];
IF base.x1 = rect.x1 THEN side ← AddSide[left, side];
loc ←
SELECT side
FROM
left, right => rect.y1 - base.y1,
top, bottom => rect.x1 - base.x1,
ENDCASE => 0;
size ←
SELECT side
FROM
left, right => rect.y2 - rect.y1,
top, bottom => rect.x2 - rect.x1,
ENDCASE => 0};
log: IO.STREAM ← CoreFrame.GetLog[];
END.