ChipmonkNMosRead.mesa
Copyright © 1983, 1985 by Xerox Corporation. All rights reserved.
Last Edited by: Kimr, October 26, 1983 9:39 am
Last Edited by: Jacobi, October 25, 1983 12:48 pm
Last Edited by: Jacobi, March 25, 1986 5:06:39 pm PST
copy from cmos to nmos, not inverse!
DIRECTORY
Atom USING [MakeAtom],
Basics USING [BITAND, BITSHIFT],
CD,
CDInstances,
CDBusCells USING [CreateBusCell],
CDCells USING [CreateEmptyCell],
CDSimpleOps,
CDDirectory USING [Include],
CDIO,
CDMenus,
CDOps,
CDOrient,
CDProperties,
CDRects USING [CreateRect],
CDRepetitions,
CDTexts,
CDViewer,
Commander USING [CommandProc, Register],
CommandTool,
FS,
IO,
NMos,
NMosContacts,
NMosTransistors,
Rope USING [ROPE, Cat, IsEmpty, FromChar],
TerminalIO,
ViewerClasses USING [Viewer];
ChipmonkNMosRead: CEDAR MONITOR
IMPORTS Atom, Basics, CDInstances, CDBusCells, CDCells, CDSimpleOps, CDDirectory, CDIO, CDMenus, CDOps, CDProperties, CDRects, CDRepetitions, CDTexts, CDViewer, Commander, CommandTool, 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 = NMos.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
];
contLevel: ARRAY [1..contTypALen] OF CD.Layer = [
NMos.dif, NMos.pol, NMos.dif, NMos.dif,
NMos.met2, NMos.dif, --NMos.nwelCont-- CD.errorLayer, NMos.dif,
NMos.pol, NMos.dif, NMos.dif, NMos.dif
]; -- for versions < 6
fileLevel: ARRAY [0..15] OF CD.Layer = [
NMos.cut, NMos.dif, NMos.pol, NMos.met,
NMos.imp, NMos.ovg, NMos.bur, CD.errorLayer --snerd-- ,
NMos.cut2, CD.errorLayer--pdif--,
CD.errorLayer--pwelcont--, NMos.met2,
CD.errorLayer--pwel--, CD.errorLayer--NMos.nwel--,
CD.errorLayer--NMos.nwelCont--, 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 𡤀
NotYetImpl: PROC [] =
BEGIN
errs ← errs+1;
TerminalIO.WriteRope["?"];
END;
BadObject: PROC [size: CD.Position ← [4, 4]] RETURNS [CD.Object] =
BEGIN
RETURN [CDRects.CreateRect[size, CD.errorLayer]]
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.Number] =
INLINE { RETURN [lambdaFactor*i] };
InOrientation: PROC [] RETURNS [CD.Orientation] =
INLINE BEGIN
i: INTEGER = InWord[];
IF i>=0 AND i<=15 THEN RETURN [i/4*2 + i MOD 2] --different representation
ELSE ERROR FileFormat;
END;
ToLevel: PROC [i: INTEGER] RETURNS [CD.Layer] =
INLINE BEGIN
IF i>= 0 AND i<= 15 THEN RETURN [fileLevel[i]]
ELSE ERROR FileFormat;
END;
InLevel: PROC [] RETURNS [CD.Layer] =
INLINE BEGIN
RETURN [ToLevel[InWord[]]]
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.Object, appProp: REFNIL, appVal: REFNIL] =
BEGIN
j, k, w, l, we, le, dumsur : INTEGER;
kk: CARDINAL;
lev: CD.Layer;
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.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[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: CARDINALLOOPHOLE[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]];
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
i: INTEGER;
w ← InWord[];
l ← InWord[];
i ← InWord[];
lev ← ToLevel[i];
SELECT i FROM
7 => {appVal ← $snerdRect; appProp ← $SignalName};
15 => {appVal ← $NOcOLRect; appProp ← $SignalName};
ENDCASE => NULL;
obj ← CDRects.CreateRect[[Lambda[w],Lambda[l]], lev];        
END;
rectangle =>
BEGIN
i: INTEGER;
w ← InWord[];
l ← InWord[];
appVal ← $Rect;
appProp ← $CDxChipmonkThinks;
i ← InWord[];
lev ← ToLevel[i];
SELECT i FROM
7 => {appVal ← $snerdRect; appProp ← $SignalName};
15 => {appVal ← $NOcOLRect; appProp ← $SignalName};
ENDCASE => NULL;
obj ← CDRects.CreateRect[[Lambda[w], Lambda[l]], lev];  
END;
text => {
dumrope ← InString[];
obj ← CDTexts.CreateText[dumrope, standardFont]
}; 
bus =>
BEGIN
w: CD.Number = Lambda[InWord[]];
l: CD.Number = Lambda[InWord[]];
lev: CD.Layer = InLevel[];
count: NAT = InWord[];
spacing: CD.Number = Lambda[InWord[]];
topInc: CD.Number = Lambda[InWord[]];
botInc: CD.Number = Lambda[InWord[]];
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];
END;
repeat =>
BEGIN
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];
END;
ENDCASE => {
obj ← BadObject[];
TerminalIO.WriteRope["** Erronous object\n"];
};
IF debugging OR debug THEN
TerminalIO.WriteRope[" done) \n"];
END; -- of InObject
InList: PROC[ver: INTEGER] RETURNS [list: CD.InstanceList ← NIL, length: INT] =
BEGIN
appProp: REFNIL;
appVal: REFNIL;
appCount: INTEGER;
inst: CD.Instance;
ob: CD.Object;
location: CD.Position;
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, appProp, appVal] ← InObject[ver];
IF ob=NIL THEN {
ob ← BadObject[];
TerminalIO.WriteRope["nil object\n"]
};
inst ← CDInstances.NewInstI[ob: ob, location: location, orientation: orientation];
list ← CONS[inst, list];
IF appProp#NIL THEN CDProperties.PutInstanceProp[inst, appProp, appVal];
IF ver > 3 THEN
BEGIN
propCount: INTEGER = InWord[];
FOR propNum: INTEGER IN [0..propCount) DO
InProp[inst];
ENDLOOP;
END;
ENDLOOP;
RETURN[list, appCount];
END;
sigName: ATOM = Atom.MakeAtom["SIGNAL NAME"];
InProp: PROC [aptr: CD.Instance] =
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[];
IF name=sigName THEN name ← $SignalName;
};
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 ← CDIO.MakeName[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.Object, leng: INT𡤀] = 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];
is: INT;
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);
is ← MAX[MIN[leng, 600], 8];
cp.simplifyOn ← is;
END;
signal: SIGNAL = CODE;
ReadChip: PROC =
BEGIN
ENABLE {
FileFormat => {
TerminalIO.WriteRope["\n**File-Format error [proceed does not clobber other designs]\n"];
SIGNAL signal;
GOTO IOError;
};
IO.EndOfStream => {
TerminalIO.WriteRope["\n**end of stream error [proceed does not clobber other designs]\n"];
SIGNAL signal;
GOTO IOError;
};
IO.Error => {
TerminalIO.WriteRope["\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, dummy, depht: INTEGER;
leng: INT;
ss: Rope.ROPE;
cdp: CD.Object;
cellPtr: CD.CellPtr;
errs𡤀
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
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];
IF cellPtr.contents=NIL THEN {
TerminalIO.WriteRope[Rope.Cat["** empty cell ", cellPtr.name, "\n"]];
cellPtr.contents ← LIST[CDInstances.NewInstI[BadObject[]]];
};
ResetSimplification[cdp, leng];
cellPtr.ir ← CDInstances.BoundingRectI[cellPtr.contents];
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; 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.WriteRope["Finished reading chip\n"];
IF errs>0 THEN {
TerminalIO.WriteInt[errs];
TerminalIO.WriteRope[" unknown objects\n"];
errs ← 0;
};
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[];
CDSimpleOps.SelectAll[design];
CDSimpleOps.TransformSelected[design, CDOrient.rotate180+CDOrient.mirrorX];
CDSimpleOps.DeselectAll[design];
[] ← CDViewer.CreateViewer[design];
};
EXITS
UserAbrt => {TerminalIO.WriteRope["read aborted\n"]};
END;
CDMenus.CreateEntry[$IOMenu, "chipmonk-output", $ChipmonkOutput];
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.