<> <> <> <<>> 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; <> extractObjProcProp: PUBLIC ATOM _ $ExtractObjProcProp; <> 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]; }; <> 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; }; <> 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]; <> }; <<-- 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]}; <> <<-- Turn the satellites into properties and put them in the context>> ParseSatellites: PROC [master: CD.Instance, context: Context] = { ref: REF _ CDProperties.GetPropFromInstance[master, satellitesProp]; IF ref=NIL THEN RETURN; FOR l: CD.InstanceList _ NARROW[ref], l.rest WHILE l#NIL DO <> ENDLOOP; }; <> <> <> <<};>> <> [] _ CDProperties.RegisterProperty[extractObjProcProp, sexKey]; <> <> <> <> <> <> END.