TRTestChip.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Last Edited by: Gasbarro September 16, 1988 2:40:19 pm PDT
DIRECTORY
Basics, BitOps, CommandTool, FS, GPIB, IO, Process, Rope, TerminalIO, XBus;
TRTestChip: CEDAR PROGRAM
IMPORTS Basics, BitOps, CommandTool, FS, GPIB, IO, Process, Rope, TerminalIO, XBus
~ BEGIN
Constants and Types
ROPE: TYPE = Rope.ROPE;
BITSHIFT: PROC [value: WORD, count: INTEGER] RETURNS [WORD] = Basics.BITSHIFT;
BITAND: Basics.BitOp = Basics.BITAND;
BITOR: Basics.BitOp = Basics.BITOR;
BITXOR: Basics.BitOp = Basics.BITXOR;
BITNOT: PROC [WORD] RETURNS [WORD] = Basics.BITNOT;
Log2: PROC [n: INT] RETURNS [INT] = BitOps.Log2;
Timing: TYPE = {Sample, Width, Delay};
PEReg: TYPE = [0..16);
PEData: TYPE = [0..1024);
Ram: TYPE = {VRam, HRam, ERam, CRam};
Channel: TYPE = [0..16);
VRamAdd: TYPE = [0..1024);
HalfClocks: TYPE = [0..20);
InvStages: TYPE = [0..20);
EdgeC: TYPE = [0..4);
EdgeF: TYPE = [0..6);
Delay: TYPE = [0..475); --nS
Width: TYPE = [5..475); --nS
Sample: TYPE = [0..480); --nS
Period: TYPE = [30..480); --nS
NSec: TYPE = CARDINAL;
ClockDivisor: TYPE = {one, two, four, eight};
Phase: TYPE = {Even, Odd};
Edge: TYPE = {Leading, Trailing};
Transition: TYPE = {Up, Down};
Format: TYPE = {NRZ, RZ, RO, RC, RT};
DataPattern: TYPE = {p00, p11, p01, p10};
clock8112: GPIB.DeviceAddr = 12;
fineMap: ARRAY EdgeF OF [0..16) = [4, 2, 12, 10, 1, 9];
baseAdd: LONG POINTER = LOOPHOLE[LONG[4000h]];
Globals
gClkPeriod: Period ← 50; --nS
gClkDivisor: ClockDivisor ← one;
gClockCtl: CARDINAL ← 0;
gDebug: BOOLFALSE;
gRamDebug: BOOLFALSE;
gCycOffset: NSec ← 0;
pause: NAT ← 100;
CBus Addresses
Pin Electronics
pinElecBase: CARDINAL ~ 000h; -- up to 17Fh
Each DUT pin
Each Timing Generator (Sample, Width, Delay)
dsr0: CARDINAL ~ 000h;
dsr1: CARDINAL ~ 001h;
invCh0: CARDINAL ~ 002h;
invCh1: CARDINAL ~ 003h;
invCh2: CARDINAL ~ 004h;
risingEdge: CARDINAL ~ 005h;
fallingEdge: CARDINAL ~ 006h;
ioCtl: CARDINAL ~ 007h;
format: CARDINAL ~ 00fh;
Decompressor
decompBase: CARDINAL ~ 180h; -- up to 1FFh
writeLoopAdd: CARDINAL ~ 180h;
writeEndAdd: CARDINAL ~ 181h;
writeExtRamAdd: CARDINAL ~ 182h;
writeExtRamCtl: CARDINAL ~ 183h;
ramWD0: CARDINAL ~ 184h;
ramWD1: CARDINAL ~ 185h;
ramWD2: CARDINAL ~ 186h;
ramWD3: CARDINAL ~ 187h;
dramCtl: CARDINAL ~ 188h;
readDebug: CARDINAL ~ 180h;
readVRamAdd: CARDINAL ~ 181h;
readHRamAdd: CARDINAL ~ 182h;
readCmd: CARDINAL ~ 183h;
ramRD0 : CARDINAL ~ 184h;
ramRD1 : CARDINAL ~ 185h;
ramRD2 : CARDINAL ~ 186h;
ramRD3 : CARDINAL ~ 187h;
Ref Clock Generator (on Multibus card)
extCtlBase: CARDINAL ~ 200h; -- up to 3FFh
clkCtl: CARDINAL  ~ 200h;
refDelay: CARDINAL ~ 201h;
ioCtl Register Bits
phaseComp: CARDINAL ~ 001h;
sampleLate: CARDINAL ~ 002h;
analogSample: CARDINAL ~ 004h;
ttlMode: CARDINAL ~ 008h;
selLateData: CARDINAL ~ 010h;
format Register Bits
nrz: CARDINAL ~ 001h;
rz: CARDINAL ~ 002h;
ro: CARDINAL ~ 004h;
rc: CARDINAL ~ 008h;
rt: CARDINAL ~ 010h;
writeExtRamCtl Register Bits
writeCRam: CARDINAL ~ 101h;
writeERam: CARDINAL ~ 102h;
writeHRam: CARDINAL ~ 104h;
writeVRam: CARDINAL ~ 108h;
readCRam: CARDINAL ~ 110h;
readERam: CARDINAL ~ 120h;
readHRam: CARDINAL ~ 140h;
readVRam: CARDINAL ~ 180h;
extRamAccess: CARDINAL ~ 100h;
vramBypass: CARDINAL ~ 200h;
readDebug Register Bits
resetMinus1: CARDINAL ~ 001h;
wrHRamLow: CARDINAL ~ 002h;
wrHRamHigh: CARDINAL ~ 004h;
fetchCmd: CARDINAL ~ 008h;
prefetch: CARDINAL ~ 010h;
error: CARDINAL ~ 020h;
InitSystem: PROC ~ {
IF gDebug THEN TerminalIO.PutRope["\nInit\n"];
InitGPIBDevices[];
SetRefDelayAbs[0];
CBusWrite[clkCtl, 0];
gClockCtl ← 0;
SetClock[100];
};
Reset: PROC ~ {
IF gDebug THEN TerminalIO.PutRope["Reset\n"];
StartCtl[FALSE, FALSE, FALSE];
CBusWrite[writeLoopAdd, 0];
CBusWrite[writeEndAdd, 0];
CBusWrite[writeExtRamCtl, 0];
StartCtl[FALSE, FALSE, TRUE];
StartCtl[FALSE, FALSE, FALSE];
};
RZDemo: PROC [lastChan: Channel] ~ {
SetClock[200];
FindTZero[];
FOR ch: Channel IN [0..lastChan] DO
RZMode[ch, ch*10, 20];
ENDLOOP;
};
FindTZero: PROC ~ {
In RZ mode force the output of the pulse generator high so that only the transitions resulting from changes in the data pipeline are observed. Skew RefCk to measure the time when the data transition occurs. Measure both rising and falling edges and call the greater of the two times the beginning of the cycle.
biggest: Channel ← 0;
new: NSec ← 0;
gCycOffset ← 0;
ClearAllPE[];
SetDataPattern[p10];
FOR ch: Channel IN Channel DO
SetFormat[ch, RZ];
ForcePulseHigh[ch];
new ← MAX[FindOutputEdge[ch, Even, Up], FindOutputEdge[ch, Odd, Down]];
IF new>gCycOffset THEN {gCycOffset ← new; biggest ← ch};
ENDLOOP;
TerminalIO.PutF["Cycle Start Offset = %g, chan: %g\n", IO.int[gCycOffset], IO.int[biggest]];
};
NRZMode: PROC [ch: Channel, delay: Delay] ~ {
dhc, whc: HalfClocks ← 0;
dis, wis: InvStages ← 0;
delayFix: NAT ← 0;
TerminalIO.PutF["Chan: %g, NRZ, Delay: %g\n", IO.int[ch], IO.int[delay]];
[dhc, dis] ← CalibrateDL[ch, Delay, delay];
[whc, wis] ← CalibrateDL[ch, Width, delay+20]; --doesn't matter how wide
MakePulse[ch, NRZ, dhc, dis, whc, wis];
DO
WHILE HoneEdge[ch, Leading, Even, Up, delay, p10] DO
IF (delayFix ← delayFix+1) > 7 THEN ERROR;
[dhc, dis] ← CalibrateDL[ch, Delay, delay-delayFix];
MakePulse[ch, NRZ, dhc, dis, whc, wis];
ENDLOOP;
IF HoneEdge[ch, Leading, Odd, Up, delay, p01] THEN {
IF (delayFix ← delayFix+1) > 7 THEN ERROR;
[dhc, dis] ← CalibrateDL[ch, Delay, delay-delayFix];
MakePulse[ch, NRZ, dhc, dis, whc, wis];
LOOP;
};
EXIT;
ENDLOOP;
SetDataPattern[p10]; --Display the result
SetRefDelay[0];
};
RZMode: PROC [ch: Channel, delay: Delay, width: Width] ~ {
dhc, whc: HalfClocks ← 0;
dis, wis: InvStages ← 0;
delayFix, widthFix: NAT ← 0;
TerminalIO.PutF["Chan: %g, RZ, Delay: %g, Width: %g\n", IO.int[ch], IO.int[delay], IO.int[width]];
[dhc, dis] ← CalibrateDL[ch, Delay, delay];
[whc, wis] ← CalibrateDL[ch, Width, delay+width];
MakePulse[ch, RZ, dhc, dis, whc, wis];
DO
WHILE HoneEdge[ch, Leading, Even, Up, delay, p10] DO
IF (delayFix ← delayFix+1) > 7 THEN ERROR;
[dhc, dis] ← CalibrateDL[ch, Delay, delay-delayFix];
MakePulse[ch, RZ, dhc, dis, whc, wis];
ENDLOOP;
WHILE HoneEdge[ch, Trailing, Even, Down, delay+width, p10] DO
IF (widthFix ← widthFix+1) > 7 THEN ERROR;
[whc, wis] ← CalibrateDL[ch, Width, delay+width-widthFix];
MakePulse[ch, RZ, dhc, dis, whc, wis];
ENDLOOP;
IF HoneEdge[ch, Leading, Odd, Up, delay, p01] THEN {
IF (delayFix ← delayFix+1) > 7 THEN ERROR;
[dhc, dis] ← CalibrateDL[ch, Delay, delay-delayFix];
MakePulse[ch, RZ, dhc, dis, whc, wis];
LOOP;
};
IF HoneEdge[ch, Trailing, Odd, Down, delay+width, p01] THEN {
IF (widthFix ← widthFix+1) > 7 THEN ERROR;
[whc, wis] ← CalibrateDL[ch, Width, delay+width-widthFix];
MakePulse[ch, RZ, dhc, dis, whc, wis];
LOOP;
};
EXIT;
ENDLOOP;
SetDataPattern[p11]; --Display the result
SetRefDelay[0];
};
ROMode: PROC [ch: Channel, delay: Delay, width: Width] ~ {
dhc, whc: HalfClocks ← 0;
dis, wis: InvStages ← 0;
delayFix, widthFix: NAT ← 0;
TerminalIO.PutF["Chan: %g, RO, Delay: %g, Width: %g\n", IO.int[ch], IO.int[delay], IO.int[width]];
[dhc, dis] ← CalibrateDL[ch, Delay, delay];
[whc, wis] ← CalibrateDL[ch, Width, delay+width];
MakePulse[ch, RO, dhc, dis, whc, wis];
DO
WHILE HoneEdge[ch, Leading, Even, Down, delay, p01] DO
IF (delayFix ← delayFix+1) > 7 THEN ERROR;
[dhc, dis] ← CalibrateDL[ch, Delay, delay-delayFix];
MakePulse[ch, RO, dhc, dis, whc, wis];
ENDLOOP;
WHILE HoneEdge[ch, Trailing, Even, Up, delay+width, p01] DO
IF (widthFix ← widthFix+1) > 7 THEN ERROR;
[whc, wis] ← CalibrateDL[ch, Width, delay+width-widthFix];
MakePulse[ch, RO, dhc, dis, whc, wis];
ENDLOOP;
IF HoneEdge[ch, Leading, Odd, Down, delay, p10] THEN {
IF (delayFix ← delayFix+1) > 7 THEN ERROR;
[dhc, dis] ← CalibrateDL[ch, Delay, delay-delayFix];
MakePulse[ch, RO, dhc, dis, whc, wis];
LOOP;
};
IF HoneEdge[ch, Trailing, Odd, Up, delay+width, p10] THEN {
IF (widthFix ← widthFix+1) > 7 THEN ERROR;
[whc, wis] ← CalibrateDL[ch, Width, delay+width-widthFix];
MakePulse[ch, RO, dhc, dis, whc, wis];
LOOP;
};
EXIT;
ENDLOOP;
SetDataPattern[p00]; --Display the result
SetRefDelay[0];
};
RTMode: PROC [ch: Channel, delay: Delay, width: Width] ~ {
RZMode[ch, delay, width];
SetFormat[ch, RT];
};
RCMode: PROC [ch: Channel, delay: Delay, width: Width] ~ {
RZMode[ch, delay, width];
SetFormat[ch, RC];
};
MakePulse: PROC [ch: Channel, f: Format, dhc: HalfClocks, dis: InvStages, whc: HalfClocks, wis: InvStages] ~ {
SetFormat[ch, f];
SetTimingChan[ch, Delay, dhc, dis];
SetTimingChan[ch, Width, whc, wis];
};
FindHC: PROC [ch: Channel, tg: Timing, t: Transition, start: HalfClocks ← 0] RETURNS [hc: HalfClocks ← 0] ~ {
SetTimingChan[ch, tg, 0, 0];
hc ← start;
WHILE NOT EdgeIsEarly[ch, t] DO
SetTimingChan[ch, tg, (hc←hc+1), 0];
ENDLOOP;
WHILE EdgeIsEarly[ch, t] DO
SetTimingChan[ch, tg, (hc←hc+1), 0];
ENDLOOP;
};
FindIS: PROC [ch: Channel, tg: Timing, hc: HalfClocks, t: Transition] RETURNS [is: InvStages ← 0]~ {
SetTimingChan[ch, tg, hc, 0];
WHILE EdgeIsEarly[ch, t] DO
SetTimingChan[ch, tg, hc, (is←is+1)];
ENDLOOP;
};
CalibrateDL: PROC [ch: Channel, tg: Timing, ns: NSec] RETURNS [hc: HalfClocks, is: InvStages] ~ {
Cal: PROC [t: Transition] RETURNS [hc: HalfClocks ← 0, is: InvStages ← 0] ~ {
IF (hc ← FindHC[ch, tg, t]) = 0 THEN hc ← FindHC[ch, tg, t, 1];
hc ← hc-1;
IF (is ← FindIS[ch, tg, hc, t]) = 0 THEN
IF hc#0 THEN {
hc ← hc-1;
is ← FindIS[ch, tg, hc, t];
} ELSE {
hc ← FindHC[ch, tg, t, 2]-1;
is ← FindIS[ch, tg, hc, t];
IF is=0 THEN ERROR;
};
is←is-1;
SetTimingChan[ch, tg, hc, is];
};
hce, hco: HalfClocks;
ise, iso: InvStages;
SetRefPhase[Even];
SetDataPattern[p11];
SetFormat[ch, RZ];
IF tg=Delay THEN SetDelayPassThru[ch] ELSE SetWidthPassThru[ch];
SetRefDelay[ns];
[hce, ise] ← Cal[Up];
SetRefPhase[Odd];
[hco, iso] ← Cal[Down];
[hc, is] ← MinDelay[hce, ise, hco, iso];
IF gDebug THEN TerminalIO.PutF["Half Clocks: %g, Inv Stages: %g\n", IO.int[hc], IO.int[is]];
};
HoneEdge: PROC [ch: Channel, e: Edge, p: Phase, t: Transition, ns: NSec, pat: DataPattern] RETURNS [tooLate: BOOL ← FALSE] ~ {
ec: EdgeC ← 0;
SetRefPhase[p];
SetRefDelay[ns];
SetDataPattern[pat];
FOR i: NAT IN EdgeC DO
TweakEdge[ch, e, p, (ec ← i), 0];
Process.PauseMsec[pause];
IF NOT EdgeIsEarly[ch, t] THEN EXIT;
ENDLOOP;
IF ec#0 THEN TweakEdge[ch, e, p, (ec ← ec-1), 0] ELSE {
TerminalIO.PutF["Too early\n"];
RETURN[TRUE];
};
FOR i: NAT IN EdgeF DO
TweakEdge[ch, e, p, ec, i];
Process.PauseMsec[pause];
IF NOT EdgeIsEarly[ch, t] THEN GOTO foundIt;
REPEAT
foundIt => {TerminalIO.PutF[" %g %g EdgeC: %g, EdgeF: %g\n",
IO.rope[IF e=Leading THEN "Leading" ELSE "Trailing"],
IO.rope[IF p=Even THEN "Even" ELSE "Odd"],
IO.int[ec], IO.int[i]]};
FINISHED => TerminalIO.PutF["Exceeded range\n"];
ENDLOOP;
};
TweakEdge: PROCEDURE [ch: Channel, e: Edge, p: Phase, ec: EdgeC, ef: EdgeF] = {
PEWrite[ch, IF p=Odd THEN risingEdge ELSE fallingEdge, MapEdge[ec, ef], IF e=Leading THEN Delay ELSE Width];
};
ClearAllPE: PROC ~ {
FOR c: Channel IN Channel DO
ClearPEChan[c];
ENDLOOP;
};
ClearPEChan: PROC [c: Channel] ~ {
FOR t: Timing IN Timing DO
SetTimingChan[c, t, 0, 0];
ENDLOOP;
PEWrite[c, ioCtl, 0];
PEWrite[c, format, nrz];
};
WhichRamRope: PROC [which: Ram] RETURNS [r: ROPE] ~ {
SELECT which FROM
VRam => r ← "VRam";
HRam => r ← "HRam";
ERam => r ← "ERam";
CRam => r ← "CRam";
ENDCASE => ERROR;
};
MinDelay: PROC [hc0: HalfClocks, is0: InvStages, hc1: HalfClocks, is1: InvStages] RETURNS [hs: HalfClocks, is: InvStages] ~ {
SELECT TRUE FROM
hc0>hc1 => RETURN[hc1, is1];
hc0<hc1 => RETURN[hc0, is0];
hc0=hc1 AND is0>is1 => RETURN[hc1, is1];
hc0=hc1 AND is0<is1 => RETURN[hc0, is0];
ENDCASE => RETURN[hc0, is0];
};
SetTimingChan: PROC [chan: Channel, timing: Timing, halfClocks: HalfClocks, invStages: InvStages, upEdgeC: EdgeC ← 0, upEdgeF: EdgeF ← 0, dnEdgeC: EdgeC ← 0, dnEdgeF: EdgeF ← 0] ~ {
PEWrite[chan, dsr0, DSR[halfClocks].high, timing];
PEWrite[chan, dsr1, DSR[halfClocks].low, timing];
PEWrite[chan, invCh0, IC[invStages, FALSE, FALSE].high, timing];
PEWrite[chan, invCh1, IC[invStages, FALSE, FALSE].mid, timing];
PEWrite[chan, invCh2, IC[invStages, FALSE, FALSE].low, timing];
PEWrite[chan, risingEdge, MapEdge[upEdgeC, upEdgeF], timing];
PEWrite[chan, fallingEdge, MapEdge[dnEdgeC, dnEdgeF], timing];
};
DSR: PROC [halfClocks: HalfClocks] RETURNS [high, low: CARDINAL] ~ {
c: BitOps.BitDWord ← 0;
c ← BitOps.IBID[TRUE, c, halfClocks/2, 12];
c ← BitOps.IBID[TRUE, c, IF (halfClocks MOD 2)=0 THEN 10 ELSE 11, 12];
high ← BitOps.ECFD[c, 0, 8, 12];
low ← BITSHIFT[BitOps.ECFD[c, 8, 4, 12], 4]; --left justify result
};
IC: PROC [invStages: InvStages, forceH, forceL: BOOL] RETURNS [high, mid, low: CARDINAL] ~ {
c: BitOps.BitDWord ← 0;
c ← BitOps.IBID[TRUE, c, invStages, 22];
IF forceL THEN c ← BitOps.IBID[TRUE, c, 20, 22];
IF forceH THEN c ← BitOps.IBID[TRUE, c, 21, 22];
high ← BitOps.ECFD[c, 0, 8, 22];
mid ← BitOps.ECFD[c, 8, 8, 22];
low ← BITSHIFT[BitOps.ECFD[c, 16, 6, 22], 2]; --left justify result
};
MapEdge: PROC [edgeC: EdgeC, edgeF: EdgeF] RETURNS [CARDINAL] ~ {
RETURN[BITOR[BITSHIFT[80h, -edgeC], fineMap[edgeF]]];
};
RamWrite: PROC [which: Ram, add: [0..1023], d0, d1, d2, d3: [0..1023]] ~ {
IF gRamDebug THEN TerminalIO.PutRope[IO.PutFLR["Write %g Add: %x, Data: %x, %x, %x, %x\n", LIST[IO.rope[
SELECT which FROM
VRam => "VRam",
HRam => "HRam",
ERam => "ERam",
CRam => "CRam",
ENDCASE => ERROR],
IO.card[add], IO.card[d0], IO.card[d1], IO.card[d2], IO.card[d3]]]];
CBusWrite[writeExtRamAdd, add];
LoadRamWD[d0, d1, d2, d3];
CBusWrite[writeExtRamCtl, extRamAccess];
CBusWrite[writeExtRamCtl, SELECT which FROM
VRam => writeVRam,
HRam => writeHRam,
ERam => writeERam,
CRam => writeCRam,
ENDCASE => ERROR];
CBusWrite[writeExtRamCtl, extRamAccess];
CBusWrite[writeExtRamCtl, 0];
};
RamRead: PROC [which: Ram, add: [0..1023]] RETURNS [d0, d1, d2, d3: [0..1023]] ~ {
CBusWrite[writeExtRamAdd, add];
CBusWrite[writeExtRamCtl, extRamAccess];
CBusWrite[writeExtRamCtl, SELECT which FROM
VRam => readVRam,
HRam => readHRam,
ERam => readERam,
CRam => readCRam,
ENDCASE => ERROR];
[d0, d1, d2, d3] ← FetchRamRD[];
CBusWrite[writeExtRamCtl, 0];
IF gRamDebug THEN TerminalIO.PutRope[IO.PutFLR["Read %g Add: %x, Data: %x, %x, %x, %x\n", LIST[IO.rope[
SELECT which FROM
VRam => "VRam",
HRam => "HRam",
ERam => "ERam",
CRam => "CRam",
ENDCASE => ERROR],
IO.card[add], IO.card[d0], IO.card[d1], IO.card[d2], IO.card[d3]]]];
};
LoadRamWD: PROC [d0, d1, d2, d3: [0..1023]] ~ {
CBusWrite[ramWD0, d0];
CBusWrite[ramWD1, d1];
CBusWrite[ramWD2, d2];
CBusWrite[ramWD3, d3];
};
FetchRamRD: PROC RETURNS [d0, d1, d2, d3: [0..1023]] ~ {
d0 ← CBusRead[ramRD0];
d1 ← CBusRead[ramRD1];
d2 ← CBusRead[ramRD2];
d3 ← CBusRead[ramRD3];
};
InitGPIBDevices: PROC ~ TRUSTED {
IF ~GPIB.InitializeController[] THEN ERROR;
GPIB.InterfaceClear[];
GPIB.SelectedDeviceClear[clock8112];
GPIB.SelectedRemoteEnable[clock8112];
-- fixed edge rate, square wave output, 5V, 0V, output on
WriteGPIB[clock8112, "W1 DTY 50% HIL -0.5V LOL -2.0V D0"];
};
ForcePulseHigh: PROC [ch: Channel] = {
SetTimingChan[ch, Delay, 0, 0];
SetTimingChan[ch, Width, 0, 0];
PEWrite[ch, invCh0, 0, Delay];
PEWrite[ch, invCh2, IC[0, TRUE, FALSE].low, Delay];
PEWrite[ch, invCh0, 0, Width];
PEWrite[ch, invCh2, IC[0, FALSE, TRUE].low, Width];
};
ForcePulseLow: PROC [ch: Channel] = {
SetTimingChan[ch, Delay, 0, 0];
SetTimingChan[ch, Width, 0, 0];
PEWrite[ch, invCh0, 0, Delay];
PEWrite[ch, invCh2, IC[0, FALSE, TRUE].low, Delay];
PEWrite[ch, invCh0, 0, Width];
PEWrite[ch, invCh2, IC[0, TRUE, FALSE].low, Width];
};
SetDelayPassThru: PROC [ch: Channel] ~ {
IF gDebug THEN TerminalIO.PutF["Set Delay pass thru\n"];
SetTimingChan[ch, Delay, 0, 0];
SetTimingChan[ch, Width, 0, 0];
PEWrite[ch, invCh2, IC[0, FALSE, FALSE].low, Delay];
PEWrite[ch, invCh0, 0, Width];
PEWrite[ch, invCh2, IC[0, FALSE, TRUE].low, Width];
};
SetWidthPassThru: PROC [ch: Channel] ~ {
IF gDebug THEN TerminalIO.PutF["Set Width pass thru\n"];
SetTimingChan[ch, Delay, 0, 0];
SetTimingChan[ch, Width, 0, 0];
PEWrite[ch, invCh0, 0, Delay];
PEWrite[ch, invCh2, IC[0, FALSE, TRUE].low, Delay];
PEWrite[ch, invCh2, IC[0, FALSE, FALSE].low, Width];
};
SetDataPattern: PROC [dp: DataPattern] ~ {
Reset[];
IF gDebug THEN TerminalIO.PutF["Set pattern: %g\n", IO.rope[SELECT dp FROM p00 => "00", p01 => "01", p10 => "10", p11 => "11", ENDCASE => ERROR]];
RamWrite[CRam, 0, 03Fh, 3FFh, 0h, 0h]; --mask: FFFF, inhibit: 0000
SELECT dp FROM
p00 => {
RamWrite[VRam, 0, 2h, 0h, 0h, 0h]; --Lit 2, 00, 00, 00
RamWrite[VRam, 1, 0h, 080h, 080h, 080h]; -- 00,Cpy 2@0,Cpy 2@0,Cpy 2@0
RamWrite[VRam, 2, 2h, 0h, 0h, 0h]; --Lit 2, 00, 00, 00
RamWrite[VRam, 3, 0h, 080h, 080h, 080h]; -- 00,Cpy 2@0,Cpy 2@0,Cpy 2@0
};
p01 => {
RamWrite[VRam, 0, 2h, 0h, 0h, 3Fh]; --Lit 2, 00, 00, 3f
RamWrite[VRam, 1, 3FFh, 080h, 080h, 080h]; -- 3FF,Cpy 2@0,Cpy 2@0,Cpy 2@0
RamWrite[VRam, 2, 2h, 0h, 0h, 3Fh]; --Lit 2, 00, 00, 3f
RamWrite[VRam, 3, 3FFh, 080h, 080h, 080h]; -- 3FF,Cpy 2@0,Cpy 2@0,Cpy 2@0
};
p10 => {
RamWrite[VRam, 0, 2h, 3Fh, 3FFh, 0h]; --Lit 2, 3f, 3FF, 00
RamWrite[VRam, 1, 0h, 080h, 080h, 080h]; -- 00,Cpy 2@0,Cpy 2@0,Cpy 2@0
RamWrite[VRam, 2, 2h, 3Fh, 3FFh, 0h]; --Lit 2, 3f, 3FF, 00
RamWrite[VRam, 3, 0h, 080h, 080h, 080h]; -- 00,Cpy 2@0,Cpy 2@0,Cpy 2@0
};
p11 => {
RamWrite[VRam, 0, 2h, 3Fh, 3FFh, 3Fh]; --Lit 2, 3f, 3FF, 3f
RamWrite[VRam, 1, 3FFh, 080h, 080h, 080h]; -- 3FF,Cpy 2@0,Cpy 2@0,Cpy 2@0
RamWrite[VRam, 2, 2h, 3Fh, 3FFh, 3Fh]; --Lit 2, 3f, 3FF, 3f
RamWrite[VRam, 3, 3FFh, 080h, 080h, 080h]; -- 3FF,Cpy 2@0,Cpy 2@0,Cpy 2@0
};
ENDCASE => ERROR;
CBusWrite[writeLoopAdd, 0];
CBusWrite[writeEndAdd, 3];
StartCtl[TRUE, TRUE, FALSE];
};
FindOutputEdge: PROC [ch: Channel, p: Phase, t: Transition] RETURNS [time: NSec ← 0] ~ {
SetRefPhase[p];
SetRefDelayAbs[time];
WHILE NOT EdgeIsEarly[ch, t] DO
SetRefDelayAbs[(time ← time+1)];
ENDLOOP;
};
EdgeIsEarly: PROCEDURE [ch: Channel, t: Transition] RETURNS [BOOL] = {
trueCount, falseCount: NAT ← 0;
FOR i: NAT IN [0..7) DO
IF (t=Down) = (BITAND[PERead[ch, ioCtl], phaseComp]#0) THEN trueCount ← trueCount+1
ELSE falseCount ← falseCount + 1;
ENDLOOP;
IF gDebug THEN TerminalIO.PutF[" %g/%g ", IO.card[trueCount], IO.card[falseCount]];
RETURN[trueCount>falseCount];
};
SetFormat: PROC [ch: Channel, f: Format] = {
PEWrite[ch, format, SELECT f FROM NRZ => nrz, RZ => rz, RO => ro, RC=> rc, RT => rt, ENDCASE => ERROR];
IF gDebug THEN TerminalIO.PutF["Set format: %g\n", IO.rope[SELECT f FROM NRZ => "NRZ", RZ => "RZ", RO => "RO", RC=> "RC", RT => "RT", ENDCASE => ERROR]]
};
SetTTLLevels: PROC [ch: Channel, b: BOOL] = {
PEWrite[ch, ioCtl, BitOps.IBIW[b, PERead[ch, ioCtl], 1, 5]];
};
SetRefDelayAbs: PROC [d: Delay] ~ {
CBusWrite[refDelay, d];
IF gDebug THEN TerminalIO.PutF["Ref clock delay: %g\n", IO.card[d]];
};
SetRefDelay: PROC [d: Delay] ~ {
SetRefDelayAbs[d+gCycOffset];
};
SetClock: PROC [period: Period] ~ {
divisor: ClockDivisor;
SELECT TRUE FROM
period IN [30..70) => {divisor ← one; gClkPeriod ← period};
period IN [70..140) => {divisor ← two; gClkPeriod ← (period+1)/2};
period IN [140..280) => {divisor ← four; gClkPeriod ← (period+2)/4};
period IN [280..560) => {divisor ← eight; gClkPeriod ← (period+4)/8};
ENDCASE => ERROR;
SetClockDivisor[divisor];
WriteGPIB[clock8112, IO.PutFR["PER %gNS", IO.card[gClkPeriod]]];
IF gDebug THEN TerminalIO.PutF["Set clock to %g ns\n", IO.card[period]]
};
StartCtl: PROC [start, loop, reset: BOOLFALSE] ~ {
gClockCtl ← BitOps.IBIW[start, gClockCtl, 5, 8];
gClockCtl ← BitOps.IBIW[loop, gClockCtl, 4, 8];
gClockCtl ← BitOps.IBIW[reset, gClockCtl, 0, 8];
CBusWrite[clkCtl, gClockCtl];
};
SetRefPhase: PROC [p: Phase] ~ {
gClockCtl ← BitOps.IBIW[p=Even, gClockCtl, 2, 8];
CBusWrite[clkCtl, gClockCtl];
IF gDebug THEN TerminalIO.PutF["Set reference phase %g\n", IO.rope[IF p=Even THEN "Even" ELSE "Odd"]]
};
SetClockDivisor: PROC [cd: ClockDivisor] ~ {
gClockCtl ← BitOps.ICIW[ORD[cd], gClockCtl, 6, 2, 8];
CBusWrite[clkCtl, gClockCtl];
gClkDivisor ← cd;
};
PEWrite: PROC [chan: Channel, reg: PEReg, data: PEData, timing: Timing ← Sample] ~ {
To write the ioCtl and Format registers, use default: timing ← Sample since these regs are not asociated with any particular timing chain
CBusWrite[(chan*24)+(timing.ORD*8)+reg, data];
};
PERead: PROC [chan: Channel, reg: PEReg, timing: Timing ← Sample] RETURNS [data: PEData] ~ {
To read the ioCtl and Format registers, use default: timing ← Sample since these regs are not asociated with any particular timing chain
data ← BITAND[CBusRead[(chan*24)+(timing.ORD*8)+reg], 0FFh]; --PE only uses 8 bits
};
CBusRead: PROC [add: [0..1023]] RETURNS [data: [0..1023]] ~ {
data ← XBus.IORead[baseAdd + add*2];
};
CBusWrite: PROC [add: [0..1023], data: [0..1023]] ~ {
XBus.IOWrite[baseAdd + add*2, data];
};
WriteGPIB: PROCEDURE [device: GPIB.DeviceAddr, msg: Rope.ROPE] = TRUSTED {
GPIB.WriteDevice[device, Rope.Concat[msg, "\n\l"]];
};
add: NAT ← 4;
loop: NAT ← 1;
data: CARDINAL ← 03FFh;
VRamTest: PROC = {
FOR j: NAT IN [0..add) DO
RamWrite[VRam, j, j, j, j, j];
ENDLOOP;
FOR i: NAT IN [0..loop) DO
FOR j: NAT IN [0..add) DO
RamWrite[VRam, 128+j, data, data, data, data];
[] ← RamRead[VRam, 128+j];
ENDLOOP;
ENDLOOP;
gRamDebug ← TRUE;
FOR j: NAT IN [0..add) DO
[] ← RamRead[VRam, j];
ENDLOOP;
FOR j: NAT IN [0..add) DO
[] ← RamRead[VRam,128+j];
ENDLOOP;
gRamDebug ← FALSE;
};
RAMWriteReadTest: PROC ~ {
TerminalIO.PutRope["\n***RAM Write/Read Test***\n"];
Reset[];
RAMTest[HRam, 32];
RAMTest[CRam, 16];
RAMTest[ERam, 16];
RAMTest[VRam, 1024];
};
RAMTest: PROC [which: Ram, size: NAT, start: NAT ← 0] = {
d0, d1, d2, d3: [0..1023] ← 0;
FOR i: NAT IN [start..start+size) DO
RamWrite[which, i, 2A0h, 2A1h, 2A2h, 2A3h];
ENDLOOP;
Process.PauseMsec[pause];
FOR i: NAT IN [start..start+size) DO
[d0, d1, d2, d3] ← RamRead[which, i];
IF d0#2A0h OR d1#2A1h OR d2#2A2h OR d3#2A3h THEN
TerminalIO.PutRope[IO.PutFLR["ERROR Pass1: %g add: %g, data: %x %x %x %x\n", LIST[IO.rope[WhichRamRope[which]], IO.card[i], IO.card[d0], IO.card[d1], IO.card[d2], IO.card[d3]]]];
RamWrite[which, i, 150h, 151h, 152h, 153h];
ENDLOOP;
Process.PauseMsec[pause];
FOR i: NAT IN [start..start+size) DO
[d0, d1, d2, d3] ← RamRead[which, i];
IF d0#150h OR d1#151h OR d2#152h OR d3#153h THEN
TerminalIO.PutRope[IO.PutFLR["ERROR Pass 2: %g add: %g, data: %x %x %x %x\n", LIST[IO.rope[WhichRamRope[which]], IO.card[i], IO.card[d0], IO.card[d1], IO.card[d2], IO.card[d3]]]];
ENDLOOP;
};
Test: PROC = {
RegWriteReadTest[];
RAMWriteReadTest[];
};
VRead: PROC [start, end: NAT] ~ {
d0, d1, d2, d3: [0..1023] ← 0;
FOR i:NAT IN [start..end) DO
[d0, d1, d2, d3] ← RamRead[VRam, i];
TerminalIO.PutRope[IO.PutFR["%x %x %x %x\n", IO.card[d0], IO.card[d1], IO.card[d2], IO.card[d3]]];
ENDLOOP;
TerminalIO.PutRope["\n"];
};
VReadLoop: PROC [start, end: NAT] ~ {
DO
FOR i:NAT IN [start..end) DO
[] ← RamRead[VRam, i];
ENDLOOP;
Process.CheckForAbort[];
ENDLOOP;
};
VWrite: PROC [start, end: NAT, data: NAT] ~ {
FOR i:NAT IN [start..end) DO
RamWrite[VRam, i, data, data, data, data];
ENDLOOP;
};
VWriteLoop: PROC [start, end, data: NAT] ~ {
DO
VWrite[start, end, data];
Process.CheckForAbort[];
ENDLOOP;
};
DecompSpeedTest: PROC ~ {
Reset[];
RamWrite[HRam, 1, 0, 0, 03fh, 03ffh];
RamWrite[CRam, 0, 03Fh, 3FFh, 0h, 0h]; --mask: FFFF, inhibit: 0000
CBusWrite[writeEndAdd, 0];
CBusWrite[writeExtRamCtl, vramBypass];
LoadRamWD[042h, 043h, 042h, 043h]; --Cpy:1@2, Cpy:1@3, Cpy:1@2, Cpy:1@3
StartCtl[TRUE, TRUE, FALSE];
};
BypassLoopTest: PROC ~ {
d0, d1, d2, d3: NAT;
TerminalIO.PutRope["\n***Bypass Loop Test***\n"];
Reset[];
CBusWrite[writeEndAdd, 0];
CBusWrite[writeExtRamCtl, vramBypass];
LoadRamWD[1h, 155h, 155h, 03C0h]; --Lit:1; 155h 155h; Cpy:15@0
StartCtl[TRUE, TRUE, FALSE];
StartCtl[FALSE, FALSE, FALSE];
FOR i: NAT IN [0..32) DO
[d0, d1, d2, d3] ← RamRead[HRam, i];
IF d0#155h OR d1#155h OR d2#155h OR d3#155h THEN
TerminalIO.PutRope[IO.PutFLR["ERROR Pass 1: HRam add: %g, data: %x %x %x %x\n", LIST[IO.card[i], IO.card[d0], IO.card[d1], IO.card[d2], IO.card[d3]]]];
ENDLOOP;
LoadRamWD[1h, 2AAh, 2AAh, 03C0h]; --Lit:1; 2AAh 2AAh; Cpy:15@0
StartCtl[TRUE, TRUE, FALSE];
StartCtl[FALSE, FALSE, FALSE];
FOR i: NAT IN [0..32) DO
[d0, d1, d2, d3] ← RamRead[HRam, i];
IF d0#155h OR d1#155h OR d2#155h OR d3#155h THEN
TerminalIO.PutRope[IO.PutFLR["ERROR Pass 2: HRam add: %g, data: %x %x %x %x\n", LIST[IO.card[i], IO.card[d0], IO.card[d1], IO.card[d2], IO.card[d3]]]];
ENDLOOP;
};
RegWriteReadTest: PROC [a: CARDINAL ← 02AAh, b: CARDINAL ← 0155h] ~ {
ErrMsg: PROC [c: Channel, r: PEReg, t: Timing, x, y, z: PEData] ~ {
TerminalIO.PutRope[IO.PutFLR["Chan: %g, Reg: %g, %g, expected: %x, got: %x, xor: %x\n", LIST[IO.card[c], IO.card[r], IO.rope[SELECT t FROM Sample => "Sample", Delay=> "Delay", Width => "Width", ENDCASE => ERROR], IO.card[x], IO.card[y], IO.card[z]]]];
};
map: ARRAY [0..7) OF CARDINAL ← [0FFh, 0F0h, 0FFh, 0FFh, 0FCh, 0FFh, 0FFh];
y, exp: CARDINAL ← 0;
TerminalIO.PutRope["\n***Register Write/Read Test***\n"];
Reset[];
FOR p: NAT IN [0..7) DO
FOR c: Channel IN Channel DO
FOR t: Timing IN Timing DO
PEWrite[c, p, a, t];
exp ← BITAND[a, map[p]];
IF (y ← BITAND[PERead[c, p, t], map[p]])#exp THEN ErrMsg[c, p, t, exp, y, BITXOR[y, exp]];
PEWrite[c, p, b, t];
exp ← BITAND[b, map[p]];
IF (y ← BITAND[PERead[c, p, t], map[p]])#exp THEN ErrMsg[c, p, t, exp, y, BITXOR[y, exp]];
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
VRamLoopTest: PROC ~ {
b: BOOL ← gRamDebug;
TerminalIO.PutRope["\n***VRam Loop Test***\n"];
Reset[];
FOR c: Channel IN Channel DO
SetTimingChan[c, Delay, 2, 0, 0, 0, 0, 0];
SetTimingChan[c, Width, 4, 0, 0, 0, 0, 0];
SetTimingChan[c, Sample, 0, 0, 0, 0, 0, 0];
PEWrite[c, ioCtl, 0];
PEWrite[c, format, rz];
ENDLOOP;
RamWrite[CRam, 0, 01Fh, 3FFh, 000h, 0h]; --mask: 7FFF, inhibit: 0000
RamWrite[VRam, 0, 5h, 0h, 0h, 20h]; --Lit 5, 0000, 20
RamWrite[VRam, 1, 1h, 0h, 2h, 20h]; -- 01, 0002, 20
RamWrite[VRam, 2, 3h, 0h, 4h, 140h]; -- 03, 0004, Cpy 5@0
RamWrite[VRam, 3, 1h, 0h, 3FFh, 140h]; --Lit 1, 03FF, Cpy 5@0
FOR i:NAT IN [0..16) DO RamWrite[ERam, i, 0, 0, 0, 0] ENDLOOP;
CBusWrite[writeEndAdd, 03h];
CBusWrite[writeLoopAdd, 0h];
StartCtl[TRUE, TRUE, FALSE];
[] ← TerminalIO.RequestRope["Type CR to quit: "];
StartCtl[FALSE, FALSE, FALSE];
gRamDebug ← TRUE;
FOR i: NAT IN [0..32) DO [] ← RamRead[HRam, i ! ABORTED => gRamDebug ← b] ENDLOOP;
FOR i: NAT IN [0..16) DO [] ← RamRead[ERam, i ! ABORTED => gRamDebug ← b] ENDLOOP;
gRamDebug ← b;
};
FromFileTest: PROC [fileName: ROPE ← "AChip3.force"] ~ {
GetData: PROC RETURNS [lastAdd: VRamAdd] ~ {
FOR add: NAT IN VRamAdd DO
RamWrite[VRam, add,
LOOPHOLE[IO.GetHWord[compStream ! IO.EndOfStream => GOTO huh]],
LOOPHOLE[IO.GetHWord[compStream ! IO.EndOfStream => GOTO huh]],
LOOPHOLE[IO.GetHWord[compStream ! IO.EndOfStream => GOTO huh]],
LOOPHOLE[IO.GetHWord[compStream ! IO.EndOfStream => GOTO done]]
];
REPEAT
huh => {
TerminalIO.PutRope["\n ***Huh? Unexpected eof in compressed input stream, STREAM TRUCATED***"];
lastAdd ← add-1;
};
done => {lastAdd ← add};
FINISHED => {TerminalIO.PutRope["\n ***Compressed input stream too long, STREAM TRUCATED***"];
lastAdd ← add
};
ENDLOOP;
};
InitChan: PROC [ch: Channel] ~ {
SetTimingChan[ch, Delay, 6, 0, 0, 0, 0, 0];
SetTimingChan[ch, Width, 10, 0, 0, 0, 0, 0];
SetTimingChan[ch, Sample, 8, 0, 0, 0, 0, 0];
PEWrite[ch, ioCtl, 0];
PEWrite[ch, format, nrz];
};
sourceStream: IO.STREAMFS.StreamOpen[fileName: Rope.Concat[fileName, ".bin"], wDir: CommandTool.CurrentWorkingDirectory[], streamOptions: FS.binaryStreamOptions];
compStream: IO.STREAMFS.StreamOpen[fileName: Rope.Concat[fileName, ".bin.com"], wDir: CommandTool.CurrentWorkingDirectory[], streamOptions: FS.binaryStreamOptions];
TerminalIO.PutRope[IO.PutFR["\n***Vectors from file: %g***\n", IO.rope[fileName]]];
FOR i: NAT IN Channel DO
InitChan[i];
ENDLOOP;
RamWrite[CRam, 0, 03Fh, 3FFh, 000h, 0h];--mask: FFFF, inhibit: 0000
CBusWrite[writeLoopAdd, 0h];
CBusWrite[writeEndAdd, GetData[]];
StartCtl[TRUE];
StartCtl[FALSE];
IO.Close[sourceStream];
IO.Close[compStream];
};
END.