ChipmonkCMosWrite.mesa
Copyright © 1983, 1985 by Xerox Corporation. All rights reserved.
Last Edited by: Jacobi, November 10, 1983 7:36 pm
Last Edited by: Jacobi, July 8, 1985 11:11:07 am PDT
DIRECTORY
Ascii,
Atom,
Basics USING [BITOR, BITSHIFT],
CD,
CDInstances,
CDBasics,
CDDirectory,
CDMarks,
CDSimpleOps,
CDOrient,
CDProperties,
CDRects,
CDRepetitions,
CDSequencer,
CDIO,
CDTexts,
CDViewer,
FS,
IO,
CMos,
CMosCMContacts,
CMosCMTransistors,
FileNames,
Rope,
RuntimeError,
TerminalIO;
ChipmonkCMosWrite: CEDAR MONITOR
IMPORTS Ascii, Atom, Basics, CDInstances, CDBasics, CDDirectory, CDMarks, CDSimpleOps, CDProperties, CDSequencer, CDIO, FileNames, FS, IO, CMos, Rope, RuntimeError, TerminalIO =
BEGIN
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 = CD.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: INT;
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 = 500;
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[7]];
contactTab: REF ARRAY CMosCMContacts.ContactType OF CARDINAL
NEW[ARRAY CMosCMContacts.ContactType OF CARDINAL];
EachEntryCount: CDDirectory.EachEntryAction =
BEGIN
WITH ob.specificRef SELECT FROM
cptr: CD.CellPtr => {cellCount ← cellCount+1};
ENDCASE => NULL;
END;
EachEntryOutput: CDDirectory.EachEntryAction =
-- ignores name parameter, takes name from cell-data itself
BEGIN
IF ob.marked=gMark THEN RETURN;
ob.marked ← gMark;
WITH ob.specificRef SELECT FROM
cptr: CD.CellPtr => {
FOR l: CD.InstanceList ← cptr.contents, l.rest WHILE l#NIL DO
IF l.first.ob.class.inDirectory THEN [] ← EachEntryOutput[name: NIL, ob: l.first.ob];
ENDLOOP;
outputedCellCount ← outputedCellCount+1;
cellNameA[outputedCellCount] ← ob;
OutCard[outputedCellCount];
OutRopeUpper[cptr.name];
OutSize[ob.size];
OutCard[20000]; -- count ??? make it big, just in case it is some kind of reference count
OutList[cptr.contents];
};
rp: CDRepetitions.RepPtr => NULL;
ENDCASE =>
IF ob.class.inDirectory THEN {
TerminalIO.WriteRope["?"];
unKnowns←unKnowns+1;
};
END;
sig: SIGNAL = CODE;
OutputDesign: ENTRY PROC [d: CD.Design, s: IO.STREAM] =
BEGIN
Doit: PROC [mark: CDMarks.MarkRange] =
BEGIN
MOutputDesign[d, s, mark]
END;
CDMarks.DoWithMark[d, Doit];
END;
MOutputDesign: PROC [d: CD.Design, s: IO.STREAM, mark: INT] =
BEGIN
ENABLE {
UNWIND => cellNameA←NIL;
PushedState => {GOTO Pushed};
RuntimeError.BoundsFault => {
TerminalIO.WriteRope["BoundsFault, maybe some feature is not representable for chipmonk; proceed is secure\n"];
SIGNAL sig;
GOTO Failed
};
RuntimeError.UNCAUGHT => {
TerminalIO.WriteRope["unknown error, maybe some feature is not representable for chipmonk; proceed is secure\n"];
SIGNAL sig;
GOTO Failed
};
};
gMark ← mark;
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[7]; -- 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.WriteRope["** unknown features: "];
TerminalIO.WriteInt[unKnowns];
TerminalIO.WriteLn[];
};
IF unknownObjects#0 THEN {
TerminalIO.WriteRope["** unknown objects: "];
TerminalIO.WriteInt[unknownObjects];
TerminalIO.WriteLn[];
};
IF unknownAtoms#0 THEN {
TerminalIO.WriteRope["** unknown properties or propertynames: "];
TerminalIO.WriteInt[unknownAtoms];
TerminalIO.WriteLn[];
};
EXITS
Pushed => {TerminalIO.WriteRope["Output Failed (pushed in cell)\n"]};
Failed => {TerminalIO.WriteRope["Output Failed \n"]};
END;
OutPushedLevels: PROC [] =
BEGIN
IF design.actual.rest#NIL THEN {
TerminalIO.WriteRope["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;
CMHasSurround: PROC [ob: CD.Object] RETURNS [yes: BOOL] =
INLINE BEGIN
yes ← ob.layer=CMos.wpdif OR ob.layer=CMos.pdif
END;
AngleExt: PROC[tob: CD.Object] RETURNS [CD.Number] = {
--copied from cmostransistorsimpl
tp: CMosCMTransistors.TransistorPtr = NARROW[tob.specificRef];
IF tob.layer=CMos.pdif OR tob.layer=CMos.nwellCont THEN {
beyondPolyX: CD.Number = MAX[0, CMos.wellSurround-tp.wExt];
RETURN [tp.width+tp.length+tp.wExt+beyondPolyX+CMos.wellSurround-tob.size.x]
};
RETURN [tp.width+tp.length+tp.wExt-tob.size.x]
};
Size: PROC [ob: CD.Object] RETURNS [CD.Position] =
BEGIN
s: CD.Position ← ob.size;
Symmetrical: PROC [] = {
s.x ← s.x-2*CMos.wellSurround;
s.y ← s.y-2*CMos.wellSurround;
};
IF CMHasSurround[ob] THEN
WITH ob.specificRef SELECT FROM
tp: CMosCMTransistors.TransistorPtr => {
IF NOT tp.angle THEN {
s.x ← tp.width+2*tp.wExt;
s.y ← tp.length+2*tp.lExt
}
ELSE -- angle -- {
-- correctness: by comparing code with CreateTransistor
aExt: CD.Number = AngleExt[ob];
s.x ← tp.width+tp.length+tp.wExt-aExt;
s.y ← tp.wExt+2*tp.lExt+aExt+tp.length
};
};
ENDCASE => Symmetrical[];
IF s.x<0 OR s.y<0 THEN ERROR;
RETURN [s]
END;
AppLocation: PROC [inst: CD.Instance] RETURNS [CD.Position] =
INLINE BEGIN
WITH inst.ob.specificRef SELECT FROM
cp: CD.CellPtr => RETURN [inst.location];
ENDCASE => RETURN [CDBasics.BaseOfRect[CDInstances.InstRectI[inst]]];
END;
OutList: PROC[list: CD.InstanceList] =
BEGIN
OutProps: PROC[props: CD.Properties] =
BEGIN
count: CARDINAL ← 0;
FOR pl: CD.Properties ← props, pl.rest WHILE pl#NIL DO
IF ISTYPE[pl.first.key, ATOM] THEN count ← count+1
ENDLOOP;
OutCard[count];
FOR pl: CD.Properties←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;
cnt: NAT ← 0;
FOR l: CD.InstanceList ← list, l.rest WHILE l#NIL DO
cnt ← cnt+1
ENDLOOP;
OutCard[cnt];
FOR l: CD.InstanceList ← list, l.rest WHILE l#NIL DO
OutSize[AppLocation[l.first]];
OutOrient[l.first.orientation];
OutObject[l.first.ob, l.first];
OutProps[l.first.properties]
ENDLOOP;
END;
OutOrient: PROC [o: CD.Orientation] =
BEGIN
c: CARDINAL = o/2*4 + 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.WriteRope[r];
unknownObjects←unknownObjects+1; OutCard[0];
};
OutRectObject: PROC[ob: CD.Object, appForRectProperty: CD.Instance←NIL] =
BEGIN
x: REF ← CDProperties.GetPropFromInstance[from: appForRectProperty, prop: $CDxChipmonkThinks];
lev: CD.Layer ← ob.layer;
IF lev=CMos.wpdif THEN {
lev ← CMos.pdif;
x ← NIL
};
IF x=$Rext THEN {
OutCard[rectangleCode];
OutSize[Size[ob]];
OutLevel[lev];
}
ELSE {
OutCard[wireCode];
OutSize[Size[ob]];
OutLevel[lev];
IF lev=CMos.pdif THEN OutCard[CMos.wellSurround];
};
END;
IF ob=NIL THEN {
OutCard[0];
unKnowns←unKnowns+1;
TerminalIO.WriteRope["nil/n"];
RETURN;
};
WITH ob.specificRef SELECT FROM
cptr: CD.CellPtr => {
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.WriteRope["**bad cell\n"]; unKnowns←unKnowns+1};
OutCard[cellNum];
};
rp: CD.RectPtr => {OutRectObject[ob, appForRectProperty]};
tp: CMosCMTransistors.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 THEN j ← Basics.BITOR[j, 100000B];
IF tp.angle THEN j ← Basics.BITOR[j, 20000B];
IF CMHasSurround[ob] THEN j ← Basics.BITOR[j, 10000B];
OutCard[j];
IF CMHasSurround[ob] THEN OutCard[CMos.wellSurround];
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
};
};
cp: CMosCMContacts.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];
IF CMHasSurround[ob] THEN OutCard[CMos.wellSurround] ELSE OutCard[0];
IF cp.typ=burr THEN {
OutNumber[s.x];
OutCard[Basics.BITOR[Basics.BITSHIFT[cp.wExt, 8], cp.lExt]];
};
};
tp: CDTexts.TextPtr => {
OutRope[tp.text];
TerminalIO.WriteRope["text; font information lost\n"];
};
rp: CDRepetitions.RepPtr => {
OutCard[repeatCode];
OutObject[rp.ob];
OutCard[0]; -- w
OutCard[0]; -- l
OutSize[rp.offset];
OutCard[rp.count];
OutOrient[rp.orientation];
};
ENDCASE =>
IF ob.class.wireTyped AND (ob.layer=CMos.wpdif) THEN {
OutRectObject[ob, appForRectProperty];
}
ELSE {
ob1: CD.Object ← CDDirectory.ExpandHard[ob, design, NIL];
IF ob1=NIL OR ob1.class=ob.class THEN OutUnknownObject["?"] --prevent recursion
ELSE {
OutObject[ob1, appForRectProperty]
}
};
END;
COutputDesign: PROC [comm: CDSequencer.Command] =
BEGIN
name, fileName: Rope.ROPE;
s: IO.STREAM;
wDir: Rope.ROPE ← CDIO.UseWorkingDirectory[comm.design];
TerminalIO.WriteRope["Chipmonk Output Design\n"];
IF Rope.IsEmpty[wDir] THEN wDir ← FileNames.CurrentWorkingDirectory[];
TerminalIO.WriteRope["Chipmonk output file name"];
IF ~Rope.IsEmpty[wDir] THEN {
TerminalIO.WriteRope[" ("];
TerminalIO.WriteRope[wDir];
TerminalIO.WriteRope[")"];
};
name ← TerminalIO.RequestRope[" > "];
fileName ← CDIO.MakeName[name, "chip", wDir];
s ← FS.StreamOpen[fileName, create !
FS.Error => IF error.group#bug THEN {
TerminalIO.WriteRope[error.explanation];
GOTO FileIOOpenFailed;
}
];
CDSimpleOps.SelectAll[comm.design];
CDSimpleOps.TransformSelected[comm.design, CDOrient.rotate180X];
OutputDesign[comm.design, s];
IO.Close[s];
CDSimpleOps.TransformSelected[comm.design, CDOrient.rotate180X];
CDSimpleOps.DeselectAll[comm.design];
TerminalIO.WriteRope[" end output\n"];
EXITS
FileIOOpenFailed => {TerminalIO.WriteRope["Open Failed\n"]};
END;
levelTab[CMos.cut] ← 0;
levelTab[CMos.ndif] ← 1;
levelTab[CMos.pol] ← 2;
levelTab[CMos.met] ← 3;
levelTab[CMos.imp] ← 4;
levelTab[CMos.ovg] ← 5;
levelTab[CMos.bur] ← 6;
levelTab[CMos.cut2] ← 8;
levelTab[CMos.pdif] ← 9;
levelTab[CMos.pwellCont] ← 10;
levelTab[CMos.met2] ← 11;
levelTab[CMos.pwell] ← 12;
levelTab[CMos.nwell] ← 13;
levelTab[CMos.nwellCont] ← 14;
contactTab[burr] ← 4;
contactTab[mDif] ← 1;
contactTab[difShort] ← 12;
contactTab[butt] ← 3;
contactTab[mPol] ← 2;
contactTab[mm2] ← 5;
CDSequencer.ImplementCommand[$ChipmonkOutput, COutputDesign];
END.