TNTImpl.mesa
Copyright Ó 1985, 1987 by Xerox Corporation. All rights reserved.
Giordano Bruno Beretta, October 17, 1985 4:37:14 pm PDT
gbb March 28, 1987 6:19:27 pm PST
Implements The Neighbourhood Table for Genista.
Gli uomini vollero piuttosto le tenebre che la luce (Giovanni, III, 19.)
DIRECTORY
Basics USING [CompareLC, Comparison],
BasicTime USING [GMT, Now, Period],
CD USING [Object, Orientation, Transformation],
CDBasics USING [DecomposeOrient],
CDOps USING [ObjectRope],
Checksum USING [ComputeChecksum],
Core USING [Wire],
DrcDebug USING [debug, dLog, PrintWire],
HashTable USING [Create, Delete, EachPairAction, Erase, Fetch, GetSize, Insert, Key, Pairs, SeqIndex, Store, Table, Value],
IO, -- debugging only
PrincOpsUtils USING [],
Rope USING [ROPE],
TNT USING [];
TNTImpl: CEDAR PROGRAM
IMPORTS Basics, BasicTime, CDBasics, CDOps, Checksum, DrcDebug, HashTable, IO
EXPORTS TNT
~ BEGIN
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, relPos: CD.Transformation];
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 [neverAccessed: BOOLTRUE, actual1, actual2: Core.Wire];
TNTrecord: TYPE = RECORD [k: TNTkey, d: TNTdata];
TNTsize: HashTable.SeqIndex = 10007;
TNThighWaterMark: HashTable.SeqIndex = (TNTsize * 2) / 3; -- optimization
sweepInterval: INT = 1200; -- in seconds
Hash: PROC [k: HashTable.Key] RETURNS [CARDINAL] ~ BEGIN
PROC [Key] RETURNS [CARDINAL]
TRUSTED {RETURN [Checksum.ComputeChecksum [0, SIZE [TNTkeyRep], LOOPHOLE [k]]]}
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^ = k2^)]
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.
t.table.Erase; t ← NIL
END; -- BlowTNT
BuildTNTrecord: PROC [o1, o2: CD.Object, t1, t2: CD.Transformation, 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[o1], LOOPHOLE[o2]]};
IF order = greater THEN BEGIN
oZ: CD.Object = o1; tZ: CD.Transformation = t1; aZ: Core.Wire = a1;
o1 ← o2; o2 ← oZ; t1 ← t2; t2 ← tZ;  a1 ← a2; a2 ← aZ
END;
rec.k.cell1 ← o1; rec.k.cell2 ← o2;
rec.k.relPos ← [[t2.off.x - t1.off.x, t2.off.y - t1.off.y], CDBasics.DecomposeOrient [t1.orient, t2.orient]];
rec.d.actual1 ← a1; rec.d.actual2 ← a2
END; -- BuildTNTrecord
RememberTNT: PUBLIC PROC [t: TNT, o1, o2: CD.Object, t1, t2: CD.Transformation, a1, a2: Core.Wire] ~ BEGIN
Puts the two objects in the neighbourhood table.
rec: TNTrecord = BuildTNTrecord [o1, o2, t1, t2, a1, a2];
[] ← t.table.Insert [rec.k, rec.d]
END; -- Remember
InTNT: PUBLIC PROC [t: TNT, o1, o2: CD.Object, t1, t2: CD.Transformation, a1, a2: Core.Wire] RETURNS [BOOL] ~ BEGIN
Asserts that a combination of two cells was already checked.
rec: TNTrecord = BuildTNTrecord [o1, o2, t1, t2, a1, a2];
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] ← t.table.Fetch [rec.k];
data ← NARROW [rawData, TNTdata];
IF DrcDebug.debug AND isThere AND NOT SameSignals [] THEN BEGIN
DrcDebug.dLog.Put1 [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.neverAccessed ← FALSE;
RETURN [isThere]
END; -- InTNT
UpdateTNT: PUBLIC PROC [t: TNT, o1, o2: CD.Object, t1, t2: CD.Transformation, a1, a2: Core.Wire] RETURNS [wasThere: BOOL] ~ BEGIN
Asserts that a combination of two cells was already checked. The new combination is remembered.
rec: TNTrecord = BuildTNTrecord [o1, o2, t1, t2, a1, a2];
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: wasThere, value: rawData] ← t.table.Fetch [rec.k];
data ← NARROW [rawData, TNTdata];
wasThere ← wasThere AND SameSignals [];
IF wasThere THEN data.neverAccessed ← FALSE
ELSE [] ← t.table.Store [rec.k, rec.d]
END; -- UpdateTNT
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: BOOLEANFALSE]
IF NARROW [value, TNTdata].neverAccessed THEN [] ← t.table.Delete [key]
END; -- RemoveCadavers
IF (BasicTime.Period[t.lastSweep,BasicTime.Now[]] > sweepInterval)
AND (t.table.GetSize > TNThighWaterMark) THEN
{[] ← t.table.Pairs [RemoveCadavers]; t.lastSweep ← BasicTime.Now []}
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"];
PrintEltShort: HashTable.EachPairAction ~ BEGIN
[key: Key, value: Value] RETURNS [quit: BOOLEANFALSE]
k: TNTkey = NARROW [key, TNTkey];
data: TNTdata = NARROW [value, TNTdata];
DrcDebug.dLog.PutF ["Key: %g, %g; %g, (%g, %g).\n", IO.card[LOOPHOLE[k.cell1]], IO.card[LOOPHOLE[k.cell2]], IO.rope[rot[k.relPos.orient]], IO.int[k.relPos.off.x], IO.int[k.relPos.off.y]];
FOR i: NAT IN [0 .. data.actual1.size) DO
DrcDebug.dLog.Put [IO.card[LOOPHOLE[data.actual1[i]]], IO.char[' ]]
ENDLOOP;
DrcDebug.dLog.Put1 [IO.char['\n]];
FOR i: NAT IN [0 .. data.actual2.size) DO
DrcDebug.dLog.Put [IO.card[LOOPHOLE[data.actual2[i]]], IO.char[' ]]
ENDLOOP;
DrcDebug.dLog.Put1 [IO.char['\n]]
END; -- PrintEltShort
PrintEltLong: HashTable.EachPairAction ~ BEGIN
[key: Key, value: Value] RETURNS [quit: BOOLEANFALSE]
k: TNTkey = NARROW [key, TNTkey];
data: TNTdata = NARROW [value, TNTdata];
DrcDebug.dLog.PutF ["Key: %g, %g; %g, (%g, %g) ", IO.card[LOOPHOLE[k.cell1]], IO.card[LOOPHOLE[k.cell2]], IO.rope[rot[k.relPos.orient]], IO.int[k.relPos.off.x], IO.int[k.relPos.off.y]];
DrcDebug.dLog.PutF ["[CD objects: <%g>, <%g>].\n", IO.rope[CDOps.ObjectRope[k.cell1]], IO.rope[CDOps.ObjectRope[k.cell2]]];
DrcDebug.PrintWire [data.actual1]; DrcDebug.PrintWire [data.actual2];
DrcDebug.dLog.Put1 [IO.char['\n]]
END; -- PrintEltLong
PrintTNTLong: PROC [t: TNT] ~ BEGIN
For debugging.
DrcDebug.dLog.PutRope ["\nNeighbourhood Table:\n"];
[] ← HashTable.Pairs [t.table, PrintEltLong]
END; -- PrintTNT
END.