SinixRawCMosBImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reversed.
Created by Bertrand Serlet October 30, 1986 12:49:32 pm PST
Bertrand Serlet March 1, 1987 11:20:44 pm PST
Last Edited by: Louis Monier March 3, 1987 10:28:59 pm PST
DIRECTORY
Basics,
CD, CDBasics, CDCells, CDDirectory, CDProperties, CDRects, CDSymbolicObjects, CDTexts, CMosB,
Core, CoreClasses, CoreGeometry, CoreOps, CoreProperties,
GList, HashTable, IO, PWObjects, Rope, Sinix, SinixOps, SinixRawCMosB, TerminalIO;
SinixRawCMosBImpl: CEDAR PROGRAM
IMPORTS Basics, CD, CDBasics, CDCells, CDDirectory, CDProperties, CDRects, CDSymbolicObjects, CDTexts, CMosB, CoreGeometry, CoreClasses, CoreOps, CoreProperties, GList, HashTable, IO, PWObjects, Rope, Sinix, SinixOps, TerminalIO
EXPORTS SinixRawCMosB
SHARES CDCells, CDRects, CDSymbolicObjects, CDTexts = BEGIN
Types
CellType: TYPE = Core.CellType;
Wire: TYPE = Core.Wire;
Wires: TYPE = Core.Wires;
Object: TYPE = CD.Object;
Properties: TYPE = Core.Properties;
ROPE: TYPE = Core.ROPE;
Mode
standardMode: Sinix.Mode = SinixOps.GetExtractMode[CMosB.cmosB];
justKeepOne: BOOLFALSE;
mode: PUBLIC Sinix.Mode ← NEW [Sinix.ModeRec ← [
extractProcProp: PWObjects.RegisterProp[$RawCMosBExtractProc, TRUE],
decoration: CoreGeometry.CreateDecoration["RawCMosB"],
nbOfLayers: standardMode.nbOfLayers,
instanceLayer: standardMode.instanceLayer,
touchProc: CoreGeometry.Touch,
fusionByName: none,
equalProc: SmallerOverlap,
userData: UserData
]];
we use the knowledge of what is the cache and what is the call
SmallerOverlap: PROC [obj: Object, cacheProperties: CD.PropList, cacheUserData: REF, properties: CD.PropList, userData: REF] RETURNS [cacheOK: BOOL] = {
cacheData: REF INT = NARROW [cacheUserData];
data: REF INT = NARROW [userData];
cacheOK ← Sinix.CompareProps[obj, cacheProperties, cacheUserData, properties, userData] AND cacheData^>=data^;
};
UserData: PROC [design: CD.Design] RETURNS [REF] = {RETURN [NEW [INT ← 0]]};
Extracting PadBlank
Necessary so that vias get extracted as one guy, not as many!
ExtractCellAsWire: Sinix.ExtractProc = {
EachInst: CDCells.InstEnumerator = {pins ← CONS [[inst.ob, inst.trans], pins]};
pins: CoreGeometry.Instances ← NIL;
wire: Wire ← CoreOps.CreateWire[];
[] ← CDCells.EnumerateInstances[obj, EachInst];
CoreGeometry.PutPins[mode.decoration, wire, pins];
result ← wire;
};
Marking Cells used once and Convert routing cells
Mark: PROC [design: CD.Design] RETURNS [total, marked: INT ← 0] = {
usage: HashTable.Table = HashTable.Create[]; -- maps every cell to the containing cell. Objects are keys, and values are either $unique, or $many if several cell contain that object.
replaceList: LIST OF CDDirectory.ReplaceRec ← NIL;
ReplaceRoutingCells: CDDirectory.EachEntryAction = {
nodes: HashTable.Table;
CheckHasSignalName: CDCells.InstEnumerator = {
quit ← CDProperties.GetInstanceProp[inst, $SignalName]=NIL OR inst.trans.orient#original;
};
InsertInst: CDCells.InstEnumerator = {
name: ROPE = NARROW [CDProperties.GetInstanceProp[inst, $SignalName]];
list: REF LIST OF PWObjects.PlacedObject ← NARROW [HashTable.Fetch[nodes, name].value];
IF list=NIL THEN list ← NEW [LIST OF PWObjects.PlacedObject ← NIL];
list^ ← CONS [[object: inst.ob, position: inst.trans.off], list^];
[] ← HashTable.Store[nodes, name, list];
};
IF NOT CDCells.IsCell[ob] THEN RETURN;
IF CDCells.EnumerateInstances[ob, CheckHasSignalName] THEN RETURN;
TerminalIO.PutF["### Replacing routing cell %g!\n", IO.rope[CDDirectory.Name[ob]]];
nodes ← HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope];
[] ← CDCells.EnumerateInstances[ob, InsertInst];
replaceList ← CONS [[old: ob, new: PWObjects.CreateRouting[CD.InterestRect[ob], PWObjects.CreateNodes[nodes]]], replaceList];
};
CountEachUse: CDDirectory.EachEntryAction = {
EachInst: CDCells.InstEnumerator = {
value: REF = HashTable.Fetch[usage, inst.ob].value;
IF NOT CDCells.IsCell[inst.ob] THEN RETURN;
[] ← HashTable.Store[usage, inst.ob, IF value=NIL THEN $unique ELSE $many];
};
IF NOT CDCells.IsCell[ob] THEN RETURN;
total ← total + 1;
[] ← CDCells.EnumerateInstances[ob, EachInst];
};
MarkUniques: HashTable.EachPairAction = {
IF value=$many THEN RETURN;
marked ← marked + 1;
CDProperties.PutProp[key, $RawFlatten, $RawFlatten];
};
[] ← CDDirectory.Enumerate[design, ReplaceRoutingCells];
WHILE replaceList#NIL DO
CDDirectory.ReplaceObject[design, replaceList.first.old, replaceList.first.new];
replaceList ← replaceList.rest;
ENDLOOP;
[] ← CDDirectory.Enumerate[design, CountEachUse];
[] ← HashTable.Pairs[usage, MarkUniques];
};
Computing corresponding cells
SortedEdges: TYPE = ARRAY CoreGeometry.Side OF LIST OF Wire ← ALL [NIL];
WireMinMax: TYPE = RECORD [wire: Wire, min, max: INT];
SortEdges: PROC [mode: Sinix.Mode, ll: CD.Layer, cellType: CellType] RETURNS [edges: SortedEdges] = {
FOR ss: CoreGeometry.Side IN CoreGeometry.Side DO
wmm: LIST OF REF WireMinMax ← NIL;
edge: LIST OF Wire ← NIL;
EachWirePin: CoreGeometry.EachWirePinProc = {
IF side#ss OR layer#ll THEN RETURN;
wmm ← CONS [NEW [WireMinMax ← [wire, min, max]], wmm];
};
CompareWMM: GList.CompareProc = {
wmm1: REF WireMinMax = NARROW [ref1];
wmm2: REF WireMinMax = NARROW [ref2];
RETURN [Basics.CompareINT[wmm2.min, wmm1.min]];
};
[] ← CoreGeometry.EnumerateNonOverlappingSides[mode.decoration, cellType, EachWirePin];
FOR list: LIST OF REF WireMinMax ← NARROW [GList.Sort[wmm, CompareWMM]], list.rest WHILE list#NIL DO
edge ← CONS [list.first.wire , edge];
ENDLOOP;
edges[ss] ← edge;
ENDLOOP;
};
MatchSourceToExtracted: PROC [sourceMode: Sinix.Mode, layer: CD.Layer, source, extractedCT: CellType, name: ROPENIL, props: Properties ← NIL] RETURNS [new: CellType] = {
sourceEdges: SortedEdges ← SortEdges[sourceMode, layer, source];
extractedEdges: SortedEdges ← SortEdges[mode, CMosB.ovg, extractedCT];
public: Wire ← CoreOps.CopyWire[source.public];
table: HashTable.Table ← HashTable.Create[]; -- from extracted to new
sourceToNew: HashTable.Table ← CoreOps.CreateBindingTable[source.public, public]; -- from source to new
FOR side: CoreGeometry.Side IN CoreGeometry.Side DO
length: INT = GList.Length[sourceEdges[side]];
IF length#GList.Length[extractedEdges[side]] THEN ERROR;
THROUGH [0 .. length) DO
sourceWire: Wire ← sourceEdges[side].first;
extractedWire: Wire ← extractedEdges[side].first;
newWire: Wire ← NARROW [HashTable.Fetch[sourceToNew, sourceWire].value];
prevNew: Wire ← NARROW [HashTable.Fetch[table, extractedWire].value];
IF prevNew#NIL AND prevNew#newWire THEN ERROR;
[] ← HashTable.Store[table, extractedWire, newWire];
ENDLOOP;
ENDLOOP;
new ← CoreClasses.CreatePermutedRecordCell[iconPublic: public, schCell: extractedCT, table: table, name: name, props: props];
};
Cell extraction
IsOverglass: PROC [obj: CD.Object] RETURNS [BOOL] = {
RETURN [obj.class=CDRects.bareRectClass AND obj.layer=CMosB.ovg];
};
ExplicitPins: CoreOps.EachWireProc = {
CoreGeometry.PutPins[mode.decoration, wire, CoreGeometry.GetPins[mode.decoration, wire]];
};
same as CoreGeometry.GetGeometry, but only keeps 1 instances (+ all overglass rectangles!).
SpecialGetGeometry: PROC [wire: Wire] RETURNS [geometry: CoreGeometry.Instances ← NIL, ovg: BOOLFALSE] = {
ConsEachGeom: CoreGeometry.EachInstanceProc = {
SELECT TRUE FROM
IsOverglass[instance.obj] => {ovg ← TRUE; geometry ← CONS [instance, geometry]};
geometry=NIL => geometry ← LIST [instance];
ENDCASE => IF NOT justKeepOne THEN geometry ← CONS [instance, geometry];
};
[] ← CoreGeometry.EnumerateGeometry[mode.decoration, wire, ConsEachGeom];
};
RawExtractCell: Sinix.ExtractProc = {
flattenSomeChild: BOOLFALSE;
rct: CoreClasses.RecordCellType;
new, record: CellType;
newInternals: Wires ← NIL; -- used only if flatten of a child necessary
instances: LIST OF CoreClasses.CellInstance ← NIL; -- used only if flatten of a child necessary
[result, props] ← Sinix.ExtractCell[obj, mode, properties, userData];
record ← NARROW [result];
rct ← NARROW [record.data];
IF rct.size=0 THEN CoreProperties.PutCellTypeProp[record, $RawFlatten, $Keep];
IF CDProperties.GetObjectProp[obj, $RawFlatten]=$RawFlatten THEN CoreProperties.PutCellTypeProp[record, $RawFlatten, $Smash];
FOR i: NAT IN [0 .. rct.size) DO
IF CoreProperties.GetCellTypeProp[rct[i].type, $RawFlatten]#NIL THEN flattenSomeChild ← TRUE;
ENDLOOP;
[] ← CoreOps.VisitWireSeq[record.public, ExplicitPins]; -- we want to avoid the TransWireIR lazyness which is using the InterestRect
IF NOT flattenSomeChild THEN RETURN;
TerminalIO.PutF["In cell %g, flattening:", IO.rope[CDDirectory.Name[obj]]];
we explicit the pins to avoid circularity (and to gain some speed up in the shared case)
[] ← CoreOps.VisitWireSeq[record.public, ExplicitPins];
FOR i: NAT IN [0 .. rct.size) DO
IF CoreProperties.GetCellTypeProp[rct[i].type, $RawFlatten]=NIL
THEN instances ← CONS [rct[i], instances]
ELSE {
The following code does not deal properly with DAGS. Who cares?
CreateWire: PROC [old: Wire] RETURNS [wire: Wire] = {
geometry: CoreGeometry.Instances; ovg: BOOL;
[geometry, ovg] ← SpecialGetGeometry[old];
geometry ← CoreGeometry.TransformList[trans, geometry];
wire ← CoreOps.CreateWire[];
CoreGeometry.PutGeometry[mode.decoration, wire, geometry];
newInternals ← CONS [wire, newInternals];
};
AddInTable: PROC [subInternal: Wire] = {
IF HashTable.Fetch[intToInt, subInternal].value#NIL THEN RETURN;
[] ← HashTable.Store[intToInt, subInternal, CreateWire[subInternal]];
};
CreateActual: PROC [oldAct: Wire] RETURNS [newAct: Wire] = {
newAct ← NARROW [HashTable.Fetch[intToInt, oldAct].value];
IF newAct#NIL THEN RETURN;
IF oldAct.size=0
THEN [] ← HashTable.Store[intToInt, oldAct, newAct ← CreateWire[oldAct]]
ELSE {
newAct ← CoreOps.CreateWires[size: oldAct.size];
FOR i: NAT IN [0 .. oldAct.size) DO newAct[i] ← CreateActual[oldAct[i]] ENDLOOP;
};
};
DecorateBinding: HashTable.EachPairAction = {
pub: Wire = NARROW [key];
act: Wire = NARROW [value];
CoreGeometry.AddGeometry[
mode.decoration, act,
CoreGeometry.TransformList[trans, SpecialGetGeometry[pub].geometry]
]; -- Hack to save some space for now!
};
name: ROPE = CoreOps.GetCellTypeName[rct[i].type];
trans: CoreGeometry.Transformation = CoreGeometry.GetTrans[mode.decoration, rct[i]];
subrct: CoreClasses.RecordCellType = NARROW [rct[i].type.data];
intToInt: HashTable.Table ← CoreOps.CreateBindingTable[rct[i].type.public, rct[i].actual];
[] ← HashTable.Pairs[intToInt, DecorateBinding];
IF NOT Rope.Equal[CDDirectory.Name[CoreGeometry.GetObject[mode.decoration, rct[i].type]], name] THEN ERROR;
TerminalIO.PutF[" %g[%g]", IO.rope[name], IO.int[subrct.size]];
CoreOps.VisitRootAtomics[subrct.internal, AddInTable];
FOR j: NAT IN [0 .. subrct.size) DO
instance: CoreClasses.CellInstance ← CoreClasses.CreateInstance[actual: CreateActual[subrct[j].actual], type: subrct[j].type, props: subrct[j].properties];
CoreGeometry.PutTrans[mode.decoration, instance, CDBasics.ComposeTransform[itemInCell: CoreGeometry.GetTrans[mode.decoration, subrct[j]], cellInWorld: trans]];
instances ← CONS [instance, instances]
ENDLOOP;
-- We flush the Sinix cache for name
IF CoreProperties.GetCellTypeProp[rct[i].type, $RawFlatten]=$Smash THEN Sinix.FlushCache[CoreGeometry.GetObject[mode.decoration, rct[i].type]];
};
ENDLOOP;
new ← CoreClasses.CreateRecordCell[
record.public,
CoreOps.UnionWire[rct.internal, CoreOps.CreateWire[newInternals]],
instances, NIL, record.properties, TRUE
];
CoreGeometry.PutObject[mode.decoration, new, CoreGeometry.GetObject[mode.decoration, record]];
If obj had already the $RawFlatten property, fine. If it did not have it and we have zero or one instance, let's make sure we'll flatten this cell
IF CDProperties.GetObjectProp[obj, $RawFlatten]#$RawFlatten AND (instances=NIL OR instances.rest=NIL) THEN CoreProperties.PutCellTypeProp[new, $RawFlatten, $Keep];
On the other hand, if we had the $RawFlatten property, but we have more subcells than rosemary can handle, forget it!
IF CDProperties.GetObjectProp[obj, $RawFlatten]=$RawFlatten AND GList.Length[instances]>10000 THEN CoreProperties.PutCellTypeProp[new, $RawFlatten, NIL];
TerminalIO.PutF[".\n"];
result ← new;
};
Initialization
Same: PROC [nameOrClass: REF] = {
class: CD.ObjectClass;
WITH nameOrClass SELECT FROM
c: CD.ObjectClass => class ← c;
r: ATOM  => class ← CD.FetchObjectClass[r, CMosB.cmosB];
ENDCASE  => ERROR;
CDProperties.PutProp[class, mode.extractProcProp, CDProperties.GetProp[class, standardMode.extractProcProp]];
};
Registering extract procs
Sinix.RegisterExtractProc[$RawExtractCell, RawExtractCell];
Sinix.RegisterExtractProc[$ExtractCellAsWire, ExtractCellAsWire];
Cells
CDProperties.PutProp[CDCells.pCellClass, mode.extractProcProp, $RawExtractCell];
Same[PWObjects.routingClass];
Pins
Same[CDSymbolicObjects.pinClass]; Same[CDSymbolicObjects.segmentClass]; Same[CDSymbolicObjects.markClass];
Rectangles
Same[CDRects.bareRectClass];
Contacts
Same[$C2SimpleCon]; Same[$C2WellSimpleCon];
Same[$C2LargeSimpleCon]; Same[$C2LargeWellSimpleCon];
Same[$C2DifShortCon]; Same[$C2WellDifShortCon];
Same[$C2Via]; Same[$C2LargeVia];
Diffusion wires
Same[$C2PDifRect]; Same[$C2NDifRect];
Transistors
Same[$C2Trans]; Same[$C2WellTrans];
Angle Transistors
Same[$C2LTrans]; Same[$C2LWellTrans];
Texts
Same[CDTexts.rigidTextClass];
Same[CDTexts.flipTextClass];
SinixOps.RegisterModeCommands[mode, CMosB.cmosB];
END.