-- File: DJExtFlatten.mesa
-- flatten hierarchy created by the disjoint circuit extractor
-- Written by Martin Newell/Dan Fitzpatrick July 1981
-- Last edited: 12-Aug-81 13:49:30
DIRECTORY
DisjointPropDefs: FROM "DisjointPropDefs" USING [GetLongProp],
DisjointTypes: FROM "DisjointTypes" USING [Symbol, Instance, PropID],
DJExtDefs: FROM "DJExtDefs",
DJExtractDefs: FROM "DJExtractDefs" USING [GetNodeLocID, GetNodesID, GetNParamID, GetParamID, GetIntTransID, GetIntCapID],
DJExtMergeDefs: FROM "DJExtMergeDefs" USING [InitMerge, FinishMerge, Merge, Lookup],
DJExtTypes: FROM "DJExtTypes" USING [ActualParameter, NodeLocation, Node, Diffusion],
DJExtUtilsDefs: FROM "DJExtUtilsDefs" USING [Create, Close, WriteCIFUnits, WriteLongDecimal, WriteFloat],
IODefs: FROM "IODefs" USING [WriteString, WriteLine, GetOutputStream, SetOutputStream],
Inline: FROM "Inline" USING [LowHalf],
Runtime: FROM "Runtime" USING [CallDebugger],
StreamDefs: FROM "StreamDefs" USING [StreamHandle];
DJExtFlatten: PROGRAM
IMPORTS DisjointPropDefs, DJExtractDefs, DJExtMergeDefs, DJExtUtilsDefs, IODefs, Inline, Runtime
EXPORTS DJExtDefs =
BEGIN
OPEN DisjointPropDefs, DisjointTypes, DJExtractDefs, DJExtMergeDefs, DJExtTypes, DJExtUtilsDefs, IODefs, Inline, Runtime, StreamDefs;
Flatten: PUBLIC PROCEDURE [symbol: Symbol] =
BEGIN
FileName:STRING ← "file.sim";
default:StreamHandle ← GetOutputStream[];
out:StreamHandle;
InitMerge[];
Offset ← 0;
xOffset ← yOffset ← 0;
etrans ← dtrans ← utrans ← btrans ← ctrans ← 0;
out ← Create[FileName];
SetOutputStream[out];
WriteString["| Scale set at "]; WriteFloat[scale]; WriteLine[""];
TFlatten[symbol];
Close[out];
WriteLongDecimal[etrans]; WriteString[": enhancement, "];
WriteLongDecimal[dtrans]; WriteString[": depletion"];
IF utrans # 0 THEN {
WriteString[", "]; WriteLongDecimal[utrans]; WriteString[": unusual implants "];
};
IF ctrans # 0 THEN {
WriteLongDecimal[ctrans]; WriteString[": poly/diff capacitors "];
};
IF btrans # 0 THEN {
WriteLongDecimal[btrans]; WriteString[": malformed transistors "];
};
WriteLine[""];
Offset ← 0;
xOffset ← yOffset ← 0;
out ← Create["file.nodes"];
SetOutputStream[out];
LFlatten[symbol];
Close[out];
SetOutputStream[default];
FinishMerge[];
END;
TFlatten: PROCEDURE [symbol: Symbol] =
BEGIN
cnt: LONG CARDINAL ← 0;
n: LONG CARDINAL;
param: ActualParameter;
curOffset: LONG INTEGER ← Offset;
xcur: REAL ← xOffset;
ycur: REAL ← yOffset;
-- for each transistor in symbol output it to file
FOR p: Node ← GetLongProp[symbol.prop,intID],p.next UNTIL p = NIL DO
WriteTransistor[p];
ENDLOOP;
-- for each capacitor in symbol output it to file
FOR cap:Node ← GetLongProp[symbol.prop,intCapID],cap.next UNTIL cap = NIL DO
WriteCap[cap];
ENDLOOP;
-- examine each of the sub-symbols
Offset ← GetLongProp[symbol.prop,nNodesID] + Offset;
param ← GetLongProp[symbol.prop,paramID];
FOR in: Instance ← symbol.insts,in.next UNTIL in = NIL DO
xOffset ← xcur + in.xOffset;yOffset ← ycur + in.yOffset;
-- set up equivelences between formal and actual parameters
n ← GetLongProp[in.symbol.prop,nparamID];
FOR i: LONG CARDINAL IN [0..n) DO
[] ← Merge[i+Offset+LONG[1],param.node[LowHalf[cnt]]+curOffset];
cnt ← cnt + 1;
IF cnt = param.count THEN { cnt ← 0; param ← param.next; };
ENDLOOP;
-- recurse
TFlatten[in.symbol];
ENDLOOP;
xOffset ← xcur;yOffset ← ycur;
END;
LFlatten: PROCEDURE [symbol: Symbol] =
BEGIN
cnt: LONG CARDINAL ← 0;
param: ActualParameter;
curOffset: LONG INTEGER ← Offset;
xcur: REAL ← xOffset;
ycur: REAL ← yOffset;
-- for each node location in symbol output it to file
FOR p: NodeLocation ← GetLongProp[symbol.prop,nodeLocID],p.next UNTIL p = NIL DO
WriteLocation[p];
ENDLOOP;
-- examine each of the sub-symbols
Offset ← GetLongProp[symbol.prop,nNodesID] + Offset;
param ← GetLongProp[symbol.prop,paramID];
FOR in: Instance ← symbol.insts,in.next UNTIL in = NIL DO
xOffset ← xcur + in.xOffset;yOffset ← ycur + in.yOffset;
-- recurse
LFlatten[in.symbol];
ENDLOOP;
xOffset ← xcur;yOffset ← ycur;
END;
WriteLocation: PROCEDURE [p:NodeLocation] =
BEGIN
WriteString["94 "];
WriteLongDecimal[Lookup[p.node+Offset]];
WriteString[" "];
WriteCIFUnits[p.x+xOffset];
WriteString[" "];
WriteCIFUnits[p.y+yOffset];
WriteLine[";"];
END;
WriteCap: PROCEDURE [cap: Node] =
BEGIN
WriteString["N "]; WriteLongDecimal[Lookup[cap.node+Offset]];
WriteString[" "]; WriteFloat[cap.carea[Diff]/scale2];
WriteString[" "]; WriteFloat[cap.cperim[Diff]/scale];
WriteString[" "]; WriteFloat[cap.carea[Poly]/scale2];
WriteString[" "]; WriteFloat[cap.cperim[Poly]/scale];
WriteString[" "]; WriteFloat[cap.carea[Metal]/scale2];
WriteString[" "]; WriteFloat[cap.cperim[Metal]/scale];
WriteLine[";"];
END;
WriteTransistor: PROCEDURE [trans: Node] =
BEGIN
cnt: CARDINAL ← 0;
FOR d:Diffusion ← trans.diff,d.next UNTIL d = NIL DO cnt ← cnt+1 ENDLOOP;
SELECT cnt FROM
1 => {-- transistor with only one diffusion
-- See if it’s a butting contact
IF trans.poly # trans.diff.node THEN {
WriteString["C "]; WriteLongDecimal[Lookup[trans.poly+Offset]];
WriteString[" "]; WriteLongDecimal[Lookup[trans.diff.node+Offset]];
WriteString[" "]; WriteTransLoc[trans];
WriteLine[";"];
ctrans ← ctrans + 1;
};
};
2 => {-- normal transistor
IF NOT trans.ion AND trans.nion THEN {
WriteString["e "];
etrans ← etrans + 1;
}
ELSE IF trans.ion AND NOT trans.nion THEN {
WriteString["d "];
dtrans ← dtrans + 1;
}
ELSE IF trans.ion AND trans.nion THEN {
WriteString["u "];
utrans ← utrans + 1;
}
ELSE CallDebugger["bug in transistor type checker"];
WriteLongDecimal[Lookup[trans.poly+Offset]];
WriteString[" "]; WriteLongDecimal[Lookup[trans.diff.node+Offset]];
WriteString[" "]; WriteLongDecimal[Lookup[trans.diff.next.node+Offset]];
WriteString[" "]; WriteTransRatio[trans];
WriteString[" "]; WriteTransLoc[trans];
WriteLine[";"];
};
ENDCASE => { -- bad transistor
WriteString["f "]; WriteLongDecimal[Lookup[trans.node+Offset]];
WriteString[" "]; WriteLongDecimal[Lookup[trans.poly+Offset]];
FOR d:Diffusion ← trans.diff,d.next UNTIL d = NIL DO
WriteString[" "]; WriteLongDecimal[Lookup[d.node+Offset]];
ENDLOOP;
WriteString[" "]; WriteTransLoc[trans];
WriteLine[";"];
btrans ← btrans + 1;
};
END;
WriteTransLoc: PROCEDURE[trans:Node] =
BEGIN
WriteFloat[(trans.x+xOffset)/scale]; WriteString[" "]; WriteFloat[(trans.y+yOffset)/scale];
END;
WriteTransRatio: PROCEDURE [t:Node] =
BEGIN
l,w: REAL;
[l,w] ← FindTransRatio[t];
WriteFloat[l/scale]; WriteString[" "]; WriteFloat[w/scale];
END;
FindTransRatio: PROCEDURE [t:Node] RETURNS[len,wid:REAL] =
BEGIN
area,p,d1,d2: REAL;
area ← t.area;
d1 ← t.diff.length;
d2 ← t.diff.next.length;
p ← (t.perim -d1 - d2)/2;
IF 0.95*d1 < d2 AND 0.95*d2 < d1 THEN-- let’s say d1 = d2
RETURN[p,d1];
IF d1 > d2 THEN { tmp:REAL ← d1; d1 ← d2; d2 ← tmp; };-- make d2 > d1
len ← p - d2 + d1;
IF len > d1 THEN {-- assume transistor is T shaped
k:REAL ← (area - (d1 * len))/(d2 - d1);-- length of wide part of T
j:REAL ← len - k;-- length of skinny part of T
s:REAL ← MIN[(d2-d1)/2,k];-- transition length
r:REAL ← (j/d1) + (s*2/(d1+d2)) + ((k-s)/d2);-- resistance
wid ← len/r;-- effective width
}
ELSE { -- can’t be T shaped; use heuristic
len ← (area/d2);
wid ← d1;
};
END;
Offset: LONG CARDINAL;
xOffset,yOffset: REAL;
nodeLocID: PropID ← GetNodeLocID[];
nNodesID: PropID ← GetNodesID[];
paramID: PropID ← GetParamID[];
nparamID: PropID ← GetNParamID[];
intID: PropID ← GetIntTransID[];
intCapID: PropID ← GetIntCapID[];
etrans,dtrans,utrans,btrans,ctrans:LONG CARDINAL;
scale: REAL ← 250;
scale2: REAL ← scale*scale;
END.