<> <> <> DIRECTORY CD, CDAtomicObjects, CDBasics, CDCells, CDDesignRules, CDInstances, CDOrient, CDSymbolicObjects, CDRects, CoreClasses, CoreOps, CoreProperties, PW, RefTab, Rope, Sinix, Stix, TerminalIO; StixImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDDesignRules, CDInstances, CDOrient, CDSymbolicObjects, CoreOps, CoreProperties, PW, RefTab, Rope, Sinix EXPORTS Stix = BEGIN OPEN Stix; <> extractedCoreProp: PUBLIC ATOM _ Sinix.extractedCoreProp; errorsProp: PUBLIC ATOM _ Sinix.errorsProp; layoutProp: PUBLIC ATOM _ CoreProperties.RegisterProperty[$StixSymbolicObject, CoreProperties.Props[[CoreProperties.propCopy, CoreProperties.PropDoCopy]]]; pinsProp: PUBLIC ATOM _ CoreProperties.RegisterProperty[$StixPins, CoreProperties.Props[[CoreProperties.propCopy, CoreProperties.PropDoCopy]]]; wireGeometryProp: PUBLIC ATOM _ CoreProperties.RegisterProperty[$StixWireGeometry, CoreProperties.Props[[CoreProperties.propCopy, CoreProperties.PropDoCopy]]]; instanceProp: PUBLIC ATOM _ CoreProperties.RegisterProperty[$StixInstance, CoreProperties.Props[[CoreProperties.propCopy, CoreProperties.PropDoCopy]]]; wireNodesProp: PUBLIC ATOM _ CoreProperties.RegisterProperty[$StixWireNodes, CoreProperties.Props[[CoreProperties.propCopy, CoreProperties.PropDoCopy]]]; nTrColor: PUBLIC Color _ $ndif; pTrColor: PUBLIC Color _ $wpdif; trGateColor: PUBLIC Color _ $pol; <> contactClass: PUBLIC Class _ NEW[ClassRec _ [ LayoutMe: LayoutContact, ExplodeMe: ExplodeContact, MyOriginNode: ContactOrigin, AllMyNodes: ContactNodes, objectType: $contact]]; wireClass: PUBLIC Class _ NEW[ClassRec _ [ LayoutMe: LayoutWire, ExplodeMe: ExplodeWire, MyOriginNode: WireOrigin, AllMyNodes: WireNodes, objectType: $wire]]; transistorClass: PUBLIC Class _ NEW[ClassRec _ [ LayoutMe: LayoutTransistor, ExplodeMe: ExplodeTransistor, MyOriginNode: TransistorOrigin, AllMyNodes: TransistorNodes, objectType: $transistor]]; stickCellClass: PUBLIC Class _ NEW[ClassRec _ [ LayoutMe: LayoutStickCell, ExplodeMe: ExplodeStickCell, MyOriginNode: StickCellOrigin, AllMyNodes: StickCellNodes, objectType: $stickCell]]; <> AllNodes: PUBLIC EnumerateNodesProc ~ {RETURN[stickPtr.class.AllMyNodes[stickPtr]]}; <<-- EnumerateNodesProc: TYPE = PROC [stickPtr: StickPtr] RETURNS [nodes: Nodes];>> ContactNodes: EnumerateNodesProc = {RETURN[LIST[Origin[stickPtr]]]}; WireNodes: EnumerateNodesProc = { wireRef: WireRef _ NARROW[stickPtr.data, WireRef]; RETURN[LIST[wireRef.origin,wireRef.other]]}; TransistorNodes: EnumerateNodesProc = { transistorRef: TransistorRef _ NARROW[stickPtr.data, TransistorRef]; RETURN[LIST[transistorRef.gate, transistorRef.ch1, transistorRef.ch2]]}; StickCellNodes: EnumerateNodesProc = {RETURN[NARROW[stickPtr.data, StickCell].allNodes]}; <> Origin: PUBLIC OriginProc ~ {RETURN[stickPtr.class.MyOriginNode[stickPtr]]}; <<-- OriginProc: TYPE = PROC [stickPtr: StickPtr] RETURNS [node: Node];>> <<>> ContactOrigin: OriginProc = {RETURN[NARROW[stickPtr.data, ContactRef].node]}; WireOrigin: OriginProc = { n1: Node _ NARROW[stickPtr.data, WireRef].origin; n2: Node _ NARROW[stickPtr.data, WireRef].other; SELECT TRUE FROM n1.pos.x=n2.pos.x => RETURN [IF n1.pos.y<=n2.pos.y THEN n1 ELSE n2]; n1.pos.y=n2.pos.y => RETURN [IF n1.pos.x<=n2.pos.x THEN n1 ELSE n2]; ENDCASE => ERROR; }; TransistorOrigin: OriginProc = {RETURN[NARROW[stickPtr.data, TransistorRef].gate]}; StickCellOrigin: OriginProc = {RETURN[NARROW[stickPtr.data, StickCell].origin]}; <> <<-- Cached creation: only one node per pos during the creation>> <<-- Nodes might overlap later, during compaction, but we do not create any node at this time>> <<-- Private nodes are not shared>> CreateNode: PUBLIC PROC [pos: Position, wire: Wire, cellType: CellType, private: BOOL _ FALSE] RETURNS [node: Node] = { stCell: StickCell _ NARROW[GetStickPtr[cellType].data, StickCell]; IF ~private THEN -- try to share an exisiting public node FOR l: Nodes _ stCell.allNodes, l.rest WHILE l#NIL DO IF l.first.pos=pos AND ~l.first.private THEN RETURN [l.first]; ENDLOOP; <<-- Either private or not found>> node _ NEW[NodeRec _ [pos: pos, private: private]]; IF stCell.origin=NIL THEN stCell.origin _ node; stCell.allNodes _ CONS[node, stCell.allNodes]; AppendWireNode[wire, node]; }; CreateContact: PUBLIC PROC [node: Node] RETURNS [stickPtr: StickPtr] = { contactRef: ContactRef _ NEW [ContactRec _ [node: node]]; stickPtr _ NEW[StickRec _ [class: contactClass, data: contactRef]]; }; CreateWire: PUBLIC PROC [n1, n2: Node, color: Color, width: NAT _ 0] RETURNS [stickPtr: StickPtr] = { wireRef: WireRef _ NEW [WireRec _ [origin: n1, other: n2, color: color, width: width]]; stickPtr _ NEW[StickRec _ [class: wireClass, data: wireRef]]; }; CreateTransistor: PUBLIC PROC [gate, ch1, ch2: Node, color: Color, width, length: NAT] RETURNS [stickPtr: StickPtr] = { transistorRef: TransistorRef _ NEW [TransistorRec _ [ gate: gate, ch1: ch1, ch2: ch2, color: color, width: width, length: length]]; stickPtr _ NEW[StickRec _ [class: transistorClass, data: transistorRef]]; }; <<-- Create an empty stick Cell>> CreateStickCell: PUBLIC PROC [name: ROPE] RETURNS [stickPtr: StickPtr] = { stickCellRef: StickCell _ NEW [StickCellRec _ [name: name]]; stickPtr _ NEW[StickRec _ [class: stickCellClass, data: stickCellRef]]; }; <> FinishCell: PUBLIC PROC [cellType: CellType] = { FinishStickPtr: EachStickPtrProc = { SELECT stickPtr.class FROM contactClass => { -- colors contactRef: ContactRef _ NARROW[stickPtr.data]; colors: Colors _ FindColorsUnder[Origin[stickPtr], wire]; IF colors=NIL THEN ERROR; contactRef.color1 _ colors.first; IF colors.rest=NIL THEN ERROR; contactRef.color2 _ colors.rest.first; }; ENDCASE => NULL; }; cell: StickPtr _ GetStickPtr[cellType]; <<-- Fill-up redundant fields in these StickPtrs (orient, ...)>> [] _ EnumerateInsts[cellType, FinishStickPtr]; <<-- A speed-up hack for the compaction>> BuildConnectTable[cell]; }; <<>> OrientStickPtr: PROC [stickPtr: StickPtr] RETURNS [Orient] ~ { RETURN [SELECT stickPtr.class FROM wireClass => FindOrient[Origin[stickPtr], OtherEnd[stickPtr]], transistorClass => FindOrient[CH1[stickPtr], CH2[stickPtr]], ENDCASE => CDOrient.original ]; }; FindOrient: PROC [n1, n2: Node] RETURNS [Orient] ~ { IF n1.pos.x=n2.pos.x THEN { -- vertical IF n1.pos.y<=n2.pos.y THEN RETURN [CDOrient.original] ELSE RETURN [CDOrient.rotate180]} ELSE { -- horizontal IF n1.pos.x<=n2.pos.x THEN RETURN [CDOrient.rotate90] ELSE RETURN [CDOrient.rotate270]}; }; <<-- Find colors under a given Node (ct or pin): explore only those in the same Core.Wire>> FindColorsUnder: PROC [node: Node, wire: Wire] RETURNS [colors: Colors _ NIL] = { FOR l: StickPtrs _ GetWireGeom[wire], l.rest WHILE l#NIL DO color: Color; stickPtr: StickPtr _ l.first; SELECT stickPtr.class FROM wireClass => IF InBetween[Origin[stickPtr], OtherEnd[stickPtr], node] THEN color _ NARROW[stickPtr.data, WireRef].color; transistorClass => { IF Gate[stickPtr]=node THEN color _ trGateColor; IF CH1[stickPtr]=node OR CH2[stickPtr]=node THEN color _ NARROW[stickPtr.data, TransistorRef].color; }; ENDCASE => LOOP; colors _ InsertColor[color, colors]; ENDLOOP; }; <<-- Avoid duplication in the list>> InsertColor: PROC [color: Color, colors: Colors] RETURNS [Colors] = { IF color=NIL THEN RETURN [colors]; FOR l: Colors _ colors, l.rest WHILE l#NIL DO IF l.first=color THEN RETURN[colors]; ENDLOOP; RETURN[CONS[color, colors]]; }; InBetween: PROC [n1, n2, n: Node] RETURNS [BOOL] ~ { IF n1.pos.x=n2.pos.x THEN { -- vertical segment RETURN [n.pos.x=n1.pos.x AND n.pos.y >= MIN[n1.pos.y, n2.pos.y] AND n.pos.y <= MAX[n1.pos.y, n2.pos.y]]} ELSE { -- horizontal segment RETURN [n.pos.y=n1.pos.y AND n.pos.x >= MIN[n1.pos.x, n2.pos.x] AND n.pos.x <= MAX[n1.pos.x, n2.pos.x]]}; }; <> <<-- All distances and sizes are converted to the new lambda; notice that the cell stays inside the same equivalence class.>> <<-- I am not convinced that this is necessary!>> ConvertToDR: PUBLIC PROC [cellType: CellType, dr: DRules] = { blowUp: INT = 10; <<-- Change sizes and internal spacing>> LambdarizeStickPtr: EachStickPtrProc = { SELECT stickPtr.class FROM contactClass => { contactRef: ContactRef _ NARROW[stickPtr.data]; contactRef.dx _ contactRef.dx*dr.lambda; contactRef.dy _ contactRef.dy*dr.lambda; }; wireClass => { wireRef: WireRef _ NARROW[stickPtr.data]; wireRef.width _ wireRef.width*dr.lambda; }; transistorClass => { transistorRef: TransistorRef _ NARROW[stickPtr.data]; transistorRef.ch1.pos _ MultModule[transistorRef.gate.pos, transistorRef.ch1.pos, dr.gateSDNodeSp]; transistorRef.ch2.pos _ MultModule[transistorRef.gate.pos, transistorRef.ch2.pos, dr.gateSDNodeSp]; transistorRef.width _ transistorRef.width*dr.lambda; transistorRef.length _ transistorRef.length*dr.lambda; }; ENDCASE => ERROR; }; <<-- Change positions>> cell: StickPtr _ GetStickPtr[cellType]; FOR l: Nodes _ AllNodes[cell], l.rest WHILE l#NIL DO l.first.pos _ Mult[l.first.pos, dr.lambda*blowUp]; ENDLOOP; [] _ EnumerateInsts[cellType, LambdarizeStickPtr]; }; MultModule: PROC [center, pos: Position, val: INT] RETURNS [vec: Position] ~ { mod: INT; vec _ CDBasics.SubPoints[pos, center]; mod _ MAX [ABS[vec.x], ABS[vec.y]]; IF vec.x#0 AND vec.y#0 THEN ERROR; -- non-manhattan vector IF mod=0 THEN ERROR; -- null vector vec _ [vec.x/mod, vec.y/mod]; vec _ CDBasics.AddPoints[center, Mult[vec, val]]; }; <> <<-- Use a RefTab: [node, wire] where wire is a Core.Wire.>> BuildConnectTable: PROC [cell: StickPtr] ~ { EnterWires: CoreOps.EachWireProc ~ { FOR l: StickPtrs _ GetWireGeom[wire], l.rest WHILE l#NIL DO SELECT l.first.class FROM contactClass => Connect[Origin[l.first], wire, stCell.tab]; wireClass => { Connect[Origin[l.first], wire, stCell.tab]; Connect[OtherEnd[l.first], wire, stCell.tab]; }; ENDCASE => ERROR; ENDLOOP; }; cellType: CellType _ GetCellType[cell]; recCell: CoreClasses.RecordCellType _ NARROW[cellType.data]; stCell: StickCell _ NARROW[cell.data, StickCell]; stCell.tab _ RefTab.Create[]; <<-- for every internal wire, take all StickPtr attached to it and build an entry [node, wire] for every node>> [] _ CoreOps.VisitWire[recCell.internal, EnterWires]; }; <<-- Two nodes are connected if they have same wire>> PlatesAreConnected: PUBLIC PROC [p1, p2: Plate, table: Tab] RETURNS [BOOL _ FALSE] = { RETURN[NodesAreConnected[p1.node, p2.node, table]]; }; NodesAreConnected: PUBLIC PROC [n1, n2: Node, table: Tab] RETURNS [BOOL _ FALSE] = { IF n1=NIL OR n2=NIL THEN RETURN; RETURN[HisWire[n1, table]=HisWire[n2, table]]; }; Connect: PROC [n: Node, w: Wire, table: Tab] ~ { IF n=NIL OR w=NIL THEN RETURN; [] _ RefTab.Store[table, n, w]; }; HisWire: PROC [node: Node, table: Tab] RETURNS [Wire] = { ref: REF _ RefTab.Fetch[table, node].val; RETURN[IF ref=NIL THEN NIL ELSE NARROW[ref, Wire]]; }; <> Layout: PUBLIC Stix.LayoutProc ~ {inst _ stickPtr.class.LayoutMe[stickPtr, cell, dr]}; <<-- A LayoutProc produces an instance of a CD object inside a cell; it takes all its parameters from the StickPtr; the position of the instance is derived from the position of its origin node, of a user-set dP (set by a compaction algorithm for example) and from a deltaP which depends on the type of the object: e.g. a contact is centered on the node.>> <<-- LayoutProc: TYPE = PROC [stickPtr: StickPtr, cell: Object, dr: DRules] RETURNS [inst: Instance];>> LayoutContact: LayoutProc = { mosOb: Object; contactRef: ContactRef _ NARROW[stickPtr.data]; deltaP: Position; mosOb _ CDDesignRules.Contact[dr: dr, l1: CDDesignRules.GetLayer[dr.techno, contactRef.color1], l2: CDDesignRules.GetLayer[dr.techno, contactRef.color2], size: [contactRef.dx, contactRef.dy]]; deltaP _ CHS[Half[CD.InterestSize[mosOb]]]; inst _ MakeNewInst[cell, mosOb, stickPtr, deltaP, dr]; }; LayoutWire: LayoutProc = { wireRef: WireRef _ NARROW[stickPtr.data]; layer: Layer _ CDDesignRules.GetLayer[dr.techno, wireRef.color]; width: INT _ MAX[ wireRef.width, CDDesignRules.MinWidth[dr, layer]]; length: INT _ Length[wireRef]; deltaP: Position _ CHS[Half[[width, width]]]; mosOb: Object _ CDDesignRules.Rect[ size: [x: width, y: length+width], layer: layer]; inst _ MakeNewInst[cell, mosOb, stickPtr, deltaP, dr]; }; LayoutTransistor: LayoutProc = { transistorRef: TransistorRef _ NARROW[stickPtr.data]; deltaP: Position; mosOb: Object; ratio: Position _ [transistorRef.width, transistorRef.length]; mosOb _ CDDesignRules.Transistor[dr: dr, difL: CDDesignRules.GetLayer[dr.techno, transistorRef.color], w: ratio.x, l: ratio.y]; deltaP _ CHS[Half[CD.InterestSize[mosOb]]]; inst _ MakeNewInst[cell, mosOb, stickPtr, deltaP, dr]; }; LayoutStickCell: LayoutProc = { LayoutEachStickPtr: EachStickPtrProc = {[] _ Layout[stickPtr, newCell, dr]}; newCell: Object _ PW.CreateEmptyCell[]; [] _ EnumerateInsts[GetCellType[stickPtr], LayoutEachStickPtr]; inst _ MakeNewInst[cell, newCell, stickPtr, [0, 0], dr]; }; <<-- Must return the instance so that we can add properties (e.g. pin)>> MakeNewInst: PROC [cell, ob: Object, stickPtr: StickPtr, deltaP: Position, dr: DRules] RETURNS [inst: Instance] = { inst _ CDCells.IncludeOb[design: NIL, cell: cell, ob: ob, position: LayoutPos[stickPtr, deltaP, dr], orientation: OrientStickPtr[stickPtr], cellCSystem: interrestCoords, obCSystem: interrestCoords, mode: dontPropagate].newInst; }; <> Explode: PUBLIC ExplodeProc ~ {stickPtr.class.ExplodeMe[stickPtr, dr]}; <<-- ExplodeProc: TYPE = PROC [stickPtr: StickPtr, dr: DRules];>> ExplodeContact: ExplodeProc = { ToPlatesProc: CDSymbolicObjects.InstEnumerator ~ { stickPtr.plates _ CONS[PinToPlate[inst, node, OrientStickPtr[stickPtr]], stickPtr.plates]; }; inst: Instance _ Layout[stickPtr, NIL, dr]; -- coordinate system? dummy: Object _ CDDesignRules.Explode[dr, inst.ob]; node: Node _ Origin[stickPtr]; stickPtr.plates _ NIL; [] _ CDSymbolicObjects.EnumerateSymbolicObs[dummy, ToPlatesProc]; }; ExplodeWire: ExplodeProc = ExplodeContact; ExplodeTransistor: ExplodeProc = { -- use channel? ToPlatesProc: CDSymbolicObjects.InstEnumerator ~ { name: ROPE _ CDSymbolicObjects.GetName[inst]; plate: Plate _ SELECT TRUE FROM Rope.Equal[name, "gate"] => PinToPlate[inst, transistorRef.gate, OrientStickPtr[stickPtr]], Rope.Equal[name, "ch1"] => PinToPlate[inst, transistorRef.ch1, OrientStickPtr[stickPtr]], Rope.Equal[name, "ch2"] => PinToPlate[inst, transistorRef.ch2, OrientStickPtr[stickPtr]], ENDCASE => ERROR; stickPtr.plates _ CONS[plate, stickPtr.plates]; }; transistorRef: TransistorRef _ NARROW[stickPtr.data]; inst: Instance _ Layout[stickPtr, NIL, dr]; -- coordinate system? dummy: Object _ CDDesignRules.Explode[dr, inst.ob]; stickPtr.plates _ NIL; [] _ CDSymbolicObjects.EnumerateSymbolicObs[dummy, ToPlatesProc]; }; PinToPlate: PROC [pin: Instance, node: Node, orient: Orient] RETURNS [plate: Plate] ~ { rect: CD.Rect _ CenterOnNode[CDInstances.InstRectI[pin], node, orient]; -- use also dP ? drect: DRect _ [r: rect, lev: CDSymbolicObjects.GetLayer[pin]]; plate _ NEW [PlateRec _ [dr: drect, node: node]]; }; ExplodeStickCell: ExplodeProc = { ExplodeEachStickPtr: EachStickPtrProc = {[] _ Explode[stickPtr, dr]}; [] _ EnumerateInsts[GetCellType[stickPtr], ExplodeEachStickPtr]; }; <> EnumerateInsts: PUBLIC PROC [cellType: CellType, proc: EachStickPtrProc] RETURNS [quit: BOOL] ~ { ProcessStickPtr: CoreOps.EachWireProc ~ { FOR l: StickPtrs _ GetWireGeom[wire], l.rest WHILE l#NIL DO IF quit _ proc[l.first, wire] THEN RETURN; -- pin, contact or wire ENDLOOP; }; <<-- All transistors>> recCell: RecordCell _ NARROW[cellType.data]; FOR i: NAT IN [0..recCell.size) DO -- instanceProp stickPtr: StickPtr _ NARROW[CoreProperties.GetCellInstanceProp[recCell[i], instanceProp]]; IF quit _ proc[stickPtr, NIL] THEN RETURN; ENDLOOP; <<-- Geometry on internal wire>> [] _ CoreOps.VisitWire[recCell.internal, ProcessStickPtr]; -- wireGeometryProp }; <<-- CellType from StickPtr>> GetCellType: PUBLIC PROC [stickPtr: StickPtr] RETURNS [CellType] ~ { ref: REF _ CoreProperties.GetProp[stickPtr.properties, extractedCoreProp]; RETURN[IF ref#NIL THEN NARROW[ref] ELSE NIL]; }; <<-- StickPtr on CellType>> GetStickPtr: PUBLIC PROC [cellType: CellType] RETURNS [StickPtr] ~ { ref: REF _ CoreProperties.GetCellTypeProp[cellType, layoutProp]; RETURN[IF ref#NIL THEN NARROW[ref] ELSE NIL]; }; PutStickPtr: PUBLIC PROC [cellType: CellType, stickPtr: StickPtr] ~ { CoreProperties.PutCellTypeProp[cellType, layoutProp, stickPtr]; }; <<-- StickPtrs on Wire>> GetWireGeom: PUBLIC PROC [wire: Wire] RETURNS [StickPtrs] ~ { ref: REF _ CoreProperties.GetWireProp[wire, wireGeometryProp]; RETURN[IF ref#NIL THEN NARROW[ref] ELSE NIL]; }; PutWireGeom: PUBLIC PROC [wire: Wire, stickPtrs: StickPtrs] ~ { CoreProperties.PutWireProp[wire, wireGeometryProp, stickPtrs]; }; AppendWireGeom: PUBLIC PROC [wire: Wire, stickPtr: StickPtr] ~ { stickPtrs: StickPtrs _ GetWireGeom[wire]; stickPtrs _ CONS[stickPtr, stickPtrs]; PutWireGeom[wire, stickPtrs]; }; <<-- Nodes on Wire>> GetWireNodes: PUBLIC PROC [wire: Wire] RETURNS [Nodes] ~ { ref: REF _ CoreProperties.GetWireProp[wire, wireNodesProp]; RETURN[IF ref#NIL THEN NARROW[ref] ELSE NIL]; }; PutWireNodes: PUBLIC PROC [wire: Wire, nodes: Nodes] ~ { CoreProperties.PutWireProp[wire, wireNodesProp, nodes]; }; AppendWireNode: PUBLIC PROC [wire: Wire, node: Node] ~ { nodes: Nodes _ GetWireNodes[wire]; nodes _ CONS[node, nodes]; PutWireNodes[wire, nodes]; }; <<-- StickPtr on CellInstance (devices or subcells)>> GetInstance: PUBLIC PROC [coreInst: CoreClasses.CellInstance] RETURNS [StickPtr] ~ { ref: REF _ CoreProperties.GetCellInstanceProp[coreInst, instanceProp]; RETURN[IF ref#NIL THEN NARROW[ref] ELSE NIL]; }; PutInstance: PUBLIC PROC [coreInst: CoreClasses.CellInstance, stickPtr: StickPtr] ~ { CoreProperties.PutCellInstanceProp[coreInst, instanceProp, stickPtr]; }; <<>> <<-- List.Member >> IsNodeOf: PROC [stickPtr: StickPtr, node: Node] RETURNS [BOOL _ FALSE] ~ { FOR l: Nodes _ AllNodes[stickPtr], l.rest WHILE l#NIL DO IF node=l.first THEN RETURN[TRUE]; ENDLOOP; }; <<-- NIL if not a wire>> OtherEnd: PUBLIC PROC [stickPtr: StickPtr] RETURNS [node: Node] = { WITH stickPtr.data SELECT FROM w: WireRef => { n1: Node _ w.origin; n2: Node _ w.other; SELECT TRUE FROM n1.pos.x=n2.pos.x => RETURN [IF n1.pos.y<=n2.pos.y THEN n2 ELSE n1]; n1.pos.y=n2.pos.y => RETURN [IF n1.pos.x<=n2.pos.x THEN n2 ELSE n1]; ENDCASE => ERROR; }; ENDCASE => RETURN [NIL]; }; <<-- NIL if not a transistor>> Gate: PROC [stickPtr: StickPtr] RETURNS [node: Node] = { WITH stickPtr.data SELECT FROM tr: TransistorRef => RETURN[tr.gate]; ENDCASE => RETURN [NIL]; }; CH1: PROC [stickPtr: StickPtr] RETURNS [node: Node] = { WITH stickPtr.data SELECT FROM tr: TransistorRef => RETURN[tr.ch1]; ENDCASE => RETURN [NIL]; }; CH2: PROC [stickPtr: StickPtr] RETURNS [node: Node] = { WITH stickPtr.data SELECT FROM tr: TransistorRef => RETURN[tr.ch2]; ENDCASE => RETURN [NIL]; }; <<-- NIL if not a single color (e.g. contact)>> TheColor: PROC [stickPtr: StickPtr] RETURNS [color: Color] = { WITH stickPtr.data SELECT FROM w: WireRef => RETURN[w.color]; tr: TransistorRef => RETURN[tr.color]; ENDCASE => RETURN [NIL]; }; Length: PROC [wireRef: WireRef] RETURNS [length: INT] = { node1, node2: Node; node1 _ wireRef.origin; node2 _ wireRef.other; length _ ABS[node1.pos.x-node2.pos.x+node1.pos.y-node2.pos.y] }; LayoutPos: PROC [stickPtr: StickPtr, deltaP: Position, dr: DRules] RETURNS [Position] ~ { RETURN [CDBasics.AddPoints[ deltaP, CDBasics.AddPoints[Origin[stickPtr].pos, stickPtr.dP]]]; }; Mult: PROC [pos: Position, n: INT] RETURNS [Position] ~ { RETURN[[pos.x*n, pos.y*n]]; }; Half: PROC [pos: Position] RETURNS [Position] ~ { RETURN[[pos.x/2, pos.y/2]]; }; CHS: PROC [pos: Position] RETURNS [Position] ~ { RETURN[[-pos.x, -pos.y]]; }; CenterOnNode: PROC [rect: CD.Rect, node: Node, orient: Orient] RETURNS [newRect: CD.Rect] = { rect _ CDOrient.OrientedRect[rect, orient]; newRect _ CDBasics.MoveRect[rect, CDBasics.SubPoints[node.pos, CDBasics.Center[rect]]]; }; END.