SageImpl.mesa
Last Edited by: Barth, July 3, 1985 4:45:03 pm PDT
Last Edited by: Gasbarro, June 14, 1985 3:37:16 pm PDT
DIRECTORY XBus, Sage;
SageImpl:
PROGRAM
IMPORTS XBus
EXPORTS Sage =
BEGIN OPEN Sage;
Error: PUBLIC ERROR [why: ErrorReason] = CODE;
ConcreteTester: TYPE = REF TesterRec;
TesterRec:
PUBLIC
TYPE =
RECORD[
bigChip: BOOL ← FALSE,
taps: PulseLineTaps,
control: ChannelControlData,
initialData: ChannelVector,
pulseGenCounterRegState: PulseGenCounterReg ← [0, 0],
pulseGenCounterCtlRegState: PulseGenCounterCtlReg ← [0, FALSE, FALSE],
pulseGenCtlRegState: PulseGenCtlReg ← [0, FALSE, FALSE, FALSE]];
PulseGenCounterReg:
TYPE =
MACHINE
DEPENDENT
RECORD[
null(0: 0..11): [0..4096) ← 0,
counter(0: 12..15): [0..16) ← 0];
PulseGenCounterCtlReg:
TYPE =
MACHINE
DEPENDENT
RECORD[
null(0: 0..13): [0..16384) ← 0,
continuous(0: 14..14): BOOL ← FALSE,
go(0: 15..15): BOOL ← FALSE];
PulseGenCtlReg:
TYPE =
MACHINE
DEPENDENT
RECORD[
null(0: 0..12): [0..8192) ← 0,
nReset(0: 13..13): BOOL ← FALSE,
feedBack15(0: 14..14): BOOL ← FALSE,
globalHold(0: 15..15): BOOL ← FALSE];
ChannelCtlReg:
TYPE =
MACHINE
DEPENDENT
RECORD[
null(0: 0..7): [0..256) ← 0,
localHold(0: 8..8): BOOL ← FALSE,
inPulseLine(0: 9..12): PulseLine ← 0,
outPulsePair(0: 13..15): PulsePair ← 0];
MultibusAddress: TYPE = LONG CARDINAL;
SageDeviceAddress: MultibusAddress = 4000H;
PulseGenCtlRegAddress: MultibusAddress = SageDeviceAddress+11H;
PulseGenCounterRegHackAddress: MultibusAddress = SageDeviceAddress+01E0H;
PulseGenCounterCtlRegAddress: MultibusAddress = SageDeviceAddress+12H;
PulseGenCounterCtlRegHackAddress: MultibusAddress = SageDeviceAddress+01D0H;
PulseGenTapAddress: MultibusAddress = SageDeviceAddress+0H;
PulseGenCounterRegAddress: MultibusAddress = SageDeviceAddress+10H;
ChannelAddress: MultibusAddress = SageDeviceAddress+20H;
ControlValue:
TYPE = {
continuous, go, reset, feedBack15, globalHold};
InputCount: CARDINAL = 8;
InputData:
TYPE =
MACHINE
DEPENDENT
RECORD[
null(0: 0..InputCount-1): [0..256),
bits(0: InputCount..15): PACKED ARRAY InputIndex OF BOOL];
InputIndex: TYPE = [0..InputCount);
InitializeTester:
PUBLIC
PROC [pulseTaps: PulseLineTaps, channelControl: ChannelControlData, initialData: ChannelVector, feedBack15:
BOOL ←
FALSE]
RETURNS [t: ConcreteTester] = {
t ← NEW[TesterRec ← [FALSE, pulseTaps, channelControl, initialData]];
{
OPEN t;
taps ← NEW[PulseLineTapRec ← pulseTaps^];
control ← NEW[ChannelControlDataRec ← channelControl^];
initialData ← NEW[ChannelVectorRec ← initialData^];
pulseGenCtlRegState.feedBack15 ← feedBack15;
DoOutput[LOOPHOLE[pulseGenCounterRegState], PulseGenCounterRegHackAddress];
DoOutput[LOOPHOLE[pulseGenCounterCtlRegState], PulseGenCounterCtlRegHackAddress];
DoOutput[LOOPHOLE[pulseGenCtlRegState], PulseGenCtlRegAddress];
SetControl[t, go, FALSE];
SetControl[t, continuous];
SetControl[t, globalHold];
FOR pl: PulseLine
IN PulseLine
DO
SetPulseLineTap[pulseLine: pl, tap: taps[pl]];
ENDLOOP;
FOR c: Channel
IN Channel
DO
SetChannelCtlReg[t: t, channel: c, register: [localHold: TRUE, inPulseLine: control[c].inputPulseLine, outPulsePair: control[c].outputPulsePair]];
ENDLOOP;
LoadOutputShiftRegisters[t, initialData];
If the following loop takes too long the data in the shift registers may die because of the delay between reset of local hold and the start of the clocks. A change in the tester hardware is needed to avoid this race. A line should be added from the channel control register to all the channel chips which forces all the channels to be static regardless of the value of local hold.
FOR c: Channel
IN Channel
DO
SetChannelCtlReg[t: t, channel: c, register: [localHold: control[c].localHold, inPulseLine: control[c].inputPulseLine, outPulsePair: control[c].outputPulsePair]];
ENDLOOP;
SetControl[t, globalHold, FALSE];
SetControl[t, globalHold];
SetControl[t, reset];
SetControl[t, reset, FALSE];
SetControl[t, go];
};
RETURN[t];
};
FinalizeTester: PUBLIC PROC [t: ConcreteTester] = {};
Run:
PUBLIC
PROC [t: ConcreteTester, v: ChannelVector] = {
LoadOutputShiftRegisters[t, v];
SetControl[t, continuous, FALSE];
SetControl[t, go, FALSE];
SetCounter[t, 16 - v.testerCycles];
SetControl[t, globalHold, FALSE];
SetControl[t, reset];
SetControl[t, reset, FALSE];
SetControl[t, go];
DO
foo:
PACKED
ARRAY [0..16)
OF
BOOL ←
LOOPHOLE[XBus.IORead[
2*PulseGenCounterCtlRegHackAddress]];
IF foo[15] THEN EXIT;
ENDLOOP;
SetControl[t, continuous];
SetControl[t, globalHold];
SetControl[t, go, FALSE];
SetControl[t, go];
FOR c:
CARDINAL ← 0, c+InputCount
UNTIL c>
LAST[Channel]
DO
FOR i: InputStage
IN InputStage
DO
data: InputData ← ReadChannelOctetData[t, c];
FOR nc: InputIndex
IN InputIndex
DO
v.stageData[c+nc].sense[i] ← data.bits[nc];
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
LoadOutputShiftRegisters:
PUBLIC
PROC [t: ConcreteTester, v: ChannelVector] = {
IF v=NIL THEN ERROR Error[nilChannelVector];
FOR c:
CARDINAL ← 0, c+2
UNTIL c>
LAST[Channel]
DO
FOR i:
CARDINAL ← 0, i+2
UNTIL i>
LAST[OutputStage]
DO
dl0, dh0, dl1, dh1: DriveState;
dl0 ← v.stageData[c].force[i];
dh0 ← v.stageData[c].force[i+1];
dl1 ← v.stageData[c+1].force[i];
dh1 ← v.stageData[c+1].force[i+1];
IF i
MOD 4 #0
THEN {
t: DriveState ← dl0; dl0 ← dh0; dh0 ← t;
t ← dl1; dl1 ← dh1; dh1 ← t;
};
WriteChannelPairData[t: t, channel0: c, dataLow0: dl0, dataHigh0: dh0, dataLow1: dl1, dataHigh1: dh1];
ENDLOOP;
ENDLOOP;
};
SetControl:
PROCEDURE [t: ConcreteTester, value: ControlValue, newValue:
BOOL ←
TRUE] = {
OPEN t;
SELECT value
FROM
continuous => pulseGenCounterCtlRegState.continuous ← newValue;
go => pulseGenCounterCtlRegState.go ← newValue;
reset => pulseGenCtlRegState.nReset ← NOT newValue;
feedBack15 => pulseGenCtlRegState.feedBack15 ← newValue;
globalHold => pulseGenCtlRegState.globalHold ← newValue;
ENDCASE => ERROR;
IF value IN [continuous .. go] THEN DoOutput[LOOPHOLE[pulseGenCounterCtlRegState], PulseGenCounterCtlRegHackAddress] ELSE DoOutput[LOOPHOLE[pulseGenCtlRegState], PulseGenCtlRegAddress];
};
SetPulseLineTap:
PROCEDURE [pulseLine: PulseLine, tap: Tap] = {
DoOutput[tap, PulseGenTapAddress+pulseLine];
};
SetChannelCtlReg:
PROCEDURE [t: ConcreteTester, channel: Channel, register: ChannelCtlReg] = {
DoOutput[LOOPHOLE[register], ChannelAddress + (channel/(IF t.bigChip THEN 32 ELSE 16))*(IF t.bigChip THEN 40H ELSE 20H) + (IF t.bigChip THEN 20H ELSE 10H) + channel MOD (IF t.bigChip THEN 32 ELSE 16)];
};
WriteChannelPairData:
PROCEDURE [t: ConcreteTester, channel0: Channel, dataLow0, dataHigh0, dataLow1, dataHigh1: DriveState] = {
dataLow: CARDINAL ← ConvertToBits[dataLow0, dataHigh0];
dataHigh: CARDINAL ← ConvertToBits[dataLow1, dataHigh1];
IF t.bigChip
THEN DoOutput[16*dataLow + dataHigh,
ChannelAddress + (channel0/32)*40H + channel0 MOD 32]
ELSE {
channelAddress: LONG CARDINAL ← ChannelAddress + (channel0/16)*20H + channel0 MOD 16;
IF (channel0 MOD 16) < 8 THEN DoOutput[16*dataLow + dataHigh, channelAddress]
ELSE DoOutput[dataLow + 16*dataHigh, channelAddress];
};
};
ConvertToBits: PROC[dataLow, dataHigh: DriveState] RETURNS [dataOut: CARDINAL] = {
01 => H, 10 => L, 11 => T, dataLow goes in bits 1 and 3 of a nibble,
dataHigh goes in bits 0 and 2 of the nibble, numbering the nibble bits
from left to right, 0 to 3, high order to low order of course.
Bits: ARRAY DriveState OF ARRAY DriveState OF CARDINAL = [[0CH, 0EH, 06H], [0DH, 0FH, 07H], [09H, 0BH, 03H]];
RETURN[Bits[dataLow][dataHigh]];
};
SetCounter:
PROCEDURE [t: ConcreteTester, value:
CARDINAL] = {
t.pulseGenCounterRegState.counter ← value;
DoOutput[LOOPHOLE[t.pulseGenCounterRegState], PulseGenCounterRegHackAddress];
};
ReadChannelOctetData:
PROCEDURE [t: ConcreteTester, channel0: Channel]
RETURNS [InputData] = {
RETURN[ LOOPHOLE [DoInput[ChannelAddress + (channel0/(IF t.bigChip THEN 32 ELSE 16))*(IF t.bigChip THEN 40H ELSE 20H) + ((channel0 MOD (IF t.bigChip THEN 32 ELSE 16)) / 8) ]]];
};
DoOutput:
PROCEDURE [word:
CARDINAL, address:
LONG
CARDINAL] = {
XBus.IOWrite[2*address, word];
};
DoInput:
PROCEDURE [address:
LONG
CARDINAL]
RETURNS [word:
CARDINAL] = {
RETURN[XBus.IORead[2*address]];
};
END.