-- SageImpl.mesa -- Last Edited by: Barth, February 8, 1985 6:00:19 pm PST DIRECTORY DicentraInputOutput, Heap, Sage; SageImpl: PROGRAM IMPORTS DicentraInputOutput, Heap EXPORTS Sage = BEGIN OPEN DicentraInputOutput, Sage; z:UNCOUNTED ZONE = Heap.systemZone; Error: PUBLIC ERROR [why: ErrorReason] = CODE; ConcreteTester: TYPE = LONG POINTER TO 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 ← z.NEW[TesterRec ← [FALSE, pulseTaps, channelControl, initialData]]; { OPEN t; taps ← z.NEW[PulseLineTapRec ← pulseTaps↑]; control ← z.NEW[ChannelControlDataRec ← channelControl↑]; initialData ← z.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] = { z.FREE[@t.taps]; z.FREE[@t.control]; z.FREE[@t.initialData]; z.FREE[@t]; }; Run: PUBLIC PROC [t: ConcreteTester, runData: ChannelSequence] = { FOR s: CARDINAL IN [0..runData.loadCount) DO v: ChannelVector ← @runData.loads[s]; 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[ Input[ LOOPHOLE[ 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; 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] = { DicentraInputOutput.Output[LOOPHOLE[word, UNSPECIFIED], LOOPHOLE[address]]; }; DoInput: PROCEDURE [address: LONG CARDINAL] RETURNS [word: CARDINAL] = { RETURN[DicentraInputOutput.Input[LOOPHOLE[address]]]; }; END.