ChipmonkNMosWrite.mesa
Copyright © 1984, 1986 by Xerox Corporation. All rights reserved.
Last edited by: Christian Jacobi, February 20, 1984 12:06 pm
Last edited by: Christian Jacobi, February 24, 1987 12:05:53 pm PST
DIRECTORY
Ascii,
Atom,
Basics USING [BITOR, BITSHIFT],
CD,
CDInstances,
CDBasics,
CDCells,
CDCellsBackdoor,
CDCommandOps,
CDDirectory,
CDIO,
CDOps,
CDProperties,
CDRects,
CDRepetitions,
CDSequencer,
CDTexts,
CDViewer,
FileNames,
FS,
HashTable,
IO,
NMos,
NMosContacts,
NMosTransistors,
Rope,
RuntimeError,
TerminalIO;
ChipmonkNMosWrite:
CEDAR
MONITOR
IMPORTS Ascii, Atom, Basics, CD, CDBasics, CDCells, CDCellsBackdoor, CDCommandOps, CDDirectory, CDInstances, CDIO, CDOps, CDProperties, CDSequencer, FileNames, FS, HashTable, IO, NMos, Rope, RuntimeError, TerminalIO =
BEGIN
TransformSelected:
PROC [design:
CD.Design, transform:
CD.Orientation, base:
CD.Rect←[0, 0, -1, -1]] = {
ib, is, orientOff: CD.Position; r, oldbb: CD.Rect; oldPseudoCellT, newPseudoCellT: CD.Transformation;
sel: CD.InstanceList = CDInstances.OnlySelected[CDOps.InstList[design]];
IF sel=NIL THEN RETURN;
oldbb ← CDInstances.BoundingRectO[sel];
IF ~CDBasics.NonEmpty[base] THEN base ← CDInstances.BoundingRectI[sel];
ib ← CDBasics.BaseOfRect[base];
is ← CDBasics.SizeOfRect[base];
oldPseudoCellT ← [ib, original];
r ← CDBasics.MapRect[CDBasics.RectAt[[0,0], is], [[0,0], transform]];
orientOff ← CDBasics.BaseOfRect[r];
newPseudoCellT ← [CDBasics.SubPoints[ib, orientOff], transform];
FOR w:
CD.InstanceList ← sel, w.rest
WHILE w#
NIL
DO
pseudoCellRel: CD.Transformation ← CDBasics.DecomposeTransform[w.first.trans, oldPseudoCellT];
w.first.trans ← CDBasics.ComposeTransform[pseudoCellRel, newPseudoCellT]
ENDLOOP;
CDOps.Redraw[design, oldbb];
CDOps.Redraw[design, CDBasics.MapRect[CDBasics.DeMapRect[oldbb, oldPseudoCellT], newPseudoCellT]]
};
lambdaInChipmonk:
INTEGER = 2;
--In Chipndale we must make no assumptions about the
--value of lambda. It can (and does) change from time to time;
--but we know that chipndales lambda is >= 2
lambdaFactor: INT = NMos.lambda/lambdaInChipmonk;
codeWordForDataFile: CARDINAL = 123751B;
instanceCode: INTEGER = 1;
transistorCode: INTEGER = 2;
contactCode: INTEGER = 3;
wireCode: INTEGER = 4;
rectangleCode: INTEGER = 5;
textCode: INTEGER = 6;
busCode: INTEGER = 7;
repeatCode: INTEGER = 8;
stream: IO.STREAM;
PushedState: ERROR = CODE;
gMark: HashTable.Table ← NIL;
OutWord:
PROC [
w: INT] =
BEGIN
i: INTEGER = w; --traps if necessary
c: CARDINAL ← LOOPHOLE[i, CARDINAL];
IO.PutChar[stream, LOOPHOLE[c / 256, CHAR]];
IO.PutChar[stream, LOOPHOLE[c MOD 256, CHAR]];
END;
OutNumber:
PROC [n:
CD.Number] =
-- does a lambda correction
BEGIN
i: INTEGER = n / lambdaFactor ; --traps if necessary
c: CARDINAL = LOOPHOLE[i];
IO.PutChar[stream, LOOPHOLE[c / 256, CHAR]];
IO.PutChar[stream, LOOPHOLE[c MOD 256, CHAR]];
END;
OutCard:
PROC [c:
CARDINAL] =
BEGIN
IO.PutChar[stream, LOOPHOLE[c / 256]];
IO.PutChar[stream, LOOPHOLE[c MOD 256]];
END;
OutRope:
PROC [r: Rope.
ROPE] =
BEGIN
leng: [0..256) = MIN[Rope.Length[r], 255];
IO.PutChar[stream, LOOPHOLE[leng, CHAR]];
FOR i:
CARDINAL
IN [0..leng)
DO
IO.PutChar[stream, Rope.Fetch[base: r, index: i]];
ENDLOOP;
IF leng MOD 2 = 0 THEN IO.PutChar[stream, LOOPHOLE[0, CHAR]];
END;
OutRopeUpper:
PROC [r: Rope.
ROPE] =
BEGIN
leng: [0..256) = MIN[Rope.Length[r], 255];
IO.PutChar[stream, LOOPHOLE[leng, CHAR]];
FOR i:
CARDINAL
IN [0..leng)
DO
IO.PutChar[stream, Ascii.Upper[Rope.Fetch[base: r, index: i]]];
ENDLOOP;
IF leng MOD 2 = 0 THEN IO.PutChar[stream, LOOPHOLE[0, CHAR]];
END;
OutLevel:
PROC [lev:
CD.Layer] =
BEGIN
OutCard[levelTab[lev]]
END;
OutSize:
PROC [s:
CD.Position] =
BEGIN
OutNumber[s.x];
OutNumber[s.y];
END;
OutRect:
PROC [r:
CD.Rect] =
BEGIN
OutNumber[r.x1];
OutNumber[r.y1];
OutNumber[r.x2];
OutNumber[r.y2];
END;
cellCount: NAT;
outputedCellCount: NAT;
maxnum: NAT = 2000;
cellNameA: REF ARRAY [0..maxnum) OF CD.Object;
design: CD.Design;
unKnowns: INT ← 0;
unknownObjects: INT ← 0;
unknownAtoms: INT ← 0;
levelTab: REF ARRAY CD.Layer OF [0..15] = NEW[ARRAY CD.Layer OF [0..15]←ALL[15]];
contactTab:
REF
ARRAY NMosContacts.ContactType
OF
CARDINAL ←
NEW[ARRAY NMosContacts.ContactType OF CARDINAL];
EachEntryCount: CDDirectory.EachEntryAction =
BEGIN
WITH ob.specific
SELECT
FROM
cptr: CD.CellSpecific => {cellCount ← cellCount+1};
ENDCASE => NULL;
END;
EachChild: CDDirectory.EachObjectProc = {
IF me.class.composed THEN [] ← EachEntryOutput[name: NIL, ob: me];
};
EachEntryOutput: CDDirectory.EachEntryAction =
-- ignores name parameter, takes name from cell-data itself
BEGIN
IF ~HashTable.Insert[gMark, ob, $x] THEN RETURN;
[] ← CDDirectory.EnumerateChildObjects[ob, EachChild];
WITH ob.specific
SELECT
FROM
cptr:
CD.CellSpecific => {
name: Rope.ROPE ← CDDirectory.Name[ob, design];
IF name=NIL THEN name ← "UNNAMED";
outputedCellCount ← outputedCellCount+1;
cellNameA[outputedCellCount] ← ob;
OutCard[outputedCellCount];
OutRopeUpper[name];
OutSize[CDBasics.SizeOfRect[ob.bbox]];
OutCard[20000]; -- count ??? make it big, just in case it is some kind of reference count
OutList[cptr.contents, cptr.sequence];
};
rp: CDRepetitions.RepSpecific => NULL;
ENDCASE =>
IF ob.class.composed
THEN {
TerminalIO.PutRope["?"];
unKnowns←unKnowns+1;
};
END;
sig: SIGNAL = CODE;
OutputDesign:
ENTRY
PROC [d:
CD.Design, s:
IO.
STREAM] = {
ENABLE UNWIND => NULL;
MOutputDesign[d, s]
};
MOutputDesign:
PROC [d:
CD.Design, s:
IO.
STREAM] =
BEGIN
ENABLE
{
UNWIND => cellNameA←NIL;
PushedState => {GOTO Pushed};
RuntimeError.BoundsFault => {
TerminalIO.PutRope["BoundsFault, maybe some feature is not representable for chipmonk; proceed is secure\n"];
SIGNAL sig;
GOTO Failed
};
RuntimeError.
UNCAUGHT => {
TerminalIO.PutRope["unknown error, maybe some feature is not representable for chipmonk; proceed is secure\n"];
SIGNAL sig;
GOTO Failed
};
};
gMark ← HashTable.Create[];
freeAtom ← 1;
auxAtom[0] ← [older: 0, younger: 0];
stream ← s;
design ← d;
unKnowns ← unknownObjects ← unknownAtoms ← 0;
cellCount ← outputedCellCount ← 0;
[] ← CDDirectory.Enumerate[design, EachEntryCount];
OutCard[codeWordForDataFile];
OutCard[8]; -- version number
OutCard[cellCount];
cellNameA ← NEW[ARRAY [0..maxnum) OF CD.Object ← ALL[NIL]];
[] ← CDDirectory.Enumerate[design, EachEntryOutput];
IF outputedCellCount#cellCount THEN ERROR;
OutPushedLevels[];
OutCard[0]; -- pushed layer 0
OutCard[0]; -- anychanges
OutList[design.actual.first.specific.contents];
cellNameA←NIL;
IF unKnowns#0
THEN {
TerminalIO.PutF1["** unknown features: %g\n", [integer[unKnowns]]];
};
IF unknownObjects#0
THEN {
TerminalIO.PutF1["** unknown objects: %g\n", [integer[unknownObjects]]];
};
IF unknownAtoms#0
THEN {
TerminalIO.PutF1["** unknown properties or propertynames: %g\n", [integer[unknownAtoms]]];
};
EXITS
Pushed => {TerminalIO.PutRope["Output Failed (pushed in cell)\n"]};
Failed => {TerminalIO.PutRope["Output Failed \n"]};
END;
OutPushedLevels:
PROC [] =
BEGIN
IF design.actual.rest#
NIL
THEN {
TerminalIO.PutRope["design is in pushed state\n"];
ERROR PushedState
};
END;
freeAtom: INTEGER ← 1;
AuxEntry: TYPE = RECORD [older, younger: INTEGER -- doubly-linked LRU list --];
auxAtom:
REF
ARRAY [0..atomTableSize]
OF AuxEntry =
NEW[ARRAY [0..atomTableSize] OF AuxEntry];
atomTableSize: INTEGER = 256;
atomTable:
REF ARRAY [1..atomTableSize]
OF Rope.
ROPE
-- for short I/O -- =
NEW[ARRAY [1..atomTableSize] OF Rope.ROPE];
ToRope:
PROC [a:
REF
ANY]
RETURNS [r: Rope.
ROPE] =
BEGIN
IF a=NIL THEN RETURN [NIL];
WITH a
SELECT
FROM
rp: Rope.ROPE => r ← rp;
at: ATOM => r ← Atom.GetPName[at];
ENDCASE => {r ← "?Unknown?"; unknownAtoms←unknownAtoms+1};
END;
OutAtom:
PROC [a:
REF
ANY] =
BEGIN
i: INTEGER;
r: Rope.
ROPE = ToRope[a];
BEGIN
FOR i ← auxAtom[0].older, auxAtom[i].older
WHILE i#0
DO
IF Rope.Equal[r, atomTable[i]]
THEN {
OutCard[LOOPHOLE[-i, CARDINAL]];
-- re-arrange LRU queue
auxAtom[auxAtom[i].older].younger ← auxAtom[i].younger;
auxAtom[auxAtom[i].younger].older ← auxAtom[i].older;
GOTO Touchi;
};
ENDLOOP;
-- add a new atom
IF freeAtom<atomTableSize THEN {i ← freeAtom; freeAtom ← freeAtom+1}
ELSE {
i ← auxAtom[0].younger; -- re-use oldest table entry
auxAtom[0].younger ← auxAtom[i].younger;
auxAtom[auxAtom[i].younger].older ← 0;
};
atomTable[i] ← r;
OutCard[i];
OutRope[r];
GOTO Touchi;
EXITS
Touchi => {
auxAtom[i].older ← auxAtom[0].older;
auxAtom[i].younger ← 0;
auxAtom[auxAtom[0].older].younger ← i;
auxAtom[0].older ← i;
};
END;
END;
HasSurround:
PROC [ob:
CD.Object]
RETURNS [yes:
BOOL←
FALSE] =
INLINE BEGIN
yes ← FALSE
RETURN [ob.layer=NMos.pdif]
END;
AngleExt:
PROC[tob:
CD.Object]
RETURNS [
CD.Number] = {
--copied from cmostransistorsimpl
tp: NMosTransistors.TransistorPtr = NARROW[tob.specific];
RETURN [tp.width+tp.length+tp.wExt-CD.InterestSize[tob].x]
};
Size:
PROC [ob:
CD.Object]
RETURNS [
CD.Position] = {
s: CD.Position ← CDBasics.SizeOfRect[ob.bbox];
IF s.x<0 OR s.y<0 THEN ERROR;
RETURN [s]
};
InstLoc:
PROC [inst:
CD.Instance]
RETURNS [
CD.Position] =
INLINE {
r: CD.Rect ← IF CDCells.IsCell[inst.ob] THEN CDInstances.InstRectO[inst] ELSE CDInstances.InstRectI[inst];
RETURN [CDBasics.BaseOfRect[r]];
};
OutList:
PROC [list:
CD.InstanceList, seq:
CD.InstanceSequence←
NIL] =
BEGIN
OutProps:
PROC [props:
CD.PropList] =
BEGIN
count: CARDINAL ← 0;
FOR pl:
CD.PropList ← props, pl.rest
WHILE pl#
NIL
DO
IF ISTYPE[pl.first.key, ATOM] THEN count ← count+1
ENDLOOP;
OutCard[count];
FOR pl:
CD.PropList←props, pl.rest
WHILE pl#
NIL
DO
IF
ISTYPE[pl.first.key,
ATOM]
THEN {
IF pl.first.key=$InstanceName
OR pl.first.key=$SignalName
THEN {
OutCard[1];
OutRope[ToRope[pl.first.val]]
}
ELSE {
OutCard[2];
OutAtom[pl.first.key];
OutAtom[pl.first.val];
}
}
ENDLOOP;
END;
OutInst:
PROC [i:
CD.Instance]
RETURNS [
BOOL←
FALSE] = {
OutSize[InstLoc[i]];
OutOrient[i.trans.orient];
OutObject[i.ob, i];
OutProps[i.properties]
};
lCnt: INT ← CDInstances.Length[list];
sCnt: INT ← IF seq=NIL THEN 0 ELSE seq.length;
OutCard[lCnt+sCnt];
[] ← CDCellsBackdoor.EnumInsts[list, seq, OutInst]
END;
OutOrient:
PROC [o:
CD.Orientation] =
BEGIN
c: CARDINAL = ORD[o]/2*4 + ORD[o] MOD 2;
OutCard[c];
END;
OutObject:
PROC[ob:
CD.Object, appForRectProperty:
CD.Instance←
NIL] =
BEGIN
OutUnknownObject:
PROC[r: Rope.
ROPE←
NIL] = {
IF NOT Rope.IsEmpty[r] THEN TerminalIO.PutRope[r];
unknownObjects←unknownObjects+1; OutCard[0];
};
OutRectObject:
PROC[ob:
CD.Object] = {
x: REF = CDProperties.GetObjectProp[from: ob, prop: $CDxChipmonkThinks];
IF x=$Rext
THEN {
OutCard[rectangleCode];
OutSize[Size[ob]];
OutLevel[ob.layer];
}
ELSE {
OutCard[wireCode];
OutSize[Size[ob]];
OutLevel[ob.layer];
}
};
IF ob=
NIL
THEN {
OutCard[0];
unKnowns←unKnowns+1;
TerminalIO.PutRope["nil/n"];
RETURN;
};
WITH ob.specific
SELECT
FROM
cptr:
CD.CellSpecific => {
cellNum: NAT ← 0;
OutCard[instanceCode];
FOR i:
NAT
IN [1..cellCount]
DO
IF ob=cellNameA[i] THEN {cellNum←i; EXIT}
ENDLOOP;
IF cellNum=0 THEN {TerminalIO.PutRope["**bad cell\n"]; unKnowns←unKnowns+1};
OutCard[cellNum];
};
rp: CD.RectSpecific => {OutRectObject[ob]};
--wrp: REF NMos.WellRectRep => {OutRectObject[ob]};
tp: NMosTransistors.TransistorPtr => {
j: CARDINAL;
OutCard[transistorCode];
OutNumber[tp.width];
OutNumber[tp.length];
IF tp.lExt/lambdaFactor>63 OR tp.wExt/lambdaFactor>63 THEN ERROR;
j ← tp.lExt/lambdaFactor+tp.wExt/lambdaFactor*64;
IF tp.pullup THEN j ← Basics.BITOR[j, 40000B];
IF tp.implant>0 THEN j ← Basics.BITOR[j, 100000B];
IF tp.angle THEN j ← Basics.BITOR[j, 20000B];
IF HasSurround[ob] THEN j ← Basics.BITOR[j, 10000B];
OutCard[j];
IF tp.angle
THEN {
s: CD.Position = Size[ob];
qq: INTEGER ← MAX[s.y-tp.wExt-tp.length-2*tp.lExt, 0]; --may be out of range
OutNumber[qq]; -- angle extension
};
IF tp.implant>0 THEN OutCard[tp.implant];
};
cp: NMosContacts.ContactPtr => {
j: CARDINAL;
s: CD.Position = Size[ob];
ss: CARDINAL ← s.y;
OutCard[contactCode];
j ← contactTab[cp.typ];
j ← Basics.BITOR[j, Basics.BITSHIFT[ss, 8]];
OutCard[j];
OutLevel[ob.layer];
OutCard[0]; --surround...
IF cp.typ=burr
THEN {
OutNumber[s.x];
OutCard[Basics.BITOR[Basics.BITSHIFT[cp.wExt, 8], cp.lExt]];
};
};
tp: CDTexts.TextSpecific => {
OutRope[tp.text];
TerminalIO.PutRope["text; font information lost\n"];
};
rp: CDRepetitions.RepSpecific => {
OutCard[repeatCode];
OutObject[rp.ob];
OutCard[0]; -- w
OutCard[0]; -- l
OutSize[rp.offset];
OutCard[rp.count];
OutOrient[rp.orientation];
};
ENDCASE => OutUnknownObject["?"];
END;
COutputDesign:
PROC [comm: CDSequencer.Command] =
BEGIN
name, fileName: Rope.ROPE;
s: IO.STREAM;
wDir: Rope.ROPE ← CDIO.GetWorkingDirectory[comm.design];
TerminalIO.PutRope["Chipmonk Output Design\n"];
IF Rope.IsEmpty[wDir] THEN wDir ← FileNames.CurrentWorkingDirectory[];
TerminalIO.PutRope["Chipmonk output file name"];
IF ~Rope.IsEmpty[wDir]
THEN {
TerminalIO.PutRopes[" (", wDir, ")"];
};
name ← TerminalIO.RequestRope[" > "];
fileName ← CDIO.MakeName[name, "chip"];
IF ~Rope.IsEmpty[wDir] THEN fileName ← FS.ExpandName[fileName, wDir].fullFName;
s ←
FS.StreamOpen[fileName, create !
FS.Error =>
IF error.group#bug
THEN {
TerminalIO.PutRope[error.explanation];
GOTO FileIOOpenFailed;
}
];
CDOps.DeselectAll[design: comm.design, setSelection: TRUE];
TransformSelected[comm.design, rotate180X];
OutputDesign[comm.design, s];
IO.Close[s];
TransformSelected[comm.design, rotate180X];
CDOps.DeselectAll[design: comm.design];
TerminalIO.PutRope[" end output\n"];
EXITS
FileIOOpenFailed => {TerminalIO.PutRope["Open Failed\n"]};
END;
levelTab[NMos.cut] ← 0;
levelTab[NMos.dif] ← 1;
levelTab[NMos.pol] ← 2;
levelTab[NMos.met] ← 3;
levelTab[NMos.imp] ← 4;
levelTab[NMos.ovg] ← 5;
levelTab[NMos.bur] ← 6;
levelTab[NMos.cut2] ← 8;
levelTab[NMos.met2] ← 11;
levelTab[NMos.cut2] ← 15;
contactTab[burr] ← 4;
contactTab[mDif] ← 1;
contactTab[butt] ← 3;
contactTab[mPol] ← 2;
contactTab[mm2] ← 5;
CDSequencer.ImplementCommand[$ChipmonkOutput, COutputDesign];
CDCommandOps.RegisterWithMenu[$IOMenu, "chipmonk-output", "certain technologies only", $ChipmonkOutput, COutputDesign, doQueue, NMos.nmos];
END.