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: CARDINALLOOPHOLE[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: BOOLFALSE] =
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 [BOOLFALSE] = {
OutSize[InstLoc[i]];
OutOrient[i.trans.orient];
OutObject[i.ob, i];
OutProps[i.properties]
};
lCnt: INT ← CDInstances.Length[list];
sCnt: INTIF 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.ROPENIL] = {
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: INTEGERMAX[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.