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]; 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] = { 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. È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 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. 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. ʬ˜Jšœ ™ Jšœ2™2J™6J˜JšÏk œ ˜J˜šœ œ˜Jšœ˜ Jšœ˜J˜—Jšœœ˜J˜Jšœœœœ˜.J˜Jšœœœ ˜%šœ œœœ˜ Jšœ œœ˜J˜J˜J˜J˜5Jšœ8œœ˜FJšœ*œœœ˜@J˜—š œœœ œœ˜4J˜J˜!J˜—š œœœ œœ˜7J˜Jšœœœ˜$Jšœœœ˜J˜—š œœœ œœ˜0J˜Jšœœœ˜ Jšœœœ˜$Jšœœœ˜%J˜—š œœœ œœ˜/J˜Jšœœœ˜!J˜%J˜(J˜—Jšœœœœ˜&J˜+J˜?J˜IJ˜FJ˜LJ˜;J˜CJ˜8J˜šœœ˜J˜/J˜—Jšœ œ˜š œ œœ œœ˜+J˜#Jš œœœ œœ˜:—Jšœ œ˜#J˜š Ïnœœœhœœœ˜²Jšœœœ+˜Ešœœ˜ Jšœœ˜)Jšœ œ*˜7Jšœœ"˜3J˜,Jšœ œ:˜KJšœ œ@˜QJšœ œ.˜?Jšœœ˜J˜J˜šœœ ˜!J˜.Jšœ˜—šœ œ ˜Jšœ9œU˜’Jšœ˜—J˜)Jšœþ™þšœ œ ˜J˜¢Jšœ˜—Jšœœ˜!J˜J˜Jšœœ˜J˜J˜—Jšœ˜ J˜J˜—Jšžœœœ˜5J˜šžœœœ*˜:J˜Jšœœ˜!Jšœœ˜J˜#Jšœœ˜!J˜Jšœœ˜J˜š˜š œœœ œœœ˜:J˜%Jšœ œœ˜Jšœ˜——J˜J˜Jšœœ˜J˜š œœœœ ˜:šœœ ˜"J˜-šœœ ˜#J˜+Jšœ˜—Jšœ˜—Jšœ˜—J˜J˜J˜—šžœœœ*˜OJšœœœœ˜,š œœ œœ ˜1š œœ œœ˜5J˜J˜J˜ J˜ J˜"šœœœ˜J˜(J˜J˜—J˜fJšœ˜—Jšœ˜—J˜J˜—šž œ œ4œœ˜YJšœ˜šœ˜J˜?J˜/Jšœ&œ ˜3J˜8J˜8Jšœœ˜—Jš œœœ œ@œ œ.˜¹J˜J˜—šžœ œ%˜?J˜,J˜J˜—šžœ œC˜^Jšœ œ'œ œœœ œœ œ œœœœ œœ˜ÉJ˜J˜—šžœ œa˜€Jšœ œ&˜7Jšœ œ&˜8šœ œ ˜1Jšœ.œ˜5—šœ˜Jšœœœ1œ˜UJšœ œ œ0˜MJšœ1˜5J˜—J˜J˜—Jšž œœ œ œ˜RJšœD™DJšœF™Fšœ>™>Jš œœ œœ œœ7˜mJšœ˜ J˜J˜—šž œ œœ˜>J˜*Jšœ œ<˜MJ˜J˜—šžœ œ(œ˜^Jšœœ&œ œœœ œœœœ œœ˜°J˜J˜—š žœ œœ œœ˜@Jšœ˜J˜J˜—š žœ œ œœœœ˜HJšœ˜J˜J˜—Jšœ˜J˜—…—¸',