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