DIRECTORY
CD, CDBasics, CDCells, CDDirectory, CDInstances, CDPinObjects, CDProperties, CDRects, CDTexts, Core, CoreClasses, CoreCompose, CoreOps, CoreProperties, PWPins, RefTab, Rope, SEX, SymTab, PWObjects;
SEXImpl:
CEDAR
PROGRAM
IMPORTS CDBasics, CDCells, CDInstances, CDPinObjects, CDProperties, CDRects, CoreClasses, CoreCompose, CoreOps, CoreProperties, PWPins, RefTab, Rope, SEX
EXPORTS SEX
SHARES CDDirectory, CDRects, CDPinObjects =
BEGIN OPEN SEX;
Extraction Procedures
ExtractInst:
PUBLIC ExtractInstProc = {
-- Look for an extract proc on the instance, then the object, then the class
refProc: REF ExtractInstProc ← NARROW [CDProperties.GetPropFromInstance[inst, extractObjProcProp]];
IF refProc=NIL THEN refProc ← NARROW [CDProperties.GetPropFromObject[inst.ob, extractObjProcProp]];
IF refProc=NIL THEN refProc ← NARROW [CDProperties.GetProp[inst.ob.class, extractObjProcProp]];
[cellType, ] ← IF refProc#NIL THEN refProc^[inst, context] ELSE DefaultExtractInst[inst, context];
};
DefaultExtractInst: ExtractInstProc = {
};
ExtractCell: ExtractInstProc = {
cellPtr: CD.CellPtr ← NARROW[inst.ob.specificRef];
cdInsts, subCells: CD.InstanceList;
public, internal: Wire;
wires, publics, internals: LIST OF Wire;
data: CoreClasses.RecordCellType;
cdInsts ← cellPtr.contents;
-- Pass 0: Produces a RefTab.Ref binding every instance to a wire, a list of wires, and a list of subCells; not clear we need the table anymore!
-- On the wire are found pins and all the geometry composing it
[wires, subCells] ← ConnectivitySearch[cdInsts];
-- Pass 1: create internal wires, def or implicit, and put actuals as props on the internal pins of the subcells
[internals, publics] ← MakeWires[wires, subCells, context];
-- Pass 2: treat the wires only used (parts of already defined wires)
FinishWires[wires, subCells, context, internals, publics];
internal ← CoreOps.CreateRecordWire[components: internals];
public ← CoreOps.CreateRecordWire[components: publics];
-- Pass 3: now all wires exist, and all pins of internal cells are decorated with actuals
-- Create instances
data ←
NEW[CoreClasses.RecordCellTypeRec ← [
internal: internal,
instances: MakeInstances[subCells, context]]];
cellType ←
NEW[Core.CellTypeRec ← [
name: cellPtr.name,
class: CoreClasses.recordCellClass,
public: public,
data: data]];
};
-- Pass 0
-- Brute force! The table associates with each instance a ref: this ref is either another entry in the table (CD.Instance), or a Wire if this instance is a root
ConnectivitySearch:
PROC [cdInsts:
CD.InstanceList]
RETURNS [wires:
LIST
OF Wire, subCells:
CD.InstanceList ←
NIL] = {
CreateListOfWiresProc: RefTab.EachPairAction = {
IF ISTYPE[val, Wire] THEN wires ← CONS[NARROW[val], wires];
quit ← FALSE;
};
connectTab: RefTab.Ref ← RefTab.Create[]; -- [key: CD.Instance, val: some instance connected to it]
-- Take a look at all instances, create a wire and decorate it with pins and geometry
FOR l:
CD.InstanceList ← cdInsts, l.rest
WHILE l#
NIL
DO
inst: CD.Instance ← l.first;
wire: Wire ← NEW[Core.WireRec];
IF ~IsCell[inst]
THEN
-- first, every wire or pin is its own root
[] ← RefTab.Store[connectTab, inst, wire];
SELECT
TRUE
FROM
IsPin[inst] => {
AddPinPropOnWire[wire, inst];
AddWireGeometryPropOnWire[wire, inst];
};
IsRectangle[inst] => {
AddWireGeometryPropOnWire[wire, inst];
};
IsCell[inst] => {
-- add the pins of the cell as geometry only
cell: CD.Instance ← inst; -- to avoid name conflict
EachPin: PWPins.InstanceEnumerator = {
AddWireGeometryPropOnWire[wire, PWPins.TransformInstance[inst, cell.ob.size, cell.location, cell.orientation]];
};
[] ← PWPins.EnumerateEdgePins[cell.ob, EachPin];
subCells ← CONS[cell, subCells];
};
ENDCASE => ERROR; -- what could inst be?
ENDLOOP;
-- Now the O(n2) part
FOR l1:
CD.InstanceList ← cdInsts, l1.rest
WHILE l1#
NIL
DO
inst1: CD.Instance ← l1.first;
FOR l2:
CD.InstanceList ← l1.rest, l2.rest
WHILE l2#
NIL
DO
inst2: CD.Instance ← l2.first;
IF Touch[inst1, inst2]
THEN {
root1: CD.Instance ← Root[connectTab, inst1];
root2: CD.Instance ← Root[connectTab, inst2];
wire1: Wire ← RootWire[connectTab, inst1];
wire2: Wire ← RootWire[connectTab, inst2];
MergeWireInfo[wire1, wire2];
[] ← RefTab.Store[connectTab, root2, root1]; -- both now point to wire1
};
ENDLOOP;
ENDLOOP;
-- Now make a list of all wires
[] ← RefTab.Pairs[connectTab, CreateListOfWiresProc];
};
-- Pass 1
-- A wire is a set of rectangles and pins connected together; its name and structure can be defined (once) by a satellite of the form "def: foo", where "def" is reserved;
-- An undefined wire is atomic unnamed.
MakeWires:
PROC [wires:
LIST
OF Wire, subCells:
CD.InstanceList, context: Context]
RETURNS [publics, internals:
LIST
OF Wire] = {
def, use: ROPE; outPins, inPins: CD.InstanceList;
FOR l:
LIST
OF Wire ← wires, l.rest
WHILE l#
NIL
DO
wire: Wire ← l.first;
newWire: Wire;
[def, use, outPins, inPins] ← InfoOnWire[wire, context];
IF Rope.Equal[def, NIL] OR ~Rope.Equal[use, NIL] THEN RETURN; -- for pass 2
IF ~Rope.Equal[def, NIL] AND ~Rope.Equal[use, NIL] THEN ERROR; -- et alors?
-- Create Internal
newWire ← CoreCompose.CreateWires[context, def]; -- hope it works for def=""
internals ← CONS[newWire, internals];
IF outPins#NIL THEN publics ← CONS[newWire, publics];
IF inPins#NIL THEN AttachWireAsActualOnEachInPin[newWire, inPins];
wire ← NIL; -- somehow, I have to take it out for pass 2
ENDLOOP;
};
-- Pass 2
-- Now using exisiting wires for making actuals
FinishWires:
PROC [wires:
LIST
OF Wire, subCells:
CD.InstanceList, context: Context, publics, internals:
LIST
OF Wire] = {
def, use: ROPE; outPins, inPins: CD.InstanceList;
FOR l:
LIST
OF Wire ← wires, l.rest
WHILE l#
NIL
DO
wire: Wire ← l.first;
subWire: Wire;
[def, use, outPins, inPins] ← InfoOnWire[wire, context];
IF outPins=NIL AND inPins=NIL THEN ERROR;
-- There is a use for sure
subWire ← FindSubWire[internals]; -- use CoreCompose
IF outPins#NIL THEN publics ← CONS[subWire, publics];
IF inPins#NIL THEN AttachWireAsActualOnEachInPin[subWire, inPins];
ENDLOOP;
};
-- Recursive call to get the cellType of subcells
MakeInstances:
PROC [subCells:
CD.InstanceList, context: Context]
RETURNS [instances: CoreClasses.CellInstanceList] = {
FOR l:
CD.InstanceList ← subCells, l.rest
WHILE l#
NIL
DO
instances ← CONS[MakeInstance[l.first, context], instances];
ENDLOOP;
};
MakeInstance:
PROC [cell:
CD.Instance, context: Context]
RETURNS [instance: CoreClasses.CellInstance]= {
};
AttachWireAsActualOnEachInPin:
PROC [wire: Wire, inPins:
CD.InstanceList] = {
};
FindSubWire:
PROC [wires:
LIST
OF Wire]
RETURNS [wire: Wire] = {
};
InfoOnWire:
PROC [wire: Wire, context: Context]
RETURNS [def, use:
ROPE, outPins, inPins:
CD.InstanceList] = {
outPins ← GetPinPropFromWire[wire];
};
MergeWireInfo:
PROC [winner, looser: Wire] = {
AppendPinPropOnWire[winner, GetPinPropFromWire[looser]];
AppendWireGeometryPropOnWire[winner, GetWireGeometryPropFromWire[looser]];
};
-- The val in the table; NIL if not found
Up:
PROC [table: RefTab.Ref, ref:
REF]
RETURNS [up:
REF ←
NIL] = {
up ← RefTab.Fetch[table, ref].val};
RootWire:
PROC [table: RefTab.Ref, inst:
CD.Instance]
RETURNS [wire: Wire] = {
wire ← NARROW[Up[table, Root[table, inst]]];
};
-- The root, i.e. the last Up[Up[...[inst]...]] whose val is a wire
Root:
PROC [table: RefTab.Ref, inst:
CD.Instance]
RETURNS [root:
CD.Instance] = {
ref: REF ← inst;
up: REF ← Up[table, ref];
WHILE ~ISTYPE[up, Wire] DO ref ← up; up ← Up[table, ref]; ENDLOOP;
root ← NARROW[ref];
};
Operations for an easy management of properties
GetPinPropFromWire:
PUBLIC
PROC [wire: Wire]
RETURNS [pins:
LIST
OF
CD.Instance] = {
pins ← NARROW [CoreProperties.GetWireProp[wire, pinsProp]];
};
PutPinPropOnWire:
PUBLIC
PROC [wire: Wire, pins:
LIST
OF
CD.Instance] = {
CoreProperties.PutWireProp[wire, pinsProp, pins];
};
AddPinPropOnWire:
PUBLIC
PROC [wire: Wire, pin:
CD.Instance] = {
pins: LIST OF CD.Instance ← CONS [pin, NARROW [CoreProperties.GetWireProp[wire, pinsProp]]];
CoreProperties.PutWireProp[wire, pinsProp, pins];
};
AppendPinPropOnWire:
PUBLIC
PROC [wire: Wire, pins:
LIST
OF
CD.Instance] = {
WHILE pins#
NIL
DO
AddWireGeometryPropOnWire[wire, pins.first];
pins ← pins.rest;
ENDLOOP;
};
GetWireGeometryPropFromWire:
PUBLIC
PROC [wire: Wire]
RETURNS [geometry:
LIST
OF
CD.Instance] = {
geometry ← NARROW [CoreProperties.GetWireProp[wire, wireGeometryProp]];
};
PutWireGeometryPropOnWire:
PUBLIC
PROC [wire: Wire, geometry:
LIST
OF
CD.Instance] = {
CoreProperties.PutWireProp[wire, wireGeometryProp, geometry];
};
AddWireGeometryPropOnWire:
PUBLIC
PROC [wire: Wire, cdInstance:
CD.Instance] = {
PutWireGeometryPropOnWire[wire, CONS [cdInstance, GetWireGeometryPropFromWire[wire]]];
};
AppendWireGeometryPropOnWire:
PUBLIC
PROC [wire: Wire, geometry:
LIST
OF
CD.Instance] = {
WHILE geometry#
NIL
DO
AddWireGeometryPropOnWire[wire, geometry.first];
geometry ← geometry.rest;
ENDLOOP;
};
Geometrical Primitives
IsRectangle:
PROC [inst:
CD.Instance]
RETURNS [
BOOL] = {
RETURN[inst.ob.class=CDRects.bareRectClass]};
IsPin:
PROC [inst:
CD.Instance]
RETURNS [
BOOL] = {
RETURN[inst.ob.class=CDPinObjects.pinObjectsClass]};
IsCell:
PROC [inst:
CD.Instance]
RETURNS [
BOOL] = {
RETURN[CDCells.IsCell[inst.ob]]};
Touch:
PROC [inst1, inst2:
CD.Instance]
RETURNS [touch:
BOOL ←
FALSE] = {
IF IsRectangle[inst1]
AND IsRectangle[inst2]
THEN
RETURN[TouchWires[InstToRect[inst1], InstToRect[inst2]]]
ELSE touch ← TouchListsRect[InstToRects[inst1], InstToRects[inst2]];
};
-- Special rule for two rectangles because crossing implies no contact
TouchWires:
PROC [rect1, rect2:
CD.Rect]
RETURNS [
BOOL ←
FALSE] = {
IF ~CDBasics.Intersect[rect1, rect2] THEN RETURN[FALSE];
IF TouchOnlyOnCorner[rect1, rect2] THEN RETURN[TRUE];
};
-- The list of rectangles defining the contact points for this instance
InstToRects:
PROC [inst:
CD.Instance]
RETURNS [listRect:
LIST
OF
CD.Rect ←
NIL] = {
SELECT
TRUE
FROM
IsRectangle[inst] OR IsPin[inst] => listRect ← CONS[InstToRect[inst]];
IsCell[inst] => {
-- enumerate pins, turn into rects and CONS them
cell: CD.Instance ← inst; -- to avoid name conflict
EachPin: PWPins.InstanceEnumerator = {
pinRect: CD.Rect ← InstToRect[PWPins.TransformInstance[inst, cell.ob.size, cell.location, cell.orientation]];
listRect ← CONS[pinRect, listRect];
};
[] ← PWPins.EnumerateEdgePins[cell.ob, EachPin];
listRect ← NIL};
ENDCASE => ERROR;
};
TouchListsRect:
PROC [listRect1, listRect2:
LIST
OF
CD.Rect]
RETURNS [
BOOL ←
FALSE] = {
FOR l1:
LIST
OF
CD.Rect ← listRect1, l1.rest
WHILE l1#
NIL
DO
rect1: CD.Rect ← l1.first;
FOR l2:
LIST
OF
CD.Rect ← listRect2, l2.rest
WHILE l2#
NIL
DO
IF TouchRects[rect1, l2.first] THEN RETURN[TRUE];
ENDLOOP;
ENDLOOP;
};
-- This rule does not apply for the intersection of two wires
TouchRects:
PROC [rect1, rect2:
CD.Rect]
RETURNS [
BOOL ←
FALSE] = {
RETURN[CDBasics.Intersect[rect1, rect2]];
};
-- The rectangle corresponding to this instance
InstToRect:
PROC [inst:
CD.Instance]
RETURNS [rect:
CD.Rect] = {
rect ← CDInstances.InstRectI[inst]};
Initialization
[] ← CDProperties.RegisterProperty[extractObjProcProp, sexKey];
CDProperties.PutProp[CDPinObjects.pinObjectsClass, extractObjProcProp, NEW [ExtractObjProc ← PinExtractObj]];
CDProperties.PutProp[CDCells.cellClass, extractObjProcProp, NEW [ExtractObjProc ← CellExtractObj]];
CDProperties.PutProp[PWObjects.abutXClass, extractObjProcProp, NEW [ExtractObjProc ← AbutExtractObj]];
CDProperties.PutProp[PWObjects.abutYClass, extractObjProcProp, NEW [ExtractObjProc ← AbutExtractObj]];
CDProperties.PutProp[PWObjects.indirectClass, extractObjProcProp, NEW [ExtractObjProc ← PWCoreOperatorExtractObj]];
CDProperties.PutProp[PWCore.gateWayClass, extractObjProcProp, NEW [ExtractObjProc ← PWCoreOperatorExtractObj]];
END.