ChipmonkCmosRead.mesa
Copyright © 1983, 1987 by Xerox Corporation. All rights reserved.
Last Edited by: Kimr, October 26, 1983 9:39 am
Last Edited by: Christian Jacobi, October 25, 1983 12:48 pm
Last edited by: Christian Jacobi, January 29, 1987 4:49:35 pm PST
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 𡤀
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: REFNIL, instVal: REFNIL] = {
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"]};
obj ← CMosCMTransistors.CreatePullUp[w: Lambda[w], l: Lambda[l], wExt: Lambda[we], lExt: Lambda[le], difLev: lev];
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: CARDINALLOOPHOLE[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: REFNIL;
instVal: REFNIL;
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.ROPENIL;
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.