-- 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.
(672)\184b10B801b12B277b8B987b9B191i47I108i46I112i31I222i56I247i7I3b1B70b9B172i50I119i31I222i7I75b13B220b9B451b16B159i34I8i29I308i17I701i14I377b13B134b15B137b14B205i17I76i12I50i29I47i24I32i26I38i17I52i10I28i15I22i32I