-- NutsMain.mesa
-- Mainline CIF-to-Chipmonk conversion
-- Modifications:
-- Dillon 19-Nov-84 9:58:40. Convert rectangular polygons to boxes
-- Also convert illegal zero-width boxes to 1/2 lambda boxes
-- Dillon February 10, 1985 10:41 AM. Convert wires to boxes
-- Also implement Flashes as square Boxes
-- Last Edit: See "herald:" below.
DIRECTORY
AuxIntDefs: FROM "AuxIntDefs" USING [IGetFirstSymbol, IGetNextSymbol, IGetRootID, ISymBB, IExpand],
AuxOutputDefs: FROM "AuxOutputDefs" USING [],
ImageDefs: FROM "ImageDefs" USING [AbortMesa],
InlineDefs: FROM "InlineDefs" USING [BITOR,BITSHIFT, COPY, LowByte, LowHalf, HighHalf],
IntDefs: FROM "IntDefs" USING [InitInterpreter, FinishInterpreter, IScaleLongInt, IUserObject],
IntTransDefs: FROM "IntTransDefs" USING [Transform],
IntStorageDefs: FROM "IntStorageDefs" USING [ObjectType, ObjectName, NilObjectName],
IODefs: FROM "IODefs" USING [WriteString, WriteLine, ReadLine, ReadDecimal, WriteDecimal, Rubout, WriteChar, CR],
NutsDictDefs: FROM "NutsDictDefs" USING [AllocateDict, Record, Lookup, What, FreeDict],
OutputDefs: FROM "OutputDefs" USING [RelationType, VisibleType],
ParserDefs: FROM "ParserDefs" USING [CommandType,InitParser,FinishParser, ParseStatement],
ParserErrorDefs: FROM "ParserErrorDefs" USING [ParserAbort, ErrorType, Report],
ParserInputDefs: FROM "ParserInputDefs" USING [InFromFile],
ParserTypeDefs: FROM "ParserTypeDefs" USING [LinkedPoint, Point, Path],
Real: FROM "Real" USING [Fix, Float],
RealFns: FROM "RealFns" USING [SqRt],
Storage: FROM "Storage" USING [CopyString, FreeString, Node, StringLength],
StreamDefs: FROM "StreamDefs" USING [DiskHandle, NewWordStream, WriteAppend],
StringDefs: FROM "StringDefs" USING [AppendChar, AppendDecimal, AppendString, EqualStrings, InvalidNumber, StringToLongNumber, WordsForString, UpperCase];
NutsMain: PROGRAM IMPORTS AuxIntDefs, ImageDefs, IntDefs, IODefs, InlineDefs, NutsDictDefs, ParserDefs, ParserErrorDefs, ParserInputDefs, Real, RealFns, Storage, StreamDefs, StringDefs EXPORTS AuxOutputDefs, OutputDefs =
BEGIN
herald: STRING ← "NUTS of February 10, 1985 10:41 AM"; -- by Dillon
UCmdType: TYPE = {SymbolName,NodeName};
UserCmd: TYPE = RECORD
[
type: UCmdType,
name: STRING,
x,y: LONG INTEGER,
stringBody: ARRAY [0..0) OF WORD];
ChipLayers: ARRAY [0..7] OF CARDINAL =
-- Mapping from MAGIC to Chipmonk layer numbers
[4, -- MAGIC 0 = implant
1, -- MAGIC 1 = diffusion
2, -- MAGIC 2 = poly
0, -- MAGIC 3 = contact
3, -- MAGIC 4 = metal
6, -- MAGIC 5 = buried
5, -- MAGIC 6 = glass
7]; -- MAGIC 7 = undef
chipSymNo: CARDINAL;
ModeType: TYPE = {Idle, Marking, ScanningSymbol, CountingItems, PuttingDefn, PuttingItems};
Mode: ModeType;
itemCount: CARDINAL;
Name: STRING ← [50];
hasName: BOOLEAN ← FALSE;
CurrentSymbol: IntStorageDefs.ObjectName; -- symbol whose definition is being processed
FileRoot: STRING ← [40];
CifFileName: STRING ← [40];
ChipFileName: STRING ← [40];
ChipFile: StreamDefs.DiskHandle;
Scale: CARDINAL ← 125; -- Half-lambda per cif unit
prevProblem, prevPrevProblem: STRING ← NIL; -- to avoid explosion of warnings
Mark: PROCEDURE [markee: IntStorageDefs.ObjectName] =
-- recursive procedure eliminates forward symbol references:
-- FOR all callee CALLED BY markee DO Mark[callee] ENDLOOP
-- then record markee in dictionary
BEGIN
IF NutsDictDefs.Lookup[markee] = 0 THEN
BEGIN
AuxIntDefs.IExpand[markee]; -- mark all callees
NutsDictDefs.Record[chipSymNo,markee]; -- then record self
chipSymNo ← chipSymNo+1;
-- ELSE already marked, nothing to do
END;
END;
PutChipFile: PROCEDURE =
BEGIN
sequenceNumber, symbolCount: CARDINAL;
PutWord [123751B]; -- Password for Chip file.
PutWord [4]; -- Version number
-- First count symbols, to determine size of dictionary
symbolCount ← 0;
CurrentSymbol ← AuxIntDefs.IGetFirstSymbol[];
UNTIL CurrentSymbol=IntStorageDefs.NilObjectName DO
symbolCount ← symbolCount+1;
CurrentSymbol ← AuxIntDefs.IGetNextSymbol[];
ENDLOOP;
NutsDictDefs.AllocateDict[symbolCount];
PutWord [symbolCount];
-- Go through list of symbols, looking for symbols not yet in dictionary.
-- For each such symbol, record first all symbols it calls, then itself.
-- (Initially none are recorded, but this changes quickly!)
chipSymNo ← 1;
SetMode[Marking];
CurrentSymbol ← AuxIntDefs.IGetFirstSymbol[];
UNTIL CurrentSymbol=IntStorageDefs.NilObjectName DO
Mark[CurrentSymbol];
CurrentSymbol ← AuxIntDefs.IGetNextSymbol[];
ENDLOOP;
-- write out symbol definitions in sorted order
SetMode[PuttingDefn];
FOR sequenceNumber IN [1..symbolCount] DO
CurrentSymbol ← NutsDictDefs.What[sequenceNumber];
PutSymbolDef[CurrentSymbol, sequenceNumber];
ENDLOOP;
CurrentSymbol ← AuxIntDefs.IGetRootID[];
SetMode[CountingItems];
AuxIntDefs.IExpand[CurrentSymbol]; -- this time, just to count items
PutWord[itemCount];
SetMode[PuttingItems];
AuxIntDefs.IExpand[CurrentSymbol]; -- now for real
SetMode[Idle];
END;
PutSymbolDef: PROCEDURE [symbol: IntStorageDefs.ObjectName, chipSymNo: CARDINAL] =
BEGIN
l,r,b,t: LONG INTEGER; -- left,right,bottom,top of BBox in CIF units
xSize,ySize: CARDINAL; -- dimensions of BBox in half-lambda
PutWord [chipSymNo];
SetMode[ScanningSymbol];
AuxIntDefs.IExpand[symbol]; -- count items, find name
PutString[GetName[chipSymNo]];
[l,r,b,t] ← AuxIntDefs.ISymBB[symbol];
xSize ← ChipScale[r-l];
ySize ← ChipScale[t-b];
PutWord[xSize];
PutWord[ySize];
PutWord[0]; -- reserved for future Chipmonks
PutWord[itemCount];
SetMode[PuttingDefn];
AuxIntDefs.IExpand[symbol]; -- list contents of symbol
END;
ParseCifFile: PROCEDURE [fname: STRING] RETURNS [ok: BOOLEAN] =
BEGIN
ENABLE ParserErrorDefs.ParserAbort=>ImageDefs.AbortMesa;
stmtCount: CARDINAL ← 0;
IODefs.WriteString["Initializing Parser"];
ok←ParserDefs.InitParser[];
IF NOT ok THEN InternalError["problem Initializing Parser"];
IODefs.WriteLine[", Interpreter"];
ok←IntDefs.InitInterpreter[];
IF NOT ok THEN InternalError["problem Initializing Interpreter"];
ok ← ParserInputDefs.InFromFile[fname];
IF ok THEN
BEGIN
IODefs.WriteString["Parsing "];
IODefs.WriteString[fname];
IODefs.WriteString["..."];
UNTIL ParserDefs.ParseStatement[]=End DO
stmtCount ← stmtCount + 1;
IF stmtCount MOD 100 = 0 THEN
BEGIN
IODefs.WriteDecimal[stmtCount];
IODefs.WriteString["..."];
END;
ENDLOOP;
IF ParserDefs.FinishParser[] THEN IODefs.WriteLine["finished."];
END
END;
GetFileNames: PROCEDURE =
BEGIN
ENABLE IODefs.Rubout=>
BEGIN
IODefs.WriteLine["XXX"];
RETRY;
END;
IODefs.WriteString["File Name (no extension): "];
IODefs.ReadLine[FileRoot];
CifFileName.length ← 0;
StringDefs.AppendString[to: CifFileName, from: FileRoot];
StringDefs.AppendString[to: CifFileName, from: ".cif"];
ChipFileName.length ← 0;
StringDefs.AppendString[to: ChipFileName, from: FileRoot];
StringDefs.AppendString[to: ChipFileName, from: ".chip"];
END;
GetLambda: PROCEDURE RETURNS [lambda: CARDINAL] =
BEGIN
ENABLE StringDefs.InvalidNumber=>
BEGIN
IODefs.WriteLine[" is invalid number!"];
RETRY;
END;
DO
IODefs.WriteString["Lambda (CIF units): "];
lambda ← IODefs.ReadDecimal[]; IODefs.WriteLine[""];
IF (lambda MOD 2) = 0 THEN RETURN[lambda];
IODefs.WriteLine["must be even!"];
ENDLOOP;
END;
OpenChipFile: PROCEDURE [filename: STRING] =
BEGIN
ChipFile ← StreamDefs.NewWordStream[filename, StreamDefs.WriteAppend];
IODefs.WriteString["Writing "];
IODefs.WriteString[filename];
IODefs.WriteString["..."];
END;
CloseChipFile: PROCEDURE =
BEGIN
ChipFile.destroy[ChipFile];
IODefs.WriteLine["finished."];
END;
ResolveRotation: PROCEDURE [length, width: LONG CARDINAL, xRotation, yRotation: LONG INTEGER] RETURNS [xSize, ySize: LONG CARDINAL] =
BEGIN
-- (xRotation, yRotation) is direction vector; (1,0) = no rotation
IF xRotation # 0 AND yRotation # 0 THEN
BEGIN
Warning ["45-degree","taken as no rotation"];
xSize ← width;
ySize ← length;
END
ELSE SELECT TRUE FROM
xRotation # 0 => -- no rotation
BEGIN
xSize ← length;
ySize ← width;
END;
yRotation # 0 => -- 90 degrees
BEGIN
xSize ← width;
ySize ← length;
END;
ENDCASE =>
BEGIN
Warning ["zero vector","taken as no rotation"];
xSize ← width;
ySize ← length;
END;
-- Hack to allow zero-dimension boxes to be expanded to 1/2 lambda.
-- Some DRC programs outline errors with such objects.
-- Treat negative sizes as errors.
IF xSize = 0 THEN xSize ← Scale;
IF ySize = 0 THEN ySize ← Scale;
END;
SetLambda: PROCEDURE [lambda: CARDINAL] =
BEGIN
Scale ← lambda/2;
END;
ChipScale: PROCEDURE [cifUnits: LONG INTEGER] RETURNS [INTEGER] =
BEGIN
quotient: LONG INTEGER;
IF cifUnits MOD Scale # 0 THEN
Warning ["Non-lambda-grid item","dimension truncated"];
quotient ← cifUnits/Scale;
IF InlineDefs.HighHalf[quotient] NOT IN [-1..0] THEN
BEGIN
Warning ["Number too big to scale","taken as zero"];
RETURN[0];
END;
RETURN [InlineDefs.LowHalf[quotient]];
END;
PutNullItem: PROCEDURE[] =
BEGIN
PutWord[0]; -- x position
PutWord[0]; -- y position
PutWord[0]; -- orientation
PutWord[0]; -- code for null item
PutWord[0]; -- contents of null item
PutWord[0]; -- zero properites
END;
PutWord: PROCEDURE[word: UNSPECIFIED] =
BEGIN
ChipFile.put[ChipFile, word];
END;
PutString: PROCEDURE[string: STRING] =
BEGIN
bflg: BOOLEAN ← FALSE;
save: CARDINAL;
i: CARDINAL;
PutByte: PROCEDURE [byte: CHARACTER] =
BEGIN
IF bflg
THEN PutWord[InlineDefs.BITOR[byte, save]]
ELSE save ← InlineDefs.BITSHIFT[byte, 8];
bflg ← NOT bflg;
END;
PutByte[InlineDefs.LowByte[string.length]];
FOR i IN [0..string.length) DO PutByte[string[i]]; ENDLOOP;
PutByte[0C]; -- complete word if odd number bytes put so far
END;
Warning: PROCEDURE [problem, fixup: STRING] =
BEGIN
chipSymNo: CARDINAL;
IF StringDefs.EqualStrings[problem, prevProblem] OR
StringDefs.EqualStrings[problem, prevPrevProblem] THEN RETURN;
Storage.FreeString[prevPrevProblem]; prevPrevProblem ← prevProblem;
prevProblem ← Storage.CopyString[problem];
IODefs.WriteString["Warning: "];
IODefs.WriteString[problem];
IF (chipSymNo←NutsDictDefs.Lookup[CurrentSymbol]) > 0 THEN
BEGIN
IODefs.WriteString[" in "];
IODefs.WriteString[GetName[chipSymNo]];
END
ELSE IF CurrentSymbol = AuxIntDefs.IGetRootID[] THEN
IODefs.WriteString[" in top level"];
IODefs.WriteString[" - "];
IODefs.WriteLine[fixup];
END;
InternalError: PROCEDURE [message: STRING] =
BEGIN
IODefs.WriteString["Fatal Internal Error: "];
IODefs.WriteLine[message];
CloseChipFile;
ImageDefs.AbortMesa;
END;
GetName: PROCEDURE [chipSymNo: CARDINAL] RETURNS [STRING] =
BEGIN
i: CARDINAL;
IF ~hasName THEN -- Invent name from file root, number.
BEGIN
Name.length ← 0;
FOR i IN [0..FileRoot.length) DO
StringDefs.AppendChar[Name,StringDefs.UpperCase[FileRoot[i]]];
ENDLOOP;
StringDefs.AppendDecimal[Name,chipSymNo];
END;
RETURN [Name];
END;
SetMode: PROCEDURE [newMode: ModeType] =
BEGIN
Mode ← newMode;
SELECT Mode FROM
ScanningSymbol =>
BEGIN
Name.length ← 0;
hasName ← FALSE;
END;
ENDCASE;
itemCount ← 0;
END;
CountItem: PROCEDURE =
BEGIN
itemCount ← itemCount + 1;
END;
-- Each routine below implements the output of one primitive geometric construct from CIF, called by Interpreter.
WireIsBox: PROCEDURE[layerName: CARDINAL, width: LONG CARDINAL,
a: ParserTypeDefs.Path,
proc: PROC [layerName: CARDINAL, length, width: LONG CARDINAL,
center: ParserTypeDefs.Point, xRotation, yRotation: LONG INTEGER]]
RETURNS [isbox: BOOLEAN] =
BEGIN
isbox ← TRUE; -- isbox returns false if any wire is not a box
-- Decompose the wire into boxes as suggested in Mead & Conway
-- i,j,k are previous, current, and next points on the wire's path.
IF a↑.length = 1 THEN -- make a flash
proc[layerName, width, width, a↑.first↑.value, 1, 0]
ELSE {
halfWidth: LONG CARDINAL = (width+1)/2;
extension, oldExtension, segLength: LONG CARDINAL;
segment, nextSeg, bend: ParserTypeDefs.Point;
j,n,nn:POINTER TO ParserTypeDefs.LinkedPoint;
j ← a.first; n ← j.next;
oldExtension ← halfWidth;
segment ← [n↑.value.x-j↑.value.x, n↑.value.y-j↑.value.y];
-- loop invariant (true on entry) n ← j.next; nn ← n.next;
FOR j ← j, n UNTIL n=NIL DO
nn ← n.next;
IF nn = NIL THEN extension ← halfWidth
ELSE {
nextSeg ← [nn↑.value.x-n↑.value.x, nn↑.value.y-n↑.value.y];
-- avoid long multiply overflows for Manhattan geometry
bend ← segment;
IF bend.x=0 THEN bend.y ← IF bend.y>0 THEN 1 ELSE -1
ELSE IF bend.y=0 THEN bend.x ← IF bend.x>0 THEN 1 ELSE -1;
bend ← [nextSeg.x*bend.x+nextSeg.y*bend.y,
nextSeg.x*bend.y-nextSeg.y*bend.x];
extension ← halfWidth*(ABS[bend.y]/(Length[bend]+ABS[bend.x]));
};
segLength ← Length[segment];
proc[layerName: layerName,
length: segLength+extension+oldExtension,
width: width,
center: [(n↑.value.x+j↑.value.x+(extension-oldExtension)*segment.x/segLength)/2,
(n↑.value.y+j↑.value.y+(extension-oldExtension)*segment.x/segLength)/2],
xRotation: segment.x,
yRotation: segment.y];
IF isbox THEN isbox ← segment.x=0 OR segment.y=0;
segment ← nextSeg;
oldExtension ← extension;
n ← nn;
ENDLOOP;
};
END;
AuxWire: PUBLIC PROCEDURE [layerName: CARDINAL, width: LONG CARDINAL, a: ParserTypeDefs.Path] =
BEGIN
-- Decompose the wire into boxes as suggested in Mead & Conway
[] ← WireIsBox[layerName, width, a, AuxBox];
END;
Length: PROCEDURE[dif:ParserTypeDefs.Point] RETURNS [LONG CARDINAL] = {
-- Utility to calculate length of vector dif.
-- Avoids using SqRt in the typical case of Manhattan orientation.
SELECT TRUE FROM
dif.x = 0 => RETURN[ABS[dif.y]];
dif.y = 0 => RETURN[ABS[dif.x]];
ENDCASE => {
x: REAL = Real.Float[dif.x];
y: REAL = Real.Float[dif.y];
RETURN[Real.Fix[RealFns.SqRt[x*x+y*y]]]
};
};
AuxFlash: PUBLIC PROCEDURE [layerName: CARDINAL, diameter: LONG CARDINAL, center: ParserTypeDefs.Point] =
BEGIN
-- Make a box of this dimension
AuxBox[layerName, diameter, diameter, center, 1, 0];
END;
PolygonIsBox: PROCEDURE [layerName: CARDINAL, a: ParserTypeDefs.Path,
proc: PROC [layerName: CARDINAL, length, width: LONG CARDINAL,
center: ParserTypeDefs.Point, xRotation, yRotation: LONG INTEGER]]
RETURNS [isbox: BOOLEAN] =
BEGIN
-- calls proc iff a describes a rectangular box
-- Special hack: convert length/width-zero polygons to 1/2 lambda boxes.
-- Some DRC programs use such polygons to outline errors.
-- Rectangular iff, for 4 points i,j,k,l (vector notation):
-- (i-j)=(l-k) (parallelogram rule, equivalently: (i-j+k-l)=0)
-- (i-j).(i-l)=0 (right angle rule)
-- The i-j direction is the length, the i-l direction is the width.
isbox ← FALSE;
IF a.length = 4 THEN { -- quadralaterals only
total: ParserTypeDefs.Point ← [0,0];
FOR j: POINTER TO ParserTypeDefs.LinkedPoint ← a.first, j.next UNTIL j=NIL DO
total.x ← j.value.x-total.x;
total.y ← j.value.y-total.y;
ENDLOOP;
IF total = [0,0] THEN { -- parallelograms only
OPEN i: a↑.first↑.value, j: a↑.first↑.next↑.value, l: a↑.last↑.value;
IF (i.x-j.x)*(i.x-l.x) + (i.y-j.y)*(i.y-l.y) = 0 THEN { -- right angles only
xRotation: LONG CARDINAL = i.x-j.x;
yRotation: LONG CARDINAL = i.y-j.y;
length: LONG CARDINAL = Length[[xRotation,yRotation]];
width: LONG CARDINAL = Length[[i.x-l.x,i.y-l.y]];
isbox ← TRUE;
-- Use diagonals for center
total.x ← (j.x+l.x)/2; total.y ← (j.y+l.y)/2;
proc[layerName, length, width, total, xRotation, yRotation];
};
};
};
END;
AuxPolygon: PUBLIC PROCEDURE [layerName: CARDINAL, a: ParserTypeDefs.Path] =
BEGIN
-- Ignore if non-rectangular, otherwise call the Box routine.
[] ← PolygonIsBox[layerName, a, AuxBox];
END;
AuxBox: PUBLIC PROCEDURE [layerName: CARDINAL, length, width: LONG CARDINAL, center: ParserTypeDefs.Point, xRotation, yRotation: LONG INTEGER] =
BEGIN
manhattan: BOOLEAN ← (xRotation=0 OR yRotation=0);
IF manhattan THEN SELECT Mode FROM
ScanningSymbol,CountingItems => CountItem;
PuttingDefn,PuttingItems =>
PutBox [layerName, length, width, center, xRotation, yRotation];
ENDCASE;
-- ELSE ignore 45's
END;
AuxUserObject: PUBLIC PROCEDURE [layerName: CARDINAL, size: CARDINAL, data: POINTER TO UNSPECIFIED] =
BEGIN
u: POINTER TO UserCmd ← data;
SELECT u↑.type FROM
SymbolName =>
BEGIN
SELECT Mode FROM
ScanningSymbol => -- register name
BEGIN
i: CARDINAL;
hasName ← TRUE;
FOR i IN [1..u↑.name.length) DO
StringDefs.AppendChar[Name,StringDefs.UpperCase[u↑.name[i]]];
ENDLOOP;
END;
ENDCASE; -- otherwise ignore
END;
NodeName =>
SELECT Mode FROM
ScanningSymbol,CountingItems => CountItem[];
PuttingDefn,PuttingItems => PutNodeName[u↑.name,u↑.x,u↑.y];
ENDCASE;
ENDCASE => InternalError["Funny User Type"];
END;
AuxCall: PUBLIC PROCEDURE [objectname: IntStorageDefs.ObjectName, number: LONG CARDINAL, xform: IntTransDefs.Transform] =
BEGIN
SELECT Mode FROM
Marking => Mark[objectname];
ScanningSymbol,CountingItems => CountItem;
PuttingDefn,PuttingItems =>
PutCall[objectname, number, xform];
ENDCASE;
END;
PutBox: PROCEDURE [layerName: CARDINAL, length, width: LONG CARDINAL, center: ParserTypeDefs.Point, xRotation, yRotation: LONG INTEGER] =
BEGIN
xSize, ySize: LONG CARDINAL;
chipX,chipY,chipOrient,chipType,chipWidth,chipLength,chipLayer: CARDINAL;
bbrel: ParserTypeDefs.Point;
[xSize,ySize] ← ResolveRotation[length, width, xRotation, yRotation];
bbrel ← BBRel[center]; -- find center rel to bbox left top corner
chipX ← ChipScale[(bbrel.x - xSize/2)];
chipY ← ChipScale[-(bbrel.y + ySize/2)];
IF xSize > ySize THEN -- long ways horizontal
BEGIN
chipOrient ← 4;
chipLength ← ChipScale[xSize];
chipWidth ← ChipScale[ySize];
END
ELSE -- long ways vertical
BEGIN
chipOrient ← 0;
chipLength ← ChipScale[ySize];
chipWidth ← ChipScale[xSize];
END;
chipLayer ← ChipLayers[layerName];
chipType ← SELECT chipLayer FROM
1,2,3 => 4, -- dif,pol,met => Chip Wire
ENDCASE => 5; -- other => Chip Rectangle
PutWord[chipX];
PutWord[chipY];
PutWord[chipOrient];
PutWord[chipType];
PutWord[chipWidth];
PutWord[chipLength];
PutWord[chipLayer];
PutWord[0]; -- zero properties (for now)
END;
PutNodeName: PROCEDURE [name: STRING, x,y: LONG INTEGER] =
BEGIN
orgrel: ParserTypeDefs.Point ← [x,y];
bbrel: ParserTypeDefs.Point ← BBRel[orgrel];
chipLayer: CARDINAL;
-- chipLayer ← ChipLayers[FindLayer[x,y]];
chipLayer ← 3;
Warning["Node name placed on Metal",name];
PutWord[ChipScale[ bbrel.x]]; -- x position
PutWord[ChipScale[-bbrel.y]]; -- y position
PutWord[0]; -- orientation
PutWord[4]; -- wire object
PutWord[0]; -- width zero
PutWord[0]; -- length zero
PutWord[chipLayer];
PutWord[1]; -- with one property...
PutWord[1]; -- of type text...
PutString[name];
END;
FindLayer: PROCEDURE [x,y: LONG INTEGER] RETURNS [cifLayer: CARDINAL] =
-- given point, finds layer there.
BEGIN
-- not implemented yet
cifLayer ← 4;
InternalError ["FindLayer Not Implemented"];
END;
PutCall: PROCEDURE [objectname: IntStorageDefs.ObjectName, number: LONG CARDINAL, xform: IntTransDefs.Transform] =
BEGIN
d,l,r,b,t,xOrigin,yOrigin,xLeft,yTop: LONG INTEGER;
chipX,chipY: INTEGER;
chipOrient: CARDINAL;
matrix: RECORD[a11,a12,a21,a22: LONG INTEGER];
leftTopRelOrigin,leftTopRelBBox: ParserTypeDefs.Point;
[l,r,b,t] ← AuxIntDefs.ISymBB[objectname]; -- bbox of called symbol relative to its origin
d ← Real.Fix[xform.a33];
matrix ← [Real.Fix[xform.a11]/d, Real.Fix[xform.a12]/d,
Real.Fix[xform.a21]/d, Real.Fix[xform.a22]/d];
xOrigin ← Real.Fix[xform.a31]/d; yOrigin ← Real.Fix[xform.a32]/d;
-- have origin of instance relative to origin of containing symbol
SELECT matrix FROM
[ 1, 0, 0, 1] => -- identity
BEGIN
chipOrient ← 0;
xLeft ← xOrigin+l;
yTop ← yOrigin+t;
END;
[-1, 0, 0, 1] => -- mirror x (about y)
BEGIN
chipOrient ← 1;
xLeft ← xOrigin-r;
yTop ← yOrigin+t;
END;
[ 0,-1, 1, 0] => -- rotate 90 clockwise
BEGIN
chipOrient ← 4;
xLeft ← xOrigin+b;
yTop ← yOrigin-l;
END;
[ 0,-1,-1, 0] => -- rotate 90 cw, then mirror x
BEGIN
chipOrient ← 5;
xLeft ← xOrigin-t;
yTop ← yOrigin-l;
END;
[-1, 0, 0,-1] => -- rotate 180
BEGIN
chipOrient ← 8;
xLeft ← xOrigin-r;
yTop ← yOrigin-b;
END;
[ 1, 0, 0,-1] => -- mirror y (about x)
BEGIN
chipOrient ← 9;
xLeft ← xOrigin+l;
yTop ← yOrigin-b;
END;
[ 0, 1,-1, 0] => -- rotate 90 counterclockwise
BEGIN
chipOrient ← 12;
xLeft ← xOrigin-t;
yTop ← yOrigin+r;
END;
[ 0, 1, 1, 0] => -- rotate 90 ccw, then mirror x
BEGIN
chipOrient ← 13;
xLeft ← xOrigin+b;
yTop ← yOrigin+r;
END;
ENDCASE => -- other
BEGIN
Warning
["Arbitrary transformation","taken as zero transform"];
chipOrient ← 0;
xLeft ← xOrigin+l;
yTop ← yOrigin+t;
END;
-- have left top of instance relative to origin of containing symbol
leftTopRelOrigin ← [xLeft,yTop];
leftTopRelBBox ← BBRel[leftTopRelOrigin];
-- have left top of instance relative to left top of containing symbol
chipX ← ChipScale[leftTopRelBBox.x];
chipY ← ChipScale[-leftTopRelBBox.y];
PutWord[chipX]; -- x position
PutWord[chipY]; -- y position
PutWord[chipOrient]; -- orientation
PutWord[1]; -- code for "call" = "cell instance"
PutWord[NutsDictDefs.Lookup[objectname]]; -- which cell
PutWord[0]; -- no properties
END;
BBRel: PROCEDURE [relOrigin: ParserTypeDefs.Point] RETURNS [relBBox: ParserTypeDefs.Point] =
-- given x, y of item relative to "origin" of enclosing symbol
-- returns x,y of item relative to left top corner of its BBox
BEGIN
IF CurrentSymbol = IntStorageDefs.NilObjectName THEN
BEGIN
relBBox.x ← relOrigin.x;
relBBox.y ← relOrigin.y;
END
ELSE
BEGIN
l,r,b,t: LONG INTEGER; -- BBox of enclosing symbol in CIF units
[l,r,b,t] ← AuxIntDefs.ISymBB[CurrentSymbol];
relBBox.x ← relOrigin.x - l;
relBBox.y ← relOrigin.y - t;
END;
END;
InitOutput: PUBLIC PROCEDURE RETURNS [BOOLEAN] =
BEGIN
InternalError["InitOutput not implemented"];
RETURN[FALSE];
END;
FinishOutput: PUBLIC PROCEDURE RETURNS [BOOLEAN] =
BEGIN
InternalError["FinishOutput not implemented"];
RETURN[FALSE];
END;
SendMessage: PUBLIC PROCEDURE [type: ParserErrorDefs.ErrorType, message: STRING, wantCR: BOOLEAN ← TRUE] =
BEGIN
IODefs.WriteString[message];
IF wantCR THEN IODefs.WriteChar[IODefs.CR];
END;
-- associates a CARDINAL with a layer name - a PACKED ARRAY [0..4) OF CHARACTER, padded by spaces to make 4 characters (if necessary)
Map: PUBLIC PROCEDURE [layerName: PACKED ARRAY [0..4) OF CHARACTER] RETURNS [CARDINAL] =
-- same layer numbers as Magic, for future compatibility
BEGIN
IF layerName[0] = 'N AND layerName[2] = ' AND layerName[3] = ' THEN
SELECT layerName[1] FROM
'I => RETURN[0]; -- implant
'D => RETURN[1]; -- diffusion
'P => RETURN[2]; -- poly
'C => RETURN[3]; -- contact
'M => RETURN[4]; -- metal
'B => RETURN[5]; -- buried
'G => RETURN[6]; -- glass
ENDCASE =>
BEGIN
ParserErrorDefs.Report["Unrecognized layer name becomes Chipmonk layer 7",Advisory];
RETURN[7];
END;
RETURN[7]; -- Never executed but necessary to keep compiler happy!
END;
-- Each routine below implements the output of one primitive geometric construct form CIF.
OutputWire: PUBLIC PROCEDURE [visible: OutputDefs.VisibleType, layerName: CARDINAL, width: LONG CARDINAL, a: ParserTypeDefs.Path] =
BEGIN
InternalError["OutputWire not implemented"];
END;
OutputFlash: PUBLIC PROCEDURE [visible: OutputDefs.VisibleType, layerName: CARDINAL, diameter: LONG CARDINAL, center: ParserTypeDefs.Point] =
BEGIN
InternalError["OutputFlash not implemented"];
END;
OutputPolygon: PUBLIC PROCEDURE [visible: OutputDefs.VisibleType, layerName: CARDINAL, a: ParserTypeDefs.Path] =
BEGIN
InternalError["OutputPolygon not implemented"];
END;
OutputBox: PUBLIC PROCEDURE [visible: OutputDefs.VisibleType, layerName: CARDINAL, length, width: LONG CARDINAL, center: ParserTypeDefs.Point, xRotation, yRotation: LONG INTEGER] =
BEGIN
InternalError["OutputBox not implemented"];
END;
OutputUserCommand: PUBLIC PROCEDURE [command: [0..9], userText: STRING] =
BEGIN
stringWords: CARDINAL = StringDefs.WordsForString[Storage.StringLength[userText]];
size: CARDINAL = SIZE[UserCmd] + stringWords;
pu: POINTER TO UserCmd = Storage.Node[size];
IF command = 9 AND userText[0] = ' THEN -- SymbolName
BEGIN
pu↑.type ← SymbolName;
InlineDefs.COPY[from: userText, nwords: stringWords, to: @pu↑.stringBody];
pu↑.name ← LOOPHOLE[@pu↑.stringBody, STRING];
pu↑.x ← pu↑.y ← 0;
END
ELSE IF command = 9 AND userText[0] = '4 AND userText[1] = ' THEN -- NodeName
BEGIN
-- code to parse node names (hastily written, could use refinement)
ENABLE StringDefs.InvalidNumber =>
BEGIN
ParserErrorDefs.Report["Fatal error, sorry: Invalid number",Fatal];
ImageDefs.AbortMesa;
END;
temp: STRING ← [20];
i: CARDINAL;
NextNumber: PROCEDURE RETURNS [LONG CARDINAL] =
BEGIN
UNTIL userText[i] IN ['-..'9] DO i←i+1; ENDLOOP; -- skip blanks etc.
temp.length ← 0;
WHILE userText[i] IN ['-..'9] AND i<userText.length DO
StringDefs.AppendChar[temp,userText[i]]; i←i+1; ENDLOOP;
RETURN
[IntDefs.IScaleLongInt[StringDefs.StringToLongNumber[temp,10]]];
END;
pu↑.type ← NodeName;
pu↑.name ← LOOPHOLE[@pu↑.stringBody, STRING];
InlineDefs.COPY[from: userText, nwords: stringWords, to: @pu↑.stringBody]; -- hack to initialize pu↑.name.maxlength
pu↑.name.length ← 0;
i←2; UNTIL userText[i] = ' DO -- copy up to first blank
StringDefs.AppendChar[pu↑.name,userText[i]];
i←i+1;
ENDLOOP;
pu↑.x ← NextNumber[];
pu↑.y ← NextNumber[];
END
ELSE -- Undef;
BEGIN
ParserErrorDefs.Report["Undefined User Object - Ignored",Advisory];
END;
IntDefs.IUserObject[size,pu];
END;
OutputUserObject: PUBLIC PROCEDURE [visible: OutputDefs.VisibleType, layerName: CARDINAL, size: CARDINAL, data: POINTER TO UNSPECIFIED] =
BEGIN
InternalError["OutputUserObject not implemented"];
END;
-- establish ordering
Relation: PUBLIC PROCEDURE [left1, right1, bottom1, top1, left2, right2, bottom2, top2: LONG INTEGER] RETURNS [OutputDefs.RelationType] =
BEGIN
InternalError["Relation not implemented"];
RETURN[dontcare];
END;
-- determine whether an item should be shown
Visible: PUBLIC PROCEDURE [kind: IntStorageDefs.ObjectType, level: CARDINAL, parentVis: OutputDefs.VisibleType, left,right,bottom,top: LONG INTEGER] RETURNS [OutputDefs.VisibleType] =
BEGIN
InternalError["Visible not implemented"];
RETURN[maybe];
END;
-- returns the bounding box of the primitive interpreted in the current context
BBWire: PUBLIC PROCEDURE [layerName: CARDINAL, width: LONG CARDINAL, a: ParserTypeDefs.Path] RETURNS [left,right,bottom,top: LONG INTEGER] =
BEGIN
BBBoxDummy: PROC [layerName: CARDINAL, length, width: LONG CARDINAL, center: ParserTypeDefs.Point, xRotation, yRotation: LONG INTEGER] =
BEGIN
a,b,c,d: LONG INTEGER;
[a,b,c,d] ← BBBox[layerName, length, width, center, xRotation, yRotation];
left ← MAX[left,a];
right ← MIN[right,b];
bottom ← MAX[bottom,c];
top ← MIN[top,d];
END;
left ← bottom ← FIRST[LONG INTEGER];
right ← top ← LAST[LONG INTEGER];
IF ~WireIsBox[layerName, width, a, BBBoxDummy] THEN {
ParserErrorDefs.Report["Non-manhattan wire ignored",Advisory];
left ← right ← bottom ← top ← 0;
};
END;
BBFlash: PUBLIC PROCEDURE [layerName: CARDINAL, diameter: LONG CARDINAL, center: ParserTypeDefs.Point] RETURNS [left,right,bottom,top: LONG INTEGER] =
BEGIN
[left,right,bottom,top] ← BBBox[layerName, diameter, diameter, center, 1, 0];
END;
BBPolygon: PUBLIC PROCEDURE [layerName: CARDINAL, a: ParserTypeDefs.Path] RETURNS [left,right,bottom,top: LONG INTEGER] =
BEGIN
BBBoxDummy: PROC [layerName: CARDINAL, length, width: LONG CARDINAL, center: ParserTypeDefs.Point, xRotation, yRotation: LONG INTEGER] =
BEGIN
[left,right,bottom,top] ← BBBox[layerName, length, width, center, xRotation, yRotation];
END;
IF ~PolygonIsBox[layerName, a, BBBoxDummy] THEN ParserErrorDefs.Report["Non-rectangular Polygon ignored",Advisory];
END;
BBBox: PUBLIC PROCEDURE [layerName: CARDINAL, length, width: LONG CARDINAL, center: ParserTypeDefs.Point, xRotation, yRotation: LONG INTEGER] RETURNS [left,right,bottom,top: LONG INTEGER] =
BEGIN
xSize,ySize: LONG CARDINAL;
manhattan: BOOLEAN ← (xRotation=0 OR yRotation=0);
IF manhattan THEN [xSize,ySize] ← ResolveRotation[length, width, xRotation, yRotation]
ELSE BEGIN
ParserErrorDefs.Report["Non-manhattan box ignored",Advisory];
xSize ← ySize ← 0;
END;
left ← center.x - xSize/2;
right ← center.x + xSize/2;
bottom ← center.y - ySize/2;
top ← center.y + ySize/2;
END;
BBUserObject: PUBLIC PROCEDURE [layerName: CARDINAL, size: CARDINAL, data: POINTER TO UNSPECIFIED] RETURNS [left,right,bottom,top: LONG INTEGER] =
BEGIN
u: POINTER TO UserCmd ← data;
SELECT u↑.type FROM
SymbolName => RETURN[0,0,0,0];
NodeName => RETURN[u↑.x,u↑.x,u↑.y,u↑.y];
ENDCASE => InternalError["Funny User Type"];
RETURN[0,0,0,0];
END;
-- Mainline code
IODefs.WriteLine[herald];
GetFileNames;
SetLambda[GetLambda[]];
UNTIL ParseCifFile[CifFileName] DO GetFileNames; ENDLOOP;
OpenChipFile[ChipFileName];
PutChipFile;
CloseChipFile;
IF NOT IntDefs.FinishInterpreter[] THEN InternalError["problem finishing Interpreter"];
NutsDictDefs.FreeDict;
END.