Fusion data structure and internal manipulation
NameWire:
TYPE =
RECORD [name:
ROPE, wire: Wire];
FusionData: TYPE = REF FusionDataRec;
FusionDataRec:
TYPE =
RECORD [
mode: Mode, -- to avoid passing it around
nir: CD.Rect, -- Rectangles for which geometry that is strictly inside (edge excluded) is not promoted public
name: ROPE, -- name of the object currently extracted
isAbut: BOOL, -- recording publics depend on this property
fused: RefTab.Ref, -- Association [fused -> root] [Wire -> Wire]. If root=NIL, then this wire is a root. Basically all the wires ever created belong to this table.
data: REF, -- different information for Abut and Cell. For abuts it contains the next rects, (REF InstanceTable.Table). For Cell, it is a LIST OF NameWire. This list is not sorted at creation time, and same name may appear several times.
rects: SEQUENCE nbOfLayers: NAT OF InstanceTable.Table -- Association (per layer) [fusion geometry -> wire] [CD.Rect -> IW]. Wire may or may not be a root.
];
AbutData: TYPE = REF AbutDataRec;
AbutDataRec:
TYPE =
RECORD [
inX: BOOL, -- to avoid passing it around
nextRects: SEQUENCE nbOfLayers: NAT OF InstanceTable.Table -- Association (per layer) [fusion geometry -> wire] [CD.Rect -> IW]. Wire may or may not be a root.
];
rect:
PROC [r:
CD.Rect]
RETURNS [
IO.Value] = {
RETURN [IO.rope[IO.PutFR["[%g, %g, %g, %g]", IO.int[r.x1], IO.int[r.y1], IO.int[r.x2], IO.int[r.y2]]]];
};
CreateRoot:
PROC [fusionData: FusionData, size:
NAT, props: Properties ←
NIL]
RETURNS [wire: Wire] = {
EachProperty:
PROC [prop:
ATOM, val:
REF
ANY ←
NIL] = {
newVal:
REF
ANY ←
SELECT prop
FROM
fusionData.mode.decoration.pinsProp => NIL,
fusionData.mode.decoration.geometryProp => NIL,
CoreOps.nameProp => NIL,
ENDCASE => val;
CoreProperties.PutWireProp[wire, prop, newVal];
};
wire ← CoreOps.CreateWires[size: size];
CoreProperties.Enumerate[props, EachProperty];
[] ← RefTab.Store[fusionData.fused, wire, NIL];
};
copyGeometry indicates if this geometry is only going to be used for fusion and does not have to figure in the geometry and pins properties (real geometry versus geometry at the level below).
InsertInstances:
PROC [fusionData: FusionData, transformation: Transformation, instances: Instances, wire: Wire, copyGeometry:
BOOL] = {
IF ~RefTab.Fetch[fusionData.fused, wire].found
THEN SIGNAL InternalBug[fusionData.name];
IF RootWire[fusionData, wire]#wire THEN SIGNAL InternalBug[fusionData.name];
FOR is: Instances ← instances, is.rest
WHILE is#
NIL
DO
inst: Instance ← CoreGeometry.Transform[transformation, is.first];
layers: LayerRange ← fusionData.mode.instanceLayer[inst];
FOR i: NAT IN [layers.min .. layers.max] DO InstanceTable.Insert[fusionData[i], inst, wire] ENDLOOP;
If a pin is found we just note that this is a public wire
IF CoreGeometry.AtEdge[fusionData.nir, inst]
THEN CoreProperties.PutWireProp[wire, $Public, $Public];
ENDLOOP;
IF copyGeometry THEN CoreGeometry.AddGeometry[fusionData.mode.decoration, wire, CoreGeometry.TransformList[transformation, instances]];
};
Fusion external manipulation
Creates a DAG Wire from a RefTab, getting rid of wires that have their father also in the list.
CreateDAGWireSeq:
PROC [table: RefTab.Ref]
RETURNS [wire: WireSeq] = {
wires: LIST OF Wire ← NIL;
EachKeyDelete: RefTab.EachPairAction = {
WireDelete:
PROC [wire: Wire] = {
IF ~RefTab.Delete[table, wire] THEN RETURN; -- already done
FOR i:
NAT
IN [0 .. wire.size)
DO
WireDelete[wire[i]];
ENDLOOP;
};
wire: Wire ← NARROW [key];
FOR i:
NAT
IN [0 .. wire.size)
DO
delete all the sons
WireDelete[wire[i]];
ENDLOOP;
};
index: NAT ← 0;
SummarizeWires: RefTab.EachPairAction = {
wire[index] ← NARROW [key];
index ← index+1;
};
[] ← RefTab.Pairs[table, EachKeyDelete];
wire ← CoreOps.CreateWires[RefTab.GetSize[table]];
[] ← RefTab.Pairs[table, SummarizeWires];
IF index#RefTab.GetSize[table] THEN SIGNAL InternalBug[NIL];
};
MakeResult:
PROC [fusionData: FusionData, obj:
CD.Object, cellInstances:
LIST
OF CoreClasses.CellInstance]
RETURNS [record: CellType] = {
decoration: CoreGeometry.Decoration = fusionData.mode.decoration;
publics: RefTab.Ref ← RefTab.Create[3];
internals: RefTab.Ref ← RefTab.Create[5];
visitOnceTab: RefTab.Ref ← RefTab.Create[];
InternalDagIfy: RefTab.EachPairAction = {
WireDagIfy:
PROC [wire: Wire, maxIter:
NAT ← 32] = {
32 should be enough to avoid 815
IF maxIter=0 THEN SIGNAL StructuralLoop[fusionData.name, wire]; -- probably loop in the Wire structure
IF RootWire[fusionData, wire]#wire THEN SIGNAL InternalBug[fusionData.name];
FOR i:
NAT
IN [0 .. wire.size)
DO
wire[i] ← RootWire[fusionData, wire[i]];
WireDagIfy[wire[i], maxIter-1];
ENDLOOP;
};
wire: Wire ← NARROW [key];
IF val#NIL THEN RETURN; -- we dagify only the roots
[] ← RefTab.Store[internals, wire, NIL];
IF CoreProperties.GetWireProp[wire, $Public]#
NIL
THEN {
[] ← RefTab.Store[publics, wire, NIL];
CoreProperties.PutWireProp[wire, $Public, NIL];
};
WireDagIfy[wire];
};
AddDecorateWire: CoreOps.EachWireProc = {
pins: Instances ← NIL;
AddPin: CoreGeometry.EachInstanceProc = {
IF CoreGeometry.AtEdge[fusionData.nir, instance] THEN pins ← CONS [instance, pins];
};
IF ~RefTab.Store[visitOnceTab, wire, wire] THEN RETURN[FALSE, FALSE]; -- only once
[] ← CoreGeometry.EnumerateGeometry[decoration, wire, AddPin];
CoreGeometry.AddPins[decoration, wire, pins];
};
We find out who are the publics and internals
[] ← RefTab.Pairs[fusionData.fused, InternalDagIfy];
We replace in all instances wires by their roots
FOR list:
LIST
OF CoreClasses.CellInstance ← cellInstances, list.rest
WHILE list#
NIL
DO
instance: CoreClasses.CellInstance ← list.first;
actual: Wire ← instance.actual;
FOR i:
NAT
IN [0 .. actual.size)
DO
wire: Wire ← RootWire[fusionData, actual[i]];
IF ~CoreOps.CorrectConform[wire, instance.type.public[i]] THEN SIGNAL StructureMismatch[fusionData.name, i, actual, instance.type.public];
actual[i] ← wire;
ENDLOOP;
ENDLOOP;
We build the CellType
record ← CoreClasses.CreateRecordCell[
public: CreateDAGWireSeq[publics], internal: CreateDAGWireSeq[internals],
instances: cellInstances,
name: fusionData.name,
giveNames: TRUE
];
CoreGeometry.PutObject[decoration, record, obj];
We set all pins to be lazy for that record
CoreGeometry.PutRecordLazyPins[decoration, record, fusionData.nir];
We correct previous statement for all explicit geometry
[] ← CoreOps.VisitWireSeq[record.public, AddDecorateWire];
We empty all tables
RefTab.Erase[visitOnceTab]; visitOnceTab ← NIL;
FOR i:
NAT
IN [0 .. fusionData.mode.nbOfLayers)
DO
InstanceTable.DeleteOutside[fusionData[i], InstanceTable.empty];
ENDLOOP;
};
LayoutFusionByName:
PROC [fusionData: FusionData] = {
refList: REF LIST OF NameWire = NARROW [fusionData.data];
nameToWire: SymTab.Ref = SymTab.Create[mod: 11];
FOR nameWires:
LIST
OF NameWire ← refList^, nameWires.rest
WHILE nameWires#
NIL
DO
wire: Wire ← RootWire[fusionData, nameWires.first.wire];
name: ROPE ← OrNames[nameWires.first.name, CoreOps.GetShortWireName[wire], fusionData.name];
previousWire: Wire ← NARROW [SymTab.Fetch[nameToWire, name].val];
IF previousWire#
NIL
THEN {
previousWire ← RootWire[fusionData, previousWire];
IF previousWire#wire
THEN {
wire ← StructuredFusion[fusionData, wire, previousWire];
PutF["Fusion by name for '%g' in cell '%g'.\n", IO.rope[name], IO.rope[fusionData.name]];
CoreProperties.PutWireProp[wire, $FusedByName, $FusedByName];
};
};
[] ← SymTab.Store[nameToWire, name, wire];
[] ← CoreOps.SetShortWireName[wire, name];
ENDLOOP;
};
NoFusionByName:
PROC [fusionData: FusionData] = {
refList: REF LIST OF NameWire = NARROW [fusionData.data];
EachNameWire: SymTab.EachPairAction = {
uniqueID: INT ← 0;
name: ROPE = NARROW [key];
wires: Wires ← NARROW [val];
[] ← CoreOps.SetShortWireName[wires.first, name];
wires ← wires.rest;
IF wires=NIL THEN RETURN;
PutF["NO fusion by name for '%g' in cell '%g'.\n", IO.rope[name], IO.rope[fusionData.name]];
WHILE wires#
NIL
DO
[] ← CoreOps.SetShortWireName[wires.first, IO.PutFR["%g$%g$", IO.rope[name], IO.int[uniqueID]]];
uniqueID ← uniqueID + 1;
wires ← wires.rest;
ENDLOOP;
};
nameToWires: SymTab.Ref = SymTab.Create[mod: 11]; -- contains (for every name) the list of roots that have it for name
FOR nameWires:
LIST
OF NameWire ← refList^, nameWires.rest
WHILE nameWires#
NIL
DO
name: ROPE ← nameWires.first.name;
wire: Wire = RootWire[fusionData, nameWires.first.wire];
wires: Wires ← NARROW [SymTab.Fetch[nameToWires, name].val];
IF NOT CoreOps.Member[wires, wire] THEN wires ← CONS [wire, wires];
[] ← SymTab.Store[nameToWires, name, wires];
ENDLOOP;
[] ← SymTab.Pairs[nameToWires, EachNameWire];
};
SchematicsFusionByName:
PROC [fusionData: FusionData] = {
refList: REF LIST OF NameWire = NARROW [fusionData.data];
nameToWire: SymTab.Ref = SymTab.Create[mod: 11];
names: ROPES ← NIL;
We first fuse all the nameWire with same name, and at the same time prepare the list of all the names that have components
FOR nameWires:
LIST
OF NameWire ← refList^, nameWires.rest
WHILE nameWires#
NIL
DO
wire: Wire ← RootWire[fusionData, nameWires.first.wire];
name: ROPE ← OrNames[nameWires.first.name, CoreOps.GetShortWireName[wire], fusionData.name];
previousWire: Wire ← NARROW [SymTab.Fetch[nameToWire, name].val];
hasComponents: BOOL = CoreOps.ParseWireName[name].components#NIL;
IF previousWire#NIL THEN previousWire ← RootWire[fusionData, previousWire];
IF previousWire#
NIL
AND previousWire#wire
THEN wire ← StructuredFusion[fusionData, wire, previousWire]
ELSE IF hasComponents THEN names ← CONS [name, names];
[] ← SymTab.Store[nameToWire, name, wire];
IF NOT hasComponents THEN [] ← CoreOps.SetShortWireName[wire, name];
ENDLOOP;
We sort the names, using the trick that foo[2].mumble or foo[2][3] are after foo[2] in the lexicographic order
names ← RopeList.Sort[names, RopeList.Compare]; -- JMF: deleted, already done next line
FOR list:
ROPES ← RopeList.Sort[names, RopeList.Compare], list.rest
WHILE list#
NIL
DO
name: ROPE ← list.first;
wire: Wire = RootWire[fusionData, NARROW [SymTab.Fetch[nameToWire, name].val]];
base: ROPE; components: ROPES ← NIL;
matchingWire: Wire;
[base, components] ← CoreOps.ParseWireName[name];
matchingWire ← NARROW [SymTab.Fetch[nameToWire, base].val];
WHILE components#
NIL
DO
index: INT ← -1;
IF matchingWire=NIL THEN SIGNAL FusionByNameMismatch[fusionData.name, IO.PutFR["Path name %g does not correspond to any wire", IO.rope[name]], wire];
matchingWire ← RootWire[fusionData, matchingWire];
FOR i:
NAT
IN [0 .. matchingWire.size)
DO
subWireName: ROPE ← CoreOps.GetShortWireName[matchingWire[i]];
IF subWireName=NIL THEN subWireName ← IO.PutR1[IO.int[i]]; -- JMF: speedup
IF subWireName=NIL THEN subWireName ← IF i<256 THEN numbers[i] ELSE IO.PutR1[IO.int[i]]; -- JMF: speedup hack to avoid allocating lots of ropes
IF Rope.Equal[subWireName, components.first]
THEN {
IF index=-1 THEN index ← i ELSE FusionByNameMismatch[fusionData.name, IO.PutFR["Current wire has 2 or more sub-wires with field `%g'", IO.rope[components.first]], wire];
};
ENDLOOP;
IF index=-1 THEN SIGNAL FusionByNameMismatch[fusionData.name, IO.PutFR["Current wire does not have a sub-wire with field `%g'", IO.rope[components.first]], wire];
matchingWire ← matchingWire[index];
components ← components.rest;
ENDLOOP;
[] ← StructuredFusion[fusionData, matchingWire, wire];
ENDLOOP;
};
AddNameWire:
PROC [fusionData: FusionData, name:
ROPE, wire: Wire] = {
nameWires: REF LIST OF NameWire ← NARROW [fusionData.data];
nameWires^ ← CONS [[name: name, wire: wire], nameWires^];
};
The following PROC implements Fisher-Galler fusion, not for efficiency, but for simplicity
RootWire:
PROC [fusionData: FusionData, wire: Wire]
RETURNS [rootWire: Wire] = {
IF wire=NIL THEN SIGNAL InternalBug[fusionData.name];
rootWire ← NARROW [RefTab.Fetch[fusionData.fused, wire].val];
IF rootWire=NIL THEN RETURN [wire];
IF rootWire=wire THEN SIGNAL InternalBug[fusionData.name];
rootWire ← RootWire[fusionData, rootWire];
[] ← RefTab.Replace[fusionData.fused, wire, rootWire];
};
This mechanism could be exported if we wanted that.
PropFusionProc:
TYPE =
PROC [prop:
ATOM, value1, value2:
REF
ANY, name:
ROPE]
RETURNS [value:
REF
ANY];
NameFusion: PropFusionProc = {
value ← OrNames[NARROW [value1], NARROW [value2], name];
};
DefaultFusion: PropFusionProc = {
IF value1#NIL AND value2#NIL AND value1#value2 THEN SIGNAL FusionPropMismatch[name, prop, value1, value2];
value ← IF value1=NIL THEN value2 ELSE value1;
};
Appends the properties of fused to the ones of root, but treating short names specially
FuseProperties:
PUBLIC
PROC [mode: Mode, fused, root: Wire, name:
ROPE] = {
EachProperty:
PROC [prop:
ATOM, val:
REF
ANY] = {
rootValue: REF ← CoreProperties.GetWireProp[root, prop];
SELECT prop
FROM
CoreOps.nameProp => nameVal ← val;
mode.decoration.geometryProp => geomVal ← val;
mode.decoration.pinsProp => pinVal ← val;
ENDCASE => CoreProperties.PutWireProp[root, prop, DefaultFusion[prop, val, rootValue, name]];
};
nameVal: REF ANY ← NIL;
geomVal: REF ANY ← NIL;
pinVal: REF ANY ← NIL;
CoreProperties.Enumerate[fused.properties, EachProperty];
IF nameVal#
NIL
THEN {
rootValue: REF ANY ← CoreProperties.GetWireProp[root, CoreOps.nameProp];
CoreProperties.PutWireProp[root, CoreOps.nameProp, NameFusion[CoreOps.nameProp, nameVal, rootValue, name]];
};
IF geomVal#NIL THEN CoreGeometry.AddGeometry[mode.decoration, root, CoreGeometry.GetGeometry[mode.decoration, fused]];
IF pinVal#
NIL
THEN CoreGeometry.AddPins[mode.decoration, root, CoreGeometry.GetPins[mode.decoration, fused]];
this never happens during Cell or Abut extraction, because pins are not yet there, but might occur when called from SisyphImpl.ProcessGlobalName
};
FuseProperties: PUBLIC PROC [mode: Mode, fused, root: Wire, name: ROPE] = {
EachProperty: PROC [prop: ATOM, val: REF ANY] = {
rootValue: REF ← CoreProperties.GetWireProp[root, prop];
SELECT prop FROM
CoreOps.nameProp => CoreProperties.PutWireProp[root, prop, NameFusion[prop, val, rootValue, name]];
mode.decoration.geometryProp => CoreGeometry.AddGeometry[mode.decoration, root, CoreGeometry.GetGeometry[mode.decoration, fused]];
mode.decoration.pinsProp => CoreGeometry.AddPins[mode.decoration, root, CoreGeometry.GetPins[mode.decoration, fused]]; -- this never happens during Cell or Abut extraction, because pins are not yet there, but might occur when called from SisyphImpl.ProcessGlobalName
ENDCASE => CoreProperties.PutWireProp[root, prop, DefaultFusion[prop, val, rootValue, name]];
};
CoreProperties.Enumerate[fused.properties, EachProperty];
};
This proc really does the fusion of fused and root, by wiping fused of some tables, and adding interesting properties of fused to root.
DeleteFused:
PROC [fusionData: FusionData, fused, root: Wire] = {
IF ~RefTab.Fetch[fusionData.fused, fused].found THEN SIGNAL InternalBug[fusionData.name];
IF RootWire[fusionData, fused]#fused THEN SIGNAL InternalBug[fusionData.name];
IF ~RefTab.Fetch[fusionData.fused, root].found THEN SIGNAL InternalBug[fusionData.name];
IF RootWire[fusionData, root]#root THEN SIGNAL InternalBug[fusionData.name];
IF fused=root THEN SIGNAL InternalBug[fusionData.name]; -- should never occur
FuseProperties[fusionData.mode, fused, root, fusionData.name];
fused.properties ← NIL; -- to help GC
[] ← RefTab.Store[fusionData.fused, fused, root];
};
StructuredFusion:
PROC [fusionData: FusionData, wire1, wire2: Wire]
RETURNS [wire: Wire] = {
wire1 ← RootWire[fusionData, wire1];
wire2 ← RootWire[fusionData, wire2];
IF wire1=wire2 THEN RETURN [wire1];
SELECT
TRUE
FROM
wire1=wire2 => wire ← wire1;
wire1.size=0 => {DeleteFused[fusionData, wire1, wire2]; wire ← wire2};
wire2.size=0 => {DeleteFused[fusionData, wire2, wire1]; wire ← wire1};
wire1.size=wire2.size => {
wire ← CreateRoot[fusionData, wire1.size];
FOR i:
NAT
IN [0 .. wire.size)
DO
wire[i] ← StructuredFusion[fusionData, wire1[i], wire2[i]];
ENDLOOP;
DeleteFused[fusionData, wire1, wire];
DeleteFused[fusionData, wire2, wire];
};
ENDCASE => SIGNAL FusionStructureMismatch[fusionData.name, wire1, wire2];
};
FindTouchingWires:
PROC [fusionData: FusionData, transformation: Transformation, geometry: Instances]
RETURNS [touchingWires:
LIST
OF Wire ←
NIL] = {
FOR insts: Instances ← geometry, insts.rest
WHILE insts#
NIL
DO
inst: Instance ← CoreGeometry.Transform[transformation, insts.first];
layers: LayerRange ← fusionData.mode.instanceLayer[inst];
rect: CD.Rect ← CoreGeometry.InlineBBox[inst];
InternalFindTouchingWires:
PROC [instance: Instance, value: InstanceTable.Value] = {
wire: Wire ← RootWire[fusionData, NARROW [value]];
IF ~RefTab.Fetch[fusionData.fused, wire].found THEN SIGNAL InternalBug[fusionData.name];
IF CoreOps.Member[touchingWires, wire] THEN RETURN;
IF fusionData.mode.touchProc[fusionData.mode.touchProc, instance, inst] THEN touchingWires ← CONS [wire, touchingWires];
};
FOR i:
NAT
IN [layers.min .. layers.max]
DO
InstanceTable.Enumerate[fusionData[i], InternalFindTouchingWires, rect];
ENDLOOP;
ENDLOOP;
};
Other Internal utilities
FusionGeometry:
PROC [fusionData: FusionData, transformation: Transformation, geometry: Instances, copyGeometry:
BOOL]
RETURNS [wire: Wire ←
NIL] = {
touchingWires: LIST OF Wire ← FindTouchingWires[fusionData, transformation, geometry];
IF touchingWires=
NIL
THEN {
wire ← CreateRoot[fusionData, 0];
InsertInstances[fusionData, transformation, geometry, wire, copyGeometry];
RETURN;
};
wire ← touchingWires.first;
InsertInstances[fusionData, transformation, geometry, wire, copyGeometry];
touchingWires ← touchingWires.rest;
WHILE touchingWires#
NIL
DO
fused: Wire ← touchingWires.first;
wire ← StructuredFusion[fusionData, fused, wire];
touchingWires ← touchingWires.rest;
ENDLOOP;
};
The complexity of this proc is partly due to the fact that we have a DAG
FusionWire:
PROC [fusionData: FusionData, dagTable: RefTab.Ref, public: Wire, transformation: Transformation, copyProps:
BOOL]
RETURNS [actual: Wire] = {
prevActual: Wire ← NARROW [RefTab.Fetch[dagTable, public].val];
structActual: Wire;
publicName: ROPE ← CoreOps.GetShortWireName[public];
pins: Instances ← CoreGeometry.GetPins[fusionData.mode.decoration, public];
IF prevActual#NIL THEN RETURN [prevActual];
structActual ← CreateRoot[fusionData, public.size, IF copyProps THEN public.properties ELSE NIL];
FOR i:
NAT
IN [0 .. public.size)
DO
structActual[i] ← FusionWire[fusionData, dagTable, public[i], transformation, copyProps];
ENDLOOP;
actual ←
IF pins=
NIL
THEN structActual
ELSE StructuredFusion[
fusionData, structActual,
FusionGeometry[fusionData, transformation, pins, copyProps]
];
IF copyProps AND publicName#NIL THEN AddNameWire[fusionData, publicName, actual];
[] ← RefTab.Store[dagTable, public, actual];
};
FusionWireSeq:
PROC [fusionData: FusionData, public: WireSeq, transformation: Transformation]
RETURNS [actual: Wire] = {
dagTable: RefTab.Ref ← RefTab.Create[3];
actual ← CoreOps.CreateWires[public.size];
FOR i:
NAT
IN [0 .. actual.size)
DO
actual[i] ← FusionWire[fusionData, dagTable, public[i], transformation, FALSE];
ENDLOOP;
};
Attention: modifies physically its argument!
SortInstances:
PROC [instances:
LIST
OF
CD.Instance]
RETURNS [sorted:
LIST
OF
CD.Instance ←
NIL] = {
Eval:
PROC [inst:
CD.Instance]
RETURNS [
INT] = {
pos: CD.Position ← CDBasics.BaseOfRect[CDInstances.InstRectI[inst]]; -- JMF : speedup
pos: CD.Position = CDBasics.BaseOfRect[CDBasicsInline.MapRect[CD.InterestRect[inst.ob], inst.trans]]; -- JMF: new version, slightly faster
RETURN [pos.x+pos.y];
};
Compare: GList.CompareProc = {
RETURN [Basics.CompareInt[Eval[NARROW [ref1]], Eval[NARROW [ref2]]]];
};
sorted ← NARROW [GList.Sort[instances, Compare]];
};
Cell and Abut Extraction
InitialOverlap:
PROC [bbox, nir:
CD.Rect]
RETURNS [overlap:
INT ← 0] = {
overlap ← UnionOverlap[overlap, bbox, [FIRST[INT], FIRST[INT], nir.x1, LAST[INT]]];
overlap ← UnionOverlap[overlap, bbox, [nir.x2, FIRST[INT], LAST[INT], LAST[INT]]];
overlap ← UnionOverlap[overlap, bbox, [FIRST[INT], FIRST[INT], LAST[INT], nir.y1]];
overlap ← UnionOverlap[overlap, bbox, [FIRST[INT], nir.y2, LAST[INT], LAST[INT]]];
};
UnionOverlap:
PROC [overlap:
INT, bbox, rect:
CD.Rect]
RETURNS [
INT] = {
interSize: CD.Position;
IF overlap*2>bbox.x2-bbox.x1 OR overlap*2>bbox.y2-bbox.y1 THEN RETURN [overlap];
interSize ← CDBasics.SizeOfRect[CDBasics.Intersection[rect, CDBasics.Extend[bbox, -overlap]]];
overlap ← MAX [overlap, MIN [interSize.x, interSize.y]];
IF overlap*2>bbox.x2-bbox.x1 OR overlap*2>bbox.y2-bbox.y1 THEN RETURN [overlap];
interSize ← CDBasics.SizeOfRect[CDBasics.Intersection[rect, CDBasics.Extend[bbox, -overlap]]];
overlap ← MAX [overlap, MIN [interSize.x, interSize.y]];
RETURN [overlap];
};
ExtractCell:
PUBLIC ExtractProc = {
ir: CD.Rect ← CD.InterestRect[obj];
cdInstances: LIST OF CD.Instance ← NIL;
nbOfInstances: INT = CDCells.CountInstances[obj];
fusionData: FusionData ← NEW [FusionDataRec[mode.nbOfLayers]];
currentInstances: LIST OF CoreClasses.CellInstance ← NIL;
EachInstance: CDCells.InstEnumerator = {cdInstances ← CONS [inst, cdInstances]};
time: BasicTime.GMT = BasicTime.Now[];
result ← SearchObjectCache[obj, mode, userData];
IF result#NIL THEN RETURN;
[] ← CDCells.EnumerateInstances[obj, EachInstance];
cdInstances ← SortInstances[cdInstances]; -- Modified in place!
fusionData.mode ← mode; fusionData.name ← mode.nameProc[obj, userData];
fusionData.nir ←
IF mode.fusionByName=none
THEN CDBasics.Extend[ir, - NARROW [userData, REF INT]^] ELSE ir;
fusionData.fused ← RefTab.Create[3]; fusionData.data ← NEW [LIST OF NameWire ← NIL]; fusionData.isAbut ← FALSE;
FOR i:
NAT
IN [0 .. mode.nbOfLayers)
DO
fusionData[i] ← InstanceTable.Create[range: obj.bbox];
ENDLOOP;
PutF["Extracting [%g] cell %g (bbox: %g, instances: %g)\n", IO.rope[IF mode.fusionByName=none THEN IO.PutFR["%g[%g]", IO.rope[mode.decoration.name], IO.int[NARROW [userData, REF INT]^]] ELSE mode.decoration.name], IO.rope[fusionData.name], rect[obj.bbox], IO.int[nbOfInstances]];
CDProperties.PutObjectProp[obj, satellitesProp, CDSatellites.GetSatelliteRopes[obj]]; -- to reinforce invariantes on the object (restriction of CDSatellites)
WHILE cdInstances#
NIL
DO
cdInstance: CD.Instance ← cdInstances.first;
subUserData: REF ← userData;
subResult: REF; subProps: Properties;
CDProperties.PutInstanceProp[cdInstance, satellitesProp, CDSatellites.GetSatelliteRopes[cdInstance]];
IF mode.fusionByName=none
THEN {
EachInstanceOverlap: CDCells.InstEnumerator = {
IF inst#cdInstance
THEN
overlap ← UnionOverlap[overlap, bbox, CDInstances.InstRectO[inst]];
};
Compute the right overlap of theses cells on this instance
bbox: CD.Rect ← CDInstances.InstRectI[cdInstance];
overlap: INT ← InitialOverlap[bbox, fusionData.nir];
[] ← CDCells.EnumerateInstances[obj, EachInstanceOverlap];
subUserData ← NEW [INT ← overlap];
};
[subResult, subProps] ← Extract[cdInstance.ob, mode, cdInstance.properties, subUserData];
IF subResult#
NIL
THEN
WITH subResult
SELECT
FROM
subWire: Wire => {
[] ← FusionWire[fusionData, RefTab.Create[1], subWire, cdInstance.trans, TRUE];
};
subWires: Wires => {
dagTable: RefTab.Ref ← RefTab.Create[3];
WHILE subWires#
NIL
DO
[] ← FusionWire[fusionData, dagTable, subWires.first, cdInstance.trans, TRUE];
subWires ← subWires.rest;
ENDLOOP;
};
subCellType: CellType => {
bbox: CD.Rect ← CDInstances.BoundingRectO[cdInstances.rest];
instance: CoreClasses.CellInstance ← CoreClasses.CreateInstance[
actual: FusionWireSeq[fusionData, subCellType.public, cdInstance.trans],
type: subCellType, props: subProps
];
it is impossible here to check for conformance, since fusion might have been done differently in different parts of the DAG
CoreGeometry.PutTrans[mode.decoration, instance, cdInstance.trans];
currentInstances ← CONS [instance, currentInstances];
We try to simplify fusionData by getting rid of all pieces of geometry which are outside the bounding box for sure
FOR i:
NAT
IN [0 .. mode.nbOfLayers)
DO
InstanceTable.DeleteOutside[fusionData[i], bbox];
ENDLOOP;
};
ENDCASE => SIGNAL InternalBug[fusionData.name];
cdInstances ← cdInstances.rest;
ENDLOOP;
Time to do fusion by name!
SELECT mode.fusionByName
FROM
layout => LayoutFusionByName[fusionData];
none => NoFusionByName[fusionData];
schematics => SchematicsFusionByName[fusionData];
ENDCASE => CallerBug[]; --no way to do fusionByName in this mode!
result ← MakeResult[fusionData, obj, currentInstances];
AddInCache[obj, mode, userData, result];
PutF["Extracted [%g] cell %g (%g sec.)\n", IO.rope[mode.decoration.name], IO.rope[fusionData.name], IO.int[BasicTime.Period[time, BasicTime.Now[]]]];
};
AbutFusionWire:
PROC [fusionData: FusionData, dagTable: RefTab.Ref, public: Wire, transformation: Transformation, subIr:
CD.Rect]
RETURNS [actual: Wire] = {
RecordEachPin: CoreGeometry.EachInstanceProc = {
sides: CoreGeometry.Sides ← CoreGeometry.GetSides[subIr, instance];
IF (~inX
AND sides[bottom])
OR (inX
AND sides[left])
THEN thesePins ← CONS [instance, thesePins];
IF (~inX
AND sides[top])
OR (inX
AND sides[right])
THEN {
inst: Instance ← CoreGeometry.Transform[transformation, instance];
layers: LayerRange ← mode.instanceLayer[inst];
FOR i: NAT IN [layers.min .. layers.max] DO InstanceTable.Insert[abutData[i], inst, structActual] ENDLOOP;
};
IF
NOT CoreGeometry.TransfedNotAtEdge[transformation, nir, instance]
THEN CoreProperties.PutWireProp[structActual, $Public, $Public];
};
prevActual: Wire ← NARROW [RefTab.Fetch[dagTable, public].val];
structActual: Wire;
abutData: AbutData ← NARROW [fusionData.data];
thesePins: Instances ← NIL; -- not transformed
mode: Mode ← fusionData.mode;
inX: BOOL ← abutData.inX;
nir: CD.Rect ← fusionData.nir;
IF prevActual#NIL THEN RETURN [prevActual];
structActual ← CreateRoot[fusionData, public.size];
[] ← CoreGeometry.EnumeratePins[fusionData.mode.decoration, public, RecordEachPin];
FOR i:
NAT
IN [0 .. public.size)
DO
structActual[i] ← AbutFusionWire[fusionData, dagTable, public[i], transformation, subIr];
ENDLOOP;
actual ←
IF thesePins=
NIL
THEN structActual
ELSE StructuredFusion[
fusionData, structActual,
FusionGeometry[fusionData, transformation, thesePins, FALSE]
];
[] ← RefTab.Store[dagTable, public, actual];
};
AbutFusionWireSeq:
PROC [fusionData: FusionData, public: WireSeq, transformation: Transformation, subIr:
CD.Rect]
RETURNS [actual: Wire] = {
dagTable: RefTab.Ref ← RefTab.Create[3];
actual ← CoreOps.CreateWires[public.size];
FOR i:
NAT
IN [0 .. actual.size)
DO
actual[i] ← AbutFusionWire[fusionData, dagTable, public[i], transformation, subIr];
ENDLOOP;
};
Attention! does not work for Raw Extraction.
ExtractAbut:
PUBLIC ExtractProc = {
ir: CD.Rect ← CD.InterestRect[obj];
range: CD.Rect ← obj.bbox;
fusionData: FusionData ← NEW [FusionDataRec[mode.nbOfLayers]];
abutData: AbutData ← NEW [AbutDataRec[mode.nbOfLayers]];
currentInstances: LIST OF CoreClasses.CellInstance ← NIL;
index: NAT ← 0;
time: BasicTime.GMT = BasicTime.Now[];
EachAbutSubObject:
PW.EachSubObjectProc = {
subIr: CD.Rect ← CD.InterestRect[subObject]; -- in the transformation coordonnate system
subResult: REF; subCellType: CellType; subProps: Properties;
instance: CoreClasses.CellInstance;
transformation: Transformation = [CDBasics.SubPoints[pos, CDBasics.BaseOfRect[subIr]]];
[subResult, subProps] ← Extract[subObject, mode, NIL, userData];
IF subResult=NIL THEN RETURN;
subCellType ← NARROW [subResult];
instance ← CoreClasses.CreateInstance[
actual: AbutFusionWireSeq[fusionData, subCellType.public, transformation, subIr],
type: subCellType, props: subProps
];
IF ~CoreOps.CorrectConform[instance.actual, subCellType.public] THEN SIGNAL StructureMismatch[fusionData.name, index, instance.actual, subCellType.public];
index ← index + 1;
FOR i:
NAT
IN [0 .. mode.nbOfLayers)
DO
table: InstanceTable.Table ← fusionData[i];
fusionData[i] ← abutData[i]; abutData[i] ← table;
InstanceTable.DeleteOutside[table, InstanceTable.empty];
ENDLOOP;
CoreGeometry.PutTrans[mode.decoration, instance, transformation];
currentInstances ← CONS [instance, currentInstances];
};
result ← SearchObjectCache[obj, mode, userData];
IF result#NIL THEN RETURN;
fusionData.mode ← mode; fusionData.name ← mode.nameProc[obj, userData]; fusionData.fused ← RefTab.Create[3]; fusionData.data ← abutData; fusionData.isAbut ← TRUE;
fusionData.nir ←
IF mode.fusionByName=none
THEN CDBasics.Extend[ir, - NARROW [userData, REF INT]^] ELSE ir;
abutData.inX ← obj.class=PW.abutXClass;
FOR i:
NAT
IN [0 .. mode.nbOfLayers)
DO
abutData[i] ← InstanceTable.Create[range: range];
ENDLOOP;
FOR i:
NAT
IN [0 .. mode.nbOfLayers)
DO
fusionData[i] ← InstanceTable.Create[range: range];
ENDLOOP;
PutF["Extracting [%g] abut %g (bbox: %g, instances: %g)\n", IO.rope[mode.decoration.name], IO.rope[fusionData.name], rect[obj.bbox], IO.int[PW.CountSubObjects[obj]]];
The main loop over "instances". Attention, we are assuming here that we are seing instances from left to right and bottom to top [this assumption is made in AbutFusionWire by the chosen sides]
[] ← PW.EnumerateSubObjects[obj, EachAbutSubObject];
result ← MakeResult[fusionData, obj, currentInstances];
AddInCache[obj, mode, userData, result];
PutF["Extracted [%g] abut %g (%g sec.)\n", IO.rope[mode.decoration.name], IO.rope[fusionData.name], IO.int[BasicTime.Period[time, BasicTime.Now[]]]];
FOR i:
NAT
IN [0 .. mode.nbOfLayers)
DO
InstanceTable.DeleteOutside[abutData[i], InstanceTable.empty];
ENDLOOP;
};
Extraction
Extract:
PUBLIC ExtractProc = {
instanceCache: InstanceCache ← NARROW [CDProperties.GetObjectProp[obj, instanceCacheProp]];
IF instanceCache#NIL AND instanceCache.mode=mode AND mode.instanceEqualProc[obj, instanceCache.properties, instanceCache.userData, properties, userData] THEN RETURN [result: instanceCache.result, props: instanceCache.props];
CDProperties.PutObjectProp[obj, satellitesProp, CDSatellites.GetSatelliteRopes[obj]];
BEGIN
priority: CedarProcess.Priority ← CedarProcess.GetPriority[];
atom: ATOM ← NARROW [CDProperties.GetListProp[properties, mode.extractProcProp]];
extractProc: ExtractProc;
IF atom=NIL THEN atom ← NARROW [CDProperties.GetObjectProp[obj, mode.extractProcProp]];
IF atom=NIL THEN atom ← NARROW [CDProperties.GetProp[obj.class, mode.extractProcProp]];
IF atom=
NIL
THEN extractProc ← ExtractExpand
ELSE {
refProc: REF ExtractProc ← NARROW [RefTab.Fetch[registeredExtractProcs, atom].val];
IF refProc=
NIL
THEN {
TerminalIO.PutF["*** ExtractProc $%g not registered. You must run the program defining it.\n", IO.atom[atom]]; SIGNAL CallerBug[];
};
extractProc ← refProc^;
};
CedarProcess.CheckAbort[];
CedarProcess.SetPriority[background];
Process.Yield[];
[result, props] ← extractProc[obj, mode, properties, userData];
We detect trivial causes of bugs!
WITH result
SELECT
FROM
wire: Wire => {};
wires: Wires => {};
cellType: CellType => IF NOT CoreGeometry.HasObject[mode.decoration, cellType] THEN SIGNAL CallerBug[]; -- decorations missing!
ENDCASE => IF result#NIL THEN SIGNAL CallerBug[]; -- probably some ExtractProc is grossly wrong
CedarProcess.SetPriority[priority];
CDProperties.PutObjectProp[obj, instanceCacheProp, NEW [InstanceCacheRec ← [mode: mode, properties: properties, userData: userData, result: result, props: props]]];
END;
};
registeredExtractProcs: RefTab.Ref ← RefTab.Create[];
RegisterExtractProc:
PUBLIC
PROC [key:
ATOM, extractProc: ExtractProc] = {
IF NOT RefTab.Store[registeredExtractProcs, key, NEW [ExtractProc ← extractProc]] THEN TerminalIO.PutF["ExtractProc overwritten for $%g.\n", IO.atom[key]];
};
ExtractRotation:
PUBLIC ExtractProc = {
specific: PW.RotationSpecific = NARROW [obj.specific];
trans: CD.Transformation = [[0, 0], specific.orientation];
result ← SearchObjectCache[obj, mode, userData];
IF result#NIL THEN RETURN;
[result, props] ← Extract[specific.obj, mode, properties, userData];
IF result=NIL THEN RETURN;
WITH result
SELECT
FROM
wire: Wire => {
newWire: Wire ← CoreOps.CopyWire[wire];
CoreGeometry.PutTransWireIRLazyPins[mode.decoration, newWire, wire, trans, CDBasics.universe];
result ← newWire;
};
wires: Wires => {
newWires: Wires ← NIL;
WHILE wires#
NIL
DO
newWire: Wire ← CoreOps.CopyWire[wires.first];
CoreGeometry.PutTransWireIRLazyPins[mode.decoration, newWire, wires.first, trans, CDBasics.universe];
newWires ← CONS [newWire, newWires];
wires ← wires.rest;
ENDLOOP;
result ← newWires;
};
cellType: CellType => {
public: Wire = CoreOps.CopyWire[cellType.public];
table: RefTab.Ref = CoreOps.CreateBindingTable[cellType.public, public];
newCellType: CellType = CoreClasses.CreatePermutedRecordCell[public, cellType, table, mode.nameProc[obj, userData]];
rct: CoreClasses.RecordCellType = NARROW [newCellType.data];
PutF["Extracting [%g] rotation %g (bbox: %g)\n", IO.rope[mode.decoration.name], IO.rope[mode.nameProc[obj, userData]], rect[obj.bbox]];
CoreGeometry.PutTrans[mode.decoration, rct[0], trans];
CoreGeometry.PutObject[mode.decoration, newCellType, obj];
CoreGeometry.PutRecordLazyPins[mode.decoration, newCellType, CD.InterestRect[obj]];
result ← newCellType;
AddInCache[obj, mode, userData, result];
};
ENDCASE => ERROR;
};
ExtractExpand:
PUBLIC ExtractProc = {
newObj: CD.Object ← CDDirectory.Expand1[obj, NIL, NIL].new;
PutF["Expanding [%g] object %g of class %g\n", IO.rope[mode.decoration.name], IO.rope[mode.nameProc[obj, userData]], IO.atom[obj.class.objectType]];
IF newObj=NIL THEN SIGNAL CallerBug[]; -- no expand proc found for this object that we do not know how to extract!
RETURN Extract[newObj, mode, CDProperties.DAppendProps[obj.properties, properties], userData];
};
OrNames:
PROC [name1, name2, objName:
ROPE]
RETURNS [name:
ROPE ←
NIL] = {
IF name1=NIL THEN RETURN [name2];
IF name2=NIL THEN RETURN [name1];
IF Rope.Equal[name1, name2] THEN RETURN [name1];
SIGNAL FusionPropMismatch[objName, CoreOps.nameProp, name1, name2];
};
NameFromSatellites:
PUBLIC
PROC [obj: Object, properties:
CD.PropList]
RETURNS [name:
ROPE ←
NIL] = {
name ← NARROW [CDProperties.GetListProp[properties, $SignalName]];
FOR ropes:
ROPES ←
NARROW [CDProperties.GetListProp[properties, satellitesProp]], ropes.rest
WHILE ropes#NIL DO name ← OrNames[name, ropes.first, CD.Describe[obj]] ENDLOOP;
FOR ropes:
ROPES ←
NARROW [CDProperties.GetObjectProp[obj, satellitesProp]], ropes.rest
WHILE ropes#NIL DO name ← OrNames[name, ropes.first, CD.Describe[obj]] ENDLOOP;
};
ExtractRect:
PUBLIC ExtractProc = {
wire: Wire;
IF obj.layer=CD.shadeLayer OR obj.layer=CD.errorLayer OR obj.layer=CD.backgroundLayer OR obj.layer=CD.outlineLayer OR obj.layer=CD.selectionLayer OR obj.layer=CD.commentLayer THEN RETURN [NIL];
wire ← CoreOps.CreateWire[name: NameFromSatellites[obj, properties]];
CoreGeometry.PutPins[mode.decoration, wire, LIST [[obj]]];
result ← wire;
};
ExtractPin:
PUBLIC ExtractProc = {
wire: Wire;
instance: CD.Instance ← CDInstances.NewInst[ob: obj, properties: properties];
layer: CD.Layer = CDSymbolicObjects.GetLayer[instance];
pinName: ROPE ← CDSymbolicObjects.GetName[instance];
IF NOT Rope.Equal[NameFromSatellites[obj, properties], pinName] THEN SIGNAL CallerBug[];
IF layer=CD.undefLayer THEN SIGNAL CallerBug[];
wire ← CoreOps.CreateWire[name: pinName];
CoreGeometry.PutPins[mode.decoration, wire, LIST [[CoreGeometry.CDPinToCoreGeometryPin[obj, properties]]]];
result ← wire;
};
ExtractAtomic:
PUBLIC ExtractProc = {
wire: Wire;
wire ← CoreOps.CreateWire[name: NameFromSatellites[obj, properties]];
CoreGeometry.PutPins[mode.decoration, wire, LIST [[obj]]];
result ← wire;
};
ExtractWellAtomic:
PUBLIC ExtractProc = {
wellLayer: CD.Layer = CDLayers.layerData[obj.layer].well;
paintLayer: CD.Layer = CDLayers.layerData[obj.layer].paint;
newObj: CD.Object ← NIL;
AddEachSubAtomic: CoreGeometry.EachInstanceProc = {
SELECT
TRUE
FROM
instance.obj.class=CDRects.bareRectClass AND instance.obj.layer=wellLayer => CoreGeometry.AddPins[mode.decoration, wellWire, LIST [instance]];
instance.obj.class=CDRects.bareRectClass => {};
ENDCASE => quit ← CoreGeometry.FlattenInstance[instance, AddEachSubAtomic];
};
paintWire, wellWire: Wire;
wires: Wires;
paintWire ← CoreOps.CreateWire[name: NameFromSatellites[obj, properties]];
wellWire ← CoreOps.CreateWire[];
[] ← CoreGeometry.FlattenInstance[[obj], AddEachSubAtomic];
Hack, hack, hack
newObj ←
IF obj.class=CDRects.wellRectClass
THEN CDRects.CreateRect[CD.InterestSize[obj], paintLayer]
ELSE CDAtomicObjects.CreateAtomicOb[obj.class.objectType, CD.InterestSize[obj], CD.LayerTechnology[obj.layer], paintLayer];
IF newObj=NIL THEN ERROR;
CoreGeometry.AddPins[mode.decoration, paintWire, LIST [[obj: newObj]]];
wires ← LIST [paintWire, wellWire];
result ← wires;
};
ExtractTransistor:
PUBLIC ExtractProc = {
Decorate:
PROC [port: CoreClasses.TransistorPort, geom: Saguaro.Geom] = {
instances: Instances = CoreGeometry.DrawListToInstances[geom.layout];
wire: Wire = cellType.public[ORD [port]];
CoreGeometry.PutPins[mode.decoration, wire, instances];
CoreGeometry.PutGeometry[mode.decoration, wire, instances];
};
et: Saguaro.ExtractedTransistor;
type: CoreClasses.TransistorType;
cellType: CellType;
result ← SearchObjectCache[obj, mode, userData];
IF result#NIL THEN RETURN;
et ← Saguaro.ExtractTransistor[obj];
type ←
SELECT et.type
FROM
nE => nE, pE => pE, ENDCASE => ERROR;
cellType ← CoreClasses.CreateTransistor[
type: type, length: et.length, width: et.width,
props: CoreProperties.Props[[CoreOps.nameProp, NameFromSatellites[obj, properties]]]
];
Decorate[gate, et.gate];
Decorate[ch1, et.ch1];
Decorate[ch2, et.ch2];
IF et.bulk.layout#NIL THEN Decorate[Vdd, et.bulk];
CoreGeometry.PutObject[mode.decoration, cellType, obj];
result ← cellType;
AddInCache[obj, mode, userData, result];
};
LazyPinsEnumerate: CoreGeometry.LazyEnumerateProc = {
node: CDRoutingObjects.Node ← NARROW [data1];
rir: REF CD.Rect ← NARROW [data2];
FOR i:
NAT
IN [0 .. node.size)
DO
instance: CoreGeometry.Instance = [node[i].object, [node[i].position]];
IF CoreGeometry.AtEdge[rir^, instance] THEN quit ← eachInstance[instance];
IF quit THEN RETURN;
ENDLOOP;
};
LazyGeometryEnumerate: CoreGeometry.LazyEnumerateProc = {
node: CDRoutingObjects.Node ← NARROW [data1];
FOR i:
NAT
IN [0 .. node.size)
DO
quit ← eachInstance[[node[i].object, [node[i].position]]];
IF quit THEN RETURN;
ENDLOOP;
};
ExtractRouting:
PUBLIC ExtractProc = {
cellType: CellType;
routing: CDRoutingObjects.RoutingSpecific = NARROW [obj.specific];
publics: LIST OF Wire ← NIL;
result ← SearchObjectCache[obj, mode, userData];
IF result#NIL THEN RETURN;
PutF["Extracting [%g] routing %g (nodes: %g)\n", IO.rope[mode.decoration.name], IO.rope[mode.nameProc[obj, userData]], IO.int[routing.size]];
We check if none of the objects contains well, and expand if not
FOR i:
NAT
IN [0 .. routing.size)
DO
node: CDRoutingObjects.Node = routing[i];
FOR j:
NAT
IN [0 .. node.size)
DO
IF CDLayers.layerData[node[j].object.layer].well#
CD.undefLayer
THEN {
PutF["Routing cell %g containing well is expanded.\n", IO.rope[mode.nameProc[obj, userData]]];
RETURN Extract[CDDirectory.Expand1[obj].new, mode, properties, userData]
};
ENDLOOP;
ENDLOOP;
FOR i:
NAT
IN [0 .. routing.size)
DO
node: CDRoutingObjects.Node = routing[i];
name: ROPE = NARROW [CDProperties.GetListProp[node.properties, $SignalName]];
wire: Wire ← CoreOps.CreateWire[name: name];
CoreGeometry.PutLazyGeometry[mode.decoration, wire, LazyGeometryEnumerate, node];
CoreGeometry.PutLazyPins[mode.decoration, wire, LazyPinsEnumerate, node, NEW [CD.Rect ← routing.ir]];
publics ← CONS [wire, publics];
ENDLOOP;
We build the CellType
cellType ← CoreClasses.CreateRecordCell[
public: CoreOps.CreateWire[publics],
internal: CoreOps.CreateWire[publics],
instances: NIL,
name: mode.nameProc[obj, userData]
];
CoreGeometry.PutObject[mode.decoration, cellType, obj];
result ← cellType;
AddInCache[obj, mode, userData, result];
};
TileInstanceArray: TYPE = REF TileInstanceArrayRec;
TileInstanceArrayRec: TYPE = RECORD [c: SEQUENCE sizeY: NAT OF TileInstanceLine];
TileInstanceLine: TYPE = REF TileInstanceLineRec;
TileInstanceLineRec: TYPE = RECORD [c: SEQUENCE sizeX: NAT OF TileInstance];
TileInstance:
TYPE =
RECORD [
instance: CoreClasses.CellInstance,
table: RefTab.Ref -- maps sub publics to actuals
TilingRoot:
PROC [fused: RefTab.Ref, wire: Wire]
RETURNS [root: Wire] = {
IF wire=NIL THEN ERROR;
root ← NARROW [RefTab.Fetch[fused, wire].val];
IF root=
NIL
THEN {
FOR i: NAT IN [0 .. wire.size) DO wire[i] ← TilingRoot[fused, wire[i]] ENDLOOP;
RETURN [wire];
};
IF root=wire THEN ERROR;
root ← TilingRoot[fused, root];
[] ← RefTab.Replace[fused, wire, root];
};
TilingFuse:
PROC [fused: RefTab.Ref, wire1, wire2: Wire] = {
root1: Wire = TilingRoot[fused, wire1];
root2: Wire = TilingRoot[fused, wire2];
IF root1=root2 THEN RETURN;
IF root1.size#root2.size THEN ERROR;
[] ← RefTab.Store[fused, root1, root2];
};
FuseNeighbors:
PROC [mode: Mode, fused: RefTab.Ref, inX:
BOOL, ti1, ti2: TileInstance, cache: RefTab.Ref] = {
FOR list:
LIST
OF CoreGeometry.WirePair ← CoreGeometry.CachedEnumerateNeighbors[mode.decoration, mode.touchProc, inX, ti1.instance.type, ti2.instance.type, cache], list.rest
WHILE list#
NIL
DO
act1: Wire = NARROW [RefTab.Fetch[ti1.table, list.first.wire1].val];
act2: Wire = NARROW [RefTab.Fetch[ti2.table, list.first.wire2].val];
IF act1=NIL OR act2=NIL THEN ERROR;
TilingFuse[fused, act1, act2];
ENDLOOP;
};
Attention! does not work for Raw Extraction.
ExtractTiling:
PUBLIC ExtractProc = {
ExtractEachTile:
PW.EachTileProc = {
subIr: CD.Rect ← CD.InterestRect[tile]; -- in the transformation coordonnate system
trans: Transformation = [CDBasics.SubPoints[pos, CDBasics.BaseOfRect[subIr]]];
subCT: CellType ← NARROW [Extract[tile, mode, NIL, userData].result];
table: RefTab.Ref ← RefTab.Create[subCT.public.size+2];
actual: WireSeq ← CoreOps.CopyWireUsingTable[subCT.public, table, FALSE];
tileInstances[y][x].instance ← CoreClasses.CreateInstance[actual: actual, type: subCT];
tileInstances[y][x].table ← table;
CoreGeometry.PutTrans[mode.decoration, tileInstances[y][x].instance, trans];
};
FixUpEachTile:
PW.EachTileProc = {
AddToPublics: CoreOps.EachWirePairProc = {
EachInstance: CoreGeometry.EachInstanceProc = {
quit ← NOT CoreGeometry.TransfedNotAtEdge[trans, ir, instance];
};
IF CoreGeometry.EnumeratePins[mode.decoration, publicWire, EachInstance]
THEN [] ← RefTab.Store[publics, TilingRoot[fused, actualWire], NIL];
};
subIr: CD.Rect ← CD.InterestRect[tile]; -- in the transformation coordonnate system
trans: Transformation = [CDBasics.SubPoints[pos, CDBasics.BaseOfRect[subIr]]];
instance: CoreClasses.CellInstance ← tileInstances[y][x].instance;
actual: Wire ← instance.actual;
strictlyInside: BOOL ← CDBasics.Inside[CoreGeometry.BBox[[tile, trans]], insideIR];
FOR i:
NAT
IN [0 .. actual.size)
DO
wire: Wire ← TilingRoot[fused, actual[i]];
[] ← RefTab.Store[internals, wire, NIL];
IF ~CoreOps.CorrectConform[wire, instance.type.public[i]]
THEN SIGNAL StructureMismatch[name, i, actual, instance.type.public];
actual[i] ← wire;
ENDLOOP;
IF NOT strictlyInside THEN [] ← CoreOps.VisitBindingSeq[instance.actual, instance.type.public, AddToPublics];
instances ← CONS [instance, instances];
};
ir: CD.Rect = CD.InterestRect[obj];
insideIR: CD.Rect = CDBasics.Extend[ir, -1];
cellType: CellType;
tileInstances: TileInstanceArray;
sizeX, sizeY: NAT;
cache: RefTab.Ref ← CoreGeometry.CreateNeighborsCache[];
fused: RefTab.Ref ← RefTab.Create[];
publics: RefTab.Ref ← RefTab.Create[];
internals: RefTab.Ref ← RefTab.Create[];
instances: LIST OF CoreClasses.CellInstance ← NIL;
name: ROPE = mode.nameProc[obj, userData];
time: BasicTime.GMT = BasicTime.Now[];
result ← SearchObjectCache[obj, mode, userData];
IF result#NIL THEN RETURN;
[sizeX, sizeY] ← PW.GetTilingSize[obj];
PutF["Extracting [%g] tiling %g (size: %g*%g)\n", IO.rope[mode.decoration.name], IO.rope[name], IO.int[sizeX], IO.int[sizeY]];
tileInstances ← NEW [TileInstanceArrayRec[sizeY]];
FOR y:
NAT
IN [0 .. sizeY)
DO
tileInstances[y] ← NEW [TileInstanceLineRec[sizeX]];
ENDLOOP;
We extract sub objects and build instances
[] ← PW.EnumerateTiles[obj, ExtractEachTile];
We fuse neighbors
FOR y:
NAT
IN [0 .. sizeY)
DO
FOR x:
NAT
IN [1 .. sizeX)
DO
FuseNeighbors[mode, fused, TRUE, tileInstances[y][x-1], tileInstances[y][x], cache];
ENDLOOP;
ENDLOOP;
cache ← CoreGeometry.CreateNeighborsCache[];
FOR x:
NAT
IN [0 .. sizeX)
DO
FOR y:
NAT
IN [1 .. sizeY)
DO
FuseNeighbors[mode, fused, FALSE, tileInstances[y-1][x], tileInstances[y][x], cache];
ENDLOOP;
ENDLOOP;
We replace in all instances wires by their roots, and accumulate instances, publics and internals
[] ← PW.EnumerateTiles[obj, FixUpEachTile];
We build the CellType
cellType ← CoreClasses.CreateRecordCell[
public: CreateDAGWireSeq[publics],
internal: CreateDAGWireSeq[internals],
instances: instances,
name: name
];
We set all pins to be lazy for that record
CoreGeometry.PutRecordLazyPins[mode.decoration, cellType, ir];
CoreGeometry.PutObject[mode.decoration, cellType, obj];
We fill the object cache
PutF["Extracted [%g] tiling %g (%g sec.)\n", IO.rope[mode.decoration.name], IO.rope[name], IO.int[BasicTime.Period[time, BasicTime.Now[]]]];
result ← cellType;
AddInCache[obj, mode, userData, result];
};
ExtractIndirect:
PUBLIC ExtractProc = {
CopyPins: CoreOps.EachWirePairProc = {
CoreGeometry.PutIndirectLazyPins[mode.decoration, actualWire, publicWire];
};
indObj: CD.Object = NARROW [obj.specific];
indCT, icon: CellType;
result ← SearchObjectCache[obj, mode, userData];
IF result#NIL THEN RETURN;
[result, props] ← Extract[indObj, mode, CDProperties.DAppendProps[obj.properties, properties], userData];
indCT ← NARROW [result];
icon ← CreateIcon[indCT];
CoreGeometry.PutObject[mode.decoration, icon, obj];
[] ← CoreOps.VisitBindingSeq[actual: icon.public, public: indCT.public, eachWirePair: CopyPins];
result ← icon;
AddInCache[obj, mode, userData, result];
};
ExtractCellAsWire:
PUBLIC ExtractProc = {
wire: Wire ← CoreOps.CreateWire[];
CoreGeometry.PutPins[mode.decoration, wire, LIST [[obj]]];
result ← wire;
};
ExtractNull: PUBLIC ExtractProc = {result ← NIL};
Lazy Extraction
lazyExtractClass:
PUBLIC Core.CellClass ←
NEW [Core.CellClassRec ← [name: "LazyExtract", recast: RecastLazyExtract]];
LazyExtractData: TYPE = REF LazyExtractDataRec;
LazyExtractDataRec:
TYPE =
RECORD [
obj: Object,
mode: Mode,
properties: CD.PropList ← NIL,
userData: REF ← NIL
];
CreateLazyExtract:
PUBLIC
PROC [public: WireSeq, obj: Object, mode: Mode, properties:
CD.PropList ←
NIL, userData:
REF ←
NIL]
RETURNS [cellType: CellType] = {
cellType ← CoreOps.CreateCellType[
class: lazyExtractClass,
public: public,
data: NEW [LazyExtractDataRec ← [obj: obj, mode: mode, properties: properties, userData: userData]]];
CoreGeometry.PutObject[mode.decoration, cellType, obj];
};
RecastLazyExtract: Core.RecastProc = {
data: LazyExtractData ← NARROW [me.data];
atom: ATOM ← NARROW [CDProperties.GetProp[data.obj.class, data.mode.extractProcProp]];
extractProc: ExtractProc ← IF atom=NIL THEN ExtractExpand ELSE NARROW [RefTab.Fetch[registeredExtractProcs, atom].val, REF ExtractProc]^;
ect: CellType ← NARROW [extractProc[data.obj, data.mode, data.properties, data.userData].result];
extractedToSource: RefTab.Ref ← MapExtractedToSource[me.public, ect.public, data.obj, data.mode];
permuted: CellType ← CoreClasses.CreatePermutedRecordCell[me.public, ect, extractedToSource];
CoreGeometry.PutTrans[data.mode.decoration, NARROW [permuted.data, CoreClasses.RecordCellType][0], []];
RETURN [permuted];
};
DecorateObjectWithLazyExtract:
PUBLIC
PROC [public: WireSeq, obj: Object, mode: Mode, properties:
CD.PropList ←
NIL, userData:
REF ←
NIL] = {
CDProperties.PutObjectProp[obj, mode.extractProcProp, $LazyExtract];
CDProperties.PutObjectProp[obj, $LazyExtractResult, CreateLazyExtract[public, obj, mode, properties, userData]];
};
LazyExtract: ExtractProc = {
result ← CDProperties.GetObjectProp[obj, $LazyExtractResult];
};
PinsCorrespondingToSeveralPublics:
PUBLIC
SIGNAL [obj: Object, public1, public2: Wire, name1, name2:
ROPE, geometry: CoreGeometry.Instances] =
CODE;
InstanceTableFromPublic:
PUBLIC
PROC [decoration: CoreGeometry.Decoration, bbox:
CD.Rect, public: WireSeq]
RETURNS [table: InstanceTable.Table] = {
FillInstanceTable:
PROC [wire: Core.Wire] = {
AddPinInTable: CoreGeometry.EachInstanceProc = {
InstanceTable.Insert[table, instance, wire];
};
[] ← CoreGeometry.EnumeratePins[decoration, wire, AddPinInTable];
};
table ← InstanceTable.Create[bbox];
CoreOps.VisitRootAtomics[public, FillInstanceTable];
};
MapExtractedToSource:
PUBLIC
PROC [source, extracted: WireSeq, obj: Object, mode: Mode]
RETURNS [extractedToSource: RefTab.Ref] = {
FillTable:
PROC [sourcePublic: Core.Wire] = {
EachSourcePin: CoreGeometry.EachInstanceProc = {
Action:
PROC [extractedInstance: CoreGeometry.Instance, value: InstanceTable.Value] = {
extractedWire: Core.Wire = NARROW [value];
prevSource: Core.Wire ← NARROW [RefTab.Fetch[extractedToSource, extractedWire].val];
IF prevSource=sourcePublic THEN RETURN; -- already considered
IF
NOT mode.touchProc[mode.touchProc, instance, extractedInstance]
THEN RETURN;
IF prevSource#
NIL
THEN
SIGNAL PinsCorrespondingToSeveralPublics[
obj, prevSource, sourcePublic,
CoreOps.GetFullWireName[source, prevSource],
CoreOps.GetFullWireName[source, sourcePublic],
LIST [instance, extractedInstance]
];
[] ← RefTab.Store[extractedToSource, extractedWire, sourcePublic];
};
InstanceTable.Enumerate[extractedInstances, Action, CoreGeometry.BBox[instance]];
};
[] ← CoreGeometry.EnumeratePins[mode.decoration, sourcePublic, EachSourcePin];
};
extractedInstances: InstanceTable.Table; -- table instance -> extractedPublic
extractedToSource ← RefTab.Create[]; -- maps extractedWire to source
extractedInstances ← InstanceTableFromPublic[mode.decoration, obj.bbox, extracted];
CoreOps.VisitRootAtomics[source, FillTable];
};
Initialization
numbers:
ARRAY [0..256)
OF
ROPE;
--
JMF: speedup hack for SchematicsFusionByName
FOR i:
NAT
IN [0..256)
DO numbers[i] ←
IO.PutR1[
IO.int[i]]
ENDLOOP;
RegisterExtractProc[$ExtractCell, ExtractCell];
RegisterExtractProc[$ExtractAbut, ExtractAbut];
RegisterExtractProc[$ExtractRotation, ExtractRotation];
RegisterExtractProc[$ExtractExpand, ExtractExpand];
RegisterExtractProc[$ExtractRect, ExtractRect];
RegisterExtractProc[$ExtractPin, ExtractPin];
RegisterExtractProc[$ExtractAtomic, ExtractAtomic];
RegisterExtractProc[$ExtractWellAtomic, ExtractWellAtomic];
RegisterExtractProc[$ExtractTransistor, ExtractTransistor];
RegisterExtractProc[$ExtractRouting, ExtractRouting];
RegisterExtractProc[$ExtractTiling, ExtractTiling];
RegisterExtractProc[$ExtractIndirect, ExtractIndirect];
RegisterExtractProc[$ExtractCellAsWire, ExtractCellAsWire];
RegisterExtractProc[$ExtractNull, ExtractNull];
RegisterExtractProc[$LazyExtract, LazyExtract];