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: BOOL ← FALSE;
gRamDebug: BOOL ← FALSE;
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:
BOOL ←
FALSE] ~ {
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.STREAM ← FS.StreamOpen[fileName: Rope.Concat[fileName, ".bin"], wDir: CommandTool.CurrentWorkingDirectory[], streamOptions: FS.binaryStreamOptions];
compStream: IO.STREAM ← FS.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.