-- PROGRAM SifGuts
-- Updated to Mesa 6.0 - January 27, 1981 11:36 AM
-- Last edited - February 5, 1981 1:31 PM

DIRECTORY
IODefs: FROM "iodefs",
Real : FROM "Real" USING [Fix],
RealFns : FROM "RealFns" USING [SqRt],
StreamDefs: FROM "streamdefs",
SystemDefs: FROM "systemdefs",
SifGutsDefs : FROM "SifGutsDefs",
SifOutputDefs : FROM "SifOutputDefs" USING [PutLayer, PutBox, PutName, PutCall, PutComment, PutDefStart, PutDefFinish, PutEnd, PutError],
StringDefs: FROM "stringdefs";


SifGuts : PROGRAM
IMPORTS IODefs, Real, RealFns, SifOutputDefs, StreamDefs, StringDefs, SystemDefs
EXPORTS SifGutsDefs

= BEGIN OPEN IODefs, Real, RealFns, SifGutsDefs, SifOutputDefs, StreamDefs, StringDefs, SystemDefs;


debugging: BOOLEAN ← FALSE;
FatalError: BOOLEAN ← FALSE;
InDefs: BOOLEAN ← FALSE;
-- Must be set whenever defining a symbol
A: LONG INTEGER;
B: LONG INTEGER;

Password : CARDINAL = 172635B; -- Icarus’s legal password
StartDefNbr, FinishDefNbr: INTEGER;

fin: StreamHandle;

Nlayers: INTEGER = 8;

-- need some layer names for layer changes to CIF
LayerNames: ARRAY [0..Nlayers) OF STRING =
[
"NI",-- implant is ICARUS layer 0
"ND",-- diffusion
"NP",-- polysilicon
"NC",-- contact cut
"NM",-- metal
"NB",-- buried contact
"NG",-- overglassing
"NX"-- extra
];

getstring : PROCEDURE[f:StreamHandle, s:STRING] =
BEGIN
-- gets a BCPL string from the given file
-- returns it in s

StrHead: TYPE = MACHINE DEPENDENT RECORD [length: [0..255],
chr2: CHARACTER];
TwoByte: TYPE = MACHINE DEPENDENT RECORD [chr1,chr2: CHARACTER];
bh: StrHead;
tb: TwoByte;
j : INTEGER;

bh←f.get[f];
s.length←bh.length;
s[0]←bh.chr2;
FOR j IN [1..bh.length/2]
DO
tb←f.get[f];
s[2*j-1]←tb.chr1;
s[2*j]←tb.chr2;
ENDLOOP;
RETURN
END;

Sgn: PROCEDURE[x: INTEGER] RETURNS[i: INTEGER] =
BEGIN -- -1,0,1 if < , = , > 0
RETURN [IF x = 0 THEN 0 ELSE IF x < 0 THEN -1 ELSE 1]
END;

Scale: PROCEDURE [x: LONG INTEGER] RETURNS [y: LONG INTEGER] =
-- Convert from icarus to CIF units (always round up)
-- This procedure should only be used for lengths
-- ScalePoint should be used to convert points
BEGIN
y ← 2*x;
END;

ScaleFl: PROCEDURE [x: REAL] RETURNS [y: LONG INTEGER] =
-- Convert from icarus to CIF units (always round up)
-- This procedure accepts floating point numbers for conversion
BEGIN
y ← Fix[(2*x) + NearOne];

END;

--ScalePoint: PROCEDURE [x,y: REAL] RETURNS [s: Point] =
-- Converts a point in icarus units to CIF units
--BEGIN
--s.x ← Fix[(x*ScaleFactorMul)/ScaleFactorDiv];
--s.y ← Fix[(y*ScaleFactorMul)/ScaleFactorDiv];
--END;

DeBlank : PROCEDURE[s:STRING] =
-- Convert all blanks in string s into stars
BEGIN
i: CARDINAL;
FOR i IN [0..s.length) DO
IF s.text[i] = ’ OR s.text[i] =’; OR s.text[i] = CR OR s.text[i] = TAB THEN s.text[i] ← ’*;
ENDLOOP;
END;

MakeSymbolCall : PROCEDURE[callNo:INTEGER,mirx,miry:BOOLEAN, rot:Point, xorigin,yorigin, xdisp,ydisp: LONG INTEGER, xcount,ycount:INTEGER] =
BEGIN
i,j: INTEGER;
xpos,ypos: LONG INTEGER;
IF xcount <= 1 OR ycount <= 1 THEN BEGIN
-- No need to create new definition since array is linear
xpos ← xorigin;
FOR i IN [1..xcount] DO
ypos ← yorigin;
FOR j IN [1..ycount] DO
PutCall[callNo, mirx, miry, rot, Point[xpos,-(ypos)]];
ypos ← ypos + ydisp;
ENDLOOP;
xpos ← xpos + xdisp;
ENDLOOP;
END
ELSE BEGIN
-- To cut down on number of calls to the symbol introduce
-- a new symbol which contains a linear array in y
-- this can be called several times changing the x position
MakeArraySymbol[FinishDefNbr, callNo, mirx, miry, rot, yorigin, ydisp, ycount];
xpos ← xorigin;
FOR i IN [1..xcount] DO
PutCall[FinishDefNbr, FALSE, FALSE, Point[LONG[1],LONG[0]], Point[xpos,LONG[0]]];
xpos ← xpos + xdisp;
ENDLOOP;
FinishDefNbr ← FinishDefNbr + 1;
END;
END;

MakeArraySymbol : PROCEDURE[symblNo,callNo:INTEGER,mirx,miry:BOOLEAN, rot:Point, yorigin, ydisp: LONG INTEGER, ycount:INTEGER] =
BEGIN
i: INTEGER;
ypos: LONG INTEGER;
IF InDefs THEN BEGIN
-- Store information and create symbol later
cell: ArraySymbolHoldingCell ← AllocateCell[];
cell.symblNo ← symblNo;
cell.callNo ← callNo;
cell.mirx ← mirx;
cell.miry ← miry;
cell.rot ← rot;
cell.yorigin ← yorigin;
cell.ydisp ← ydisp;
cell.ycount ← ycount;
cell.next ← CellList;
CellList ← cell;
END
ELSE BEGIN
-- Not in definitions, cannot delay output symbol any longer
-- since it would create an illegal forward reference
InDefs ← TRUE;
PutDefStart[symblNo,A,B,""];
ypos ← yorigin;
FOR i IN [1..ycount] DO
PutCall[callNo,mirx,miry,rot,Point[LONG[0],-(ypos)]];
ypos ← ypos + ydisp;
ENDLOOP;
PutDefFinish[];
InDefs ← FALSE;
END;
END;

AllocateCell : PROCEDURE RETURNS[ArraySymbolHoldingCell] =
BEGIN
RETURN[AllocateHeapNode[SIZE[ArraySymbolHoldingCellRecord]]];
END;

FreeCell : PROCEDURE [cell:ArraySymbolHoldingCell] =
BEGIN
FreeHeapNode[cell];
END;

ItemOutput : PROCEDURE =
-- prints out pertinent info on items
-- notice also that this routine does the scaling!!!
BEGIN

-- ICARUS form
iteminfotype : TYPE = MACHINE DEPENDENT RECORD[
disappear : [0..1],
type : [0..7],
layer : [0..15],
state : [0..7],
w : [0..31] ];
mirrot: TYPE = MACHINE DEPENDENT RECORD[mir,rot: [0..255]];

sqrt2f: CARDINAL = 27146;
-- .414... x 2↑16
info: iteminfotype;
xmin,ymin,xmax,ymax,xdif: INTEGER;
nx,ny,dx,dy,origx,origy,def: INTEGER;
mr: mirrot;
distmp: LONG INTEGER;
s: STRING ← [255]; -- for throwing away text
p: Point;

-- get the common part of an item
info←fin.get[fin]; -- all sorts of strange fields there
xmin←fin.get[fin]; ymin←fin.get[fin];
xmax←fin.get[fin]; ymax←fin.get[fin];

BEGIN OPEN info;


-- ****** handle all the cases that ICARUS might give ******
-- notice that we must go into the TEXT code segment (type=2)
-- and the INSTANCE code segment (type=4) even if we aren’t
-- outputting, because the representations of those items in
-- the file are larger than the LINE and BOX representations
-- ****** ******

SELECT type FROM

-- LINE (45-degree type) ITEM

0 =>
BEGIN -- Line type object, convert into a box
angle: Point;
IF w = 0 THEN RETURN;
IF xmin = xmax OR ymin = ymax THEN RETURN; -- don’t do zero-length ones
IF layer < Nlayers THEN
PutLayer[LayerNames[layer]]
ELSE BEGIN
FatalError ← TRUE;
PutError["Illegal layer number encountered"];
END;

xdif ← ABS[xmax-xmin];
-- we take advantage of fact that lines must be
-- 45 deg. or -45
distmp ← ScaleFl[SqrtOf2*xdif];

p ← [(LONG[xmax]+LONG[xmin]), -(LONG[ymax]+LONG[ymin])];

IF Sgn[xmax-xmin] # Sgn[ymax-ymin]
THEN angle ← [LONG[1],LONG[1]]
ELSE angle ← [LONG[1],LONG[-1]];
PutBox[distmp, Scale[w], p, angle];
END;

-- BOX (rectangular, 0-degree rotation) ITEM

1 =>
BEGIN -- Box type object

IF xmin = xmax OR ymin = ymax THEN RETURN; -- don’t do zero-length ones
IF layer < Nlayers THEN
PutLayer[LayerNames[layer]]
ELSE BEGIN
FatalError ← TRUE;
PutError["Illegal layer number encountered"];
END;

-- these must be scaled to 10x or something
PutBox[Scale[ABS[xmax-xmin]], Scale[ABS[ymax-ymin]],
[(LONG[xmax]+LONG[xmin]), -(LONG[ymax]+LONG[ymin])],
Point[LONG[1],LONG[0]] ];
END;

-- TEXT (BCPL string) ITEM

2 =>
BEGIN
getstring[fin,s];
DeBlank[s];--Remove all blanks from string s, blanks must not appear in names
PutName[Scale[xmin],Scale[-(ymin)],s];
END;


-- SYMBOL INSTANCE

4 =>
BEGIN -- symbol instance .. do a call
angle: Point ← [LONG[1],LONG[0]];
rot:INTEGER;
nx←fin.get[fin];ny←fin.get[fin];
dx←fin.get[fin];dy←fin.get[fin];
origx←fin.get[fin];origy←fin.get[fin];
mr←fin.get[fin];
def ← fin.get[fin] + StartDefNbr - 1;
rot ← mr.rot MOD 4;
IF rot = 1 THEN angle ← [LONG[0],LONG[-1]]
ELSE IF rot = 2 THEN angle ← [LONG[-1],LONG[0]]
ELSE IF rot = 3 THEN angle ← [LONG[0],LONG[1]];

MakeSymbolCall[def, mr.mir/2=1, (mr.mir MOD 2)=1, angle, Scale[origx], Scale[origy], Scale[dx], Scale[dy], nx, ny];
END;
ENDCASE => BEGIN
FatalError ← TRUE;
PutError["Found Weird Type Thing"];
END;
END; -- of the open clause
RETURN
END; -- of ItemOutput

DoDefs: PROCEDURE [Ndefs: INTEGER] =
BEGIN
nv,j,k,Defnum: INTEGER;
defname: STRING ← [255];
tempString: STRING ← [255];

FOR Defnum IN [StartDefNbr..StartDefNbr+Ndefs) DO
-- throw away extra information given with symbol definition
FOR j IN [1..5] DO -- throw away the bounding box
nv←fin.get[fin];
ENDLOOP;
--nv is number of vertices in the def (we dont care, do we?)
FOR j IN [1..2*nv] DO k←fin.get[fin] ENDLOOP; -- throw them away

-- extract important information, the name and the items
getstring[fin,defname]; -- the thing has a name
nv←fin.get[fin]; -- number of items in this definition

-- start the definition, and output CIF for each item
DefineSymbol[Defnum,A,B,defname];
FOR j IN [1..nv] DO ItemOutput[] ENDLOOP;
DefineFinish[];
ENDLOOP; -- end of definitions loop
END;

DefineSymbol: PROCEDURE [N: INTEGER, A,B: LONG INTEGER, name: STRING] =
BEGIN
InDefs ← TRUE;
PutDefStart[N,A,B,name];
END;

DefineFinish: PROCEDURE =
BEGIN
cell: ArraySymbolHoldingCell;

PutDefFinish[];
InDefs ← FALSE;
-- Check if any arrays caused need for new symbol to be created
FOR cell ← CellList, CellList UNTIL cell = NIL DO
CellList ← cell.next;
MakeArraySymbol[cell.symblNo,cell.callNo,cell.mirx,cell.miry,
cell.rot,cell.yorigin,cell.ydisp,cell.ycount];
FreeCell[cell];
ENDLOOP;
END;

SetScale: PROCEDURE[mul,div: LONG INTEGER] =
-- Set global scale factors to mul & div
BEGIN
A ← mul;
B ← 2*div;
END;

IcToCif: PUBLIC PROCEDURE[inputFileName: STRING, mul,div: LONG INTEGER, StartDefNumber: INTEGER]
RETURNS[error:BOOLEAN, Ndefs: INTEGER] =
BEGIN
s: STRING ← [255];
Top: INTEGER;
SetScale[mul,div];
IF debugging THEN WriteLine["Initializing."];
StartDefNbr ← StartDefNumber;
-- open that file
fin←NewWordStream[inputFileName, Read];
IF fin.get[fin] # Password THEN
BEGIN
s.length ← 0;
StringDefs.AppendString[s, inputFileName];
StringDefs.AppendString[s, " is not an Icarus file"];
PutError[s];
RETURN[error←TRUE, Ndefs←0];
END;

s.length ← 0;
StringDefs.AppendString[s, "Created by Sif from "];
StringDefs.AppendString[s, inputFileName];
PutComment[s];

Ndefs←fin.get[fin]; --get the number of definitions to follow
FinishDefNbr ← StartDefNbr + Ndefs;
-- do the symbol defs
IF debugging THEN WriteLine["Starting on Definitions."];
DoDefs[Ndefs];

-- Put top level instances in symbol ’Top’
Top ← FinishDefNbr;
FinishDefNbr ← FinishDefNbr + 1;
IF debugging THEN WriteLine["Starting on Items."];
DefineSymbol[Top,A,B,""];
WHILE NOT fin.endof[fin] DO ItemOutput[]; ENDLOOP;
DefineFinish[];

-- One call format
PutCall[Top,FALSE,FALSE,[LONG[1],LONG[0]],[LONG[0],LONG[0]]];

PutEnd[];
fin.destroy[fin];
RETURN[error←FatalError, Ndefs←FinishDefNbr-StartDefNbr];
END;

ArraySymbolHoldingCell:TYPE = POINTER TO ArraySymbolHoldingCellRecord;
ArraySymbolHoldingCellRecord:TYPE = RECORD [
next: ArraySymbolHoldingCell,
symblNo,callNo:INTEGER,
mirx,miry:BOOLEAN,
rot:Point,
yorigin,ydisp:LONG INTEGER,
ycount:INTEGER
];
CellList: ArraySymbolHoldingCell ← NIL;
one: REAL ← 1;
two: REAL ← 2;
half:REAL ← one/two;
SqrtOf2: REAL ← SqRt[two];
NearThousand: REAL ← 999;
NearOne: REAL ← NearThousand/1000;
END.