IFUCoreDataImpl:
CEDAR
PROGRAM
IMPORTS CCDUtils, CD, CDBasics, CDCells, CDDirectory, CDRects, CDSymbolicObjects, Convert, CoreBlock, CoreFrame, CoreLibrary, CoreName, CoreOps, CoreWire, CoreXform, HashTable, IFUCoreCells, IFUCoreData, CoreInstCell, IO, PW, PWC, Rope
EXPORTS IFUCoreData =
BEGIN
ROPE: TYPE = Core.ROPE;
NameLetterCode: TYPE = IFUCoreData.NameLetterCode;
NameLetterCodeRec: TYPE = IFUCoreData.NameLetterCodeRec;
NWMML: TYPE = PWC.NWMML;
GND: ROPE ← CoreName.RopeNm["GND"];
VDD: ROPE ← CoreName.RopeNm["VDD"];
minus: ROPE ← CoreName.RopeNm["-"];
plus: ROPE ← CoreName.RopeNm["+"];
nil: ROPE ← CoreName.RopeNm["nil"];
pwrList: LIST OF REF ← LIST[GND, VDD];
Signal: SIGNAL = CODE;
dpCellClass:
PUBLIC Core.CellClass ←
CoreOps.SetClassPrintProc[
NEW[Core.CellClassRec ← [name: "IFUCoreData", recast: NIL]],
ClassPrintProc];
ClassPrintProc: CoreOps.PrintClassProc = {
dpData: IFUCoreData.DpCellData ← NARROW[data];
IO.PutF[out, "Data Path Subclass: %g Type: \n", IO.rope[dpData.subClass] ];
CoreOps.PrintWire[dpData.type.w, out, 2] };
RegisterSubClassExpand:
PUBLIC
PROC
[type: CoreFrame.ExpandType, subClass: ROPE, expand: CoreFrame.ExpandProc] = {
IF type = soft
THEN [ ] ← HashTable.Store[expandSoft, subClass, NEW[CoreFrame.ExpandProc← expand]]
ELSE [ ] ← HashTable.Store[expandHard,subClass, NEW[CoreFrame.ExpandProc← expand]]};
expandHard: HashTable.Table ←
HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope];
expandSoft: HashTable.Table ←
HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope];
Sequencial48:
PUBLIC CoreXform.Xform ←
CoreXform.GenXform[LIST[ [4, 0], [8, 1] ]];
Interleaved48:
PUBLIC CoreXform.Xform ←
CoreXform.GenXform[LIST[ [4, 1], [8, 0] ]];
CellProc:
PUBLIC
PROC [
subClass: ROPE ← NIL,
type: ROPE ← NIL,
name: ROPE ← NIL,
left: REF ← NIL,
right: REF ← NIL,
top: REF ← NIL,
bot: REF ← NIL,
in: REF ← NIL,
out: REF ← NIL,
data: REF ← NIL,
channels: INT ← 6,
xform: CoreXform.Xform ← IFUCoreData.Interleaved48 ]
RETURNS [cellType: Core.CellType] = {
ctx: CoreName.Context ← CoreName.NewContext[];
public: CoreWire.CWire;
strucType: CoreWire.CWire;
expandSoftProc: REF CoreFrame.ExpandProc;
expandHardProc: REF CoreFrame.ExpandProc;
xforms: CoreXform.Xforms ← CoreXform.GenXforms[xform];
public ← [CoreOps.CreateWire[
LIST[
RdListOfXfrmWires[ctx, "top", top, xforms],
RdListOfXfrmWires[ctx, "bot", bot, xforms],
RdListOfXfrmWires[ctx, "in", in, xforms],
RdListOfXfrmWires[ctx, "out", out, xforms],
RdListOfXfrmWires[ctx, "right", right, NIL], -- if needed put xform on rope
RdListOfXfrmWires[ctx, "left", left, NIL], -- if needed put xform on rope
RdListOfXfrmWires[ctx, "pwr", pwrList, NIL] ]]];
ctx ← CoreName.KillContext[ctx];
ctx ← CoreName.NewContext[];
strucType ← [RdListOfXfrmWires[ctx, "type", LIST[type], xforms][0]];
ctx ← CoreName.KillContext[ctx];
DeleteGV[public.f["top"].w];
DeleteGV[public.f["bot"].w];
cellType ← CoreOps.SetCellTypeName[
NEW [ Core.CellTypeRec ← [
class: dpCellClass,
public: public.w,
data:
NEW[IFUCoreData.DpCellDataRec ← [
subClass: subClass,
type: strucType,
data: data,
channels: channels ] ],
properties: NIL] ],
name];
expandSoftProc ← NARROW[HashTable.Fetch[expandSoft, subClass].value];
expandHardProc ← NARROW[HashTable.Fetch[expandHard, subClass].value];
IF expandSoftProc=NIL THEN Signal[];
IF expandHardProc=NIL THEN Signal[];
CoreFrame.SetFrameExpandProc[soft, cellType, expandSoftProc ];
CoreFrame.SetFrameExpandProc[hard, cellType, expandHardProc ]};
If ref is a list then sform applies to it.
If not, xforms applies to the elements of the list;
RdListOfXfrmWires:
PROC[ctx: CoreName.Context, name: ROPE, ref:
REF, xforms: CoreXform.Xforms]
RETURNS[wire: Core.Wire] = {
new: CoreXform.Xforms;
[ref, new] ← Parse[ref];
IF new#NIL THEN xforms ← new;
IF
ISTYPE[ref,
LIST
OF
REF]
THEN wire ← GenWireFmList[ctx, NARROW[ ref], xforms]
ELSE wire ← GenWireFmItem[ctx, ref, xforms];
[ ] ← CoreName.WireNm[wire, name];
FOR jj:
INT
IN [0..wire.size)
DO
CoreXform.SetXform[wire[jj], CoreXform.GenXform[xforms]] ENDLOOP };
DeleteGV:
PROC[top: Core.Wire] = {
-- doesn't work for top node
DeleteGVMain:
PROC[wire: Core.Wire]
RETURNS[new: Core.Wire] = {
IF wire.size=0
THEN
RETURN[
SELECT CoreName.WireNm[wire].n
FROM
GND, VDD => CoreOps.CreateWires[0] ENDCASE => wire]
ELSE FOR i: INT IN [0..wire.size) DO wire[i] ← DeleteGVMain[wire[i]] ENDLOOP;
RETURN[wire]};
[] ← DeleteGVMain[top]};
Can't use this because wires are shared. Sharing maybe useful in the future if the row public gets used to make a celltype, but for now, rowWires are just used to package names.
DeleteGV: PROC[wire: Core.Wire] = {
SELECT CoreName.WireNm[wire].n FROM
GND, VDD => [ ] ← CoreOps.SetShortWireName[wire, NIL] ENDCASE;
FOR i: INT IN [0..wire.size) DO DeleteGV[wire[i]] ENDLOOP};
LISTIndexItem:
PUBLIC
PROC[list:
LIST
OF
REF, index:
INT]
RETURNS[item:
REF] = {
FOR index ← index, index-1 WHILE index#0 AND list#NIL DO list←list.rest ENDLOOP;
RETURN[IF list=NIL THEN NIL ELSE list.first]};
LISTLength:
PUBLIC
PROC [list:
LIST
OF
REF]
RETURNS[size:
INT] =
{FOR size ← 0, size+1 WHILE list#NIL DO list←list.rest ENDLOOP};
AddGVToLIST:
PROC [list:
LIST
OF
REF, rngWord:
INT, indexGV:
BOOL ←
FALSE]
RETURNS[new: LIST OF REF] = {
FOR ii:
INT
DECREASING
IN [0..
MAX[rngWord+2, LISTLength[list]])
DO
item: REF ← LISTIndexItem[list, ii];
IF ii=rngWord+1 THEN item ← IF indexGV THEN VDD.Cat["."] ELSE VDD;
IF ii=rngWord THEN item ← IF indexGV THEN GND.Cat["."] ELSE GND;
new ← CONS[item, new] ENDLOOP};
Parse:
PROC[ref:
REF]
RETURNS[reff:
REF, xforms: CoreXform.Xforms] = {
IF ref=NIL THEN RETURN[NIL, NIL];
WITH ref
SELECT
FROM
rope: Rope.ROPE => {[reff, xforms] ← ParseRope[rope]; RETURN[reff, xforms]};
text:
REF
TEXT => {
rope: Rope.ROPE ← Rope.FromRefText[text];
[reff, xforms] ← ParseRope[rope]; RETURN[reff, xforms]};
list:
LIST
OF
REF => {
temp: LIST OF REF;
FOR list ← list, list.rest
WHILE list#
NIL
DO
temp ← CONS[Parse[list.first].reff, temp]; ENDLOOP;
list ← temp; temp ← NIL;
FOR list ← list, list.rest
WHILE list#
NIL
DO temp ←
CONS[list.first, temp]
ENDLOOP;
RETURN[temp, NIL]};
list:
LIST
OF
ROPE => {
result, temp: LIST OF REF ← NIL;
FOR list ← list, list.rest
WHILE list#
NIL
DO
temp ← CONS[ParseRope[list.first].reff, temp]; ENDLOOP;
FOR temp ← temp, temp.rest
WHILE temp#
NIL
DO result ← CONS[temp.first, result] ENDLOOP;
RETURN[result, NIL]};
ENDCASE => {Signal[]; RETURN[NIL, NIL]}};
ParseRope:
PROC[rope:
ROPE]
RETURNS[reff:
REF, xforms: CoreXform.Xforms] = {
ParseRopeItem:
PROC
RETURNS[
REF ←
NIL] = {
item: ROPE;
item ← ris.GetTokenRope[! IO.EndOfStream => CONTINUE].token;
IF item=NIL THEN RETURN[NIL];
SELECT item.Fetch[0]
FROM
'(, '[ => RETURN[ParseRopeList[]];
'), '] => Signal[];
ENDCASE => RETURN[CoreName.RopeNm[item]]};
ParseRopeList:
PROC
RETURNS[lst:
LIST
OF
REF ←
NIL] = {
temp: LIST OF REF ← NIL;
DO
item: ROPE ← ris.GetTokenRope[! IO.EndOfStream => EXIT].token;
SELECT item.Fetch[0]
FROM
'(, '[ => lst ← CONS[ParseRopeList[], lst];
'), '] => EXIT;
IN ['0..'9] => {
IN ['A..'Z] => {lst ← CONS[CoreName.RopeNm[item], lst]};
ENDCASE => {Signal[]; lst ← CONS[CoreName.RopeNm[item], lst]}; -- prob. bad name
ENDLOOP;
temp ← lst; lst ← NIL;
FOR temp ← temp, temp.rest WHILE temp#NIL DO lst ← CONS[temp.first, lst] ENDLOOP};
ris: IO.STREAM ← IO.RIS[rope];
reff ← ParseRopeItem[] };
GenWireFmList:
PROC[ctx: CoreName.Context, list:
LIST
OF
REF, dims: CoreXform.Xforms]
RETURNS[wire: Core.Wire] = {
size: INT ← 0;
IF list=NIL THEN RETURN[ CoreOps.CreateWires[0, nil] ];
FOR lst: LIST OF REF ← list, lst.rest WHILE lst#NIL DO size ← size + 1; ENDLOOP;
wire ← NEW[Core.WireRec[size]]; size ← 0;
FOR lst:
LIST
OF
REF ← list, lst.rest
WHILE lst#
NIL
DO
wire[size] ← GenWireFmItem[ctx, lst.first, dims]; size ← size + 1; ENDLOOP};
GenWireFmItem:
PROC[ctx: CoreName.Context, item:
REF, dims: CoreXform.Xforms]
RETURNS[wire: Core.Wire] = {
IF item=NIL THEN RETURN[ CoreOps.CreateWires[0, nil] ];
WITH item
SELECT
FROM
first:
LIST
OF
REF =>
wire ← GenWireFmList[ctx, first, IF dims=NIL THEN NIL ELSE dims.rest];
first: Rope.
ROPE => {
SELECT first.Fetch[first.Length[]-1]
FROM
'.,
IN ['0..'9] => {
size: INT ← 0;
list: LIST OF REF;
IF dims=
NIL
THEN wire ← CoreName.CtxWire[ctx, first, 0]
ELSE {
wire ← CoreName.CtxWire[ctx, first, dims.first.size];
IF wire=NIL THEN ERROR; -- probably missing '( )'s
list ← BlowUpRope[first, dims.first.size];
FOR size:
INT
IN [0..wire.size)
DO
wire[size] ← GenWireFmItem[ctx, list.first, dims.rest];
list ← list.rest ENDLOOP} };
ENDCASE => wire ← CoreName.CtxWire[ctx, first, 0] };
ENDCASE => ERROR;
IF wire=NIL THEN ERROR};
BlowUpRope:
PROC[rope:
ROPE, size:
INT]
RETURNS[ropes:
LIST
OF
REF←
NIL]= {
FOR int:
INT
DECREASING
IN [0..size)
DO
ropes ←
CONS[
CoreName.RopeNm[ IO.PutFR["%g%g", IO.rope[rope], IO.int[int]] ],
ropes ]; ENDLOOP};
CellWidth:
PUBLIC
PROC[chans:
INT]
RETURNS[
INT] = {
refCell: Core.CellType ← CoreLibrary.Get[IFUCoreCells.library, "DpLatchBlank"];
RETURN[chans*CCDUtils.metPitch+PWC.InterestSize[refCell].x]};
in0Rp: ROPE ← CoreName.RopeNm["in0"];
in1Rp: ROPE ← CoreName.RopeNm["in1"];
cont: CD.Object ← CCDUtils.Contact[CCDUtils.cmosPoly];
ybias: INT ← CCDUtils.polW/2 - cont.size.y/2;
gndXBias: INT ← -cont.size.x/2 + 1*CCDUtils.metPitch - cont.size.x/2;
vddXBias: INT ← -cont.size.x/2 + 2*CCDUtils.metPitch - cont.size.x/2;
ConstantInputVariant:
PUBLIC PROC [name, in0, in1:
ROPE]
RETURNS [cell: Core.CellType] ={
in0 ← CoreName.RopeNm[in0];
in1 ← CoreName.RopeNm[in1];
IF in0#
GND
AND in1#
GND
AND in0#
VDD
AND in1#
VDD
THEN RETURN[ CoreLibrary.Get[IFUCoreCells.library, name] ] ELSE {
nMod0: ROPE ← SELECT in0 FROM VDD => "-V", GND => "-G", ENDCASE => "-=";
nMod1: ROPE ← SELECT in1 FROM VDD => "-V", GND => "-G", ENDCASE => "-=";
altName: ROPE ← name.Cat[nMod0, nMod1];
cell ← NARROW[HashTable.Fetch[IFUCoreCells.library.table, altName].value];
IF cell#
NIL
THEN
RETURN[cell]
ELSE {
locs: LIST OF CD.Position ← NIL;
orig: CD.Object ← CDDirectory.Fetch[IFUCoreCells.library.design, name].object;
new: CD.Object ← CoreLibrary.Flatten[orig];
iBase: CD.Position ← CDBasics.BaseOfRect[CD.InterestRect[new]];
list: CD.InstanceList ← NARROW [new.specificRef, CD.CellPtr].contents;
FOR list ← list, list.rest
WHILE list #
NIL
DO
OPEN Sym: CDSymbolicObjects;
IF list=NIL THEN EXIT;
IF Sym.IsPin[list.first.ob]
THEN {
inst: CD.Instance ← list.first;
conn: BOOL;
yLoc: INT;
sides: CoreBlock.Sides;
vddLoc, gndLoc: CD.Position;
[sides, yLoc,] ← CoreBlock.GetInstSideLocSize[new, inst];
conn ← CoreBlock.OnSide[left, sides];
vddLoc ← [vddXBias, yLoc+ybias];
gndLoc ← [gndXBias, yLoc+ybias];
SELECT CoreName.RopeNm[Sym.GetName[inst]]
FROM
in0Rp => {
SELECT in0
FROM
VDD =>{Sym.SetName[inst, VDD]; IF conn THEN locs←CONS[vddLoc, locs]};
GND =>{Sym.SetName[inst, GND]; IF conn THEN locs←CONS[gndLoc, locs]};
ENDCASE };
in1Rp => {
SELECT in1
FROM
VDD =>{Sym.SetName[inst, VDD]; IF conn THEN locs←CONS[vddLoc, locs]};
GND =>{Sym.SetName[inst, GND]; IF conn THEN locs←CONS[gndLoc, locs]};
ENDCASE };
ENDCASE };
ENDLOOP;
FOR locs ← locs, locs.rest
WHILE locs#
NIL
DO
[ ] ← PW.IncludeInCell[new, cont, locs.first] ENDLOOP;
[ ] ← CDCells.RepositionCell[new, NIL];
cell ← CoreLibrary.ObjCell[new, altName];
CoreLibrary.Set[ IFUCoreCells.library, altName, cell] } } };
ConnSpec: TYPE = REF ConnSeqRec;
ConnSeqRec: TYPE = RECORD[SEQUENCE size: CARDINAL OF CnntRec];
CnntRec: TYPE = RECORD[name: ROPE, min, max: INT, layer: CD.Layer];
GenericCellRegistry: HashTable.Table ← HashTable.Create[];
CreateNameLetterCode:
PUBLIC
PROC
[genericID:
REF, list:
LIST
OF CoreWire.CWire, xformBit:
INT]
RETURNS[code: NameLetterCode] = {
code ← InitNameLetterCode[];
IF genericID=
NIL
THEN code.name ← CoreName.ID["BitRouteRef"]
ELSE {
code.name ← NARROW[HashTable.Fetch[GenericCellRegistry, genericID].value];
IF code.name =
NIL
THEN {
IF genericID=NIL THEN genericID ← CoreName.ID["BitRouteRef"];
code.name ←
WITH genericID
SELECT
FROM
rope: ROPE => genericID ← CoreName.RopeNm[rope],
text: REF TEXT => genericID ← CoreName.RopeNm[Rope.FromRefText[text]],
ENDCASE => CoreName.ID["BitRouteRef"];
[ ] ← HashTable.Store[GenericCellRegistry, genericID, code.name]} };
FOR list ← list, list.rest
WHILE list#
NIL
DO
code.name ← code.name.Cat[ "|" ];
FOR index:
INT
IN [0..list.first.w.size)
DO
code.name ← code.name.Cat
[UniqueLetter[code, list.first.i[index].x[xformBit].n[] ] ] ENDLOOP;
ENDLOOP};
Encode:
PUBLIC
PROC[code: NameLetterCode, name:
ROPE]
RETURNS[letter:
ROPE] =
{letter ← NARROW[HashTable.Fetch[code.letFmNm, name].value]};
Decode:
PUBLIC
PROC[code: NameLetterCode, letter:
ROPE]
RETURNS[name:
ROPE] =
{name ← NARROW[HashTable.Fetch[code.nmFmLet, letter].value]};
InitNameLetterCode:
PROC
RETURNS[code: NameLetterCode] = {
code ←
NEW[ NameLetterCodeRec ← [
name: NIL,
letFmNm: HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope],
nmFmLet: HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope],
char: 'a,
none: CoreName.RopeNm["="] ] ];
[ ] ← HashTable.Store[code.letFmNm, VDD, plus];
[ ] ← HashTable.Store[code.nmFmLet, plus, VDD];
[ ] ← HashTable.Store[code.letFmNm, GND, minus];
[ ] ← HashTable.Store[code.nmFmLet, minus, GND] };
UniqueLetter:
PROC[code: NameLetterCode, name:
ROPE]
RETURNS[letter:
ROPE] = {
name ← CoreName.RopeNm[name];
IF name.Length[]=0 OR name=nil THEN RETURN[code.none];
letter ← NARROW[HashTable.Fetch[code.letFmNm, name].value];
IF letter#NIL THEN RETURN[letter];
letter ← CoreName.RopeNm[Convert.RopeFromChar[code.char, FALSE]];
[ ] ← HashTable.Store[code.letFmNm, name, letter];
[ ] ← HashTable.Store[code.nmFmLet, letter, name];
SELECT code.char
FROM
IN ['a..'z) => code.char ← code.char + 1;
'z => code.char ← 'A;
IN ['A..'Z) => code.char ← code.char + 1;
ENDCASE => Signal[]};
DpBitRoute:
PUBLIC
PROC[
specificCell: Core.CellType,
genericCell: Core.CellType,
rowWire: CoreWire.CWire,
phyBit: INT,
channels: INT,
specificName: ROPE ← NIL ] RETURNS [glue: Core.CellType] = {
renameProc: CoreInstCell.RenameProc ~
{new ← code.Decode[letter: old]; IF new=NIL THEN Signal[]; RETURN[new]};
code: IFUCoreData.NameLetterCode ← CreateNameLetterCode
[genericID: genericCell, xformBit: phyBit, list:
LIST[
rowWire.f["top" ],
rowWire.f["in" ],
rowWire.f["out" ],
rowWire.f["right" ],
rowWire.f["left" ],
rowWire.f["bot" ] ]];
genericObj: CD.Object;
generic: Core.CellType ← CoreLibrary.Get[IFUCoreCells.library, code.name];
IF generic=
NIL
THEN {
size: INT ← PWC.InterestSize[specificCell].y;
list: LIST OF NWMML ← CCDUtils.SidePinList[specificCell, left];
count: INT ← 0;
connSpec: ConnSpec;
FOR temp:
LIST
OF
NWMML ← list, temp.rest
WHILE temp#
NIL
DO
count ← count + 1 ENDLOOP;
connSpec ← NEW[ConnSeqRec[count+2]];
connSpec[0] ← [NIL, 0, 0, CCDUtils.cmosMet];
connSpec[connSpec.size-1] ← [NIL, size, size, CCDUtils.cmosMet];
FOR count
IN [1..connSpec.size-1)
DO
connSpec[count] ← [
name: code.Encode[list.first.name],
min: list.first.min,
max: list.first.max,
layer: list.first.layer ];
list ← list.rest ENDLOOP;
genericObj ← IncludeBitWiring[code, connSpec, rowWire, phyBit, channels];
generic ← CoreLibrary.ObjCell[genericObj, code.name ];
CoreLibrary.Set[IFUCoreCells.library, code.name, generic]};
IF specificName = NIL THEN specificName ← CoreName.CellNm[specificCell].n;
IF specificName =
NIL
THEN specificName ← CoreName.ID["BitRoute"]
ELSE specificName ← Rope.Cat[specificName, "BitRoute"];
glue ← CoreInstCell.SpecificGeneric[generic, renameProc];
glue ← CoreFrame.NewFrameCell[0, specificName, [cell: glue ]] };
IncludeBitWiring:
PROC[code: IFUCoreData.NameLetterCode, connSpec: ConnSpec, rowWire: CoreWire.CWire, xBit, channels:
INT]
RETURNS[cell: CD.Object] = {
OPEN CM: CCDUtils;
Same:
PROC[idx1, idx2:
CARDINAL]
RETURNS[
BOOL] =
{RETURN[Rope.Equal[connSpec[idx1].name, connSpec[idx2].name]]};
tIdx: CARDINAL ← connSpec.size-1;
bIdx: CARDINAL ← 0;
cell ← CDCells.CreateEmptyCell[];
Vertical connections
FOR col:
INT
IN [0..channels)
DO
Add:
PROC[idx1, idx2:
CARDINAL]
RETURNS[
BOOL] = {
IF ~Same[idx1, idx2] THEN RETURN[FALSE];
loc.y ← connSpec[idx1].min;
size.y ← connSpec[idx2].max - connSpec[idx1].min;
IF size.y < 0 THEN ERROR;
CCDUtils.AddRet[cell:cell, size: size, loc: loc, level: CM.cmosMet];
RETURN[TRUE]};
size: CD.Position ← [CM.metW, 0];
loc: CD.Position ← [CM.leftTail+col*CM.metPitch-CM.metW/2, 0];
connSpec[tIdx].name ← code.Encode[rowWire.f["top"].i[col].x[xBit].n];
connSpec[bIdx].name ← code.Encode[rowWire.f["bot"].i[col].x[xBit].n];
SELECT connSpec[tIdx].name FROM GND, VDD => connSpec[tIdx].name←NIL ENDCASE;
SELECT connSpec[bIdx].name FROM GND, VDD => connSpec[bIdx].name←NIL ENDCASE;
IF connSpec[tIdx].name#
NIL
THEN
FOR row:
INT
IN [bIdx..tIdx)
DO
CM.PutPin[cell, [
CM.metW,
CM.metW], [loc.x, connSpec[tIdx].max-
CM.metW],
CM.cmosMet, connSpec[tIdx].name];
IF Add[ row, tIdx]
THEN
EXIT;
REPEAT
FINISHED => {
log.PutF["Orphan top signal: %g",
IO.rope[IFUCoreData.Decode[code, connSpec[tIdx].name]]];
Signal[]} ENDLOOP;
IF connSpec[bIdx].name#
NIL
THEN
FOR row:
INT
DECREASING
IN (bIdx..tIdx)
DO
CM.PutPin[cell, [CM.metW, CM.metW], [loc.x, 0], CM.cmosMet, connSpec[bIdx].name];
IF Add[ bIdx, row]
THEN
EXIT;
REPEAT
FINISHED =>
IF ~Same[bIdx, tIdx]
THEN {
log.PutF["Orphan bottom signal: %g",
IO.rope[IFUCoreData.Decode[code, connSpec[bIdx].name]]];
Signal[]} ENDLOOP;
ENDLOOP;
Horizontal connections
FOR row:
INT
IN (bIdx..tIdx)
DO
ctct: CD.Object ← CM.Contact[connSpec[row].layer];
wire: CD.Object;
wWdth: INT ← connSpec[row].max - connSpec[row].min;
Pin:
PROC[side: {left, right}] = {
xLoc: INT ← IF side = right THEN channels*CM.metPitch-CM.cnctSize ELSE 0;
CM.PutPin[cell, [
CM.cnctSize, wWdth],
[xLoc, connSpec[row].min], connSpec[row].layer, connSpec[row].name]};
IF connSpec[row].layer =
CM.cmosMet2
THEN {
wire ← CDRects.CreateRect[[channels*CM.metPitch, wWdth], connSpec[row].layer];
Pin[left]; Pin[right];
[] ← PW.IncludeInCell[cell, wire, [0, connSpec[row].min]]};
FOR col:
INT
IN [0..channels)
DO
wLen: INT ← (channels-1-col)*CM.metPitch + CM.rightTail;
wLoc: CD.Position ← [CM.leftTail + col*CM.metPitch, connSpec[row].min];
connSpec[tIdx].name ← code.Encode[rowWire.f["top"].i[col].x[xBit].n];
connSpec[bIdx].name ← code.Encode[rowWire.f["bot"].i[col].x[xBit].n];
IF ~Same[row, tIdx] AND ~Same[row, bIdx] THEN LOOP;
wire ← CDRects.CreateRect[[wLen, wWdth], connSpec[row].layer];
Pin[right];
[] ←
PW.IncludeInCell[cell, ctct,
[wLoc.x-CM.cnctSize/2, wLoc.y-(CM.cnctSize-wWdth)/2]];
[] ← PW.IncludeInCell[cell, wire, wLoc];
ENDLOOP;
ENDLOOP;
CDCells.SetInterestRect[cell, [0, 0, channels*CM.metPitch, connSpec[tIdx].max]];
[ ] ← CDCells.RepositionCell[cell, NIL] };
BlockSides:
PUBLIC PROC[cell: Core.CellType, cwire: CoreWire.CWire] = {
BlockSideIfNotUsed:
PROC[wire: Core.Wire] = {
sides: CoreBlock.Sides ← CoreBlock.GetWireSide[wire];
name: ROPE ← CoreName.WireNm[wire].n;
ltrt: BOOL ← cwire.f["left"].f[name].w#NIL OR cwire.f["right"].f[name].w#NIL;
IF NOT ltrt THEN RETURN;
SELECT name FROM VDD, GND => RETURN ENDCASE;
IF cwire.f["left" ].f[name].w=NIL THEN sides ← CoreBlock.DelSide[left, sides];
IF cwire.f["right" ].f[name].w=NIL THEN sides ← CoreBlock.DelSide[right, sides];
CoreBlock.PutWireSide[wire, sides]};
CoreOps.VisitRootAtomics[cell.public, BlockSideIfNotUsed]};
log: IO.STREAM ← CoreFrame.GetLog[];
END.