<> <> <> <> <<>> DIRECTORY Ascii, Atom, Basics USING [BITOR, BITSHIFT], CD, CDInstances, CDBasics, CDDirectory, CDIO, CDMarks, CDSimpleOps, CDOrient, CDProperties, CDRects, CDRepetitions, CDSequencer, CDTexts, CDViewer, FileNames, FS, IO, NMos, NMosContacts, NMosTransistors, Rope, RuntimeError, TerminalIO; ChipmonkNMosWrite: CEDAR MONITOR IMPORTS Ascii, Atom, Basics, CDInstances, CDBasics, CDDirectory, CDIO, CDMarks, CDSimpleOps, 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 = NMos.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: CARDINAL _ LOOPHOLE[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[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=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[8]; -- 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 { 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.Object] RETURNS [yes: BOOL_FALSE] = INLINE BEGIN yes _ FALSE <> END; AngleExt: PROC[tob: CD.Object] RETURNS [CD.Number] = { <<--copied from cmostransistorsimpl>> tp: NMosTransistors.TransistorPtr = NARROW[tob.specificRef]; RETURN [tp.width+tp.length+tp.wExt-tob.size.x] }; Size: PROC [ob: CD.Object] RETURNS [CD.Position] = BEGIN s: CD.Position _ ob.size; IF s.x<0 OR s.y<0 THEN ERROR; RETURN [s] END; AppLocation: PROC [aptr: CD.Instance] RETURNS [CD.Position] = INLINE BEGIN WITH aptr.ob.specificRef SELECT FROM cp: CD.CellPtr => RETURN [aptr.location]; ENDCASE => RETURN [CDBasics.BaseOfRect[CDInstances.InstRectI[aptr]]]; END; OutList: PROC[list: CD.InstanceList] = BEGIN OutProps: PROC [props: CD.PropList] = BEGIN count: CARDINAL _ 0; FOR pl: CD.PropList _ props, pl.rest WHILE pl#NIL DO IF ISTYPE[pl.first.key, ATOM] THEN count _ count+1 ENDLOOP; OutCard[count]; FOR pl: CD.PropList_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.ROPE_NIL] = { IF NOT Rope.IsEmpty[r] THEN TerminalIO.WriteRope[r]; unknownObjects_unknownObjects+1; OutCard[0]; }; OutRectObject: PROC[ob: CD.Object] = { x: REF = CDProperties.GetObjectProp[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=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 tp.angle THEN { s: CD.Position = Size[ob]; qq: INTEGER _ MAX[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.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]; OutCard[0]; --surround... 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 => OutUnknownObject["?"]; END; COutputDesign: PROC [comm: CDSequencer.Command] = BEGIN name, fileName: Rope.ROPE; s: IO.STREAM; wDir: Rope.ROPE _ CDIO.GetWorkingDirectory[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.WriteRopes[" (", wDir, ")"]; }; 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.cut2] _ 8; levelTab[NMos.met2] _ 11; levelTab[NMos.cut2] _ 15; contactTab[burr] _ 4; contactTab[mDif] _ 1; contactTab[butt] _ 3; contactTab[mPol] _ 2; contactTab[mm2] _ 5; CDSequencer.ImplementCommand[$ChipmonkOutput, COutputDesign]; END.