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.