<> <> <> <> <> DIRECTORY Atom USING [MakeAtom], Basics USING [BITAND, BITSHIFT], CD, CDInstances, CDBasics, CDBusCells USING [CreateBusCell], CDCells, CDCommandOps, CDIO USING [MakeName], CDDirectory USING [Include], CDOps, CDProperties, CDRects USING [CreateRect], CDRepetitions, CDSequencer, CDTexts, CDViewer, Commander USING [CommandProc, Register], CommandTool, FS, IO, CMos, CMosCMContacts, CMosCMTransistors, Rope, TerminalIO, ViewerClasses USING [Viewer]; ChipmonkCmosRead: CEDAR MONITOR IMPORTS Atom, Basics, CD, CDBasics, CDInstances, CDBusCells, CDCells, CDDirectory, CDIO, CDOps, CDCommandOps, CDProperties, CDRects, CDRepetitions, CDSequencer, CDTexts, CDViewer, Commander, FS, IO, CMos, CMosCMContacts, CMosCMTransistors, CommandTool, Rope, TerminalIO SHARES CDProperties = BEGIN TransformSelected: PROC [design: CD.Design, transform: CD.Orientation, base: CD.Rect_[0, 0, -1, -1]] = { ib, is, orientOff: CD.Position; r, oldbb: CD.Rect; oldPseudoCellT, newPseudoCellT: CD.Transformation; sel: CD.InstanceList = CDInstances.OnlySelected[CDOps.InstList[design]]; IF sel=NIL THEN RETURN; oldbb _ CDInstances.BoundingRectO[sel]; IF ~CDBasics.NonEmpty[base] THEN base _ CDInstances.BoundingRectI[sel]; ib _ CDBasics.BaseOfRect[base]; is _ CDBasics.SizeOfRect[base]; oldPseudoCellT _ [ib, original]; r _ CDBasics.MapRect[CDBasics.RectAt[[0,0], is], [[0,0], transform]]; orientOff _ CDBasics.BaseOfRect[r]; newPseudoCellT _ [CDBasics.SubPoints[ib, orientOff], transform]; FOR w: CD.InstanceList _ sel, w.rest WHILE w#NIL DO pseudoCellRel: CD.Transformation _ CDBasics.DecomposeTransform[w.first.trans, oldPseudoCellT]; w.first.trans _ CDBasics.ComposeTransform[pseudoCellRel, newPseudoCellT] ENDLOOP; CDOps.Redraw[design, oldbb]; CDOps.Redraw[design, CDBasics.MapRect[CDBasics.DeMapRect[oldbb, oldPseudoCellT], newPseudoCellT]] }; <<-- global constants>> 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 = CMos.lambda/lambdaInChipmonk; instance: INTEGER = 1; transistor: INTEGER = 2; contact: INTEGER = 3; wire: INTEGER = 4; rectangle: INTEGER = 5; text: INTEGER = 6; bus: INTEGER = 7; repeat: INTEGER = 8; contTypALen: INTEGER = 12; maxCellNum: INTEGER = 1500; codeWordForDataFile : CARDINAL = 123751B; debugging: BOOLEAN = FALSE; debug: BOOLEAN = FALSE; atomTableSize: INTEGER = 256; contTypA: ARRAY [1..contTypALen] OF contType = [ mDif, mPol, butt, burr, mm2, mDif, mDif, mm2, mm2, mm2, mm2, difShort]; contLayer: ARRAY [1..contTypALen] OF CD.Layer = [ CMos.ndif, CMos.pol, CMos.ndif, CMos.ndif, CMos.met2, CMos.pdif, CMos.nwellCont, CMos.ndif, CMos.pol, CMos.ndif, CMos.ndif, CMos.ndif ]; -- for versions < 6 cmToCDLayer: ARRAY [0..15] OF CD.Layer = [ CMos.cut, CMos.ndif, CMos.pol, CMos.met, CMos.imp, CMos.ovg, CMos.bur, CD.errorLayer --snerd-- , CMos.cut2, CMos.pdif, CMos.pwellCont, CMos.met2, CMos.pwell, CMos.nwell, CMos.nwellCont, CD.errorLayer --NOcOL-- ]; <<-- global vars>> contType: TYPE = {burr, mDif, difShort, butt, mPol, mm2}; design: CD.Design; cellNameA: REF ARRAY [0..maxCellNum] OF CD.Object _ NEW[ARRAY [0..maxCellNum] OF CD.Object]; atomTable: REF ARRAY [1..atomTableSize] OF ATOM _ NEW[ARRAY [1..atomTableSize] OF ATOM]; standardFont: CDTexts.CDFont = CDTexts.MakeFont[name: "Xerox/TiogaFonts/Tioga10"]; chipfile: IO.STREAM; fileName: Rope.ROPE; errs: INT _0; NotYetImpl: PROC [] = { errs _ errs+1; TerminalIO.PutRope["?"]; }; BadObject: PROC [size: CD.Position _ [4, 4]] RETURNS [CD.Object] = { RETURN [CDRects.CreateRect[size, CD.errorLayer]] }; InWord: PROC RETURNS [INTEGER] = { highbyte: CARDINAL = LOOPHOLE[IO.GetChar[chipfile], CARDINAL]; lowbyte: CARDINAL = LOOPHOLE[IO.GetChar[chipfile], CARDINAL]; RETURN [ LOOPHOLE[(256*highbyte) + lowbyte, INTEGER] ]; }; FileFormat: ERROR = CODE; Lambda: PROCEDURE [i: INT] RETURNS [CD.Number] = INLINE { RETURN [lambdaFactor*i] }; InOrientation: PROC [] RETURNS [CD.Orientation] = INLINE { i: INTEGER = InWord[]; IF i>=0 AND i<=15 THEN RETURN [VAL[i/4*2 + i MOD 2]] --different representation ELSE ERROR FileFormat; }; ToLayer: PROC [i: INTEGER] RETURNS [CD.Layer] = INLINE { IF i>= 0 AND i<= 15 THEN RETURN [cmToCDLayer[i]] ELSE ERROR FileFormat; }; InLayer: PROC [] RETURNS [CD.Layer] = INLINE { RETURN [ToLayer[InWord[]]] }; NewCellName: PROC [index: INTEGER] RETURNS [cellName: Rope.ROPE] = { cellName _ IO.PutFR[ "cell#%d", IO.int[index]]; }; InObject: PROC[version: INTEGER] RETURNS [obj: CD.Object, instProp: REF_NIL, instVal: REF_NIL] = { j, k, w, l, we, le, dumsur: INTEGER; kk: CARDINAL; lev: CD.Layer; dumrope: Rope.ROPE; IF debugging OR debug THEN TerminalIO.PutRope[" (Include new object ... "]; j _ InWord[]; SELECT j FROM instance => { k _ InWord[]; -- cell ID num obj _ cellNameA[k]; }; transistor => { aExt: CD.Number _ 0; w _ InWord[]; l _ InWord[]; kk _ LOOPHOLE[InWord[]]; IF version > 4 AND LOOPHOLE[Basics.BITAND[kk, 10000B], CARDINAL] # 0 THEN dumsur _ InWord[]; IF LOOPHOLE[Basics.BITAND[LOOPHOLE[kk, CARDINAL], 20000B], CARDINAL] # 0 THEN aExt _ Lambda[InWord[]]; -- if angle get angle ext. IF LOOPHOLE[Basics.BITAND[kk, 100000B], CARDINAL]#0 THEN { IF version>7 THEN [] _ InWord[]; -- implant }; we _ Basics.BITAND[Basics.BITSHIFT[kk, -6], 77B]; le _ Basics.BITAND[kk, 77B]; lev _ IF Basics.BITAND[kk, 10000B]#0 THEN CMos.pdif ELSE CMos.ndif; SELECT TRUE FROM LOOPHOLE[Basics.BITAND[kk, 40000B], CARDINAL] #0 => {obj _ NIL; TerminalIO.PutRope[" error: pullup in cmos\n"]}; <> LOOPHOLE[Basics.BITAND[kk, 20000B], CARDINAL] #0 => obj _ CMosCMTransistors.CreateAngleTransistor[w: Lambda[w], l: Lambda[l], wExt: Lambda[we], lExt: Lambda[le], aExt: aExt, difLev: lev]; ENDCASE => obj _ CMosCMTransistors.CreateTransistor[w: Lambda[w], l: Lambda[l], wExt: Lambda[we], lExt: Lambda[le], difLev: lev]; }; contact => { j: CARDINAL _ LOOPHOLE[InWord[]]; -- get contact type k: CARDINAL _ Basics.BITAND[j, 37B]; -- get contact type l: CARDINAL _ Basics.BITSHIFT[j, -8]; lev _ IF version > 5 THEN InLayer[] ELSE contLayer[k]; IF version > 4 THEN dumsur _ LOOPHOLE[InWord[]]; SELECT contTypA[k] FROM mPol => obj _ CMosCMContacts.CreatePolyCon[Lambda[l]]; mDif => obj _ CMosCMContacts.CreateDifCon[Lambda[l], lev]; difShort => obj _ CMosCMContacts.CreateDifShortCon[lev]; butt => obj_ CMosCMContacts.CreateButCon[lev]; burr => BEGIN w _ LOOPHOLE[InWord[]]; k _ LOOPHOLE[InWord[]]; j _ Basics.BITSHIFT[k, -8]; obj _ CMosCMContacts.CreateBurCon[w: Lambda[w], l: Lambda[l], wex: Lambda[j], lex: Lambda[LOOPHOLE[Basics.BITAND[k, 37B], CARDINAL]], difLev: lev]; END; mm2 => obj _ CMosCMContacts.CreateMmCon[Lambda[l], 0, 0]; ENDCASE => {TerminalIO.PutRope[" Error in selecting contact type "]; ERROR}; }; wire => { i: INTEGER; w _ InWord[]; l _ InWord[]; i _ InWord[]; lev _ ToLayer[i]; IF lev=CMos.pdif THEN lev _ CMos.wpdif; SELECT i FROM 7 => {instVal _ $snerdRect; instProp _ $SignalName}; 15 => {instVal _ $NOcOLRect; instProp _ $SignalName}; ENDCASE => NULL; IF version > 4 AND lev = CMos.wpdif THEN dumsur _ InWord[]; obj _ CDRects.CreateRect[[Lambda[w],Lambda[l]], lev]; }; rectangle => { i: INTEGER; w _ InWord[]; l _ InWord[]; instVal _ $Rect; instProp _ $CDxChipmonkThinks; i _ InWord[]; lev _ ToLayer[i]; IF lev=CMos.pdif THEN lev _ CMos.wpdif; SELECT i FROM 7 => {instVal _ $snerdRect; instProp _ $SignalName}; 15 => {instVal _ $NOcOLRect; instProp _ $SignalName}; ENDCASE => NULL; obj _ CDRects.CreateRect[[Lambda[w], Lambda[l]], lev]; }; text => { dumrope _ InString[]; obj _ CDTexts.Create[dumrope, standardFont] }; bus => { w: CD.Number = Lambda[InWord[]]; l: CD.Number = Lambda[InWord[]]; lev: CD.Layer = InLayer[]; count: NAT = InWord[]; spacing: CD.Number = Lambda[InWord[]]; topInc: CD.Number = Lambda[InWord[]]; botInc: CD.Number = Lambda[InWord[]]; IF lev=CMos.pdif THEN {TerminalIO.PutRope["**bus implant is not drawn\n"]}; obj _ CDBusCells.CreateBusCell[ design: design, sizeOfFirst: [w, l], lev: lev, count: count, offset: [spacing, topInc], lengIncrement: botInc-topInc ]; -- compare: obj _ Chipmonk.makeBus[l, w, lev, count, spacing, topInc, botInc]; }; repeat => { rob: CD.Object = InObject[version].obj; ignoredw: INT = InWord[]; -- ignored ignoredl: INT = InWord[]; -- ignored dx: CD.Number = Lambda[InWord[]]; dy: CD.Number = Lambda[InWord[]]; count: NAT _ InWord[]; orient: CD.Orientation _ InOrientation[]; obj _ CDRepetitions.CreateRepetition[design: design, ob: rob, count: count, offset: [dx, dy], orientation: orient]; }; ENDCASE => { obj _ BadObject[]; TerminalIO.PutRope["** erronous object\n"]; }; }; -- InObject InList: PROC[ver: INTEGER] RETURNS [list: CD.InstanceList _ NIL, length: INT] = { instProp: REF _ NIL; instVal: REF _ NIL; instCount: INTEGER; inst: CD.Instance; ob: CD.Object; location: CD.Position; orientation: CD.Orientation; IF debugging OR debug THEN TerminalIO.PutRope["start list\n"]; instCount _ InWord[]; FOR iNum: INTEGER IN [0..instCount) DO location.x _ Lambda[InWord[]]; location.y _ Lambda[InWord[]]; orientation _ InOrientation[]; [ob, instProp, instVal] _ InObject[ver]; IF ob=NIL THEN { ob _ BadObject[]; TerminalIO.PutRope["nil object\n"] }; inst _ CDInstances.NewInst[ob: ob]; inst.trans _ CDOps.FitObjectI[ob, location, orientation]; list _ CONS[inst, list]; IF instProp#NIL THEN CDProperties.PutInstanceProp[onto: inst, prop: instProp, val: instVal]; IF ver > 3 THEN BEGIN propCount: INTEGER = InWord[]; FOR propNum: INTEGER IN [0..propCount) DO InProp[inst]; ENDLOOP; END; ENDLOOP; IF debugging OR debug THEN TerminalIO.PutRope["end list\n"]; RETURN[list, instCount]; }; oldSigName: ATOM = Atom.MakeAtom["SIGNAL NAME"]; InProp: PROC [inst: CD.Instance] = { kind: INTEGER _ InWord[]; name: REF _ NIL; value: REF; SELECT kind FROM 1 => { IF inst=NIL OR inst.ob=NIL OR ISTYPE[inst.ob.specific, CD.RectSpecific] THEN name _ $SignalName ELSE name _ $InstanceName; value _ InString[]; }; 2 => { name _ InAtom[]; value _ InAtom[]; IF name=oldSigName THEN name _ $SignalName; }; ENDCASE => { name _ NIL; TerminalIO.PutRope["** unknown property kind\n"]; }; IF name#NIL AND inst#NIL AND inst.ob#NIL THEN CDProperties.PutProp[onto: inst, prop: name, val: value] }; InAtom: PROC [] RETURNS[a: ATOM] = { i: INTEGER _ InWord[]; IF i<0 THEN { a _ atomTable[-i] } ELSE IF i>0 THEN { a _ Atom.MakeAtom[InString[]]; IF i <= atomTableSize THEN atomTable[i] _ a ELSE TerminalIO.PutRope["** atom table code wrong\n"]; } ELSE { TerminalIO.PutRope["** atom code wrong\n"]; a _ NIL } }; InString: PROC [] RETURNS[s: Rope.ROPE] = { j, len: CARDINAL; flg: BOOLEAN; j _ LOOPHOLE[InWord[]]; len _ Basics.BITSHIFT[j, -8]; IF len = 0 THEN BEGIN s _ ""; RETURN; END; flg _ TRUE; FOR i: CARDINAL IN [0..len) DO IF flg THEN s _ Rope.Cat[s, Rope.FromChar[LOOPHOLE[Basics.BITAND[j, 377B], CHAR]]] ELSE { j _ LOOPHOLE[InWord[]]; s _ Rope.Cat[s, Rope.FromChar[LOOPHOLE[Basics.BITSHIFT[j, -8], CHAR]]]; }; flg _ NOT flg; ENDLOOP; }; FileOpened: PROC [name: Rope.ROPE] RETURNS [fileWasOpened: BOOLEAN] = { IF Rope.IsEmpty[name] THEN name _ TerminalIO.RequestRope["Input file > "]; fileName _ CDIO.MakeName[name, "chip"]; chipfile _ FS.StreamOpen[fileName ! FS.Error => IF error.group#bug THEN { TerminalIO.PutRopes[fileName, " not opened: ", error.explanation]; TerminalIO.PutRope["\n"]; GOTO FileName }]; TerminalIO.PutRopes["File being read is ", fileName, "\n"]; fileWasOpened _ TRUE; EXITS FileName => {fileWasOpened _ FALSE}; }; signal: SIGNAL = CODE; ReadChip: PROC = { ENABLE { FileFormat => { TerminalIO.PutRope["\n**File-Format error [proceed does not clobber other designs]\n"]; SIGNAL signal; GOTO IOError; }; IO.EndOfStream => { TerminalIO.PutRope["\n**end of stream error [proceed does not clobber other designs]\n"]; SIGNAL signal; GOTO IOError; }; IO.Error => { TerminalIO.PutRope["\n**io error[proceed does not clobber other designs]\n"]; <<--if you are debugging here: inspect "ec">> SIGNAL signal; GOTO IOError; }; }; i, j, k, ver, cCnt, depht: INTEGER; leng: INT; ss: Rope.ROPE; cob: CD.Object; cellSpecific: CD.CellSpecific; errs _ 0; i _ InWord[]; IF i # LOOPHOLE[codeWordForDataFile, INTEGER] AND NOT TerminalIO.Confirm["doesn't look like a .chip file -- should program continue?"] THEN RETURN; ver _ InWord[]; cCnt _ InWord[]; IF cCnt > maxCellNum THEN CDSequencer.Quit["Too many different kinds of cells in design...aborting read\n"]; IF ver < 3 THEN CDSequencer.Quit[" Version number too low...aborting read\n"]; IF ver>8 THEN CDSequencer.Quit[" new chipmonk version unknown to chipndale...aborting read\n"]; FOR j IN [0..cCnt] DO cellNameA[j] _ CDCells.CreateEmptyCell[]; ENDLOOP; TerminalIO.PutRope["Starting cell directory\n"]; FOR k IN [1..cCnt] DO name: Rope.ROPE _ NIL; j _ InWord[]; cob _ cellNameA[j]; ss _ InString[]; --cob.size.x--[] _ Lambda[InWord[]]; --cob.size.y--[] _ Lambda[InWord[]]; [] _ InWord[]; -- this is some count in chipmonk ?? cellSpecific _ NARROW[cob.specific, CD.CellSpecific]; [cellSpecific.contents, leng] _ InList[ver]; IF NOT Rope.IsEmpty[ss] THEN name _ ss ELSE name _ NewCellName[k]; [] _ CDDirectory.Include[design: design, object: cob, name: name, fiddle: TRUE]; IF CDCells.IsEmpty[cob] THEN { TerminalIO.PutRopes["** empty cell ", CD.Describe[cob, NIL, design], "\n"]; cellSpecific.contents _ LIST[CDInstances.NewInst[BadObject[]]]; }; [] _ CDCells.ResizeCell[NIL, cob]; CDCells.SetSimplificationTreshhold[cob]; ENDLOOP; TerminalIO.PutRope["finished cell directory\n"]; depht _ IF ver<7 THEN 0 ELSE InWord[]; IF depht>0 THEN { TerminalIO.PutRope["***design was pushed in; not read in correctly\n"]; RETURN; }; IF ver>=7 THEN { fileChangeCode: INTEGER = InWord[]; }; design.actual.first.specific.contents _ InList[ver].list; design.name _ fileName; TerminalIO.PutRope["Finished reading chip\n"]; IF errs>0 THEN { TerminalIO.PutF1["%g unknown objects\n", IO.int[errs]]; errs _ 0; }; IO.Close[chipfile]; EXITS IOError => {TerminalIO.PutRope[" proceed; discard this design\n"];}; }; -- ReadChip CommandReadChip: ENTRY Commander.CommandProc = { ENABLE { TerminalIO.UserAbort => GOTO UserAbrt; UNWIND => NULL; }; list: LIST OF Rope.ROPE; length: NAT; name: Rope.ROPE; [list, length] _ CommandTool.ParseToList[cmd]; IF length=0 THEN name _ NIL ELSE IF length=1 THEN name _ list.first ELSE { result _ $Failure; msg _ "unknown arguments"; RETURN }; design_ CDOps.CreateDesign[CMos.cmos]; IF FileOpened[name] THEN { ReadChip[]; CDOps.DeselectAll[design: design, setSelection: TRUE]; TransformSelected[design, rotate180X]; CDOps.DeselectAll[design]; [] _ CDViewer.CreateViewer[design]; }; EXITS UserAbrt => {TerminalIO.PutRope["read aborted\n"]}; }; TestRead: ENTRY Commander.CommandProc = { ENABLE { IO.EndOfStream => GOTO IOEnd; UNWIND => NULL; }; w: CARDINAL; IF FileOpened[NIL] THEN { TerminalIO.PutRope["--startfile--\n"]; DO w _ LOOPHOLE[InWord[]]; TerminalIO.PutF1["%7b\n", IO.card[w]]; ENDLOOP; }; EXITS IOEnd => {TerminalIO.PutRope["--endfile--\n"]}; }; CDCommandOps.RegisterWithMenu[$IOMenu, "chipmonk-output", "converts to old Chipmonk format", $ChipmonkOutput]; Commander.Register["///Commands/CDTestRead", TestRead, "ChipNDale test feature: Reads file and display it on Terminal"]; Commander.Register["///Commands/CDReadCMCMos", CommandReadChip, "Converts old cmos Chipmonk file to ChipNDale CMosA"]; END.