ChipmonkNMosWrite.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Last Edited by: Jacobi, February 20, 1984 12:06 pm
Last Edited by: Jacobi, April 11, 1985 11:15:43 am PST
DIRECTORY
Ascii,
Atom,
Basics USING [BITOR, BITSHIFT],
CD,
CDApplications,
CDBasics,
CDDirectory,
CDIO,
CDMarks,
CDSimpleOps,
CDOrient,
CDPrivate,
CDProperties,
CDRects,
CDRepetitions,
CDSequencer,
CDTexts,
CDViewer,
FileNames,
FS,
IO,
NMos,
NMosContacts,
NMosTransistors,
Rope,
RuntimeError,
TerminalIO;
ChipmonkNMosWrite: CEDAR MONITOR
IMPORTS Ascii, Atom, Basics, CDApplications, CDBasics, CDDirectory, CDIO, CDMarks, CDSimpleOps, CDPrivate, CDProperties, CDSequencer, FileNames, FS, IO, NMos, 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;
markValue: 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.ObPtr;
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.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=markValue THEN RETURN;
ob.marked←markValue;
WITH ob.specificRef SELECT FROM
cptr: CD.CellPtr => {
FOR l: CD.ApplicationList ← cptr.contents, l.rest WHILE l#NIL DO
IF l.first.ob.p.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.p.inDirectory THEN {
TerminalIO.WriteRope["?"];
unKnowns←unKnowns+1;
};
END;
OutputDesign: ENTRY PROC [d: CD.Design, s: IO.STREAM] =
BEGIN
ENABLE {
UNWIND => cellNameA←NIL;
PushedState => {GOTO Pushed};
RuntimeError.BoundsFault => {
TerminalIO.WriteRope["BoundsFault, maybe some feature is not representable for chipmonk\n"];
CDPrivate.Debug[msg: "BoundsFault, proceed is secure", mayProceed: TRUE];
GOTO Failed
};
RuntimeError.UNCAUGHT => {
TerminalIO.WriteRope["unknown error, maybe some feature is not representable for chipmonk\n"];
CDPrivate.Debug[msg: "unknown error, but, proceed is secure", mayProceed: TRUE];
GOTO Failed
};
};
markValue ← CDMarks.GetNewMark[d];
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.ObPtr ← 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;
HasSurround: PROC [ob: CD.ObPtr] RETURNS [yes: BOOLFALSE] =
INLINE BEGIN
yes ← FALSE
RETURN [ob.layer=NMos.pdif]
END;
AngleExt: PROC[tob: CD.ObPtr] RETURNS [CD.DesignNumber] = {
--copied from cmostransistorsimpl
tp: NMosTransistors.TransistorPtr = NARROW[tob.specificRef];
IF tob.layer=NMos.pdif OR tob.layer=NMos.nwelCont THEN {
beyondPolyX: CD.DesignNumber = MAX[0, NMos.wellSurround-tp.wExt];
RETURN [tp.width+tp.length+tp.wExt+beyondPolyX+NMos.wellSurround-tob.size.x]
};
RETURN [tp.width+tp.length+tp.wExt-tob.size.x]
};
Size: PROC [ob: CD.ObPtr] RETURNS [CD.DesignPosition] =
BEGIN
s: CD.DesignPosition ← ob.size;
Symmetrical: PROC [] = {
s.x ← s.x; 2*NMos.wellSurround;
s.y ← s.y-2*NMos.wellSurround;
};
IF HasSurround[ob] THEN
WITH ob.specificRef SELECT FROM
tp: NMosTransistors.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.DesignNumber = 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 [aptr: CD.ApplicationPtr] RETURNS [CD.DesignPosition] =
INLINE BEGIN
WITH aptr.ob.specificRef SELECT FROM
cp: CD.CellPtr => RETURN [aptr.location];
ENDCASE => RETURN [CDBasics.BaseOfRect[CDApplications.ARectI[aptr]]];
END;
OutList: PROC[list: CD.ApplicationList] =
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.ApplicationList ← list, l.rest WHILE l#NIL DO
cnt ← cnt+1
ENDLOOP;
OutCard[cnt];
FOR l: CD.ApplicationList ← 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.ObPtr, appForRectProperty: CD.ApplicationPtr←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.ObPtr] = {
x: REF = CDProperties.GetPropFromObject[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.layer=NMos.pdif THEN OutCard[NMos.wellSurround];
}
};
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]};
--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 HasSurround[ob] THEN OutCard[NMos.wellSurround];
IF tp.angle THEN {
s: CD.DesignPosition = 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.DesignPosition = 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 HasSurround[ob] THEN OutCard[NMos.wellSurround] ELSE
OutCard[0];
IF cp.typ=burr THEN {
OutNumber[s.x];
OutCard[Basics.BITOR[Basics.BITSHIFT[cp.wExt, 8], cp.lExt]];
};
};
do no more exist in ChipNDale
bp: CDBusses.BusPtr => {
OutCard[busCode];
OutSize[bp.sizeOfFirst];
OutLevel[ob.layer];
OutCard[bp.count];
OutSize[bp.offset];
OutNumber[bp.lengIncrement+bp.offset.y];
};
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 => OutUnknownObject["?"];
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"];
IF ~Rope.IsEmpty[wDir] THEN fileName ← FS.ExpandName[fileName, wDir].fullFName;
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[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.snerd] ← 7;
levelTab[NMos.cut2] ← 8;
--XXX levelTab[NMos.pdif] ← 9;
--XXX levelTab[NMos.pwelCont] ← 10;
levelTab[NMos.met2] ← 11;
--XXX levelTab[NMos.pwel] ← 12;
levelTab[NMos.nwel] ← 13;
levelTab[NMos.nwelCont] ← 14;
levelTab[NMos.cut2] ← 15;
contactTab[burr] ← 4;
contactTab[mDif] ← 1;
contactTab[difShort] ← 12;
contactTab[butt] ← 3;
contactTab[mPol] ← 2;
contactTab[mm2] ← 5;
CDSequencer.ImplementCommand[$ChipmonkOutput, COutputDesign];
END.