<> <> <> <> DIRECTORY Atom USING [MakeAtom], Basics USING [BITAND, BITSHIFT],CD, CDApplications, CDBusses USING [CreateBus], CDCells USING [CreateEmptyCell], CDDirectory USING [Include], CDCommands, CDExtras, CDInline, CDIOExtras, CDOps, CDOrient, CDPrivate, CDProperties, CDRects USING [CreateRect], CDRepetitions, CDTexts, CDViewer, Commander USING [CommandProc, Register], CommandTool, FileNames, FS, IO, NMos, NMosContacts, NMosTransistors, Rope USING [ROPE, Cat, IsEmpty, FromChar], TerminalIO, ViewerClasses USING [Viewer]; ChipmonkNMosRead: CEDAR MONITOR IMPORTS Atom, Basics, CDApplications, CDBusses, CDCells, CDCommands, CDDirectory, CDExtras, CDIOExtras, CDOps, CDPrivate, CDProperties, CDRects, CDRepetitions, CDTexts, CDViewer, Commander, CommandTool, FileNames, FS, IO, NMos, NMosContacts, NMosTransistors, Rope, TerminalIO SHARES CDProperties = BEGIN <<-- 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 = CD.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 = 500; 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 ]; contLevel: ARRAY [1..contTypALen] OF CD.Level = [ NMos.dif, NMos.pol, NMos.dif, NMos.dif, NMos.met2, NMos.dif, NMos.nwelCont, NMos.dif, NMos.pol, NMos.dif, NMos.dif, NMos.dif ]; -- for versions < 6 fileLevel: ARRAY [0..15] OF CD.Level = [ NMos.cut, NMos.dif, NMos.pol, NMos.met, NMos.imp, NMos.ovg, NMos.bur, NMos.snerd, NMos.cut2, NMos.NOcOL--pdif--, NMos.NOcOL--pwelcont--, NMos.met2, NMos.NOcOL--pwel--, NMos.nwel, NMos.nwelCont, NMos.NOcOL ]; <<-- global vars>> contType: TYPE = {burr, mDif, difShort, butt, mPol, mm2}; design: CD.Design; cellNameA: REF ARRAY [0..maxCellNum] OF CD.ObPtr _ NEW[ARRAY [0..maxCellNum] OF CD.ObPtr]; atomTable: REF ARRAY [1..atomTableSize] OF ATOM _ NEW[ARRAY [1..atomTableSize] OF ATOM]; standardFont: REF CDTexts.FontRec = CDTexts.GetFont[key: $CDxCompatibilityFont, technology: NMos.nmos]; chipfile: IO.STREAM; fileName: Rope.ROPE; errs: INT _0; NotYetImpl: PROC [] = BEGIN errs _ errs+1; TerminalIO.WriteRope["?"]; END; InWord: PROC RETURNS [INTEGER] = BEGIN highbyte: CARDINAL = LOOPHOLE[IO.GetChar[chipfile], CARDINAL]; lowbyte: CARDINAL = LOOPHOLE[IO.GetChar[chipfile], CARDINAL]; RETURN [ LOOPHOLE[(256*highbyte) + lowbyte, INTEGER] ]; END; FileFormat: ERROR = CODE; Lambda: PROCEDURE [i: INT] RETURNS [CD.DesignNumber] = INLINE { RETURN [lambdaFactor*i] }; InOrientation: PROC [] RETURNS [CD.Orientation] = INLINE BEGIN i: INTEGER = InWord[]; IF i>=FIRST[CD.Orientation] AND i<=LAST[CD.Orientation] THEN RETURN [i] ELSE ERROR FileFormat; END; InLevel: PROC [] RETURNS [CD.Level] = INLINE BEGIN i: INTEGER = InWord[]; IF i>= 0 AND i<= 15 THEN RETURN [fileLevel[i]] ELSE ERROR FileFormat; END; NewCellName: PROC [index: INTEGER] RETURNS [cellName: Rope.ROPE] = BEGIN cellName _ IO.PutFR[ "cell#%d", IO.int[index]]; END; InObject: PROC[version: INTEGER] RETURNS [obj: CD.ObPtr, rectProp: BOOL_FALSE] = BEGIN j, k, w, l, we, le, dumsur : INTEGER; kk: CARDINAL; lev: CD.Level; dumrope: Rope.ROPE; IF debugging OR debug THEN TerminalIO.WriteRope[" (Include new object ... "]; j _ InWord[]; SELECT j FROM instance => BEGIN k _ InWord[]; -- cell ID num obj _ cellNameA[k]; END; transistor => BEGIN impl: NMosTransistors.Implant _ NMosTransistors.enhancement; aExt: CD.DesignNumber _ 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[kk, 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 impl _ InWord[] ELSE impl _ LAST[NMosTransistors.Implant] }; we _ Basics.BITAND[Basics.BITSHIFT[kk, -6], 77B]; le _ Basics.BITAND[kk, 77B]; <<--lev _ IF Basics.BITAND[kk, 10000B] # LOOPHOLE[0] THEN NMos.pdif ELSE NMos.dif;>> obj _ SELECT TRUE FROM LOOPHOLE[Basics.BITAND[kk,40000B], CARDINAL] #0 => NMosTransistors.CreatePullUp[Lambda[w], Lambda[l], Lambda[we], Lambda[le]], LOOPHOLE[Basics.BITAND[kk, 20000B], CARDINAL] #0 => NMosTransistors.CreateAngleTransistor[ w: Lambda[w], l: Lambda[l], wExt: Lambda[we], lExt: Lambda[le], aExt: aExt, implant: impl ], ENDCASE => NMosTransistors.CreateTransistor[ w: Lambda[w], l: Lambda[l], wExt: Lambda[we], lExt: Lambda[le], implant: impl ]; END; contact => BEGIN j: CARDINAL _ LOOPHOLE[InWord[]]; -- get contact type kk: CARDINAL _ Basics.BITAND[j, 37B]; -- get contact type l: CARDINAL _ Basics.BITSHIFT[j, -8]; lev _ IF version > 5 THEN InLevel[] ELSE contLevel[kk]; IF version > 4 THEN dumsur _ LOOPHOLE[InWord[]]; SELECT contTypA[kk] FROM mPol => obj _ NMosContacts.CreatePolyCon[Lambda[l]]; mDif => obj _ NMosContacts.CreateDifCon[Lambda[l]]; <<-- difShort => obj _ NMosContacts.CreateDifShortCon[lev]; ************>> butt => obj_ NMosContacts.CreateButCon[]; burr => BEGIN w _ LOOPHOLE[InWord[]]; kk _ LOOPHOLE[InWord[]]; j _ Basics.BITSHIFT[kk, -8]; obj _ NMosContacts.CreateBurCon[Lambda[w], Lambda[l], Lambda[j], Lambda[LOOPHOLE[Basics.BITAND[kk, 37B], CARDINAL]]]; END; mm2 => obj _ NMosContacts.CreateMmCon[Lambda[l], 0, 0]; ENDCASE => ERROR; END; wire => BEGIN w _ InWord[]; l _ InWord[]; lev _ InLevel[]; <<-- IF version > 4 AND lev = NMos.pdif THEN dumsur _ InWord[];>> obj _ CDRects.CreateRect[[Lambda[w],Lambda[l]], lev]; END; rectangle => BEGIN w _ InWord[]; l _ InWord[]; lev _ InLevel[]; obj _ CDRects.CreateRect[[Lambda[w], Lambda[l]], lev]; rectProp _ TRUE; END; text => { dumrope _ InString[]; obj _ CDTexts.CreateText[dumrope, standardFont] }; bus => BEGIN w: CD.DesignNumber = Lambda[InWord[]]; l: CD.DesignNumber = Lambda[InWord[]]; lev: CD.Level = InLevel[]; count: NAT = InWord[]; spacing: CD.DesignNumber = Lambda[InWord[]]; topInc: CD.DesignNumber = Lambda[InWord[]]; botInc: CD.DesignNumber = Lambda[InWord[]]; obj _ CDBusses.CreateBus[ sizeOfFirst: [w, l], lev: lev, count: count, offset: [spacing, topInc], lengIncrement: botInc-topInc ]; -- compare: obj _ Chipmonk.makeBus[l, w, lev, count, spacing, topInc, botInc]; END; repeat => BEGIN rob: CD.ObPtr = InObject[version].obj; ignoredw: INT = InWord[]; -- ignored ignoredl: INT = InWord[]; -- ignored dx: CD.DesignNumber = Lambda[InWord[]]; dy: CD.DesignNumber = Lambda[InWord[]]; count: NAT _ InWord[]; orient: CD.Orientation _ InOrientation[]; obj _ CDRepetitions.CreateRepetition[design: design, ob: rob, count: count, offset: [dx, dy], orientation: orient]; END; ENDCASE => {TerminalIO.WriteRope["** Erronous object\n"]; obj _ NIL}; IF debugging OR debug THEN TerminalIO.WriteRope[" done) \n"]; END; -- of InObject InList: PROC[ver: INTEGER] RETURNS [list: CD.ApplicationList _ NIL, length: INT] = BEGIN rectProp: BOOL _ FALSE; appCount: INTEGER; app: CD.ApplicationPtr; ob: CD.ObPtr; location: CD.DesignPosition; orientation: CD.Orientation; IF debugging OR debug THEN TerminalIO.WriteRope["start list\n"]; appCount _ InWord[]; FOR appNum: INTEGER IN [0..appCount) DO location.x _ Lambda[InWord[]]; location.y _ Lambda[InWord[]]; orientation _ InOrientation[]; [ob, rectProp] _ InObject[ver]; IF ob#NIL THEN { app _ CDApplications.NewApplicationI[ob: ob, location: location, orientation: orientation]; list _ CONS[app, list]; IF rectProp THEN CDProperties.PutPropOnApplication[onto: app, prop: $CDxChipmonkThinks, val: $Rect]; } ELSE { app _ NEW[CD.Application]; TerminalIO.WriteRope["nil object\n"] }; IF ver > 3 THEN BEGIN propCount: INTEGER = InWord[]; FOR propNum: INTEGER IN [0..propCount) DO InProp[app]; ENDLOOP; END; ENDLOOP; IF debugging OR debug THEN TerminalIO.WriteRope["end list\n"]; RETURN[list, appCount]; END; InProp: PROC [aptr: CD.ApplicationPtr] = BEGIN kind: INTEGER _ InWord[]; name: REF _ NIL; value: REF; SELECT kind FROM 1 => { IF aptr=NIL OR aptr.ob=NIL OR ISTYPE[aptr.ob.specificRef, CD.RectPtr] THEN name _ $SignalName ELSE name _ $InstanceName; value _ InString[]; }; 2 => { name _ InAtom[]; value _ InAtom[]; }; ENDCASE => { name _ NIL; TerminalIO.WriteRope["** unknown property kind\n"]; }; IF name#NIL AND aptr#NIL AND aptr.ob#NIL THEN CDProperties.PutProp[onto: aptr, prop: name, val: value] END; InAtom: PROC [] RETURNS[a: ATOM] = BEGIN 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.WriteRope["** Atom table code wrong\n"]; } ELSE { TerminalIO.WriteRope["** Atom code wrong\n"]; a _ NIL } END; InString: PROC [] RETURNS[s: Rope.ROPE] = BEGIN j, i, len: CARDINAL; flg: BOOLEAN; j _ LOOPHOLE[InWord[]]; len _ Basics.BITSHIFT[j, -8]; IF len = 0 THEN BEGIN s _ ""; RETURN; END; flg _ TRUE; FOR i IN [0..len) DO IF flg THEN s _ Rope.Cat[s, Rope.FromChar[LOOPHOLE[Basics.BITAND[j, 377B], CHAR]]] ELSE BEGIN j _ LOOPHOLE[InWord[]]; s _ Rope.Cat[s, Rope.FromChar[LOOPHOLE[Basics.BITSHIFT[j, -8], CHAR]]]; END; flg _ NOT flg; ENDLOOP; END; FileOpened: PROC [name: Rope.ROPE] RETURNS [fileWasOpened: BOOLEAN] = BEGIN <<--get file name>> IF Rope.IsEmpty[name] THEN name _ TerminalIO.RequestRope["Input file > "]; fileName _ CDExtras.AppendExt[name, "chip"]; chipfile _ FS.StreamOpen[fileName ! FS.Error => IF error.group#bug THEN { TerminalIO.WriteRope[fileName]; TerminalIO.WriteRope[" not opened: "]; TerminalIO.WriteRope[error.explanation]; TerminalIO.WriteLn[]; GOTO FileName }]; TerminalIO.WriteRope["File being read is "]; TerminalIO.WriteRope[fileName]; TerminalIO.WriteRope["\n"]; fileWasOpened _ TRUE; EXITS FileName => {fileWasOpened _ FALSE}; END; ResetSimplification: PROC[cell: CD.ObPtr, leng: INT_0] = INLINE BEGIN long: INT ~ MAX[MAX[cell.size.y, cell.size.x], 1]; short: INT ~ MAX[MIN[cell.size.y, cell.size.x], 1]; cp: CD.CellPtr ~ NARROW[cell.specificRef]; leng _ leng/2+6; leng _ MAX[MIN[leng, 300], 8]; <<--make it symetric now using shorter size>> IF cell.size.y>cell.size.x THEN { leng _ (leng*long)/short; }; leng _ MAX[MIN[leng, 600], 8]; <<--introduce longer side>> leng _ (leng*3)/(2+(long/short)/2); cp.simplifyOn _ MAX[MIN[leng, 600], 8]; END; ReadChip: PROC = BEGIN ENABLE { FileFormat => { TerminalIO.WriteRope["\n**File-Format error\n"]; CDPrivate.Debug[msg: "file format; [proceed does not clobber other designs]"]; GOTO IOError; }; IO.EndOfStream => { TerminalIO.WriteRope["\n**end of stream error\n"]; CDPrivate.Debug[msg: "file format; [proceed does not clobber other designs]"]; GOTO IOError; }; IO.Error => { TerminalIO.WriteRope["\n**io error\n"]; <<--if you are debugging here: inspect "ec">> CDPrivate.Debug[msg: "io error [proceed does not clobber other designs]"]; GOTO IOError; }; }; i, j, k, ver, cCnt, dummy, depht: INTEGER; leng: INT; ss: Rope.ROPE; cdp: CD.ObPtr; cellPtr: CD.CellPtr; errs_0; i _ InWord[]; IF i # LOOPHOLE[codeWordForDataFile, INTEGER] AND NOT TerminalIO.UserSaysYes[ "Doesn't look like a .chip file -- should program continue?"] THEN RETURN; ver _ InWord[]; cCnt _ InWord[]; IF cCnt > maxCellNum THEN BEGIN TerminalIO.WriteRope["Too many different kinds of cells in design...aborting read\n"]; RETURN; END; IF ver < 3 THEN BEGIN TerminalIO.WriteRope[" Version number too low...aborting read\n"]; RETURN; END; IF ver>8 THEN BEGIN TerminalIO.WriteRope[" new chipmonk version unknown to chipndale...aborting read\n"]; RETURN; END; FOR j IN [0..cCnt] DO cellNameA[j] _ CDCells.CreateEmptyCell[]; ENDLOOP; TerminalIO.WriteRope["Starting cell directory\n"]; FOR k IN [1..cCnt] DO j _ InWord[]; cdp _ cellNameA[j]; ss _ InString[]; cdp.size.x _ Lambda[InWord[]]; cdp.size.y _ Lambda[InWord[]]; dummy _ InWord[]; cellPtr _ NARROW[cdp.specificRef, CD.CellPtr]; [cellPtr.contents, leng] _ InList[ver]; IF NOT Rope.IsEmpty[ss] THEN cellPtr.name _ ss ELSE cellPtr.name _ NewCellName[k]; [] _ CDDirectory.Include[design: design, object: cdp, fiddleName: TRUE]; ENDLOOP; TerminalIO.WriteRope["Finished cell directory\n"]; depht _ IF ver<7 THEN 0 ELSE InWord[]; IF depht>0 THEN { TerminalIO.WriteRope["***design was pushed in\nnot read in correctly\n"]; RETURN; }; IF ver>=7 THEN { fileChangeCode: INTEGER = InWord[]; }; design.actual.first.specific.contents _ InList[ver].list; design.name _ fileName; TerminalIO.WriteRope["Finished reading chip\n"]; IF errs>0 THEN BEGIN TerminalIO.WriteInt[errs]; errs _ 0; TerminalIO.WriteRope[" unknown objects\n"]; END; IO.Close[chipfile]; EXITS IOError => {TerminalIO.WriteRope[" proceed; discard this design\n"];}; END; -- of ReadChip CommandReadChip: ENTRY Commander.CommandProc = BEGIN 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[NMos.nmos]; IF FileOpened[name] THEN { ReadChip[]; CDCommands.SelectAll[design]; CDCommands.TransformSelected[design, CDOrient.rotate180+CDOrient.mirrorX]; CDCommands.DeselectAll[design]; [] _ CDViewer.CreateViewer[design]; CDIOExtras.SetDesignsWorkingDirectory[design, FileNames.CurrentWorkingDirectory[]]; }; EXITS UserAbrt => {TerminalIO.WriteRope["read aborted\n"]}; END; Commander.Register[ key: "CDReadNMos", proc: CommandReadChip, doc: "Reads old nmos Chipmonk file" ]; Commander.Register[ key: "CDReadCMNMos", proc: CommandReadChip, doc: "Reads old nmos Chipmonk file" ]; END.