DIRECTORY
Atom USING [GetPName],
BasicTime USING [Now],
CD USING [combined, Design, FetchObjectClass, Instance, InstanceList, Layer, LayerKey, LayerTechnology, Number, Object, Orientation, original, Position, Rect, Technology],
CDBasics USING [AddPoints, empty, Extend, Intersect, Intersection, SizeOfRect],
CDDirectory USING [Fetch],
CDErrors USING [IncludeMessage, RemoveMessages],
CDOrient USING [ComposeOrient, DecomposeOrient, MapRect, original],
CDProperties USING [GetProp, PutProp, PutPropOnObject, RegisterProperty],
CDSimpleRules USING [MinDist, MinWidth, NotKnown],
Core USING [CellType, Properties, Wire],
CoreClasses USING [recordCellClass, RecordCellType, transistorCellClass, unspecifiedCellClass],
CoreOps USING [CreateWires, CopyWire, GetCellTypeName, GetShortWireName, SetShortWireName],
CoreProperties USING [CopyProps, GetProp, propCompare, propCopy, PropDoCopy, PropIntCompare, propPrint, PropPrintProc, Props, PutProp, RegisterProperty, StoreProperties],
IO USING [card, char, Error, ErrorCode, int, noWhereStream, Put1, PutF, PutF1, PutFR, PutFR1, refAny, rope, STREAM, time],
RefTab USING [Create, EachPairAction, Fetch, Insert, Pairs, Ref, SeqIndex],
Rope USING [Cat, ROPE],
SoS USING [CellHullProc, CellToCellProc, CheckCell, DRV, DesignRuleViolation, ErrorRect, FindGeometry, MaterialToCellProc, State, StateRec],
SoSTNT USING [BlowTNT, InitTNT, InTNT, RememberTNT, SweepTNT, TNT],
ViewerIO USING [CreateViewerStreams],
ViewerTools USING [FindExistingViewer, Viewer];
SoSImpl: CEDAR PROGRAM
IMPORTS Atom, BasicTime, CD, CDBasics, CDDirectory, CDErrors, CDOrient, CDProperties, CDSimpleRules, CoreClasses, CoreOps, CoreProperties, IO, RefTab, Rope, SoSTNT, ViewerIO, ViewerTools
EXPORTS SoS ~ BEGIN
OPEN SoSTNT;
debug: BOOL _ FALSE;		-- to start debugging enter: _ SoSImpl.Debug[]
occDebug: BOOL = FALSE;		-- for occasional debugging
useTNT: BOOL = TRUE;		-- for timing analysis only
persist: BOOL _ TRUE;		-- depends on Sinix (try hard to flag CD design)
fast: BOOL = TRUE;		-- if FALSE then SoS is purely "object oriented"
break: SIGNAL = CODE;		-- for debugging; related to property $SoSBreak
coreMess: SIGNAL = CODE;	-- clean up before issuing coreInconsistent
coreInconsistent: PUBLIC ERROR = CODE;
mLog: IO.STREAM;		-- messages
dLog: IO.STREAM _ IO.noWhereStream;	-- debugging
State: TYPE = SoS.State;	-- REF StateRec;
StateRec: TYPE = SoS.StateRec;
DRV: TYPE = SoS.DRV;	-- REF DesignRuleViolation
DesignRuleViolation: TYPE = SoS.DesignRuleViolation;
ErrorRect: TYPE = SoS.ErrorRect;
checked: ATOM = CoreProperties.RegisterProperty [$SoSWasHere];
DRVkey: PUBLIC ATOM _ CoreProperties.RegisterProperty [$SoSError];
bbKey: ATOM _ CoreProperties.RegisterProperty [$SoSbb];
trace: ATOM = CoreProperties.RegisterProperty [$SoSSeparationChecked];
analysis: ATOM = CoreProperties.RegisterProperty [$SoSAnalysis];
cellHull: ATOM = CoreProperties.RegisterProperty [$SoSHull];
matToCell: ATOM = CoreProperties.RegisterProperty [$SoSmc];
cellToCell: ATOM = CoreProperties.RegisterProperty [$SoScc];
rectClass: ATOM = $Rect;
pinClass: ATOM = $PinOb0;
doNotAnalyse: ATOM = $DoNotDRC;
previousTechnology: CD.Technology _ NIL;
previousMaxSeparation: CD.Number _ 100;
specialLayers: CD.Layer = 5;	-- combined, highLightShade, highLightError, pinRepresentation
errorFeedbackCutOff: CARDINAL = 50;	-- after this number of errors, a | is no longer displayed in the ChipNDale Terminal viewer.
WireSet: TYPE = REF WireSetRec;	-- the wires of a set of cells
WireSetRec: TYPE = RECORD [elt: SEQUENCE size: NAT OF Core.Wire];
PropSet: TYPE = REF PropSetRec;	-- the wires of a set of cells
PropSetRec: TYPE = RECORD [p: SEQUENCE size: NAT OF Core.Properties];
CheckDesignRules: PUBLIC PROC [cell: Core.CellType, design: CD.Design _ NIL, abortFlag: REF BOOL _ NIL, verbose: BOOL _ FALSE, cdObjKey, cdInstKey, cdInstListKey: ATOM] ~ BEGIN
ENABLE BEGIN
IO.Error => IF ec = StreamClosed THEN BEGIN
s: IO.STREAM;
m: BOOL = (stream = mLog);
IF m THEN StartLog [] ELSE Debug [];
s _ IF m THEN mLog ELSE dLog;
CONTINUE
END
END;
state: State _ NEW [StateRec];
messy: BOOL _ FALSE;
fakeActual: Core.Wire;
cellName: Rope.ROPE = CoreOps.GetCellTypeName [cell];
IO.PutF [stream: mLog,
format: "\nChecking wire geometry in cell %l%g%l of design %g\n",
v1: IO.rope ["b"], v2: IO.rope [cellName], v3: IO.rope ["B"], v4: IO.rope [design.name]];
IF debug THEN IO.PutF [stream: dLog,
format: "\n%g.  design: %g, cell: %g\n",
v1: IO.time [],
v2: IO.rope [design.name],
v3: IF cellName = NIL THEN IO.refAny [cell] ELSE IO.rope [cellName]];
state.design _ design;
state.abort _ IF abortFlag # NIL THEN abortFlag ELSE NEW [BOOL _ FALSE];
IF useTNT THEN state.nt _ InitTNT [];
IF design.technology # previousTechnology THEN BEGIN
previousMaxSeparation _ ComputeMaxSeparation [design.technology];
previousTechnology _ design.technology
END;
state.maxSeparation _ previousMaxSeparation;
state.globalErrorCount _ 0;
state.verbose _ verbose;
state.cdObjKey _ cdObjKey;
state.cdInstKey _ cdInstKey;
state.cdInstListKey _ cdInstListKey;
fakeActual _ CoreOps.CopyWire [cell.public];
CheckCoreCell [self: cell,
state: state,
actual: fakeActual,
loc: [0, 0],
orient: CDOrient.original
! coreMess => {messy _ TRUE; CONTINUE}];
IF useTNT THEN BlowTNT [state.nt];
IF messy THEN BEGIN
IF debug THEN break;
cell.properties _ CoreProperties.PutProp [cell.properties, checked, NIL];
coreInconsistent
END;
IO.PutF [stream: mLog,
format: "\nNumber of design violations found: %l%g%l\n",
v1: IO.rope ["b"], v2: IO.card [state.globalErrorCount], v3: IO.rope ["B"]]
END;	-- CheckDesignRules
FindGeometry: TYPE = SoS.FindGeometry;
FindCDRect: FindGeometry ~ BEGIN
Send: PROC ~ INLINE BEGIN
getRect: REF FindGeometry _ NARROW [CDProperties.GetProp [from: self.ob, prop: analysis]];
IF getRect = NIL THEN getRect _ NARROW [CDProperties.GetProp [self.ob.class, analysis]];
IF getRect = NIL THEN BEGIN
mLog.Put1 [IO.rope ["\nUnexpected object class. You may proceed, but should get your stuff updated.\n"]];
SIGNAL break;
getRect _ NEW [FindGeometry _ FindNoGeom]
END;
[r, l] _ getRect [self]
END;	-- Send
IF fast THEN
SELECT self.ob.class.objectType FROM
rectClass => [r, l] _ FindRectGeom [self];
pinClass => [r, l] _ FindNoGeom [self];
ENDCASE => Send []
ELSE Send []
END;	-- FindCDRect
FindRectGeom: FindGeometry ~ BEGIN
IF debug THEN CDProperties.PutPropOnObject [self.ob, trace, trace];
r _ CDOrient.MapRect [itemInCell: [0, 0, self.ob.size.x, self.ob.size.y],
cellSize: self.ob.size,
cellInstOrient: self.orientation,
cellInstPos: self.location];
l _ self.ob.layer
END;	-- FindRectGeom
FindNoGeom: FindGeometry ~ BEGIN
IF debug THEN CDProperties.PutPropOnObject [self.ob, trace, trace]
END;	-- FindNoGeom
RegisterGeomProcs: PROC ~ BEGIN
[] _ CDProperties.PutProp [
onto: CD.FetchObjectClass [rectClass],
prop: analysis,
val: NEW [FindGeometry _ FindRectGeom]];
[] _ CDProperties.PutProp [
onto: CD.FetchObjectClass [pinClass],
prop: analysis,
val: NEW [FindGeometry _ FindNoGeom]]
END;	-- RegisterGeomProcs
GetObject: PROC [cell: Core.CellType, state: State] RETURNS [obj: CD.Object] ~ INLINE BEGIN
obj _ NARROW [CoreProperties.GetProp [cell.properties, state.cdObjKey], CD.Object];
IF persist AND (obj=NIL) THEN obj _ CDDirectory.Fetch [state.design, CoreOps.GetCellTypeName[cell]].object;
RETURN [obj];
END;	-- GetObject
CheckCell: TYPE = SoS.CheckCell;
CheckCoreCell: CheckCell ~ BEGIN
Send: PROC ~ INLINE BEGIN
check: REF CheckCell _ NARROW [CoreProperties.GetProp [self.properties, analysis]];
IF check = NIL THEN check _ NARROW [CoreProperties.GetProp [self.class.properties, analysis]];
IF check = NIL THEN BEGIN
obj: CD.Object = GetObject [self, state];
IF obj = NIL THEN RETURN;	-- Cell contains no rectangles
check _ NEW [CheckCell _ DoNotCheck];
MarkError [self, state, [obj.class.interestRect[obj], "Cell has no provisions to be checked"]]
END;
check^ [self, state, actual, loc, orient]
END;	-- Send
IF fast THEN
SELECT self.class FROM
CoreClasses.recordCellClass => CheckRecord [self, state, actual, loc, orient];
CoreClasses.transistorCellClass => CheckTransistor [self, state, actual, loc, orient];
CoreClasses.unspecifiedCellClass => NULL;
ENDCASE => Send []
ELSE Send []
END;	-- CheckCoreCell
CheckRecord: CheckCell ~ BEGIN
origin: CD.Position = [0, 0];
cellData: CoreClasses.RecordCellType;
bindingTable: RefTab.Ref;
boundInternal: Core.Wire;
propagatedActuals: WireSet;	-- one wire per subcell
savedProps: PropSet;		-- holds properties during recursion
ownName: Rope.ROPE = CoreOps.GetCellTypeName [self];
IF (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL) OR (CoreProperties.GetProp[self.properties, checked]#NIL) THEN RETURN;
IO.Put1 [mLog, IO.char ['.]];
IF debug THEN IO.PutF [stream: dLog,
format: "\nChecking cell %l%g%l .\n",
v1: IO.rope ["e"],
v2: IF ownName = NIL THEN IO.refAny [self] ELSE IO.rope [ownName],
v3: IO.rope ["E"]];
IF state.abort^ THEN ERROR ABORTED;
ClearErrors [self, state];
cellData _ NARROW [self.data, CoreClasses.RecordCellType];
savedProps _ NEW [PropSetRec[actual.size]];
FOR p: NAT IN [0 .. actual.size) DO
savedProps[p] _ CoreProperties.CopyProps [actual[p].properties];
ENDLOOP;
bindingTable _ CreateBindingTable [actual: actual, public: self.public];
boundInternal _ BindInternal [bindingTable, cellData.internal, state];
IF occDebug THEN BEGIN
dLog.PutF1 ["Binding and propagating: %g. Binding table:\n", IO.rope [ownName]];
PrintBinding [bindingTable];
dLog.PutF1 ["Bound internal of %g:\n", IO.rope [ownName]];
PrintWire [boundInternal]
END;
propagatedActuals _ NEW [WireSetRec[cellData.size]];
FOR sub: NAT IN [0 .. cellData.size) DO
propagatedActuals[sub] _ PropagateBinding [state, bindingTable, cellData.instances[sub].actual]
ENDLOOP;
FlushBindingTable [bindingTable];
FOR sub: NAT IN [0 .. cellData.size) DO
cdInst: CD.Instance = NARROW [CoreProperties.GetProp [cellData.instances[sub].properties, state.cdInstKey]];
IF (cdInst = NIL) THEN coreMess;
CheckCoreCell [self: cellData.instances[sub].type,
state: state,
actual: propagatedActuals[sub],
loc: CDBasics.AddPoints [loc, cdInst.location],
orient: CDOrient.ComposeOrient [orient, cdInst.orientation]]
ENDLOOP;
IF occDebug THEN BEGIN
dLog.PutF1 ["Verifying: %g\nbound internal:\n", IO.rope [ownName]];
PrintWire [boundInternal]
END;
FOR i: NAT IN [0 .. cellData.internal.size) DO
FOR j: NAT IN (i .. cellData.internal.size) DO
MaterialSeparation [state: state,
cell: self,
w1: boundInternal[i],
w2: boundInternal[j],
loc1: origin, loc2: origin,
orient1: CD.original, orient2: CD.original]
ENDLOOP;
WidthCheck [self, state, boundInternal[i]]
ENDLOOP;
FOR sub: NAT IN [0 .. cellData.size) DO
cdInst: CD.Instance = NARROW [CoreProperties.GetProp [cellData.instances[sub].properties, state.cdInstKey]];
IF (cdInst = NIL) THEN coreMess;
FOR i: NAT IN [0 .. cellData.internal.size) DO
MaterialToCellSeparation [state: state,
self: cellData.instances[sub].type,
actual: propagatedActuals[sub],
wire: cellData.internal[i],
father: self,	-- for error marking
materialLoc: loc,
cellLoc: cdInst.location,
materialOrient: orient,
cellOrient: cdInst.orientation]
ENDLOOP
ENDLOOP;
IF useTNT THEN SweepTNT [state.nt];
FOR sub1: NAT IN [0 .. cellData.size) DO
cdInst1: CD.Instance = NARROW [CoreProperties.GetProp [cellData.instances[sub1].properties, state.cdInstKey]];
IF (cdInst1 = NIL) THEN coreMess;
FOR sub2: NAT IN (sub1 .. cellData.size) DO
cdInst2: CD.Instance = NARROW [CoreProperties.GetProp [cellData.instances[sub2].properties, state.cdInstKey]];
IF (cdInst2 = NIL) THEN coreMess;
IF useTNT AND (InTNT [state.nt, cdInst1, cdInst2, propagatedActuals[sub1], propagatedActuals[sub2]]) THEN LOOP;
CellToCellSeparation [state: state,
self: cellData.instances[sub1].type,
otherCell: cellData.instances[sub2].type,
selfActual: propagatedActuals[sub1],
otherActual: propagatedActuals[sub2],
father: self,	-- for error marking
selfLoc: CDBasics.AddPoints [loc, cdInst1.location],
otherLoc: CDBasics.AddPoints [loc, cdInst2.location],
selfOrient: CDOrient.ComposeOrient [orient, cdInst1.orientation],
otherOrient: CDOrient.ComposeOrient [orient, cdInst2.orientation]];
IF useTNT THEN RememberTNT [state.nt, cdInst1, cdInst2, propagatedActuals[sub1], propagatedActuals[sub2]]
ENDLOOP
ENDLOOP;
FOR p: NAT IN [0 .. self.public.size) DO
actual[p].properties _ CoreProperties.CopyProps [savedProps[p]];
ENDLOOP;
self.properties _ CoreProperties.PutProp [self.properties, checked, checked]
END;	-- CheckRecord
CheckTransistor: CheckCell ~ BEGIN
DoNotCheck [self, state, actual, loc, orient]
END;	-- CheckTransistor
DoNotCheck: CheckCell ~ BEGIN
self.properties _ CoreProperties.PutProp [self.properties, checked, checked]
END;	-- DoNotCheck
RegisterAnalysisProcs: PROC ~ BEGIN
CoreClasses.recordCellClass.properties _ CoreProperties.PutProp [
on: CoreClasses.recordCellClass.properties,
prop: analysis,
value: NEW [CheckCell _ CheckRecord]];
CoreClasses.transistorCellClass.properties _ CoreProperties.PutProp [CoreClasses.transistorCellClass.properties, analysis, NEW [CheckCell _ CheckTransistor]];
CoreClasses.unspecifiedCellClass.properties _ CoreProperties.PutProp [CoreClasses.unspecifiedCellClass.properties, analysis, NEW [CheckCell _ DoNotCheck]];
END;	-- RegisterAnalysisProcs
CellHullProc: TYPE = SoS.CellHullProc;
AtomicWireHull: PROC [w: Core.Wire, state: State] RETURNS [h: CD.Rect _ CDBasics.empty] ~ BEGIN
stored: REF CD.Rect _ NARROW [CoreProperties.GetProp [w.properties, bbKey]];
geom: CD.InstanceList;
IF w.size > 0 THEN break;	-- wire is not atomic
IF (stored # NIL) THEN RETURN [stored^];
geom _ NARROW [CoreProperties.GetProp [w.properties, state.cdInstListKey]];
FOR g: CD.InstanceList _ geom, g.rest WHILE g # NIL DO
r: CD.Rect = FindCDRect [g.first].r;
h.x1 _ MIN [h.x1, r.x1];	h.y1 _ MIN [h.y1, r.y1];
h.x2 _ MAX [h.x2, r.x2];	h.y2 _ MAX [h.y2, r.y2]
ENDLOOP;
stored _ NEW [CD.Rect _ h];
w.properties _ CoreProperties.PutProp [w.properties, bbKey, stored]
END;	-- AtomicWireHull
CellHull: CellHullProc ~ BEGIN
hull: REF CellHullProc _ NEW [CellHullProc];
SELECT self.class FROM
CoreClasses.recordCellClass => hull^ _ RecordCellHull;
CoreClasses.transistorCellClass => hull^ _ TransistorHull;
CoreClasses.unspecifiedCellClass => hull^ _ UnspecifiedHull;
ENDCASE => BEGIN
hull _ NARROW [CoreProperties.GetProp [self.properties, cellHull]];
IF hull = NIL THEN hull _ NARROW [CoreProperties.GetProp [self.class.properties, cellHull]];
IF hull = NIL THEN hull^ _ UnspecifiedHull;
END;
RETURN [hull^ [self, state]]
END;	-- CellHull;
RecordCellHull: CellHullProc ~ BEGIN
stored: REF CD.Rect _ NARROW [CoreProperties.GetProp [self.properties, bbKey]];
IF (stored = NIL) THEN BEGIN
cellData: CoreClasses.RecordCellType = NARROW [self.data, CoreClasses.RecordCellType];
IF cellData.internal.size = 0 THEN break;	-- atomic wire not expected here
FOR i: NAT IN [0 .. cellData.internal.size) DO
a: CD.Rect = AtomicWireHull [cellData.internal[i], state];
h.x1 _ MIN [h.x1, a.x1];	h.y1 _ MIN [h.y1, a.y1];
h.x2 _ MAX [h.x2, a.x2];	h.y2 _ MAX [h.y2, a.y2]
ENDLOOP;
FOR sub: NAT IN [0 .. cellData.size) DO
r: CD.Rect = CellHull [cellData.instances[sub].type, state];
h.x1 _ MIN [h.x1, r.x1];	h.y1 _ MIN [h.y1, r.y1];
h.x2 _ MAX [h.x2, r.x2];	h.y2 _ MAX [h.y2, r.y2]
ENDLOOP;
stored _ NEW [CD.Rect _ h];
self.properties _ CoreProperties.PutProp [self.properties, bbKey, stored]
END
END;	-- RecordCellHull
TransistorHull: CellHullProc ~ BEGIN
stored: REF CD.Rect _ NARROW [CoreProperties.GetProp [self.properties, bbKey]];
IF (stored = NIL) THEN BEGIN
wire: Core.Wire = self.public;
IF wire.size = 0 THEN break;	-- atomic wire not expected here
FOR i: NAT IN [0 .. wire.size) DO
a: CD.Rect = AtomicWireHull [wire[i], state];
h.x1 _ MIN [h.x1, a.x1];	h.y1 _ MIN [h.y1, a.y1];
h.x2 _ MAX [h.x2, a.x2];	h.y2 _ MAX [h.y2, a.y2]
ENDLOOP;
stored _ NEW [CD.Rect _ h];
self.properties _ CoreProperties.PutProp [self.properties, bbKey, stored]
END
END;	-- TransistorHull
UnspecifiedHull: CellHullProc ~ BEGIN
stored: REF CD.Rect _ NARROW [CoreProperties.GetProp [self.properties, bbKey]];
IF (stored = NIL) THEN BEGIN
stored _ NEW [CD.Rect _ h];
self.properties _ CoreProperties.PutProp [self.properties, bbKey, stored]
END
END;	-- UnspecifiedHull
RegisterPruningProcs: PROC ~ BEGIN
CoreClasses.recordCellClass.properties _ CoreProperties.PutProp [
on: CoreClasses.recordCellClass.properties,
prop: cellHull,
value: NEW [CellHullProc _ RecordCellHull]];
CoreClasses.transistorCellClass.properties _ CoreProperties.PutProp [CoreClasses.transistorCellClass.properties, cellHull, NEW [CellHullProc _ TransistorHull]];
CoreClasses.unspecifiedCellClass.properties _ CoreProperties.PutProp [CoreClasses.unspecifiedCellClass.properties, cellHull, NEW [CellHullProc _ UnspecifiedHull]]
END;	-- RegisterPruningProcs
CreateBindingTable: PROC [actual, public: Core.Wire] RETURNS [bindingTable: RefTab.Ref] ~ BEGIN
tableSize: RefTab.SeqIndex _ public.size;
IF actual.size # public.size THEN BEGIN
IF debug THEN BEGIN
dLog.Put1 [IO.rope ["actual.size # public.size. Actual wire:\n"]]; PrintWire [actual];
dLog.Put1 [IO.rope ["Public wire:\n"]]; PrintWire [public];
ERROR
END
ELSE coreMess
END;
IF (tableSize MOD 2) = 0 THEN tableSize _ tableSize.SUCC;
bindingTable _ RefTab.Create [tableSize];
FOR i: NAT IN [0 .. public.size) DO
[] _ RefTab.Insert [x: bindingTable, key: public[i], val: actual[i]]
ENDLOOP
END;	-- CreateBindingTable
FlushBindingTable: PROC [bindingTable: RefTab.Ref] ~ INLINE BEGIN
bindingTable _ NIL
END;	-- FlushBindingTable
PropagateBinding: PROC [state: State, bindingTable: RefTab.Ref, actual: Core.Wire] RETURNS [boundActual: Core.Wire] ~ BEGIN
PropagateAtomic: PROC [state: State, bindingTable: RefTab.Ref, actual: Core.Wire] RETURNS [boundActual: Core.Wire] ~ INLINE BEGIN
boundActual _ NARROW [RefTab.Fetch [bindingTable, actual].val];
IF boundActual = NIL THEN BEGIN
name: Rope.ROPE = IF debug THEN IO.PutFR1 ["New signal # %g", IO.card [state.wireCreationCount]] ELSE "New signal by SoS";
boundActual _ CoreOps.CreateWires [size: 0, name: name];
state.wireCreationCount _ state.wireCreationCount.SUCC;
[] _ RefTab.Insert [x: bindingTable, key: actual, val: boundActual]
END
ELSE boundActual _ CoreOps.SetShortWireName [boundActual, CoreOps.GetShortWireName[actual]]
END;	-- PropagateAtomic
boundActual _ CoreOps.CreateWires [actual.size];
FOR i: NAT IN [0 .. actual.size) DO
boundActual[i] _ PropagateAtomic [state, bindingTable, actual[i]]
ENDLOOP
END;	-- PropagateBinding
BindInternal: PROC [bindingTable: RefTab.Ref, internal: Core.Wire, state: State] RETURNS [boundInternal: Core.Wire] ~ BEGIN
boundInternal _ CoreOps.CopyWire [internal];
FOR i: NAT IN [0 .. internal.size) DO
b: Core.Wire = NARROW [RefTab.Fetch [bindingTable, internal[i]].val];
IF b # NIL THEN BEGIN
boundInternal[i] _ b;
boundInternal[i].properties _ CoreProperties.CopyProps [internal[i].properties]
END
ENDLOOP
END;	-- BindInternal
BindTransistor: PROC [public, actual: Core.Wire, state: State] RETURNS [tw: Core.Wire] ~ BEGIN
tw _ CoreOps.CopyWire [public];
FOR i: NAT IN [0 .. public.size) DO
tw[i] _ actual[i];
tw[i].properties _ CoreProperties.CopyProps [public[i].properties]
ENDLOOP
END;	-- BindTransistor
MaterialToCellProc: TYPE = SoS.MaterialToCellProc;
CellToCellProc: TYPE = SoS.CellToCellProc;
WidthCheck: PROC [c: Core.CellType, s: State, w: Core.Wire] ~ BEGIN
min: CD.Number;
r: CD.Rect;	l: CD.Layer;	key: ATOM;
il: CD.InstanceList = NARROW [CoreProperties.GetProp [w.properties, s.cdInstListKey]];
FOR i: CD.InstanceList _ il, i.rest WHILE i # NIL DO
[r, l] _ FindCDRect [i.first];
key _ CD.LayerKey [l];
IF (l < specialLayers) OR (key = NIL) THEN LOOP;
min _ CDSimpleRules.MinWidth [l];
IF ((r.x2 - r.x1) < min) OR ((r.y2 - r.y1) < min) THEN
MarkError [c, s, [r, Rope.Cat ["Width violation on layer ", Atom.GetPName [CD.LayerKey [l]], " (wire ", CoreOps.GetShortWireName[w], ")"]]]
ENDLOOP
END;	-- WidthCheck
MaterialSeparation: PROC [cell: Core.CellType, state: State, w1, w2: Core.Wire, loc1, loc2: CD.Position, orient1, orient2: CD.Orientation] ~ BEGIN
cd1, cd2: CD.InstanceList;	obj1, obj2: CD.Object;
r1, r2, r, s: CD.Rect;
l1, l2: CD.Layer;	key1, key2: ATOM;
sep: CD.Number;
Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN
RETURN [CDBasics.Intersect [CDBasics.Extend[AtomicWireHull[w1,state],state.maxSeparation], AtomicWireHull[w2,state]]]
END;	-- Intersect
IF state.abort^ THEN ERROR ABORTED;
IF (w1 = w2) THEN RETURN;	-- aequipotential material
cd1 _ NARROW [CoreProperties.GetProp [w1.properties, state.cdInstListKey]];
cd2 _ NARROW [CoreProperties.GetProp [w2.properties, state.cdInstListKey]];
IF (cd1 = NIL) OR (cd2 = NIL) THEN RETURN;	-- Skip wires without geometry
IF (NOT Intersect[]) THEN RETURN;		-- or whose geometry is too far apart.
FOR outer: CD.InstanceList _ cd1, outer.rest WHILE outer # NIL DO
obj1 _ outer.first.ob;
[r1, l1] _ FindCDRect [outer.first];
key1 _ CD.LayerKey [l1];
IF (l1 < specialLayers) OR (key1 = NIL) THEN LOOP;
r1 _ CDOrient.MapRect [itemInCell: r1,
cellSize: outer.first.ob.size,
cellInstOrient: orient1,
cellInstPos: loc1];
FOR inner: CD.InstanceList _ cd2, inner.rest WHILE inner # NIL DO
IF state.abort^ THEN ERROR ABORTED;
obj2 _ inner.first.ob;
IF debug AND (obj1#NIL) AND (obj2#NIL) AND (CDProperties.GetProp[obj1,$SoSBreak]#NIL) AND (CDProperties.GetProp[obj1,$SoSBreak]#NIL) THEN SIGNAL break;
[r2, l2] _ FindCDRect [inner.first];
key2 _ CD.LayerKey [l2];
IF (l2 < specialLayers) OR (key2 = NIL) THEN LOOP;
sep _ CDSimpleRules.MinDist [l1, l2 ! CDSimpleRules.NotKnown => sep _ 0];
IF sep = 0 THEN LOOP;
r2 _ CDOrient.MapRect [r2, inner.first.ob.size, orient2, loc2];
r _ CDBasics.Extend [r1, sep / 2]; s _ CDBasics.Extend [r2, sep / 2];
IF ((r.x1<s.x2) AND (s.x1<r.x2) AND (r.y1<s.y2) AND (s.y1<r.y2)) THEN BEGIN
rect1: Rope.ROPE = Rope.Cat [Atom.GetPName [key1], " (wire ", CoreOps.GetShortWireName[w1], ")"];
rect2: Rope.ROPE = Rope.Cat [Atom.GetPName [key2], " (wire ", CoreOps.GetShortWireName[w2], ")"];
MarkError [cell, state, [CDBasics.Intersection[r,s], Rope.Cat["Separation violation between ", rect1, " and ", rect2]]];
END
ENDLOOP	-- inner
ENDLOOP	-- outer
END;	-- MaterialSeparation
MaterialToCellSeparation: MaterialToCellProc ~ BEGIN
Send: PROC ~ INLINE BEGIN
check: REF MaterialToCellProc _ NARROW [CoreProperties.GetProp [self.properties, matToCell]];
IF check = NIL THEN check _ NARROW [CoreProperties.GetProp [self.class.properties, matToCell]];
IF check = NIL THEN BEGIN
obj: CD.Object = GetObject [self, state];
IF obj = NIL THEN RETURN;	-- Cell contains no rectangles
check _ NEW [MaterialToCellProc _ MaterialToUnspecifiedSeparation];
MarkError [self, state, [obj.class.interestRect[obj], "Cell has no provisions to be checked"]]
END;
check^ [self, state, actual, wire, father, materialLoc, cellLoc, materialOrient, cellOrient]
END;	-- Send
IF fast THEN
SELECT self.class FROM
CoreClasses.recordCellClass => MaterialToRecordCellSeparation [self, state, actual, wire, father, materialLoc, cellLoc, materialOrient, cellOrient];
CoreClasses.transistorCellClass => MaterialToTransistorSeparation [self, state, actual, wire, father, materialLoc, cellLoc, materialOrient, cellOrient];
CoreClasses.unspecifiedCellClass => MaterialToUnspecifiedSeparation [self, state, actual, wire, father, materialLoc, cellLoc, materialOrient, cellOrient];
ENDCASE => Send []
ELSE Send []
END;	-- MaterialToCellSeparation
MaterialToTransistorSeparation: MaterialToCellProc ~ BEGIN
wbb, tbb: CD.Rect;		-- bounding boxes
tw: Core.Wire;
Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN
RETURN [CDBasics.Intersect [CDBasics.Extend[tbb,state.maxSeparation], wbb]]
END;	-- Intersect
IF state.abort^ THEN ERROR ABORTED;
IF (CoreProperties.GetProp [self.properties, doNotAnalyse] # NIL) THEN RETURN;
wbb _ AtomicWireHull [wire, state];
wbb _ CDOrient.MapRect [itemInCell: wbb,
cellSize: CDBasics.SizeOfRect [wbb],
cellInstOrient: materialOrient,
cellInstPos: materialLoc];
tbb _ TransistorHull [self, state];
tbb _ CDOrient.MapRect [itemInCell: tbb,
cellSize: CDBasics.SizeOfRect [tbb],
cellInstOrient: cellOrient,
cellInstPos: cellLoc];
IF (NOT Intersect[]) THEN RETURN;
tw _ BindTransistor [self.public, actual, state];
FOR i: NAT IN [0 .. tw.size) DO
MaterialSeparation [state: state,
cell: father,
w1: tw[i],
w2: wire,
loc1: cellLoc,
loc2: materialLoc,
orient1: cellOrient, 
orient2: materialOrient]
ENDLOOP
END;	-- MaterialToTransistorSeparation
MaterialToUnspecifiedSeparation: MaterialToCellProc ~ BEGIN
NULL
END;	-- MaterialToUnspecifiedSeparation
MaterialToRecordCellSeparation: MaterialToCellProc  ~ BEGIN
wbb, cbb: CD.Rect;		-- bounding boxes
boundInternal: Core.Wire;
propagatedActuals: WireSet;	-- one wire per subcell
bindingTable: RefTab.Ref;
cellData: CoreClasses.RecordCellType _ NARROW [self.data];
Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN
RETURN [CDBasics.Intersect [CDBasics.Extend[cbb,state.maxSeparation], wbb]]
END;	-- Intersect
IF state.abort^ THEN ERROR ABORTED;
IF (CoreProperties.GetProp [self.properties, doNotAnalyse] # NIL) OR (cellData.internal.size = 0) THEN RETURN;
wbb _ AtomicWireHull [wire, state];
wbb _ CDOrient.MapRect [itemInCell: wbb,
cellSize: CDBasics.SizeOfRect [wbb],
cellInstOrient: materialOrient,
cellInstPos: materialLoc];
cbb _ RecordCellHull [self, state];
cbb _ CDOrient.MapRect [itemInCell: cbb,
cellSize: CDBasics.SizeOfRect [cbb],
cellInstOrient: cellOrient,
cellInstPos: cellLoc];
IF (NOT Intersect[]) THEN RETURN;
bindingTable _ CreateBindingTable [actual: actual, public: self.public];
boundInternal _ BindInternal [bindingTable, cellData.internal, state];
FOR i: NAT IN [0 .. boundInternal.size) DO
MaterialSeparation [state: state,
cell: father,
w1: boundInternal[i],
w2: wire,
loc1: cellLoc,
loc2: materialLoc,
orient1: cellOrient, 
orient2: materialOrient]
ENDLOOP;
propagatedActuals _ NEW [WireSetRec[cellData.size]];
FOR sub: NAT IN [0 .. cellData.size) DO
propagatedActuals[sub] _ PropagateBinding [state, bindingTable, cellData.instances[sub].actual]
ENDLOOP;
FlushBindingTable [bindingTable];
FOR sub: NAT IN [0 .. cellData.size) DO
cdInst: CD.Instance = NARROW [CoreProperties.GetProp [cellData.instances[sub].properties, state.cdInstKey]];
IF (cdInst = NIL) THEN coreMess;
MaterialToCellSeparation [self: cellData.instances[sub].type,
state: state,
actual: propagatedActuals[sub],
wire: wire,
father: self,
materialLoc: materialLoc,
cellLoc: CDBasics.AddPoints [cellLoc, cdInst.location],
materialOrient: materialOrient,
cellOrient: CDOrient.ComposeOrient [cellOrient, cdInst.orientation]]
ENDLOOP
END;	-- MaterialToRecordCellSeparation
CellToCellSeparation: CellToCellProc ~ BEGIN
Send: PROC ~ INLINE BEGIN
check: REF CellToCellProc _ NARROW [CoreProperties.GetProp [self.properties, cellToCell]];
IF check = NIL THEN check _ NARROW [CoreProperties.GetProp [self.class.properties, cellToCell]];
IF check = NIL THEN BEGIN
obj: CD.Object = GetObject [self, state];
IF obj = NIL THEN RETURN;	-- Cell contains no rectangles
check _ NEW [CellToCellProc _ UnspecifiedToAnyClassSeparation];
MarkError [self, state, [obj.class.interestRect[obj], "Cell has no provisions to be checked"]]
END;
check^ [self, state, otherCell, selfActual, otherActual, father, selfLoc, otherLoc, selfOrient, otherOrient]
END;	-- Send
SELECT otherCell.class FROM
CoreClasses.unspecifiedCellClass => RETURN;
CoreClasses.recordCellClass => NULL;	-- default case
CoreClasses.transistorCellClass =>	-- nasty case
IF self.class = CoreClasses.transistorCellClass THEN BEGIN
IF fast THEN
TransistorToTransistorSeparation [self, state, otherCell, selfActual, otherActual, father, selfLoc, otherLoc, selfOrient, otherOrient]
ELSE Send [];
RETURN
END
ELSE BEGIN	-- swap
selfZ: Core.CellType = self;
selfActualZ: Core.Wire = selfActual;
selfLocZ: CD.Position = selfLoc;
selfOrientZ: CD.Orientation = selfOrient;
self _ otherCell;		otherCell _ selfZ;
selfActual _ otherActual;	otherActual _ selfActualZ;
selfLoc _ otherLoc;		otherLoc _ selfLocZ;
selfOrient _ otherOrient;		otherOrient _ selfOrientZ
END;
ENDCASE => ERROR;
IF fast THEN
SELECT self.class FROM
CoreClasses.recordCellClass => RecordCellToRecordCellSeparation [self, state, otherCell, selfActual, otherActual, father, selfLoc, otherLoc, selfOrient, otherOrient];
CoreClasses.transistorCellClass => TransistorToRecordCellSeparation [self, state, otherCell, selfActual, otherActual, father, selfLoc, otherLoc, selfOrient, otherOrient];
CoreClasses.unspecifiedCellClass => UnspecifiedToAnyClassSeparation [self, state, otherCell, selfActual, otherActual, father, selfLoc, otherLoc, selfOrient, otherOrient];
ENDCASE => Send []
ELSE Send []
END;	-- CellToCellSeparation
TransistorToRecordCellSeparation: CellToCellProc ~ BEGIN
cbb1, cbb2: CD.Rect;		-- bounding boxes
othersCellData: CoreClasses.RecordCellType _ NARROW [otherCell.data];
othersBindingTable: RefTab.Ref;
tw: Core.Wire;
othersBoundInternal: Core.Wire;
ownName: Rope.ROPE = CoreOps.GetCellTypeName [self];
otherName: Rope.ROPE = CoreOps.GetCellTypeName [otherCell];
Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN
RETURN [CDBasics.Intersect [CDBasics.Extend[cbb1,state.maxSeparation], cbb2]]
END;	-- Intersect
IF state.abort^ THEN ERROR ABORTED;
IF (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL) OR (CoreProperties.GetProp [otherCell.properties, doNotAnalyse]#NIL) THEN RETURN;
IF debug THEN BEGIN
IO.PutF [stream: dLog,
format: "Checking transistor %l%g%l vs. %g.  ",
v1: IO.rope ["e"],
v2: IF ownName = NIL THEN IO.refAny [self] ELSE IO.rope [ownName],
v3: IO.rope ["E"],
v4: IF otherName = NIL THEN IO.refAny [otherCell] ELSE IO.rope [otherName]];
IO.PutF [stream: dLog,
format: "Rel. orient: %g, dist: (%g, %g).\n",
v1: IO.int [CDOrient.DecomposeOrient [otherOrient, selfOrient]],
v2: IO.int [(otherLoc.x - selfLoc.x) / previousTechnology.lambda],
v3: IO.int [(otherLoc.y - selfLoc.y) / previousTechnology.lambda]]
END;
cbb1 _ RecordCellHull [self, state];
cbb1 _ CDOrient.MapRect [itemInCell: cbb1,
cellSize: CDBasics.SizeOfRect [cbb1],
cellInstOrient: selfOrient,
cellInstPos: selfLoc];
cbb2 _ RecordCellHull [otherCell, state];
cbb2 _ CDOrient.MapRect [itemInCell: cbb2,
cellSize: CDBasics.SizeOfRect [cbb2],
cellInstOrient: otherOrient,
cellInstPos: otherLoc];
IF (NOT Intersect[]) THEN RETURN;
IF state.abort^ THEN ERROR ABORTED;
othersBindingTable _ CreateBindingTable [actual: otherActual, public: otherCell.public];
othersBoundInternal _ BindInternal [othersBindingTable, othersCellData.internal, state];
tw _ BindTransistor [self.public, selfActual, state];
FlushBindingTable [othersBindingTable];
FOR i: NAT IN [0 .. tw.size) DO
FOR j: NAT IN [0 .. othersCellData.internal.size) DO
MaterialSeparation [state: state,
cell: father,	-- the cell getting the error flag --
w1: tw[i],
w2: othersBoundInternal[j],
loc1: selfLoc,
loc2: otherLoc,
orient1: selfOrient,
orient2: otherOrient]
ENDLOOP
ENDLOOP
END;	-- TransistorToRecordCellSeparation
TransistorToTransistorSeparation: CellToCellProc ~ BEGIN
cbb1, cbb2: CD.Rect;		-- bounding boxes
tw1, tw2: Core.Wire;
ownName: Rope.ROPE = CoreOps.GetCellTypeName [self];
otherName: Rope.ROPE = CoreOps.GetCellTypeName [otherCell];
Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN
RETURN [CDBasics.Intersect [CDBasics.Extend[cbb1,state.maxSeparation], cbb2]]
END;	-- Intersect
IF state.abort^ THEN ERROR ABORTED;
IF (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL) OR (CoreProperties.GetProp [otherCell.properties, doNotAnalyse]#NIL) THEN RETURN;
cbb1 _ RecordCellHull [self, state];
cbb1 _ CDOrient.MapRect [itemInCell: cbb1,
cellSize: CDBasics.SizeOfRect [cbb1],
cellInstOrient: selfOrient,
cellInstPos: selfLoc];
cbb2 _ RecordCellHull [otherCell, state];
cbb2 _ CDOrient.MapRect [itemInCell: cbb2,
cellSize: CDBasics.SizeOfRect [cbb2],
cellInstOrient: otherOrient,
cellInstPos: otherLoc];
IF (NOT Intersect[]) THEN RETURN;
IF state.abort^ THEN ERROR ABORTED;
tw1 _ BindTransistor [self.public, selfActual, state];
tw2 _ BindTransistor [otherCell.public, otherActual, state];
FOR i: NAT IN [0 .. tw1.size) DO
FOR j: NAT IN [0 .. tw2.size) DO
MaterialSeparation [state: state,
cell: father,	-- the cell getting the error flag --
w1: tw1[i],
w2: tw2[j],
loc1: selfLoc,
loc2: otherLoc,
orient1: selfOrient,
orient2: otherOrient]
ENDLOOP
ENDLOOP
END;	-- TransistorToTransistorSeparation
UnspecifiedToAnyClassSeparation: CellToCellProc ~ BEGIN
NULL
END;	-- UnspecifiedToAnyClassSeparation
RecordCellToRecordCellSeparation: CellToCellProc ~ BEGIN
cbb1, cbb2: CD.Rect;		-- bounding boxes
ownCellData: CoreClasses.RecordCellType _ NARROW [self.data];
othersCellData: CoreClasses.RecordCellType _ NARROW [otherCell.data];
ownBindingTable, othersBindingTable: RefTab.Ref;
ownBoundInternal, othersBoundInternal: Core.Wire;
ownName: Rope.ROPE = CoreOps.GetCellTypeName [self];
otherName: Rope.ROPE = CoreOps.GetCellTypeName [otherCell];
Intersect: PROC RETURNS [BOOL] ~ INLINE BEGIN
RETURN [CDBasics.Intersect [CDBasics.Extend[cbb1,state.maxSeparation], cbb2]]
END;	-- Intersect
IF state.abort^ THEN ERROR ABORTED;
IF (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL) OR (CoreProperties.GetProp [otherCell.properties, doNotAnalyse]#NIL) THEN RETURN;
IF debug THEN BEGIN
IO.PutF [stream: dLog,
format: "Checking cell %l%g%l vs. %g.  ",
v1: IO.rope ["e"],
v2: IF ownName = NIL THEN IO.refAny [self] ELSE IO.rope [ownName],
v3: IO.rope ["E"],
v4: IF otherName = NIL THEN IO.refAny [otherCell] ELSE IO.rope [otherName]];
IO.PutF [stream: dLog,
format: "Rel. orient: %g, dist: (%g, %g).\n",
v1: IO.int [CDOrient.DecomposeOrient [otherOrient, selfOrient]],
v2: IO.int [(otherLoc.x - selfLoc.x) / previousTechnology.lambda],
v3: IO.int [(otherLoc.y - selfLoc.y) / previousTechnology.lambda]]
END;
cbb1 _ RecordCellHull [self, state];
cbb1 _ CDOrient.MapRect [itemInCell: cbb1,
cellSize: CDBasics.SizeOfRect [cbb1],
cellInstOrient: selfOrient,
cellInstPos: selfLoc];
cbb2 _ RecordCellHull [otherCell, state];
cbb2 _ CDOrient.MapRect [itemInCell: cbb2,
cellSize: CDBasics.SizeOfRect [cbb2],
cellInstOrient: otherOrient,
cellInstPos: otherLoc];
IF (NOT Intersect[]) THEN RETURN;
IF state.abort^ THEN ERROR ABORTED;
ownBindingTable _ CreateBindingTable [actual: selfActual, public: self.public];
othersBindingTable _ CreateBindingTable [actual: otherActual, public: otherCell.public];
ownBoundInternal _ BindInternal [ownBindingTable, ownCellData.internal, state];
othersBoundInternal _ BindInternal [othersBindingTable, othersCellData.internal, state];
FlushBindingTable [ownBindingTable];  FlushBindingTable [othersBindingTable];
FOR i: NAT IN [0 .. ownCellData.internal.size) DO
FOR j: NAT IN [0 .. othersCellData.internal.size) DO
MaterialSeparation [state: state,
cell: father,	-- the cell getting the error flag --
w1: ownBoundInternal[i],
w2: othersBoundInternal[j],
loc1: selfLoc,
loc2: otherLoc,
orient1: selfOrient,
orient2: otherOrient]
ENDLOOP
ENDLOOP
END;	-- RecordCellToRecordCellSeparation
ComputeMaxSeparation: PROC [technology: CD.Technology] RETURNS [maxSeparation: CD.Number] ~ BEGIN
maxSeparation _ 0;
FOR s1: CD.Layer IN CD.Layer DO
IF CD.LayerTechnology[s1] = technology THEN
FOR s2: CD.Layer IN CD.Layer DO
IF CD.LayerTechnology[s2] = technology THEN BEGIN
sep: CD.Number = CDSimpleRules.MinDist [s1, s2 ! CDSimpleRules.NotKnown => LOOP];	-- try to filter out inappropriate layers
maxSeparation _ MAX [maxSeparation, sep]
END
ENDLOOP
ENDLOOP
END;	-- ComputeMaxSeparation
RegisterSeparationProcs: PROC ~ BEGIN
CoreClasses.recordCellClass.properties _ CoreProperties.PutProp [
on: CoreClasses.recordCellClass.properties,
prop: matToCell,
value: NEW [MaterialToCellProc _ MaterialToRecordCellSeparation]];
CoreClasses.transistorCellClass.properties _ CoreProperties.PutProp [CoreClasses.transistorCellClass.properties, matToCell, NEW [MaterialToCellProc _ MaterialToTransistorSeparation]];
CoreClasses.unspecifiedCellClass.properties _ CoreProperties.PutProp [CoreClasses.unspecifiedCellClass.properties, matToCell, NEW [MaterialToCellProc _ MaterialToUnspecifiedSeparation]];
CoreClasses.recordCellClass.properties _ CoreProperties.PutProp [
on: CoreClasses.recordCellClass.properties,
prop: cellToCell,
value: NEW [CellToCellProc _ RecordCellToRecordCellSeparation]];
CoreClasses.transistorCellClass.properties _ CoreProperties.PutProp [CoreClasses.transistorCellClass.properties, cellToCell, NEW [CellToCellProc _ TransistorToRecordCellSeparation]];
CoreClasses.unspecifiedCellClass.properties _ CoreProperties.PutProp [CoreClasses.unspecifiedCellClass.properties, cellToCell, NEW [CellToCellProc _ UnspecifiedToAnyClassSeparation]];
END;	-- RegisterSeparationProcs
ClearErrors: PROC [obj: Core.CellType, state: State] ~ BEGIN
CDErrors.RemoveMessages [
design: state.design,
ob: NARROW [CoreProperties.GetProp [obj.properties, state.cdObjKey]],
owner: DRVkey];
obj.properties _ CoreProperties.PutProp [obj.properties, DRVkey, NIL]
END;	-- ClearErrors
MarkError: PROC [obj: Core.CellType, state: State, e: ErrorRect] ~ BEGIN
objName: Rope.ROPE = CoreOps.GetCellTypeName [obj];
cdObj: CD.Object _ GetObject [obj, state];
violations: DRV _ NARROW [CoreProperties.GetProp [obj.properties, DRVkey]];
longMsg: Rope.ROPE _ IO.PutFR ["%g: %g",
IF objName=NIL THEN IO.refAny [obj] ELSE IO.rope [objName], IO.rope[e.msg]];
done: BOOL _ FALSE;	-- important
IF (violations = NIL) THEN BEGIN
violations _ NEW [DesignRuleViolation];
violations.count _ 1;	violations.places _ LIST [e]
END
ELSE BEGIN
violations.count _ violations.count.SUCC;
violations.places _ CONS [e, violations.places]
END;
obj.properties _ CoreProperties.PutProp [on: obj.properties, prop: DRVkey, value: violations];
state.globalErrorCount  _ state.globalErrorCount.SUCC;
IF state.globalErrorCount < errorFeedbackCutOff THEN IO.Put1 [mLog, IO.char ['|]];
IF (state.design # NIL) AND (cdObj #  NIL) THEN
done _ CDErrors.IncludeMessage [
design: state.design,
ob: cdObj,
rect: CDBasics.Extend [e.r, 1],
message: e.msg,
owner: DRVkey].done;
IF state.abort^ THEN ERROR ABORTED;
IF NOT done THEN longMsg _ Rope.Cat [r1: longMsg, r2: " (not flagged in the layout)"];
IF debug THEN IO.PutF1 [dLog, "%g\n", IO.rope [longMsg]];
IF state.verbose THEN IO.PutF1 [mLog, "\n%g\n", IO.rope [longMsg]]
END;	-- MarkError
PrintError: CoreProperties.PropPrintProc ~ BEGIN
IO.PutF1 [stream: to,
format: "SoS error count = %g ",
value: IO.int [NARROW[val,DRV].count]]
END;	-- PrintError
PrintChecked: CoreProperties.PropPrintProc ~ BEGIN
IO.Put1 [stream: to, value: IO.rope ["Design rules checked"]]
END;	-- PrintChecked
RegisterProperties: PROC ~ BEGIN
IF (NOT CDProperties.RegisterProperty [DRVkey, $gbb])
OR (NOT CDProperties.RegisterProperty [checked, $gbb])
OR (NOT CDProperties.RegisterProperty [bbKey, $gbb])
OR (NOT CDProperties.RegisterProperty [cellHull, $gbb])
OR (NOT CDProperties.RegisterProperty [trace, $gbb])
THEN IF NOT debug THEN ERROR;	-- somebody is already using it. This check is necessary because in some future ChipNDale and Core may get the same property scope and they will then need different keys.
CoreProperties.StoreProperties [prop: DRVkey, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy],
[CoreProperties.propCompare, CoreProperties.PropIntCompare],
[CoreProperties.propPrint, NEW [CoreProperties.PropPrintProc _ PrintError]]]];
CoreProperties.StoreProperties [prop: checked, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy],
[CoreProperties.propPrint, NEW [CoreProperties.PropPrintProc _ PrintChecked]]]];
CoreProperties.StoreProperties [prop: bbKey, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy]]];
CoreProperties.StoreProperties [prop: cellHull, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy]]];
CoreProperties.StoreProperties [prop: trace, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy]]];
CoreProperties.StoreProperties [prop: analysis, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy]]];
CoreProperties.StoreProperties [prop: matToCell, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy]]];
CoreProperties.StoreProperties [prop: cellToCell, properties: CoreProperties.Props [[CoreProperties.propCopy, CoreProperties.PropDoCopy]]];
END;	-- RegisterProperties
StartLog: PROC ~ BEGIN
viewer: ViewerTools.Viewer;
dummy: IO.STREAM;
name: Rope.ROPE;
viewer _ ViewerTools.FindExistingViewer ["Terminal"];
name _ IF viewer # NIL THEN "Terminal" ELSE "Son of Spinifex";
[in: dummy, out: mLog] _ ViewerIO.CreateViewerStreams [name, viewer];
END;	-- StartLog
Debug: PROC  ~ BEGIN
viewer: ViewerTools.Viewer;
dummy: IO.STREAM;
debug _ TRUE;
viewer _ ViewerTools.FindExistingViewer ["SoS debug"];
[in: dummy, out: dLog] _ ViewerIO.CreateViewerStreams ["SoS debug", viewer];
IF dLog = NIL THEN dLog _ mLog
END;	-- Debug
PrintWire: PROC [w: Core.Wire] ~ BEGIN
dLog.PutF ["%g %g %g\n", IO.rope [CoreOps.GetShortWireName[w]], IO.card [LOOPHOLE[w]], IO.refAny [w]];
FOR i: NAT IN [0 .. w.size) DO
dLog.PutF ["\t(%g) %g %g %g\n", IO.card [i], IO.rope [CoreOps.GetShortWireName[w[i]]], IO.card [LOOPHOLE[w[i]]], IO.refAny [w[i]]]
ENDLOOP
END;	-- PrintWire
PrintEntryShort: RefTab.EachPairAction ~ BEGIN
dLog.PutF ["public: %g\t actual: %g\n", IO.card [LOOPHOLE[key]], IO.card [LOOPHOLE[val]]];
RETURN [FALSE]
END;	-- PrintEntryShort
PrintEntryLong: RefTab.EachPairAction ~ BEGIN
PrintWire [NARROW [key, Core.Wire]];	PrintWire [NARROW [val, Core.Wire]];
dLog.Put1 [IO.char['\n]];
RETURN [FALSE]
END;	-- PrintEntryLong
PrintBinding: PROC [bindingTable: RefTab.Ref] ~ BEGIN
[] _ RefTab.Pairs [bindingTable, PrintEntryShort]
END;	-- PrintBinding
StartLog [];	-- Should be first, so problems can be communicated
IF debug THEN Debug[];
RegisterProperties [];	-- CD & Core
RegisterGeomProcs [];	-- ChipNDale
RegisterPruningProcs []; RegisterAnalysisProcs []; RegisterSeparationProcs []	-- Core
END.
��*^��SoSImpl.mesa				Agewmetrhtos
Copyright c 1985 by Xerox Corporation.  All rights reserved.
Giordano Bruno Beretta, October 17, 1985 4:37:14 pm PDT
gbb March 7, 1986 12:55:03 pm PST
SoS is the Son of Spinifex. It is a hierarchical design rule checker that monkeys around in a Core design and tries to find all the ChipNDale geometry in order to check as many design rules as it possibly can.
Gli uomini vollero piuttosto le tenebre che la luce (Giovanni, III, 19.)
Note: Output to noWhereStream passes all I/O code, and hence is very slow !
StateRec: TYPE = RECORD [design: CD.Design,
abort: REF BOOL,
nt: SoSTNT.TNT,
maxSeparation: CD.Number _ 100,
globalErrorCount: CARDINAL,
verbose: BOOL,
wireCreationCount: CARDINAL _ 1,
cdObjKey: ATOM,
cdInstKey: ATOM,
cdInstListKey: ATOM];
RECORD [count: INT _ 0, places: LIST OF ErrorRect]
RECORD [r: CD.Rect, msg: Rope.ROPE]
SoS keys. For simplicity they are registered both with ChipNDale and Core and have the same name
Attached to CellTypes.
Error report may be processed by clients.
Cache for the bounding box.
Debugging only.  Attached to ChipNDale objects processed.
SoS analysis procedures (one for each ChpiNDale object class and one for each Core cell class)
ChipNDale keys used by the Son of Spinifex
Core keys used by the Son of Spinifex
Activation procedure
The external interface.
DRC.
Clean up.
Actions on ChipNDale objects
We have to consider only the objects of the rectangle class. All others are converted to rectangles in the flattening the extractor causes to allow the simulator to highlight nodes.
PROC [self: CD.Instance] RETURNS [r: CD.Rect _ CDBasics.empty, l: CD.Layer _ CD.combined]
PROC [self: CD.Instance] RETURNS [r: CD.Rect _ CDBasics.empty, l: CD.Layer _ CD.combined]
PROC [self: CD.Instance] RETURNS [r: CD.Rect _ CDBasics.empty, l: CD.Layer _ CD.combined]
For objects of the class $Rect.
The object contributes no geometry.
At this place foer ease of maintenance. Called in the module initialisation part.
Actions on Core objects
PROC [self: Core.CellType, state: State, actual: Core.Wire, loc: CD.Position, orient: CD.Orientation];
[self: Core.CellType, state: State, actual: Core.Wire, loc: CD.Position, orient: CD.Orientation]
To be able to compare wires by comparing refs, the bound internal is the actual wire with the properties of the internal wire.  Note that in this way the properties of the internal wire are propagated up to the actual wire; hence the actual wire has to be restored when popping up.
The propagated actuals must be determined here once for all, because new actual wires will differ from call to call.
The catechism states, that the recursion on the subcells has to take place at the end of the check among the internal of self and its subcells, in the procedure MaterialToCellSeparation.  Nomen est omen, so I put the recursion step in here where it makes more sense to me.  Furthermore the catechism states that the world is top-down, and that hence the recursion step is done at the end.  Beside yielding a better program structure, this allows for more agressive (i.e. geometric) pruning.
Check the internal.
Since in this case the error will go into the cell itself, we produce cell relative coordinates by appropriately setting loc1, loc2, orient1, and orient2.
Check the separation between the internal of self and its subcells.
Check the separation between the subcells of self.
Wires that were propagated down under recursion now contain all the geometry of the leaf cells.  Here we restore the status quo ante.
[self: Core.CellType, state: State, actual: Core.Wire, loc: CD.Position, orient: CD.Orientation]
Transistors are atomic ChipNDale objects and are supposed to be correct by construction.
[self: Core.CellType, state: State, actual: Core.Wire, loc: CD.Position, orient: CD.Orientation]
(self.class = CoreClasses.unspecifiedCellClass) OR (CoreProperties.GetProp [self.properties, doNotAnalyse]#NIL);
Called in the module initialisation part.
Pruning
PROC [self: Core.CellType, state: State] RETURNS [h: CD.Rect _ CDBasics.empty]
Coputes the bounding box of the rectangles of material that make up a wire.
PROC [self: Core.CellType, state: State] RETURNS [h: CD.Rect _ CDBasics.empty]
Needed for recursion.
[self: Core.CellType, state: State] RETURNS [h: CD.Rect _ CDBasics.empty]
Note: because of the program flow a run time this recursion does not really propagate, since at this point stored # NIL.
[self: Core.CellType, state: State] RETURNS [h: CD.Rect _ CDBasics.empty]
[self: Core.CellType, state: State] RETURNS [h: CD.Rect _ CDBasics.empty]
Called in the module initialisation part.
Binding
Called to propagate the binding on level down. Applied to the actual wire.
For elements of sequence.
If an actual wire of a subcell is not in the binding table of the containing cell, this wire starts in the containing cell. Hence we create a new wire. It is inserted into the binding table because two cells may share it.
For full sequence.
If the wire is not in the binding table, it does not interface, hence it has not to be bound.
To be able to compare wires by comparing refs, the bound internal is the actual wire with the properties of the internal wire.  Note that in this way the properties of the internal wire are propagated up to the actual wire; hence the actual wire has to be restored when popping up.
We have to preserve the geometry that is hanging on the public subset of the wire.
boundInternal[i] _ CoreOps.SetShortWireName [wire: boundInternal[i],
name: CoreOps.GetShortWireName[internal[i]]];
boundInternal[i].properties _ CopyGeomProps [internal[i].properties, boundInternal[i].properties, state]
Please read comments in BindInternal.
tw[i] _ CoreOps.SetShortWireName [wire: tw[i],
name: CoreOps.GetShortWireName[public[i]]];
tw[i].properties _ CopyGeomProps [public[i].properties, tw[i].properties, state]
CopyGeomProps: PROC [from, to: Core.Properties, state: State] RETURNS [copy: Core.Properties] ~ BEGIN
We need to preserve only the geometric properties, and can care less of the others.
copy _ CoreProperties.PutProp [on: to,
prop: state.cdObjKey,
value: CoreProperties.GetProp [from, state.cdObjKey]];
copy _ CoreProperties.PutProp [on: to,
prop: state.cdInstKey,
value: CoreProperties.GetProp [from, state.cdInstKey]];
copy _ CoreProperties.PutProp [on: to,
prop: state.cdInstListKey,
value: CoreProperties.GetProp [from, state.cdInstListKey]];
copy _ CoreProperties.PutProp [on: to,
prop: bbKey,
value: CoreProperties.GetProp [from, bbKey]];
END;	-- CopyGeomProps
Separation and width check procedures
PROC [self: Core.CellType, state: State, actual, wire: Core.Wire, father: Core.CellType, materialLoc, cellLoc: CD.Position, materialOrient, cellOrient: CD.Orientation];
PROC [self: Core.CellType, state: State, otherCell: Core.CellType, selfActual, otherActual: Core.Wire, father: Core.CellType, selfLoc, otherLoc: CD.Position, selfOrient, otherOrient: CD.Orientation];
The location and orientation are needed place the error rectangle.
At the moment our simplicistic approach does not have any knowledge of the topology. Therefore we cannot really test this rule.
If two unrelated rectangles of material intersect, an error is flagged.
The parameter cell selects the cell receiving possible error messages. It must be the father of the cell containing w1 and the cell containing w2.
Filter out the special layers. Also the extractor creates material at illegal levels. We try heuristically to filter it out here.
Probe 1: Call the debugger. Give property $SoSBreak to two pieces of material that violate a rule but are not flagged.
Probe 2: Set a break point after this line to see why a wrong violation is flagged.
[self: Core.CellType, state: State, actual, wire: Core.Wire, father: Core.CellType, materialLoc, cellLoc: CD.Position, materialOrient, cellOrient: CD.Orientation]
For convenience.
[self: Core.CellType, state: State, actual, wire: Core.Wire, father: Core.CellType, materialLoc, cellLoc: CD.Position, materialOrient, cellOrient: CD.Orientation]
Find the bounding box of wire and check whether it has a non-empty intersection with the internal wire of the cell.
Check each element of the transistor wire of the cell against each element of wire.
[self: Core.CellType, state: State, actual, wire: Core.Wire, father: Core.CellType, materialLoc, cellLoc: CD.Position, materialOrient, cellOrient: CD.Orientation]
[self: Core.CellType, state: State, actual, wire: Core.Wire, father: Core.CellType, materialLoc, cellLoc: CD.Position, materialOrient, cellOrient: CD.Orientation]
Find the bounding box of wire and check whether it has a non-empty intersection with the internal wire of the cell.
Check each element of the internal wire of the cell against each element of wire.
The propagated actuals must be determined here once for all, because new actual wires will differ from call to call.
Check intersections between subcells of cell and wire.
[self: Core.CellType, state: State, otherCell: Core.CellType, selfActual, otherActual: Core.Wire, father: Core.CellType, selfLoc, otherLoc: CD.Position, selfOrient, otherOrient: CD.Orientation]
For convenience.
[self: Core.CellType, state: State, otherCell: Core.CellType, selfActual, otherActual: Core.Wire, father: Core.CellType, selfLoc, otherLoc: CD.Position, selfOrient, otherOrient: CD.Orientation]
Preamble.
Check the separation between the internal of transistor and cell2.
[self: Core.CellType, state: State, otherCell: Core.CellType, selfActual, otherActual: Core.Wire, father: Core.CellType, selfLoc, otherLoc: CD.Position, selfOrient, otherOrient: CD.Orientation]
Preamble.
Check the separation between the internal of cell1 and cell2.
[self: Core.CellType, state: State, otherCell: Core.CellType, selfActual, otherActual: Core.Wire, father: Core.CellType, selfLoc, otherLoc: CD.Position, selfOrient, otherOrient: CD.Orientation]
[self: Core.CellType, state: State, otherCell: Core.CellType, selfActual, otherActual: Core.Wire, father: Core.CellType, selfLoc, otherLoc: CD.Position, selfOrient, otherOrient: CD.Orientation]
Preamble.
Check the separation between the internal of cell1 and cell2.
Initialises the separation table. This is where the technology comes in !
Called in the module initialisation part.
Error flagging
Removes the error rectangles from a given ChipNDale object (e.g. a cell).
Puts an error rectangle r into the ChipNDale object obj, and maintains an error counter in the Core structure.
Property registrations
Registers all properties.
ChipNDale
Core
Logging & Debugging
Iniitalises the log streams. Should cater for errors IO.Error [$Failure, NIL], IO.Error [StreamClosed].
Callable from the interpreter. Creates and enebles the degug log.
For debugging purposes.
[key: Key, val: Val] RETURNS [quit: BOOLEAN]
[key: Key, val: Val] RETURNS [quit: BOOLEAN]
For debugging purposes.
Initialisation
�Ê*}��˜�codešœÐeg™Kšœ
Ïmœ1™<Kšœ7™7K™!—Icode2™ÑIquotešÏsH™HšÏk	˜	Kšœ œ˜Kšœ
 œ˜Kš œ œ£˜«Kšœ	 œA˜OKšœ œ	˜Kšœ	 œ"˜0Kšœ	 œ5˜CKšœ
 œ7˜IKšœ œ˜2Kšœ œ˜(Kšœ œN˜_Kšœ œN˜[Kšœ œ–˜ªKš œ œd œ˜zKšœ œ?˜KKšœ œ œ˜Kšœ œ+ œU˜ŒKšœ œ2 œ˜CKšœ	 œ˜%Kšœ œ˜/—LšÐblœ œ ˜Lš œ œp œ-˜ºš œ ˜Lš œ˜Iunitšœ œ œÏcÏo˜DKšœ
 œ œ¢˜4Kšœ œ œ¢˜1Kšœ	 œ œ¢0˜GKšœ œ œ¢0˜DKšœ œ œ¢&œ	˜FKšœ
 œ œ¢+˜DKšœ œ œ˜&Kšœ œ œ¢˜šœ œ œ œ¢˜0KšœÏe
œ.™K—Lšœ œ¢˜)šœ
 œ˜Kš!œ
 œ œ
 œ œ œ
 œ¢œ œ! œ œ œ œ¢œ œ¢œ œ™ï—Lš œ œ œ¢˜/šœ œ˜4Kš œ	 œ œ œ™2—šœ œ˜ Kš œ œ œ™#—L™`šœ	 œ1˜>Kšœ¤	œ™—šœ œ œ/˜BK™)—šœ œ,˜7K™—šœ œ;˜FKšœ9™9—L™^Kšœ
 œ2˜@Kšœ
 œ.˜<Kšœ œ,˜;Kšœ œ,˜<L™*Kšœ œ	˜Kšœ
 œ˜L™%Kšœ œ
˜Lšœ œ œ˜(Kšœ œ˜'Lšœ œ¢>˜[Lšœ œ¢\˜€Lšœ	 œ œ
¢˜>Kšœ œ œ œ œ œ˜ALšœ	 œ œ
¢˜>Kšœ œ œ œ œ œ˜E—head™šÏnœ œ œ œ
 œ
 œ œ œ œ œ& œ ˜°K™š œ ˜š œ
 œ œ ˜+Kšœ œ œ˜
Kšœ œ˜Kš œ œ
 œ
˜$Kšœ œ œ œ˜Kš ˜Kš ˜—Kš œ˜—Nšœ œ˜Kšœ œ œ˜Kšœ˜Kšœ œ"˜5Nš œ œF œ œ œ œ˜²Kš œ œ œB œ œ œ œ œ œ œ œ˜¾Kšœ˜Kšœ œ
 œ œ œ œ œ œ˜HKš œ œ˜%š œ( œ ˜4KšœA˜AKšœ&˜&Kš œ˜—Kšœ,˜,Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ$˜$N™Kšœ,˜,Kšœ{ œ œ˜ŒKš œ œ˜"š œ œ ˜K™	Kš œ œ˜KšœD œ˜IKšœ˜Kš ˜—Kš
 œ œ= œ œ$ œ˜›Kš œ¢˜——™K™µšœ œ˜&Lš œ œ œ œ œ	 œ
™Y—š¥
œ ˜ Kš œ œ œ œ œ	 œ
™Yš¥œ œ œ ˜Kšœ	 œ œ8˜ZKš œ œ œ œ2˜Xš œ œ œ ˜Kšœ œ\˜iKš œ˜
Kšœ
 œ˜)Kš œ˜—Kšœ˜Kš œ¢˜—š œ ˜š œ ˜$Kšœ*˜*Kšœ'˜'Kš œ˜——Kš œ˜Kš œ¢
˜—š¥œ ˜"Kš œ œ œ œ œ	 œ
™YK™Kš œ œ6˜CKšœ ˜ Kšœ˜Kš œ¢˜—š¥
œ ˜ K™#Kš œ œ5˜BKš œ¢
˜—š¥œ œ ˜K™QKšœ" œ4 œ ˜{Kšœ" œ3 œ˜wKš œ¢˜—š¥	œ œ% œ œ œ ˜[Kšœ œ< œ	˜SKš œ	 œ œ œN˜kKš œ˜
Kš œ¢˜——™šœ œ˜ Kš œ= œ œ™f—š¥
œ ˜ š¥œ œ œ ˜Kšœ œ
 œ6˜SKš œ	 œ œ	 œ<˜^š œ	 œ œ ˜Kšœ œ"˜)Kš	 œ œ œ œ¢˜8Kšœ œ˜%Kšœ^˜^Kš ˜—Kšœ)˜)Kš œ¢˜—š œ ˜š œ ˜KšœN˜NKšœV˜VKšœ$ œ˜)Kš œ˜——Kš œ˜Kš œ¢˜—š¥œ ˜Kšœ< œ œ
™`Kšœ œ˜Kšœ%˜%Kšœ˜Kšœ˜Kšœ¢˜3Kšœ¢$˜:Kšœ œ"˜4Nš œ9 œ œ3 œ œ œ˜†Kš œ
 œ˜Kš œ œ œ? œ œ œ œ œ œ œ œ
˜´Kš œ œ œ œ˜#Kšœ˜Kšœ œ)˜:N™™Kšœ
 œ˜+š œ œ œ ˜#Kšœ@˜@Kš œ˜—NšœH˜HKšœF˜Fš œ
 œ ˜Kšœ= œ˜PKšœ˜Kšœ' œ˜:Kšœ˜Kš œ˜—K™tKšœ œ˜4š œ œ œ ˜'Kšœ_˜_Kš œ˜—Nšœ!˜!Nšœy¤œ$¤œ±™êš œ œ œ ˜'Kšœ œ œP˜lKš œ œ œ
˜ KšœÍ˜ÍKš œ˜—N™š œ
 œ ˜Kšœ0 œ˜CKšœ˜Kš œ˜—Kš	œy¤œ¤œ¤œ¤œ™šš œ œ œ ˜.š œ œ œ ˜.Kšœ œ œ
˜¡Kš ˜—Kšœ*˜*—Kš œ˜Nšœ-¤œ™Cš œ œ œ ˜'Kšœ œ œP˜lKš œ œ œ
˜ š œ œ œ ˜.Kšœ–¢œc˜ŽKš ˜—Kš œ˜—Nšœ-¤œ™2Kš œ œ˜#š œ œ œ ˜(Kšœ	 œ œQ˜nKš œ œ œ
˜!š œ œ œ ˜+Kšœ	 œ œQ˜nKš œ œ œ
˜!Kš œ œX œ ˜oLšœÌ¢œñ˜ÑLš œ œ[˜iLš ˜—Lš œ˜—N™…š œ œ œ ˜(Kšœ@˜@Kš œ˜—NšœL˜LKš œ¢˜—š¥œ ˜"Kšœ< œ œ
™`K™XKšœ-˜-Kš œ¢˜—š¥
œ ˜Kšœ< œ œ
™`Kšœ0 œ9 œ™pKšœL˜LKš œ¢
˜—š¥œ œ ˜#K™)Nšœ… œ˜¤Kšœ{ œ ˜žKšœ} œ˜›Kš œ¢˜——™šœ œ˜&Lš œ% œ œ™N—š	¥œ œ œ œ ˜_K™KKšœ œ œ œ0˜LKšœ œ˜Kš œ œ¢˜/Kš œ œ œ œ˜(Kšœ œ>˜Kš	 œ œ œ œ ˜6Kšœ œ˜$Jšœ œ œ˜1Jšœ œ œ
˜0Kš œ˜—Kšœ	 œ œ˜KšœC˜CKš œ¢˜—š¥œ ˜Lš œ% œ œ™NL™Lšœ œ œ˜,š œ ˜Kšœ6˜6Kšœ:˜:Kšœ<˜<š œ ˜Kšœ œ6˜CKš œ œ œ œ<˜\Kš œ œ œ ˜+Kš ˜——Kš œ˜Kš œ¢˜—š¥œ ˜$Kšœ$ œ œ™IKšœ œ œ œ3˜Oš œ œ œ ˜Kšœ' œ)˜VKš œ œ¢ ˜Jš œ œ œ ˜.Kšœ œ5˜:Jšœ œ œ˜1Jšœ œ œ
˜0Kš œ˜—š œ œ œ ˜'Kšœk¤œ œ™xKšœ œ7˜<Jšœ œ œ˜1Jšœ œ œ
˜0Kš œ˜—Kšœ	 œ œ˜KšœI˜IKš ˜—Kš œ¢˜—š¥œ ˜$Kšœ$ œ œ™IKšœ œ œ œ3˜Oš œ œ œ ˜Kšœ˜Kš œ œ¢ ˜=š œ œ œ ˜!Kšœ œ(˜-Jšœ œ œ˜1Jšœ œ œ
˜0Kš œ˜—Kšœ	 œ œ˜KšœI˜IKš ˜—Kš œ¢˜—š¥œ ˜%Kšœ$ œ œ™IKšœ œ œ œ3˜Oš œ œ œ ˜Kšœ	 œ œ˜KšœI˜IKš ˜—Kš œ¢˜—š¥œ œ ˜"K™)Kšœt¤œ	 œ"˜ªKšœq¤œ œ"˜ Kšœs¤œ œ"˜¢Kš œ¢˜——™š¥œ œ œ ˜_Kšœ)˜)š œ œ ˜'š œ œ ˜Kšœ œI˜VKšœ œ.˜;Kš ˜Kš ˜—Kš œ	˜
Kš œ˜—Kš œ œ œ œ˜9Kšœ)˜)š œ œ œ ˜#KšœD˜DKš ˜—Kš œ¢˜—š¥œ œ œ ˜AKšœ ˜Kš œ¢˜—š¥œ œ= œ ˜{K™Jš	¥œ œ= œ œ ˜K™Kšœ œ+˜?K™Ýš œ œ œ ˜Kš
œ œ œ œ œ œ! œ˜zKšœ8˜8Kšœ2 œ˜7KšœC˜CKš ˜—Kš œW˜[Kš œ¢˜—Nšœ0˜0š œ œ œ ˜#KšœA˜AKš ˜—Kš œ¢˜—š¥œ œ? œ ˜{K™Kšœ,˜,š œ œ œ ˜%Kšœ œ0˜EK™]š œ œ œ ˜K™™Kšœ ˜K™RKšœr™rKšœh™hKšœO˜OKš ˜—Kš ˜—Kš œ¢˜—š¥œ œ+ œ ˜^Kšœ¤œ™%Kšœ˜š œ œ œ ˜#Kšœ˜KšœZ™ZKšœP™PKšœB˜BKš ˜—Kš œ¢˜—š¥
œ œ+ œ ™eK™SKšœs™sKšœu™uKšœ}™}Kšœa™aKš œ¢
™——™%šœ œ˜2Lš œk œ' œ™¨—šœ œ˜*Kš œ œ$ œ™Ç—š¥
œ œ. ˜CK™BK™Kšœ œ˜Kšœ œ
 œ
 œ˜#Kšœ œ œ:˜Vš	 œ œ œ œ ˜4Kšœ˜Kšœ œ˜Kš
 œ œ œ œ œ˜0Kšœ!˜!š œ œ ˜6KšœK œ>˜‹—Kš ˜—Kš œ¢
˜—š	¥œ œD œ œ ˜’K™GKšœ¤œb¤œ¤œ™’Kšœ
 œ œ˜1Kšœ œ˜Kšœ œ œ˜#Kšœ œ˜š¥	œ œ œ œ œ ˜-Kš œo˜uKš œ¢˜—Nš œ œ˜#Kš œ œ œ¢˜4Kšœ œ?˜KKšœ œ?˜KKš
 œ œ œ œ œ œ¢˜IKš	 œ œ œ œ¢&˜Iš	 œ œ  œ	 œ ˜AKšœ˜Kšœ$˜$Kšœ œ˜Kšœ™Kš
 œ œ	 œ œ œ˜2Kšœr˜rš	 œ œ  œ	 œ ˜AKš œ œ˜#Kšœ˜KšÏbœ"¤	œC™vKš œ œ œ œ œ œ' œ œ' œ œ œ˜—Kšœ$˜$Kšœ œ˜Kš
 œ œ	 œ œ œ˜2KšœI˜IKš œ œ œ˜Kšœ?˜?KšœE˜Eš œ œ
 œ
 œ
 œ ˜KKšœ œQ˜aKšœ œQ˜aKš¦œK™SKšœx˜xKš ˜—Kš œ¢˜—Kš œ¢˜—Kš œ¢˜—š¥œ ˜4Kšœj œ' œ
™¢Kšœ™š¥œ œ œ ˜Kšœ œ œ7˜]Kš œ	 œ œ	 œ=˜_š œ	 œ œ ˜Kšœ œ"˜)Kš	 œ œ œ œ¢˜8Kšœ œ8˜CKšœ^˜^Kš ˜—Kšœ\˜\Kš œ¢˜—š œ ˜š œ ˜Kšœ”˜”Kšœ˜˜˜Kšœš˜šKš œ˜——Kš œ˜Kš œ¢˜ —š¥œ ˜:Kšœj œ' œ
™¢Kšœ
 œ¢˜%Kšœ˜š¥	œ œ œ œ œ ˜-Kš œE˜KKš œ¢	˜—Nš œ œ˜#Kš œ; œ œ œ˜NNšœ¤œV™sKšœ#˜#Kšœˆ˜ˆKšœ#˜#Kšœ€˜€Kš œ œ œ œ˜!Nšœ1˜1NšœN¤œ™Sš œ œ œ ˜Kšœ•˜•Kš ˜—Kš œ¢!˜&—š¥œ ˜;Kšœj œ' œ
™¢Kš ˜Kš œ¢"˜'—š¥œ ˜;Kšœj œ' œ
™¢Kšœ
 œ¢˜%Kšœ˜Kšœ¢˜3Kšœ˜Kšœ' œ
˜:š¥	œ œ œ œ œ ˜-Kš œE˜KKš œ¢	˜—Nš œ œ˜#Kš
 œ; œ œ œ œ˜nNšœ¤œV™sKšœ#˜#Kšœˆ˜ˆKšœ#˜#Kšœ€˜€Kš œ œ œ œ˜!NšœL¤œ™QKšœH˜HKšœF˜Fš œ œ œ ˜*Kšœ ˜ Kš œ˜—N™tKšœ œ˜4š œ œ œ ˜'Kšœ_˜_Kš œ˜—Nšœ!˜!Nšœ(¤œ¤œ™6š œ œ œ ˜'Kšœ œ œP˜lKš œ œ œ
˜ Kšœ¼˜¼Kš ˜—Kš œ¢!˜&—š¥œ ˜,LšœŒ œ$ œ
™ÁK™š¥œ œ œ ˜Kšœ œ œ8˜ZKš œ	 œ œ	 œ>˜`š œ	 œ œ ˜Kšœ œ"˜)Kš	 œ œ œ œ¢˜8Kšœ œ4˜?Kšœ^˜^Kš ˜—Kšœl˜lKš œ¢˜—š œ ˜Kšœ$ œ˜+Kšœ œ¢˜4šœ#¢
˜0š œ- œ ˜:š œ ˜Kšœ†˜†—Kš œ	˜
Kš ˜Kš ˜—š œ œ¢˜Kšœ˜Kšœ$˜$Kšœ
 œ˜ Kšœ
 œ˜)Kšœ%˜%Kšœ4˜4Kšœ)˜)Kšœ4˜4Kš œ˜——Kš œ œ˜—š œ ˜š œ ˜Kšœ¦˜¦Kšœª˜ªKšœª˜ªKš œ˜——Kš œ˜Kš œ¢˜—š¥ œ ˜8LšœŒ œ$ œ
™ÁKšœ œ¢˜'Kšœ- œ˜EKšœ˜Kšœ˜Kšœ˜Kšœ œ"˜4Kšœ œ'˜;š¥	œ œ œ œ œ ˜-Kš œG˜MKš œ¢	˜—N™	Kš œ œ˜#Kš œ9 œ œ> œ œ œ˜‘š œ œ ˜Kš œI œ œ œ œ œ œ œ œ œ
 œ œ œ œ œ˜üKš œG œ? œA œ<˜‹Kš œ˜—Kšœ$˜$Kšœƒ˜ƒKšœ)˜)Kšœ…˜…Kš œ œ œ œ˜!Nšœ-¤
œ¤œ™BKš œ œ˜#KšœX˜XKšœX˜XKšœ5˜5Kšœ'˜'š œ œ œ ˜š œ œ œ% ˜4Kšœ0¢%œq˜ÆKš ˜—Kš ˜—Kš œ¢#˜(—š¥ œ ˜8LšœŒ œ$ œ
™ÁKšœ œ¢˜'Kšœ˜Kšœ œ"˜4Kšœ œ'˜;š¥	œ œ œ œ œ ˜-Kš œG˜MKš œ¢	˜—N™	Kš œ œ˜#Kš œ9 œ œ> œ œ œ˜‘Kšœ$˜$Kšœƒ˜ƒKšœ)˜)Kšœ…˜…Kš œ œ œ œ˜!Nšœ-¤œ¤œ™=Kš œ œ˜#Kšœ6˜6Kšœ<˜<š œ œ œ ˜ š œ œ œ ˜ Kšœ0¢%œb˜·Kš ˜—Kš ˜—Kš œ¢#˜(—š¥œ ˜7LšœŒ œ$ œ
™ÁKš ˜Kš œ¢"˜'—š¥ œ ˜8LšœŒ œ$ œ
™ÁKšœ œ¢˜'Kšœ* œ
˜=Kšœ- œ˜EKšœ0˜0Kšœ1˜1Kšœ œ"˜4Kšœ œ'˜;š¥	œ œ œ œ œ ˜-Kš œG˜MKš œ¢	˜—N™	Kš œ œ˜#Kš œ9 œ œ> œ œ œ˜‘š œ œ ˜Kš œC œ œ œ œ œ œ œ œ œ
 œ œ œ œ œ˜öKš œG œ? œA œ<˜‹Kš œ˜—Kšœ$˜$Kšœƒ˜ƒKšœ)˜)Kšœ…˜…Kš œ œ œ œ˜!Nšœ-¤œ¤œ™=Kš œ œ˜#KšœO˜OKšœX˜XKšœO˜OKšœX˜XKšœM˜Mš œ œ œ" ˜1š œ œ œ% ˜4Kšœ0¢%œ˜ÔKš ˜—Kš ˜—Kš œ¢#˜(—š¥œ œ œ
 œ œ ˜aK™IKšœ˜š	 œ œ œ œ ˜š œ œ! ˜+š	 œ œ œ œ ˜š œ œ" œ ˜1Kšœ œD œ¢)˜{Kšœ œ˜(Kš ˜—Kš ˜——Kš ˜—Kš œ¢˜—š¥œ œ ˜%K™)Nšœt¤	œ	 œ8˜ÁKšœq¤	œ œ8˜·Kšœs¤	œ œ9˜ºNšœt¤
œ	 œ6˜ÀKšœq¤
œ œ6˜¶Kšœs¤
œ œ5˜·Kš œ¢˜——™š¥œ œ& ˜<K™IKšœ4 œK˜…KšœA œ˜EKš œ¢˜—š¥	œ œ4 ˜HKšœn™nKšœ œ!˜3Kšœ œ!˜*Kšœ œ œ3˜KKšœ œ œ œ	 œ œ œ œ œ œ˜uKšœ œ œ¢˜ š œ œ œ ˜ Kšœ
 œ˜'Kšœ* œ˜2Kš ˜—š œ ˜
Kšœ$ œ˜)Kšœ œ˜/Kš œ˜—Kšœ^˜^Nšœ1 œ˜6Kš œ. œ œ
 œ˜Rš	 œ œ œ œ ˜/Kšœ†˜†—Kš œ œ œ œ˜#Kš œ œ œF˜VKš œ œ œ œ˜9Kš œ œ œ œ˜BKš œ¢	˜——™š¥
œ! ˜0Kš œ< œ œ œ	˜]Kš œ¢
˜—š¥œ! ˜2Kš œ œ˜=Kš œ¢˜—š¥œ œ ˜ K™N™	š œ œ/ œ œ0 œ œ. œ œ1 œ œ-˜ŽKš œ œ œ œ œ¢ª˜È—N™Kšœ&¤œv œ: œ0˜‘Kšœ&¤œt œ2˜×Kšœ&¤œ[˜†Kšœ&¤œ[˜‰Kšœ&¤œ[˜†Nšœ&¤œ[˜‰Kšœ&¤	œ[˜ŠKšœ&¤
œ[˜‹Kš œ¢˜——™š¥œ œ ˜Kšœ5Ðek¤§¤§¤™gKšœ˜Kšœ œ œ˜Kšœ œ˜Kšœ5˜5Kš	œ œ
 œ œ œ˜>KšœE˜EKš œ¢˜—š¥œ œ ˜K™AKšœ˜Kšœ œ œ˜Kšœ œ˜
Kšœ6˜6KšœL˜LKš œ œ˜Kš œ¢˜
—š¥	œ œ ˜&K™Kš	œ œ% œ œ œ
˜fš œ œ œ ˜Kšœ  œ œ( œ œ	 œ˜‚Kš ˜—Kš œ¢˜—š¥œ ˜.Kšœ œ œ™,Kš	œ( œ œ œ œ˜ZKš œ œ˜Kš œ¢˜—š¥œ ˜-Kšœ œ œ™,Kšœ œ œ˜IKšœ œ˜Kš œ œ˜Kš œ¢˜—š¥œ œ ˜5K™Nšœ1˜1Kš œ¢˜——šœ™Kšœ
¢3˜@Kš œ œ	˜Kšœ¢˜#Kšœ¢˜"KšœN¢˜U—Lš œ˜—�…—����£8��ø��