-- 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