<> <> <> <<>> DIRECTORY Ascii, Atom, Basics USING [BITOR, BITSHIFT], CD, CDApplications, CDBusses, CDDirectory, CDExtras, CDInline, CDIOExtras, CDMarks, CDCommands, CDOrient, CDPrivate, CDProperties, CDRects, CDRepetitions, CDSequencer, CDTexts, CDViewer, FS, IO, CMos, CMosContacts, CMosTransistors, FileNames, Rope, RuntimeError, TerminalIO; ChipmonkCMosWrite: CEDAR MONITOR IMPORTS Ascii, Atom, Basics, CDApplications, CDDirectory, CDExtras, CDInline, CDIOExtras, CDMarks, CDCommands, CDOrient, CDPrivate, CDProperties, CDSequencer, FileNames, FS, IO, CMos, 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: 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.Level] = 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.Level OF [0..15] = NEW[ARRAY CD.Level OF [0..15]_ALL[15]]; contactTab: REF ARRAY CMosContacts.ContactType OF CARDINAL _ NEW[ARRAY CMosContacts.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.hasChildren 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.hasChildren 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; CDMarks.ClearAllAccessibleMarks[design]; [] _ CDDirectory.Enumerate[design, EachEntryCount]; OutCard[codeWordForDataFile]; OutCard[7]; -- 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 level 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.ObPtr] RETURNS [yes: BOOL_FALSE] = INLINE BEGIN RETURN [ob.level=CMos.pdif] END; AngleExt: PROC[tob: CD.ObPtr] RETURNS [CD.DesignNumber] = { <<--copied from cmostransistorsimpl>> tp: CMosTransistors.TransistorPtr = NARROW[tob.specificRef]; IF tob.level=CMos.pdif OR tob.level=CMos.nwelCont THEN { beyondPolyX: CD.DesignNumber = MAX[0, CMos.wellSurround-tp.wExt]; RETURN [tp.width+tp.length+tp.wExt+beyondPolyX+CMos.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*CMos.wellSurround; s.y _ s.y-2*CMos.wellSurround; }; IF HasSurround[ob] THEN WITH ob.specificRef SELECT FROM tp: CMosTransistors.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 RETURN [CDInline.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 count _ count+1 ENDLOOP; OutCard[count]; FOR pl: CD.Properties_props, pl.rest WHILE pl#NIL DO 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]]; OutCard[l.first.orientation]; OutObject[l.first.ob, l.first]; OutProps[l.first.properties] ENDLOOP; END; OutObject: PROC[ob: CD.ObPtr, appForRectProperty: CD.ApplicationPtr_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.ObPtr, appForRectProperty: CD.ApplicationPtr_NIL] = { x: REF _ CDProperties.GetPropFromApplication[from: appForRectProperty, prop: $CDxChipmonkThinks]; <<--for some time only: compatibility>> IF x=NIL THEN x _ CDProperties.GetPropFromObject[from: ob, prop: $CDxChipmonkThinks]; IF x=$Rext THEN { OutCard[rectangleCode]; OutSize[Size[ob]]; OutLevel[ob.level]; } ELSE { OutCard[wireCode]; OutSize[Size[ob]]; OutLevel[ob.level]; IF ob.level=CMos.pdif THEN OutCard[CMos.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, appForRectProperty]}; wrp: REF CMos.WellRectRep => {OutRectObject[ob, appForRectProperty]}; tp: CMosTransistors.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 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[CMos.wellSurround]; IF tp.angle THEN { s: CD.DesignPosition = Size[ob]; qq: INTEGER _ MAX[s.y-tp.wExt-tp.length-2*tp.lExt, 0]; --may be out of range OutNumber[qq]; -- angle extension }; }; cp: CMosContacts.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.level]; IF HasSurround[ob] THEN OutCard[CMos.wellSurround] ELSE OutCard[0]; IF cp.typ=burr THEN { OutNumber[s.x]; OutCard[Basics.BITOR[Basics.BITSHIFT[cp.wExt, 8], cp.lExt]]; }; }; bp: CDBusses.BusPtr => { OutCard[busCode]; OutSize[bp.sizeOfFirst]; OutLevel[ob.level]; 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]; OutCard[rp.orientation]; }; ENDCASE => OutUnknownObject["?"]; END; COutputDesign: PROC [comm: CDSequencer.Command] = BEGIN name, fileName: Rope.ROPE; s: IO.STREAM; wDir: Rope.ROPE _ CDIOExtras.GetDesignsWorkingDirectory[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 _ CDExtras.AppendExt[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; } ]; CDCommands.SelectAll[comm.design]; CDCommands.TransformSelected[comm.design, CDOrient.rotate180+CDOrient.mirrorX]; OutputDesign[comm.design, s]; IO.Close[s]; CDCommands.TransformSelected[comm.design, CDOrient.rotate180+CDOrient.mirrorX]; CDCommands.DeselectAll[comm.design]; TerminalIO.WriteRope[" end output\n"]; EXITS FileIOOpenFailed => {TerminalIO.WriteRope["Open Failed\n"]}; END; levelTab[CMos.cut] _ 0; levelTab[CMos.ndif] _ 1; levelTab[CMos.pol] _ 2; levelTab[CMos.met] _ 3; levelTab[CMos.imp] _ 4; levelTab[CMos.ovg] _ 5; levelTab[CMos.bur] _ 6; levelTab[CMos.snerd] _ 7; levelTab[CMos.cut2] _ 8; levelTab[CMos.pdif] _ 9; levelTab[CMos.pwelCont] _ 10; levelTab[CMos.met2] _ 11; levelTab[CMos.pwel] _ 12; levelTab[CMos.nwel] _ 13; levelTab[CMos.nwelCont] _ 14; levelTab[CMos.NOcOL] _ 15; contactTab[burr] _ 4; contactTab[mDif] _ 1; contactTab[difShort] _ 12; contactTab[butt] _ 3; contactTab[mPol] _ 2; contactTab[mm2] _ 5; CDSequencer.ImplementCommand[$ChipmonkOutput, COutputDesign]; END.