-- Subroutine to generate CIF from Chipmonk
-- last modified by McCreight, April 12, 1983 5:31 PM
-- to fix resolution bug..
-- adapted from ppio.mesa by McCreight, November 9, 1982 5:09 PM
DIRECTORY
ChipOrient,
ChipUserInt,
InlineDefs,
StreamDefs,
StringDefs,
ppdddefs,
ppddefs,
ppdefs,
ppMainDefs,
pppdefs,
ppoutdefs,
TimeDefs,
ZoneAllocDefs;
CIFGen: PROGRAM
IMPORTS
ChipOrient, ChipUserInt, InlineDefs,
ppdefs, ppdddefs, ppMainDefs, pppdefs,
StreamDefs, StringDefs, TimeDefs, ZoneAllocDefs
EXPORTS ppdefs =
BEGIN
OPEN InlineDefs, StreamDefs, ppdefs, ppdddefs,
ChipOrient, ChipUserInt;
INT: TYPE = LONG INTEGER;
aux: PUBLIC TYPE = CifCell;
CifCellPtr: TYPE = LONG POINTER TO CifCell;
CifCell: TYPE = RECORD[id: CellId];
CellId: TYPE = CARDINAL;
cifLayName: ARRAY level OF STRING ←
[cut: "NC",
dif: "ND",
pol: "NP",
met: "NM",
imp: "NI",
ovg: "NG",
bur: "NB",
snerd: "X",
cut2: "NC2",
pdif: "Q",
pwelCont: "X",
met2: "NM2",
pwel: "X",
nwel: "T",
nwelCont: "X",
NOcOL: "X"];
chipmonkLayName: ARRAY level OF STRING ←
[cut: "cut",
dif: "dif",
pol: "pol",
met: "met",
imp: "imp",
ovg: "ovg",
bur: "bur",
snerd: "",
cut2: "cut2",
pdif: "pdif",
pwelCont: "pwelCont",
met2: "met2",
pwel: "pwel",
nwel: "nwel",
nwelCont: "nwelCont",
NOcOL: ""];
infinity: locNum = LAST[locNum];
cellCnt: CellId ← 0;
cifFile: StreamDefs.DiskHandle ← NIL;
levelAnnounced: BOOLEAN ← FALSE;
curLevel: level;
cifScale: INT ← 200; -- CIF units per lambda
cifDrR: drRecord ← [
[x1: -infinity, y1: -infinity, x2: infinity, y2: infinity],
[x1: -infinity, y1: -infinity, x2: infinity, y2: infinity],
cifOrArea, cifOrArea,
nullOutl, nullCifDrawText, 0];
nullOutl: PROCEDURE[a, b, c, d: INTEGER, q: color,
p: POINTER TO Rect] = {NULL};
nullCifDrawText: PROCEDURE[x, y, sx, sy: INTEGER,
s: STRING, pz: POINTER TO Rect] = {NULL};
cifDefineObject: PROC [ob: obPtr] =
BEGIN
SymHeader: PROC =
BEGIN
cifOutStr["DS "];
cellCnt ← cellCnt+1;
cifOutNum[cellCnt];
ob.auxPnt ← uz.NEW[CifCell ← [id: cellCnt]];
cifOutStr[" "];
cifOutNum[cifScale]; -- CIF units per lambda
cifOutStr[" "];
cifOutNum[Lambda*resolution];
cifOutEndCom[];
END;
SymTrailer: PROC =
BEGIN
cifOutStr["DF"];
cifOutEndCom[];
END;
IF ob.auxPnt#NIL THEN RETURN; -- already defined
WITH dob: ob SELECT FROM
wire, rect => NULL;
cell =>
BEGIN
pp: listPtr;
FOR pp ← dob.ptr, pp.nxt WHILE pp # NIL DO
cifDefineObject[pp.ob];
ENDLOOP;
SymHeader[];
IF dob.ptr=masterList THEN
cifDrawCellName["TopLevelDesign"]
ELSE
FOR cl: LONG POINTER TO cList ← cellList, cl.nxt
WHILE cl#NIL DO
IF cl.ob = @dob THEN
{cifDrawCellName[cl.name]; EXIT};
ENDLOOP;
FOR pp ← dob.ptr, pp.nxt WHILE pp # NIL DO
-- first call all interior cells
WITH cob: pp.ob SELECT FROM
rect, wire => NULL;
ENDCASE =>
BEGIN
refCorner: Rect = ChipOrient.MapRect[
itemInCell: [0, 0, 0, 0],
cellSize: [x: cob.size[0], y: cob.size[1]],
cellInstOrient: pp.idx,
cellInstPos: [x: pp.lx, y: pp.ly]];
cifSymbolCall[@cob];
IF pp.idx # 0 THEN
BEGIN
jj: CARDINAL;
IF (jj ← BITAND[pp.idx, 12]) # 0 THEN
BEGIN
cifOutStr[" R "];
cifOutStr[SELECT jj FROM
4 => "0,1",
8 => "-1,0",
12 => "0,-1",
ENDCASE => "1,0" -- we'll never use this one --];
END;
IF BITAND[pp.idx, 1] # 0 THEN cifOutStr[" M X"];
END;
IF refCorner.x1#0 OR refCorner.y1#0 THEN
BEGIN
cifOutStr[" T "];
cifOutPoint[refCorner.x1, refCorner.y1];
END;
cifOutEndCom[];
END;
ENDLOOP;
-- next generate all rectangles, by layer
FOR curLevel IN level DO
levelAnnounced ← FALSE;
FOR pp ← dob.ptr, pp.nxt WHILE pp # NIL DO
WITH cob: pp.ob SELECT FROM
rect, wire =>
IF cob.l=curLevel THEN
cob.p.drawme[pp.idx][@cob, pp.lx, pp.ly, @cifDrR];
ENDCASE => NULL;
ENDLOOP;
ENDLOOP;
-- finally generate all signal names
FOR pp ← dob.ptr, pp.nxt WHILE pp # NIL DO
IF pp.gotText THEN
WITH cob: pp.ob SELECT FROM
wire =>
cifLabelTerminal[pp, getTextProp[pp].s, pp.ob.l];
cont =>
BEGIN
lev: level = (SELECT cob.typ FROM
burr => pol,
ENDCASE => met);
cifLabelTerminal[pp, getTextProp[pp].s, lev];
END;
ENDCASE => NULL;
ENDLOOP;
SymTrailer[];
END; -- of cell
ENDCASE => -- geometry
BEGIN
SymHeader[];
FOR curLevel IN level DO
levelAnnounced ← FALSE;
dob.p.drawme[0][@dob, 0, 0, @cifDrR];
ENDLOOP;
SymTrailer[];
END;
END;
cifSymbolCall: PROCEDURE[ob: obPtr] =
BEGIN
cp: CifCellPtr = ob.auxPnt;
IF cp=NIL THEN ERROR;
cifOutStr["C "];
cifOutNum[cp.id];
END;
cifOrArea: PROCEDURE [x1, y1, x2, y2: INTEGER, l: level,
p: POINTER TO Rect] =
BEGIN
IF l # curLevel OR x2=x1 OR y2=y1 THEN RETURN;
IF x2<x1 THEN
{t: locNum ← x1; x1 ← x2; x2 ← t};
IF y2<y1 THEN
{t: locNum ← y1; y1 ← y2; y2 ← t};
IF NOT levelAnnounced THEN
BEGIN
cifOutStr["L "];
cifOutStr[cifLayName[curLevel]];
cifOutEndCom[];
levelAnnounced ← TRUE;
END;
IF bloatImplant AND l=imp THEN
BEGIN
x1 ← x1-Lambda/2;
x2 ← x2+Lambda/2;
y1 ← y1-Lambda/2;
y2 ← y2+Lambda/2;
END;
cifOutStr["B "];
cifOutNum[resolution*ABS[x2 - x1]]; -- width
cifOutChr[' ];
cifOutNum[resolution*ABS[y2 - y1]];
cifOutChr[' ];
IF (resolution*(LONG[x1]+x2)) MOD 2 # 0 THEN
RemarkAtPoint[
p: [(x1+x2)/2, (y1+y2)/2],
s: "Point off-grid in x."];
cifOutNum[resolution*(LONG[x1]+x2)/2]; -- center
cifOutChr[',];
IF (resolution*(LONG[y1]+y2)) MOD 2 # 0 THEN
RemarkAtPoint[
p: [(x1+x2)/2, (y1+y2)/2],
s: "Point off-grid in y."];
cifOutNum[resolution*(LONG[y1]+y2)/2];
cifOutEndCom[];
END;
cifLabelTerminal: PROCEDURE [lp: listPtr, s: STRING,
lev: level] =
BEGIN
size: Point =
Size[size: [x: lp.ob.size[0], y: lp.ob.size[1]], orient: lp.idx];
cifOutStr["94 "];
cifOutStr[s];
cifOutStr[" "];
cifOutPoint[lp.lx+size.x/2, lp.ly+size.y/2]; -- in the center
cifOutStr[" "];
cifOutStr[cifLayName[lev]];
cifOutEndCom[];
END;
cifDrawCellName: PROCEDURE [s: STRING] =
BEGIN
cifOutStr["9 "];
cifOutStr[s];
cifOutEndCom[];
END;
cifOutStr: PUBLIC PROCEDURE [s: STRING] =
BEGIN
FOR i: CARDINAL IN [0..s.length) DO
cifFile.put[cifFile, s[i]];
ENDLOOP;
END;
cifOutChr: PUBLIC PROCEDURE [c: CHARACTER] = INLINE
{cifFile.put[cifFile, c]};
cifOutEndCom: PROCEDURE =
{cifOutChr[';]; cifOutChr[15C]};
cifOutNum: PUBLIC PROCEDURE [n: INT] =
BEGIN
IF n < 0 THEN {cifOutChr['-]; n ← -n};
IF n>9 THEN cifOutNum[n/10];
cifOutChr['0 + LowHalf[n MOD 10]];
END;
cifOutPoint: PROCEDURE [x, y: locNum] =
{cifOutPair[resolution*x, resolution*y]};
cifOutPair: PROCEDURE [x, y: INT] =
{cifOutNum[x]; cifOutChr[',]; cifOutNum[y]};
findname: PROCEDURE [p: LONG POINTER TO cell object]
RETURNS[s: STRING] =
BEGIN
cp: LONG POINTER TO cList←cellList;
s ← "";
FOR cp: LONG POINTER TO cList←cellList, cp.nxt
WHILE cp # NIL DO
IF cp.ob = p THEN {s ← cp.name; RETURN};
ENDLOOP;
END;
CoordRect: TYPE = RECORD [x1, y1, x2, y2: INT];
mainRect: CoordRect ← [x1: LAST[INT], y1: LAST[INT],
x2: -LAST[INT], y2: -LAST[INT]];
cifMeasureR: drRecord ← [
[x1: -infinity, y1: -infinity, x2: infinity, y2: infinity],
[x1: -infinity, y1: -infinity, x2: infinity, y2: infinity],
cifMeasureArea, cifMeasureArea,
nullOutl, nullCifDrawText, 0];
cifMeasureArea: PROCEDURE [x1, y1, x2, y2: INTEGER, l: level,
p: POINTER TO Rect] =
BEGIN
IF x2=x1 OR y2=y1 THEN RETURN;
IF x2<x1 THEN
{t: locNum ← x1; x1 ← x2; x2 ← t};
IF y2<y1 THEN
{t: locNum ← y1; y1 ← y2; y2 ← t};
mainRect ←
[x1: MIN[x1, mainRect.x1], y1: MIN[y1, mainRect.y1],
x2: MAX[x2, mainRect.x2], y2: MAX[y2, mainRect.y2]];
END;
NullLpAux: PROCEDURE[lp: listPtr] =
BEGIN
WHILE lp#NIL DO
NullObAux[lp.ob];
lp ← lp.nxt;
ENDLOOP;
END;
NullObAux: PROCEDURE[ob: obPtr] =
BEGIN
ob.auxPnt ← NIL;
WITH o: ob SELECT FROM
cell => NullLpAux[o.ptr];
ENDCASE => NULL;
END;
-- Module START code
uz: UNCOUNTED ZONE ←
ZoneAllocDefs.GetAnXMZone[checkSegments: TRUE];
bloatImplant: BOOLEAN;
resolution: INT;
name, comment: STRING ← NIL;
NullLpAux[masterList];
BEGIN OPEN StringDefs, TimeDefs;
ENABLE Punt, UNWIND => GOTO Finished;
time: STRING ← [100];
mainOb: object ← [
p: NIL,
size: [infinity, infinity, infinity],
refCnt: 0,
auxPnt: NIL,
l: NOcOL,
returnable: FALSE,
marked: FALSE,
varpart: cell[cnt: 0, ptr: masterList, super: NIL]];
name ← RequestString["Name of CIF file:"];
IF name=NIL OR name.length=0 THEN
name ← newString[ppMainDefs.fileName];
name ← FixExtension[name, ".cif"];
cifFile ← NewByteStream[name, WriteAppend];
bloatImplant ← HeSaysYes[
"Should I bloat implant rectangles by lambda/2 in all directions?"];
resolution ← IF HeSaysYes[
"Will all CIF co-ordinates lie on a half-lambda grid?",
"(almost always true...)"] THEN 1 ELSE 2;
cifScale ← RequestInteger["How many CIF units per lambda?",
"(1 CIF unit = 0.01 micrometer)"];
time.length ← 0;
AppendDayTime[time, UnpackDT[CurrentDayTime[]]];
cifOutStr["("];
cifOutStr[name];
cifOutStr[" - generated "];
cifOutStr[time];
cifOutStr[" by Xerox PARC Chipmonk with Lambda = "];
cifOutNum[cifScale];
cifOutStr[" CIF units)"];
cifOutEndCom[];
pppdefs.drCell0[ob: @mainOb, x: 0, y: 0, pr: @cifMeasureR];
cifOutStr["(Origin = [x: 0, y: 0], Size = [x: "];
cifOutNum[(cifScale*(mainRect.x2-mainRect.x1))/Lambda];
cifOutStr[", y: "];
cifOutNum[(cifScale*(mainRect.y2-mainRect.y1))/Lambda];
cifOutStr["] CIF units)"];
cifOutEndCom[];
IF bloatImplant THEN
BEGIN
cifOutStr["( Implant rectangles bloated by lambda/2 from Chipmonk design )"];
cifOutEndCom[];
END;
comment ← RequestString[s1: "Comment line:",
s2: "(any parentheses must be balanced)",
s3: "(CR for no comment)",
lowerCaseOK: TRUE];
WHILE comment#NIL AND comment.length>0 DO
cifOutStr["( "];
cifOutStr[comment];
cifOutStr[" )"];
cifOutEndCom[];
FreeString[comment];
comment ← NIL;
comment ← RequestString[s1: "Another comment line:",
s2: "(any parentheses must be balanced)",
s3: "(CR for no further comments)",
lowerCaseOK: TRUE];
ENDLOOP;
IF HeSaysYes["Want to change standard layer names?"] THEN
FOR l:level IN level DO
IF chipmonkLayName[l].length > 0 THEN
BEGIN
cln: STRING ← NIL;
s1: STRING ← [100];
s2: STRING ← [100];
s1.length ← s2.length ← 0;
AppendString[to: s1, from: "CIF name for "];
AppendString[to: s1, from: chipmonkLayName[l]];
AppendString[to: s1, from: "?"];
AppendString[to: s2, from: "(CR to keep standard name of "];
AppendString[to: s2, from: cifLayName[l]];
AppendString[to: s2, from: ")"];
cln ← RequestString[s1, s2];
IF cln # NIL AND cln.length > 0 THEN
cifLayName[l] ← cln;
END;
ENDLOOP;
cifDefineObject[@mainOb];
cifSymbolCall[@mainOb];
cifOutStr[" M Y T "];
cifOutPair[x: -cifScale*mainRect.x1/Lambda,
y: cifScale*mainRect.y2/Lambda];
cifOutStr[";"];
cifOutChr[15C];
cifOutStr["End ..."];
cifOutChr[15C];
EXITS Finished => NULL;
END;
IF cifFile#NIL THEN
BEGIN
TruncateDiskStream[cifFile];
cifFile ← NIL;
END;
IF name#NIL THEN {FreeString[name]; name ← NIL};
IF comment#NIL THEN {FreeString[comment]; comment ← NIL};
NullLpAux[masterList];
uz ← ZoneAllocDefs.DestroyAnXMZone[uz];
END. -- of CIFGen