MintLayoutImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Christian LeCocq December 17, 1986 11:43:16 am PST
Bertrand Serlet October 18, 1986 8:12:25 pm PDT
DIRECTORY
Core,
CoreClasses,
CoreFlat,
CoreOps,
HashTable,
IO,
Mint,
Rope,
WriteCapa;
MintLayoutImpl: CEDAR PROGRAM
IMPORTS
CoreClasses,
CoreFlat,
CoreOps,
HashTable,
IO,
Mint,
WriteCapa
EXPORTS
Mint
~ BEGIN OPEN Mint;
FlatCellProc: TYPE = PROC [cell: Core.CellType, target: CoreFlat.FlatCellTypeRec ← CoreFlat.allFlatCells, flatCell: CoreFlat.FlatCellTypeRec ← [], instance: CoreClasses.CellInstance ← NIL, parent: Core.CellType ← NIL, flatParent: CoreFlat.FlatCellTypeRec ← [], data: REF ANYNIL, wireName: HashTable.Table];
some usefull definitions
totalSets: CARDINAL ← 0;
TypeTable: PUBLIC ARRAY CoreClasses.TransistorType OF TType ←
[NEW[TTypeRec ← ["nETran", 20000.0]],
NEW[TTypeRec ← ["pETran", 50000.0]],
NEW[TTypeRec ← ["nDTran", 20000.0]]];
debug: BOOLFALSE;
verbose: BOOLFALSE;
debugCellType: Core.CellType ← NIL;
debugCircuit: Circuit ← NIL;
debugNode: Node ← NIL;
debugNodeList: NodeList ← NIL;
Basic data stuctures builders
CreateCircuit: PROC [rootCell: Core.CellType] RETURNS [circuit: Circuit] ~ {
circuit ← NEW[CircuitRec];
circuit.rootCell ← rootCell;
circuit.info ← NEW[InfoRec];
circuit.nodeTable ← HashTable.Create[equal: CoreFlat.FlatWireEqual, hash: CoreFlat.FlatWireHash];
};
BuildNode: PUBLIC PROC[flatWire: CoreFlat.FlatWire, circuit: Circuit] RETURNS [Node] = {
This procedure sees if a given node exists, and makes a new one if necessary. A pointer is returned to the new or existing node.
new: Node;
val: HashTable.Value;
found: BOOLEAN;
[found: found, value: val] ← HashTable.Fetch[circuit.nodeTable, flatWire];
IF found THEN RETURN[NARROW[val]];
new ← NEW[NodeRec];
new.flatWire ← flatWire;
IF debug THEN new.watched ← TRUE; -- keeps everything for ever if you debug the cell ... or the program.
[] ← HashTable.Store[table: circuit.nodeTable, key: flatWire, value: new];
circuit.info.totalNodes ← circuit.info.totalNodes + 1;
new.cap ← WriteCapa.GetRootCap[flatWire.wire];
IF new.cap#0 THEN circuit.info.capNodes ← circuit.info.capNodes + 1;
RETURN [new];
};
BuildFet: PROC[gate, ch1, ch2: CoreFlat.FlatWire, type: CoreClasses.TransistorType, l, w: INT, circuit: Circuit] = {
This procedure builds a transistor data structure and links it into the network under construction.
cap: REAL;
fet: Fet;
fet ← NEW[FetRec];
fet.type ← type;
fet.gate ← BuildNode[gate, circuit];
fet.ch1 ← BuildNode[ch1, circuit];
fet.ch2 ← BuildNode[ch2, circuit];
fet.rOnInv ← w/(l * TypeTable[type].rOn);
fet.switch ← FALSE;
fet.gate.fetList ← CONS[fet, fet.gate.fetList];
IF fet.ch1 # fet.gate THEN fet.ch1.fetList ← CONS[fet, fet.ch1.fetList];
IF (fet.ch2 # fet.gate) AND (fet.ch2 # fet.ch1) THEN fet.ch2.fetList ← CONS[fet, fet.ch2.fetList];
circuit.info.totalFets[fet.type] ← circuit.info.totalFets[fet.type] + 1;
};
BuildNodeList: PUBLIC PROC [name: Rope.ROPE, oldList: NodeList, circuit: Circuit] RETURNS [newList: NodeList] ~ {
node: Node ← NodeFromRope[name, circuit];
IF node=NIL THEN RETURN[oldList];
newList ← CONS[node, oldList];
};
Input From Core
NextCellType: PROC [cell: Core.CellType, target: CoreFlat.FlatCellTypeRec, flatCell: CoreFlat.FlatCellTypeRec, instance: CoreClasses.CellInstance, parent: Core.CellType, flatParent: CoreFlat.FlatCellTypeRec, data: REF ANY, wireName: HashTable.Table, proc: FlatCellProc] = {
BindCellType: CoreFlat.UnboundFlatCellProc = {
BindPublicToActual: CoreOps.EachWirePairProc = {
PROC [actualWire, publicWire: Wire]
IF publicWire.size=0 THEN {
flatWire: CoreFlat.FlatWire ← NARROW[HashTable.Fetch[table: wireName, key: actualWire].value];
[] ← HashTable.Store[table: wireName, key: publicWire, value: flatWire];
};
};
IF CoreOps.VisitBinding[actual: IF instance=NIL OR instance.type#cell THEN previous.public ELSE instance.actual, public: cell.public, eachWirePair: BindPublicToActual] THEN ERROR;
proc[cell, target, flatCell, instance, parent, flatParent, data, wireName];
};
previous: Core.CellType ← cell;
CoreFlat.NextUnboundCellType[cell, target, flatCell, instance, parent, flatParent, data, BindCellType];
};
Flatten: FlatCellProc = {
circuit: Circuit ← NARROW[data];
SELECT cell.class FROM
CoreClasses.transistorCellClass => {
gateWire: CoreFlat.FlatWire ← NARROW[HashTable.Fetch[table: wireName, key: cell.public[ORD[CoreClasses.TransistorPort.gate]]].value];
ch1Wire: CoreFlat.FlatWire ← NARROW[HashTable.Fetch[table: wireName, key: cell.public[ORD[CoreClasses.TransistorPort.ch1]]].value];
ch2Wire: CoreFlat.FlatWire ← NARROW[HashTable.Fetch[table: wireName, key: cell.public[ORD[CoreClasses.TransistorPort.ch2]]].value];
tran: CoreClasses.Transistor ← NARROW[cell.data];
BuildFet[gateWire, ch1Wire, ch2Wire, tran.type, tran.length, tran.width, circuit];
};
CoreClasses.recordCellClass => {
MarkAtomicPublic: PROC[wire: Core.Wire] = {
[] ← HashTable.Store[table: publics, key: wire, value: $Public];
};
InsertInternal: PROC[wire: Core.Wire] = {
IF NOT HashTable.Fetch[table: publics, key: wire].found THEN {
InsertWire[wire, flatCell, circuit, wireName];
};
};
rct: CoreClasses.RecordCellType;
publics: HashTable.Table ← HashTable.Create[cell.public.size+1];
rct ← NARROW[cell.data];
CoreOps.VisitRootAtomics[root: cell.public, eachWire: MarkAtomicPublic];
CoreOps.VisitRootAtomics[root: rct.internal, eachWire: InsertInternal];
NextCellType[cell, target, flatCell, instance, parent, flatParent, data, wireName, Flatten]
};
ENDCASE => {
NextCellType[cell, target, flatCell, instance, parent, flatParent, data, wireName, Flatten]
};
};
InsertWire: PROC [wire: Core.Wire, flatCell: CoreFlat.FlatCellTypeRec, circuit: Circuit, wireName: HashTable.Table, wireRoot: CoreFlat.WireRoot ← internal] = {
node: Node;
flatWire: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec];
flatWire.flatCell ← flatCell;
flatWire.wireRoot ← wireRoot;
flatWire.wire ← wire;
node ← BuildNode[flatWire, circuit];
[] ← HashTable.Store[table: wireName, key: wire, value: flatWire];
};
NetFromCore: PUBLIC PROC[ct: Core.CellType, circuit: Circuit] = {
InsertPublic: PROC[wire: Core.Wire] = {
InsertWire[wire, CoreFlat.rootCellType, circuit, wireName, public];
};
wireName: HashTable.Table ← HashTable.Create[];
IO.PutF[Mint.StdOut, "\nConverting cell %g . . .", IO.rope[CoreOps.GetCellTypeName[ct]]];
CoreOps.VisitRootAtomics[root: ct.public, eachWire: InsertPublic];
Flatten[cell: ct, data: circuit, wireName: wireName];
IO.PutRope[Mint.StdOut, " \nFinished\n"];
};
Circuit Preparation
Stats: PUBLIC PROC[circuit: Circuit] = {
total: INT ← 0;
IO.PutF[Mint.StdOut, "\nTotal number of nodes: %d.", IO.int[circuit.info.totalNodes]];
IO.PutF[Mint.StdOut, "\nTotal number of capas: %d.", IO.int[circuit.info.capNodes]];
FOR i: CoreClasses.TransistorType IN CoreClasses.TransistorType DO
IF circuit.info.totalFets[i] = 0 THEN LOOP;
IO.PutF[Mint.StdOut, "\nNumber of %s transistors: %d.", IO.rope[TypeTable[i].name], IO.int[circuit.info.totalFets[i]]];
total ← total + circuit.info.totalFets[i];
ENDLOOP;
IO.PutF[Mint.StdOut, "\nTotal number of transistors: %d.", IO.int[total]];
};
InputData: PUBLIC PROC [ct: Core.CellType, layout: BOOLEANTRUE] RETURNS [circuit: Circuit] ~ {
GuessInput: PROC[wire: Core.Wire] = {
ropeName: Rope.ROPE ← CoreOps.GetFullWireNames[ct.public, wire].first;
flatWire: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec ← [
flatCell: CoreFlat.rootCellType,
wire: wire
]];
node: Node ← NARROW[HashTable.Fetch[circuit.nodeTable, flatWire].value];
IF node#VddNode AND node#GndNode THEN {
node.input ← TRUE;
FOR iFet: FetList ← node.fetList, iFet.rest UNTIL iFet=NIL DO
IF iFet.first.ch1=node OR iFet.first.ch2=node THEN {
node.input ← FALSE;
EXIT;
};
ENDLOOP;
};
IF node.input THEN IF verbose THEN IO.PutF[Mint.StdOut, "\ninput: %g", IO.rope[ropeName]]
ELSE {
node.watched ← TRUE;
IF verbose THEN IO.PutF[Mint.StdOut, "\n : %g", IO.rope[ropeName]];
};
}; -- GuessInput
GndNode, VddNode: Node;
circuit ← CreateCircuit[ct];
NetFromCore[ct, circuit];
GndNode ← Mint.NodeFromRope["public.Gnd", circuit];
VddNode ← Mint.NodeFromRope["public.Vdd", circuit];
CoreOps.VisitRootAtomics[root: ct.public, eachWire: GuessInput];
Stats[circuit];
};
NextNodeList: PROC [set: Set, fetList: FetList] RETURNS [nodeList: NodeList ← NIL] ~ {
FOR iFetList: FetList ← fetList, iFetList.rest UNTIL iFetList = NIL DO
IF NOT iFetList.first.ch1.done THEN {
nodeList ← CONS[iFetList.first.ch1, nodeList];
iFetList.first.ch1.done ← TRUE;
AddNodeToSet[set, iFetList.first.ch1];
};
IF NOT iFetList.first.ch2.done THEN {
nodeList ← CONS[iFetList.first.ch2, nodeList];
iFetList.first.ch2.done ← TRUE;
AddNodeToSet[set, iFetList.first.ch2];
};
ENDLOOP;
}; --NextNodeList
NextFetList: PROC [set: Set, nodeList: NodeList] RETURNS [fetList: FetList ← NIL] ~ {
FOR iNodeList: NodeList ← nodeList, iNodeList.rest UNTIL iNodeList = NIL DO
FOR iFetList: FetList ← iNodeList.first.fetList, iFetList.rest UNTIL iFetList = NIL DO
IF NOT iFetList.first.done THEN
IF iFetList.first.gate # iNodeList.first THEN {
fetList ← CONS[iFetList.first, fetList];
iFetList.first.done ← TRUE;
AddFetToSet[set, iFetList.first];
};
ENDLOOP;
ENDLOOP;
}; --NextFetList
AddNodeToSet: PROC [set: Set, node: Node] ~ {
set.lNodes ← CONS[node, set.lNodes];
set.type.nNodes ← set.type.nNodes+1;
node.done ← TRUE;
};
AddFetToSet: PROC [set: Set, fet: Fet] ~ {
set.lFets ← CONS[fet, set.lFets];
fet.done ← TRUE;
set.type.nFets[fet.type] ← set.type.nFets[fet.type]+1;
};
PrepareSets: PUBLIC PROC [circuit: Circuit, fixedVList: NodeList] ~ {
FindOneSet: HashTable.EachPairAction ~ {
PROC [key: Key, value: Value] RETURNS [quit: BOOLEANFALSE];
nodeList: NodeList;
fetList: FetList;
set: Set;
node: Node ← NARROW[value];
IF node.done THEN RETURN;
set ← NEW[SetRec];
set.type ← NEW[SetTypeRec];
totalSets ← totalSets+1;
nodeList ← LIST[node];
AddNodeToSet[set, node];
UNTIL nodeList = NIL DO
fetList ← NextFetList[set, nodeList];
nodeList ← NextNodeList[set, fetList];
ENDLOOP;
FindInputs[set];
FindFixedV[set, fixedVList, GndNode, VddNode];
FOR il: Library ← circuit.library, il.rest UNTIL il=NIL DO
IF TypeEqual[set.type, il.first.type] THEN {
il.first.nElem ← il.first.nElem+1;
il.first.setList ← CONS[set, il.first.setList];
set.type ← il.first.type;
RETURN;
};
ENDLOOP;
circuit.library ← CONS[NEW[LibraryElemRec ← [set.type, 1, LIST[set]]], circuit.library];
};
GndNode: Node ← Mint.NodeFromRope["public.Gnd", circuit];
VddNode: Node ← Mint.NodeFromRope["public.Vdd", circuit];
FOR inode: NodeList ← fixedVList, inode.rest UNTIL inode=NIL DO
inode.first.done ← TRUE;
inode.first.input ← TRUE;
ENDLOOP;
[] ← HashTable.Pairs[circuit.nodeTable, FindOneSet]
}; -- PrepareSets
FindInputs: PROC [set: Set] ~ {
found: BOOLEAN;
FOR ifet: FetList ← set.lFets, ifet.rest UNTIL ifet=NIL DO
found ← FALSE;
FOR inode: NodeList ← set.lNodes, inode.rest UNTIL inode=NIL DO
IF inode.first=ifet.first.gate THEN {
found ← TRUE;
EXIT;
};
ENDLOOP;
IF ~found THEN {
found ← FALSE;
FOR inode: NodeList ← set.inList, inode.rest UNTIL inode=NIL DO
IF inode.first=ifet.first.gate THEN {
found ← TRUE;
EXIT;
};
ENDLOOP;
IF ~found THEN {
set.type.nInput ← set.type.nInput+1;
set.inList ← CONS[ifet.first.gate, set.inList];
ifet.first.gate.setList ← CONS[set, ifet.first.gate.setList]
};
};
ENDLOOP;
};
FindFixedV: PROC [set: Set, fixedVList: NodeList, GndNode, VddNode: Node] ~ {
found: BOOLEAN;
FOR ifet: FetList ← set.lFets, ifet.rest UNTIL ifet=NIL DO
FOR fix: NodeList ← fixedVList, fix.rest UNTIL fix=NIL DO
IF ifet.first.ch1=fix.first OR ifet.first.ch2=fix.first THEN {
IF fix.first=VddNode THEN set.type.nVddTran ← set.type.nVddTran+1;
IF fix.first=GndNode THEN set.type.nGndTran ← set.type.nGndTran+1;
found ← FALSE;
FOR inode: NodeList ← set.fixedV, inode.rest UNTIL inode=NIL DO
IF inode.first=fix.first THEN {
found ← TRUE;
EXIT;
};
ENDLOOP;
IF ~found THEN set.fixedV ← CONS[fix.first, set.fixedV];
};
ENDLOOP;
ENDLOOP;
};
TypeEqual: PROC [s1, s2: SetType] RETURNS [ok: BOOLEANFALSE] ~ {
FOR tt: CoreClasses.TransistorType IN CoreClasses.TransistorType DO
IF s1.nFets[tt]#s2.nFets[tt] THEN RETURN;
ENDLOOP;
IF s1.nVddTran#s2.nVddTran THEN RETURN;
IF s1.nGndTran#s2.nGndTran THEN RETURN;
IF s1.nNodes#s2.nNodes THEN RETURN;
IF s1.nInput#s2.nInput THEN RETURN;
ok ← TRUE;
};
PrintSetType: PROC [out: IO.STREAM, setType: SetType] ~ {
IO.PutF[out, " %4d, %4d,", IO.int[setType.nFets[nE]], IO.int[setType.nFets[pE]]];
IO.PutF[out, " %4d, %4d, %4d, %4d", IO.int[setType.nVddTran], IO.int[setType.nGndTran], IO.int[setType.nNodes], IO.int[setType.nInput]];
};
SolveInverter: PROC [set: Set, t: ps] RETURNS [tlast: ps] ~ {
out: Node ~ set.lNodes.first;
in: Node ~ set.inList.first;
... to be finished.
};
ErrMsg: PROC [nodeList: NodeList, msg: Rope.ROPE, circuit: Circuit] ~ {
IO.PutF[Mint.StdOut, "\n%g:", IO.rope[msg]];
FOR iNodeList: NodeList ← nodeList, iNodeList.rest UNTIL iNodeList=NIL DO
IO.PutF[Mint.StdOut, "\n%g", IO.rope[Mint.RopeFromNode[iNodeList.first, circuit]]];
ENDLOOP;
IO.PutF[Mint.StdOut, "\n" ];
};
CheckLibrary: PUBLIC PROC [circuit: Circuit] ~ {
n: NAT ← 0;
FOR il: Library ← circuit.library, il.rest UNTIL il=NIL DO
SELECT TRUE FROM
il.first.type.nFets[nE]+il.first.type.nFets[pE]=0 => FOR iSetList: SetList ← il.first.setList, iSetList.rest UNTIL iSetList=NIL DO
IF iSetList.first.lNodes.first.flatWire.wireRoot#public THEN {
IF iSetList.first.lNodes.first.setList=NIL THEN ErrMsg[iSetList.first.lNodes, "These Nodes are isolated", circuit] ELSE ErrMsg[iSetList.first.lNodes, "These Nodes are not loaded by any fet", circuit]};
ENDLOOP;
il.first.type.nVddTran=0 => FOR iSetList: SetList ← il.first.setList, iSetList.rest UNTIL iSetList=NIL DO
ErrMsg[iSetList.first.lNodes, "These Nodes have no path to Vdd", circuit];
ENDLOOP;
il.first.type.nGndTran=0 => FOR iSetList: SetList ← il.first.setList, iSetList.rest UNTIL iSetList=NIL DO
ErrMsg[iSetList.first.lNodes, "These Nodes have no path to Gnd", circuit];
ENDLOOP;
ENDCASE;
ENDLOOP;
};
OutputResults: PUBLIC PROC [circuit: Circuit] ~ {
n: NAT ← 0;
IO.PutF[Mint.StdOut, "\n nE pE ^Vdd ^Gnd nodes inputs"];
FOR il: Library ← circuit.library, il.rest UNTIL il=NIL DO
IO.PutF[Mint.StdOut, "\n%5d el: %5d Type: ", IO.int[n], IO.int[il.first.nElem]];
PrintSetType[Mint.StdOut, il.first.type];
n ← n+1;
ENDLOOP;
};
IO.PutRope[Mint.StdOut, "\nMintLayout\n"];
END.