StixImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Louis Monier December 6, 1985 2:29:32 pm PST
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;
Properties connecting Core to 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;
Classes
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]];
How to access all the nodes
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]};
How to access the Origin Node
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]};
Creation procs: minimum information, no context
-- 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: BOOLFALSE] 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]];
};
Must be called as soon as all objects have been put into the cell
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]]};
};
Must be called before layout or compaction, as soon as DRules are known
-- 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]];
};
Electrical Connectivity
-- 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 [BOOLFALSE] = {
RETURN[NodesAreConnected[p1.node, p2.node, table]];
};
NodesAreConnected: PUBLIC PROC [n1, n2: Node, table: Tab] RETURNS [BOOLFALSE] = {
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: from StickPtr to CMOS instances
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: INTMAX[
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 procs: from symbolic object + technology to plates
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];
};
General Utilities
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 [BOOLFALSE] ~ {
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.