DIRECTORY
Basics USING [CompareLC, Comparison],
BasicTime USING [GMT, Now, Period],
CD USING [Instance, Object, Orientation, Position],
CDBasics USING [DecomposeOrient],
CDOps USING [ObjectRope],
Checksum USING [ComputeChecksum],
Core USING [Wire],
CoreOps USING [GetShortWireName],
HashTable USING [Create, Delete, EachPairAction, Erase, Fetch, GetSize, Insert, Key, Pairs, SeqIndex, Table, Value],
IO, -- debugging only
PrincOpsUtils USING [],
Rope USING [ROPE],
SoSTNT USING [],
ViewerIO USING [CreateViewerStreams],
ViewerTools USING [FindExistingViewer, Viewer];
The neighbourhood table
TNT: PUBLIC TYPE = REF TNTRep; -- The Neighbourhood Table
TNTRep: PUBLIC TYPE = RECORD [table: HashTable.Table, lastSweep: BasicTime.GMT];
TNTkey: TYPE = REF TNTkeyRep;
TNTkeyRep:
TYPE =
RECORD [cell1, cell2:
CD.Object,
relOrient:
CD.Orientation,
dist:
CD.Position];
Different wires may point to the same sequence of elements. [Se dovesse essere che la medesima configurazione si ripetesse spesso con differenti segnali, occorrerebbe mettere due campi contenenti i fili xorati.]
TNTdata: TYPE = REF TNTdataRep;
TNTdataRep: TYPE = RECORD [access: REF BOOL,
actual1, actual2: Core.Wire];
TNTrecord: TYPE = RECORD [k: TNTkey, d: TNTdata];
TNTsize: HashTable.SeqIndex = 2973;
TNThighWaterMark: HashTable.SeqIndex = TNTsize / 3 * 2; -- optimization
sweepInterval: INT = 120; -- in seconds
accessed: REF BOOL = NEW [BOOL ← TRUE];
neverAccessed: REF BOOL = NEW [BOOL ← FALSE];
debug: BOOL ← FALSE;
dLog: IO.STREAM ← IO.noWhereStream; -- re-assign with interpreter
Hash:
PROC [k: HashTable.Key]
RETURNS [
CARDINAL] ~
BEGIN
PROC [Key] RETURNS [CARDINAL]
TRUSTED
BEGIN
RETURN [Checksum.ComputeChecksum [0, SIZE [TNTkeyRep], LOOPHOLE [k]]]
END
END; -- Hash
Match:
PROC [a, b: HashTable.Key]
RETURNS [
BOOL] ~
BEGIN
HashTable.EqualProc
k1: TNTkey = NARROW [a, TNTkey]; k2: TNTkey = NARROW [b, TNTkey];
RETURN [(k1.cell1 = k2.cell1) AND (k1.cell2 = k2.cell2) AND (k1.relOrient = k2.relOrient) AND (k1.dist.x = k2.dist.x) AND (k1.dist.y = k2.dist.y)]
END; -- Match
InitTNT:
PUBLIC
PROC
RETURNS [t:
TNT] ~
BEGIN
To be called for each design rule check.
t ← NEW [TNTRep ← [table: HashTable.Create [TNTsize, Match, Hash],
lastSweep: BasicTime.Now []]];
END; -- InitTNT
BlowTNT:
PUBLIC
PROC [t:
TNT] ~
BEGIN
To be called after each design rule check.
HashTable.Erase [t.table]; t ← NIL
END; -- BlowTNT
BuildTNTrecord:
PROC [i1, i2:
CD.Instance, a1, a2: Core.Wire]
RETURNS [rec: TNTrecord] ~
BEGIN
Save a look-up.
order: Basics.Comparison;
rec.k ← NEW [TNTkeyRep]; rec.d ← NEW [TNTdataRep];
TRUSTED {order ← Basics.CompareLC [LOOPHOLE[i1.ob], LOOPHOLE[i2.ob]]};
IF order = greater
THEN
BEGIN
iZ: CD.Instance = i1; aZ: Core.Wire = a1;
i1 ← i2; i2 ← iZ; a1 ← a2; a2 ← aZ
END;
rec.k.cell1 ← i1.ob; rec.k.cell2 ← i2.ob;
rec.k.relOrient ← CDBasics.DecomposeOrient [i1.trans.orient, i2.trans.orient];
rec.k.dist.x ← i2.trans.off.x - i1.trans.off.x;
rec.k.dist.y ← i2.trans.off.y - i1.trans.off.y;
rec.d.access ← neverAccessed;
rec.d.actual1 ← a1; rec.d.actual2 ← a2
END; -- BuildTNTrecord
RememberTNT:
PUBLIC
PROC [t:
TNT, inst1, inst2:
CD.Instance, actual1, actual2: Core.Wire] ~
BEGIN
Puts the two objects in the neighbourhood table.
rec: TNTrecord = BuildTNTrecord [inst1, inst2, actual1, actual2];
[] ← HashTable.Insert [t.table, rec.k, rec.d]
END; -- Remember
InTNT:
PUBLIC
PROC [t:
TNT, inst1, inst2:
CD.Instance, actual1, actual2: Core.Wire]
RETURNS [
BOOL] ~
BEGIN
Asserts that a combination of two cells was already checked.
rec: TNTrecord = BuildTNTrecord [inst1, inst2, actual1, actual2];
isThere: BOOL; rawData: HashTable.Value; data: TNTdata;
SameSignals:
PROC
RETURNS [
BOOL] ~
INLINE
BEGIN
IF (data.actual1.size # rec.d.actual1.size) OR (data.actual2.size # rec.d.actual2.size) THEN RETURN [FALSE];
FOR i:
NAT
IN [0 .. rec.d.actual1.size)
DO
IF (rec.d.actual1[i] # data.actual1[i]) THEN RETURN [FALSE]
ENDLOOP;
FOR i:
NAT
IN [0 .. rec.d.actual2.size)
DO
IF (rec.d.actual2[i] # data.actual2[i]) THEN RETURN [FALSE]
ENDLOOP;
RETURN [TRUE]
END; -- SameSignals
[found: isThere, value: rawData] ← HashTable.Fetch [t.table, rec.k];
data ← NARROW [rawData, TNTdata];
IF debug
AND isThere
AND
NOT SameSignals []
THEN
BEGIN
IO.Put1 [dLog, IO.rope["Same key, but different signals:\n"]];
[] ← PrintEltLong [rec.k, rec.d]; [] ← PrintEltLong [rec.k, data]
END;
isThere ← isThere AND SameSignals [];
IF isThere THEN data.access ← accessed;
RETURN [isThere]
END; -- InTNT
SweepTNT:
PUBLIC
PROC [t:
TNT] ~
BEGIN
If the neighbourhood table is almost full and sufficient time has elapsed, the entries never accessed are removed from the table. To be called periodically by the main Core traversal mechanism. This procedure must be fast as a bullet, so do not put in additional stuff.
RemoveCadavers: HashTable.EachPairAction ~
BEGIN
PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN ← FALSE]
IF NARROW [value, TNTdata].access = neverAccessed THEN [] ← HashTable.Delete [t.table, key]
END; -- RemoveCadavers
IF (BasicTime.Period[t.lastSweep,BasicTime.Now[]] > sweepInterval)
AND (HashTable.GetSize[t.table] > TNThighWaterMark)
THEN
BEGIN
[] ← HashTable.Pairs [t.table, RemoveCadavers];
t.lastSweep ← BasicTime.Now []
END
END; -- SweepTNT
Debugging
rot: ARRAY CD.Orientation OF Rope.ROPE ~ [original: "0", mirrorX: "x", rotate90: "90", rotate90X: "90x", rotate180: "180", rotate180X: "180x", rotate270: "-90", rotate270X: "-90x"];
Debug:
PROC ~
BEGIN
Callable from the interpreter. Creates and enebles the degug log.
viewer: ViewerTools.Viewer;
dummy: IO.STREAM;
debug ← TRUE;
viewer ← ViewerTools.FindExistingViewer ["SoS debug"];
[in: dummy, out: dLog] ← ViewerIO.CreateViewerStreams ["SoS debug", viewer]
END; -- Debug
PrintWire:
PROC [w: Core.Wire] ~
BEGIN
For debugging purposes.
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
PrintEltShort: HashTable.EachPairAction ~
BEGIN
[key: Key, value: Value] RETURNS [quit: BOOLEAN ← FALSE]
k: TNTkey = NARROW [key, TNTkey];
data: TNTdata = NARROW [value, TNTdata];
dLog.PutF ["Key: %g, %g; %g, (%g, %g).\n", IO.card[LOOPHOLE[k.cell1]], IO.card[LOOPHOLE[k.cell2]], IO.rope[rot[k.relOrient]], IO.int[k.dist.x], IO.int[k.dist.y]];
FOR i:
NAT
IN [0 .. data.actual1.size)
DO
IO.Put [dLog, IO.card[LOOPHOLE[data.actual1[i]]], IO.char[' ]]
ENDLOOP;
IO.Put [dLog, IO.char['\n]];
FOR i:
NAT
IN [0 .. data.actual2.size)
DO
IO.Put [dLog, IO.card[LOOPHOLE[data.actual2[i]]], IO.char[' ]]
ENDLOOP;
IO.Put [dLog, IO.char['\n]]
END; -- PrintEltShort
PrintEltLong: HashTable.EachPairAction ~
BEGIN
[key: Key, value: Value] RETURNS [quit: BOOLEAN ← FALSE]
k: TNTkey = NARROW [key, TNTkey];
data: TNTdata = NARROW [value, TNTdata];
dLog.PutF ["Key: %g, %g; %g, (%g, %g) ", IO.card[LOOPHOLE[k.cell1]], IO.card[LOOPHOLE[k.cell2]], IO.rope[rot[k.relOrient]], IO.int[k.dist.x], IO.int[k.dist.y]];
dLog.PutF ["[CD objects: <%g>, <%g>].\n", IO.rope[CDOps.ObjectRope[k.cell1]], IO.rope[CDOps.ObjectRope[k.cell2]]];
PrintWire [data.actual1]; PrintWire [data.actual2]; IO.Put [dLog, IO.char['\n]]
END; -- PrintEltLong
PrintTNTLong:
PROC [t:
TNT] ~
BEGIN
For debugging.
IO.Put1 [dLog, IO.rope["\nNeighbourhood Table:\n"]];
[] ← HashTable.Pairs [t.table, PrintEltLong]
END; -- PrintTNT
IF debug THEN Debug []