DIRECTORY SystemVersion USING [machineType], ChipTest, ChipTestRemote, ChipTestRemoteRpcControl USING [InterfaceRecord, ImportNewInterface], Basics USING [BITAND, BITXOR], PrincOps USING [zMISC], Process USING [Detach, Pause, MsecToTicks], PupDefs USING [GetPupAddress, GetMyName], PupTypes USING [fillInSocketID], Rope USING [ROPE, Length], SafeStorage USING [EstablishFinalization, CantEstablishFinalization, ReEstablishFinalization, FinalizationQueue, NewFQ, FQNext], VM USING [Interval, nullInterval, PageNumber, Allocate, Free, Pin, Unpin, AddressForPageNumber, WordsForPages, PagesForWords]; ChipTestImpl: CEDAR MONITOR IMPORTS SystemVersion, ChipTestRemoteRpcControl, Basics, Process, PupDefs, Rope, SafeStorage, VM EXPORTS ChipTest = BEGIN OPEN ChipTest; trues: PUBLIC ChannelVecRef _ NEW[ChannelVec = ALL[TRUE]]; falses: PUBLIC ChannelVecRef _ NEW[ChannelVec = ALL[FALSE]]; LocalTester: TYPE = RECORD [ reserved: BOOL _ FALSE ]; LocalTesterRef: TYPE = REF LocalTester; RemoteTester: TYPE = RECORD [ interface: ChipTestRemoteRpcControl.InterfaceRecord, stores: ChipTestRemote.RegStores ]; RemoteTesterRef: TYPE = REF RemoteTester; StepControl: TYPE = MACHINE DEPENDENT RECORD [ quadWdCnt (0: 0..1): [1..4], checkSecond (0: 2..2): BOOLEAN _ FALSE, checkFirst (0: 3..3): BOOLEAN _ FALSE]; StepControlArray: TYPE = PACKED ARRAY [0..0) OF StepControl; TestDataArray: TYPE = RECORD [ finalI: ChannelVec, t: ARRAY [0..0) OF WORD]; BufDesc: TYPE = RECORD [ base: Tester, unSteppedTestData: [0..16] _ 0, i: ChannelVecRef _ NIL, stepCount, stepMaxCount: INT _ 0, stepInterval: VM.Interval _ VM.nullInterval, steps: LONG POINTER TO StepControlArray _ NIL, testDataSize, testDataMaxSize: INT _ 0, testDataInterval: VM.Interval _ VM.nullInterval, testData: LONG POINTER TO TestDataArray _ NIL ]; BufRef: TYPE = REF BufDesc; Window: TYPE = RECORD [ buf: Tester, firstWord: INT, check, abd: BOOL _ FALSE, comm: LoadABD _ [command: loadD] ]; WindowRef: TYPE = REF Window; localTester: Tester = NEW[TesterOb _ [ flush: FlushLocal, writeR: WriteRLocal, readI: ReadILocal, data: NEW[LocalTester _ []]]]; OpenTester: PUBLIC PROC [server: Rope.ROPE _ NIL] RETURNS [Tester] = BEGIN t: Tester; IF server = NIL OR Rope.Length[server]=0 OR PupDefs.GetPupAddress[PupTypes.fillInSocketID, PupDefs.GetMyName[]]=PupDefs.GetPupAddress[PupTypes.fillInSocketID, server] THEN BEGIN IF SystemVersion.machineType # dolphin THEN SIGNAL IsntADolphin; t _ localTester; END ELSE BEGIN interface: ChipTestRemoteRpcControl.InterfaceRecord = ChipTestRemoteRpcControl.ImportNewInterface[interfaceName: [instance: server]]; t _ NEW[TesterOb _ [ flush: FlushRemote, writeR: WriteRRemote, readI: ReadIRemote, data: NEW[RemoteTester _ [interface: interface]]]]; finalizeList _ CONS[t.data, finalizeList]; END; Initialize[t]; RETURN[t]; END; Initialize: PUBLIC ENTRY PROC [t: Tester, aToB, aToI: NSec _ 100] = TRUSTED BEGIN ENABLE UNWIND => NULL; Initializer: TYPE = MACHINE DEPENDENT RECORD [ unused (0: 0..13): [0..0] _ 0, enableWakeup (0: 14..14): BOOL _ FALSE, notReset (0: 15..15): BOOL _ TRUE]; t.d _ t.a _ t.b _ NIL; t.writeR[t: t, reg: init, value: LOOPHOLE[Initializer[]]]; t.writeR[t: t, reg: control, value: LOOPHOLE[SetFirstIGroup[group: 0]]]; InternalPutABDelay[t: t, d: aToB]; InternalPutAIDelay[t: t, d: aToI]; t.flush[t: t]; END; aToBOffset: NSec _ 0; PutABDelay: PUBLIC ENTRY PROC [t: Tester, d: NSec] = {InternalPutABDelay[t: t, d: d ! UNWIND => NULL]}; InternalPutABDelay: PROC [t: Tester, d: NSec] = INLINE {PutComputedDelay[t, [clock: B], d-aToBOffset]}; aToIOffset: NSec _ 0; PutAIDelay: PUBLIC ENTRY PROC [t: Tester, d: NSec] = {InternalPutAIDelay[t: t, d: d ! UNWIND => NULL]}; InternalPutAIDelay: PROC [t: Tester, d: NSec] = INLINE {PutComputedDelay[t, [clock: I], d-aToIOffset]}; PutComputedDelay: PROC [t: Tester, comm: LoadDelay, delay: NSec] = TRUSTED BEGIN delay _ MAX[0, MIN[180, delay]]; comm.delay1 _ delay/16; delay _ delay MOD 16; comm.delay2 _ delay/2; comm.delay3 _ delay MOD 2; t.writeR[t: t, reg: control, value: LOOPHOLE[comm]]; END; PutDisables: PUBLIC ENTRY PROC [ t: Tester, p: ChannelVecRef, makeBufWindow: BOOL _ FALSE ] RETURNS [ window: Tester ] = {RETURN[InternalPutDisables[t, p, makeBufWindow ! UNWIND => NULL]]}; InternalPutDisables: PROC [ t: Tester, p: ChannelVecRef, makeBufWindow: BOOL _ FALSE ] RETURNS [ window: Tester ] = BEGIN IF p#NIL THEN BEGIN window _ DoLoadABD[t: t, comm: LoadABD[command: loadD], old: t.d, new: p, makeBufWindow: makeBufWindow]; IF t.d=NIL THEN t.d _ NEW[ChannelVec]; t.d^ _ p^; IF window#NIL THEN {window.d _ t.d; t.d _ NIL}; END ELSE window _ NIL; END; GetDisables: PUBLIC ENTRY PROC [t: Tester] RETURNS [ChannelVecRef] = {RETURN[IF t.d=NIL THEN NIL ELSE NEW[ChannelVec _ t.d^]]}; PutABuf: PUBLIC ENTRY PROC [ t: Tester, p: ChannelVecRef, makeBufWindow: BOOL _ FALSE ] RETURNS [ window: Tester ] = {RETURN[InternalPutABuf[t, p, makeBufWindow ! UNWIND => NULL]]}; InternalPutABuf: PROC [ t: Tester, p: ChannelVecRef, makeBufWindow: BOOL _ FALSE ] RETURNS [ window: Tester ] = BEGIN IF p#NIL THEN BEGIN window _ DoLoadABD[t: t, comm: LoadABD[command: loadA], old: t.a, new: p, makeBufWindow: makeBufWindow]; IF t.a=NIL THEN t.a _ NEW[ChannelVec]; t.a^ _ p^; IF window#NIL THEN {window.d _ t.a; t.a _ NIL}; END ELSE window _ NIL; END; GetABuf: PUBLIC ENTRY PROC [t: Tester] RETURNS [ChannelVecRef] = {RETURN[IF t.a=NIL THEN NIL ELSE NEW[ChannelVec _ t.a^]]}; PutBBuf: PUBLIC ENTRY PROC [ t: Tester, p: ChannelVecRef, makeBufWindow: BOOL _ FALSE ] RETURNS [ window: Tester ] = {RETURN[InternalPutBBuf[t, p, makeBufWindow ! UNWIND => NULL]]}; InternalPutBBuf: PROC [ t: Tester, p: ChannelVecRef, makeBufWindow: BOOL _ FALSE ] RETURNS [ window: Tester ] = BEGIN IF p#NIL THEN BEGIN window _ DoLoadABD[t: t, comm: LoadABD[command: loadB], old: t.b, new: p, makeBufWindow: makeBufWindow]; IF t.b=NIL THEN t.b _ NEW[ChannelVec]; t.b^ _ p^; IF window#NIL THEN {window.d _ t.b; t.b _ NIL}; END ELSE window _ NIL; END; GetBBuf: PUBLIC ENTRY PROC [t: Tester] RETURNS [ChannelVecRef] = {RETURN[IF t.b=NIL THEN NIL ELSE NEW[ChannelVec _ t.b^]]}; DoLoadABD: PROC [ t: Tester, comm: LoadABD, old, new: ChannelVecRef, makeBufWindow: BOOL ] RETURNS [ window: Tester _ NIL ] = TRUSTED BEGIN IF makeBufWindow AND new=NIL THEN new _ NEW[ChannelVec _ ALL[FALSE]]; IF new#NIL THEN BEGIN WITH t.data SELECT FROM b: BufRef => BEGIN IF makeBufWindow THEN BEGIN window _ NEW[TesterOb _ [ data: NEW[Window _ [buf: t, firstWord: b.testDataSize, abd: TRUE, comm: comm]] ]]; old _ NIL; END; FOR i: ByteIndex IN ByteIndex DO IF old=NIL OR LOOPHOLE[new, REF ChannelByteVec][i]#LOOPHOLE[old, REF ChannelByteVec][i] THEN BEGIN comm.pinGroup _ i; comm.data _ LOOPHOLE[new, REF ChannelByteVec][i]; t.writeR[t: t, reg: control, value: LOOPHOLE[comm]]; END; ENDLOOP; END; w: WindowRef => BEGIN IF w.abd AND w.comm=comm THEN BEGIN buf: BufRef = NARROW[w.buf.data]; FOR i: ByteIndex IN ByteIndex DO LOOPHOLE[@buf.testData.t[w.firstWord+i], LONG POINTER TO LoadABD].data _ LOOPHOLE[new, REF ChannelByteVec][i]; ENDLOOP; END ELSE ERROR IllegalOp; END; ENDCASE => FOR i: ByteIndex IN ByteIndex DO comm.pinGroup _ i; comm.data _ LOOPHOLE[new, REF ChannelByteVec][i]; t.writeR[t: t, reg: control, value: LOOPHOLE[comm]]; ENDLOOP; END; END; Step: PUBLIC ENTRY PROC [t: Tester] = TRUSTED BEGIN ENABLE UNWIND => NULL; IF t.d = NIL THEN [] _ InternalPutDisables[t: t, p: NEW[ChannelVec _ ALL[TRUE]]]; IF t.a = NIL THEN [] _ InternalPutABuf[t: t, p: NEW[ChannelVec _ ALL[FALSE]]]; IF t.b = NIL THEN [] _ InternalPutBBuf[t: t, p: NEW[ChannelVec _ ALL[TRUE]]]; WITH t.data SELECT FROM b: BufRef => BEGIN IF b.unSteppedTestData>0 AND NOT LOOPHOLE[b.testData.t[b.testDataSize-1], JustStrobe].strobe THEN LOOPHOLE[b.testData.t[b.testDataSize-1], JustStrobe].strobe _ TRUE ELSE t.writeR[t: t, reg: control, value: LOOPHOLE[JustStrobe[]]]; b.i _ NIL; END; ENDCASE => t.writeR[t: t, reg: control, value: LOOPHOLE[JustStrobe[]]]; END; GetIBuf: PUBLIC ENTRY PROC [t: Tester] RETURNS [ChannelVecRef] = BEGIN ENABLE UNWIND => NULL; WITH t.data SELECT FROM buf: BufRef => RETURN[buf.i]; ENDCASE => {RETURN[NEW[ChannelVec _ t.readI[t: t]]]}; END; ci: RWChannelVecRef _ NIL; CheckI: PUBLIC ENTRY PROC [ t: Tester, expected: ChannelVecRef, mask: ChannelVecRef _ NIL, makeBufWindow: BOOL _ FALSE ] RETURNS [ CheckResult ] = TRUSTED BEGIN ENABLE UNWIND => NULL; IF mask^ = falses^ THEN RETURN[[0, NIL]]; -- not a real test WITH t.data SELECT FROM buf: BufRef => BEGIN PutCheckIntoBuffer: PROC [min: WordIndex] = TRUSTED BEGIN IncreaseTestData[buf, 8]; FOR i: [0..3] IN [0..3] DO buf.testData.t[buf.testDataSize-8+i] _ LOOPHOLE[expected, REF ChannelWordVec][i+min]; buf.testData.t[buf.testDataSize-4+i] _ LOOPHOLE[mask, REF ChannelWordVec][i+min]; ENDLOOP; END; window: Tester _ NIL; buf: BufRef = NARROW[t.data]; IF NOT makeBufWindow AND mask^ = falses^ THEN RETURN[[0, NIL]]; -- not a real test FinishStep[t]; WHILE buf.steps[buf.stepCount-1].checkSecond OR buf.steps[buf.stepCount-1].checkFirst DO t.writeR[t: t, reg: control, value: LOOPHOLE[NoOp]]; FinishStep[t]; ENDLOOP; IF makeBufWindow THEN BEGIN window _ NEW[TesterOb _ [ data: NEW[Window _ [buf: t, firstWord: buf.testDataSize, check: TRUE]] ]]; END; FOR i: WordIndex IN [0..3] DO IF makeBufWindow OR LOOPHOLE[mask, REF ChannelWordVec][i]#0 THEN BEGIN buf.steps[buf.stepCount-1].checkFirst _ TRUE; PutCheckIntoBuffer[min: 0]; EXIT; END; ENDLOOP; FOR i: WordIndex IN [4..7] DO IF makeBufWindow OR LOOPHOLE[mask, REF ChannelWordVec][i]#0 THEN BEGIN buf.steps[buf.stepCount-1].checkSecond _ TRUE; PutCheckIntoBuffer[min: 4]; EXIT; END; ENDLOOP; RETURN[[buf.stepCount, window]]; END; w: WindowRef => BEGIN ResetCheckInBuffer: PROC [min: WordIndex] = TRUSTED BEGIN FOR i: [0..3] IN [0..3] DO buf.testData.t[w.firstWord+i] _ LOOPHOLE[expected, REF ChannelWordVec][i+min]; buf.testData.t[w.firstWord+4+i] _ LOOPHOLE[mask, REF ChannelWordVec][i+min]; ENDLOOP; END; buf: BufRef = NARROW[w.buf.data]; IF NOT w.check THEN ERROR IllegalOp; ResetCheckInBuffer[min: 0]; ResetCheckInBuffer[min: 4]; RETURN[[0, NIL]]; END; ENDCASE => BEGIN IF ci = NIL THEN ci _ NEW[ChannelVec]; ci^ _ t.readI[t: t]; FOR j: WordIndex IN WordIndex DO diff: WORD = Basics.BITAND[LOOPHOLE[mask, REF ChannelWordVec][j], Basics.BITXOR[LOOPHOLE[ci, REF ChannelWordVec][j], LOOPHOLE[expected, REF ChannelWordVec][j]]]; IF diff#0 THEN BEGIN FOR k: Channel IN [16*j..16*(j+1)) DO IF mask[k] AND (expected[k]#ci[k]) THEN ERROR CheckFailure[checkId: 1, mask: mask, expected: expected, was: ci, errChannel: k]; REPEAT FINISHED => ERROR; ENDLOOP; END; ENDLOOP; RETURN[[1, NIL]]; END; END; CheckFailure: PUBLIC ERROR [checkId: CARDINAL, mask, expected, was: ChannelVecRef, errChannel: Channel] = CODE; IllegalOp: PUBLIC ERROR = CODE; BufferR: PROC [t: Tester, reg, value: WORD] = TRUSTED BEGIN buf: BufRef = NARROW[t.data]; IF reg#control THEN ERROR IllegalOp; IF buf.unSteppedTestData>=16 THEN FinishStep[t]; IncreaseTestData[buf, 1]; buf.testData.t[buf.testDataSize-1] _ value; buf.unSteppedTestData _ buf.unSteppedTestData+1; END; FinishStep: PROC [t: Tester] = TRUSTED BEGIN buf: BufRef = NARROW[t.data]; IF buf.testDataSize=0 THEN t.writeR[t: t, reg: control, value: LOOPHOLE[NoOp]]; IF buf.unSteppedTestData>0 THEN BEGIN WHILE buf.unSteppedTestData MOD 4 # 0 DO -- fill out quadword t.writeR[t: t, reg: control, value: LOOPHOLE[NoOp]]; ENDLOOP; IncreaseSteps[buf, 1]; buf.steps[buf.stepCount-1] _ StepControl[quadWdCnt: buf.unSteppedTestData/4]; buf.unSteppedTestData _ 0; END; END; IncreaseTestData: PROC [buf: BufRef, increase: CARDINAL] = TRUSTED BEGIN newTestDataSize: CARDINAL = buf.testDataSize+increase; IF newTestDataSize>buf.testDataMaxSize THEN BEGIN newPagesNeeded: NAT = VM.PagesForWords[(13*newTestDataSize)/10]+2; newInterval: VM.Interval = VM.Allocate[count: newPagesNeeded]; newTestData: LONG POINTER TO TestDataArray = LOOPHOLE[VM.AddressForPageNumber[newInterval.page]]; FOR i: INT IN [0..buf.testDataSize) DO newTestData.t[i] _ buf.testData.t[i]; ENDLOOP; IF buf.testData # NIL THEN VM.Free[buf.testDataInterval]; buf.testDataMaxSize _ VM.WordsForPages[newPagesNeeded]-SIZE[TestDataArray]; buf.testDataInterval _ newInterval; buf.testData _ newTestData; END; buf.testDataSize _ newTestDataSize; END; IncreaseSteps: PROC [buf: BufRef, increase: CARDINAL] = TRUSTED BEGIN newStepCount: CARDINAL = buf.stepCount+increase; IF newStepCount>buf.stepMaxCount THEN BEGIN newPagesNeeded: NAT = VM.PagesForWords[(13*buf.stepMaxCount)/(4*10)]+1; newInterval: VM.Interval = VM.Allocate[count: newPagesNeeded]; newSteps: LONG POINTER TO StepControlArray = LOOPHOLE[VM.AddressForPageNumber[newInterval.page]]; FOR i: INT IN [0..buf.stepCount) DO newSteps[i] _ buf.steps[i]; ENDLOOP; IF buf.steps # NIL THEN VM.Free[buf.stepInterval]; buf.stepMaxCount _ 4*VM.WordsForPages[newPagesNeeded]; buf.stepInterval _ newInterval; buf.steps _ newSteps; END; buf.stepCount _ newStepCount; END; ExecuteBuffer: PUBLIC ENTRY PROC [t: Tester] = {InternalExecuteBuffer[t ! UNWIND => NULL]}; InternalExecuteBuffer: PROC [t: Tester] = TRUSTED BEGIN SendTestBuf: PROC [stepCount: CARDINAL, stepControl: LONG POINTER, -- resident testData: LONG POINTER -- quadword-aligned, resident -- ] RETURNS [undoneSteps: CARDINAL] = TRUSTED MACHINE CODE BEGIN PrincOps.zMISC, 14B -- miscSendBuf --; END; WITH t.data SELECT FROM buf: BufRef => BEGIN undoneSteps: CARDINAL; IF buf.testDataSize=0 THEN RETURN; IF buf.unSteppedTestData>0 THEN FinishStep[t]; VM.Pin[buf.testDataInterval]; VM.Pin[buf.stepInterval]; undoneSteps _ IF SystemVersion.machineType=dolphin THEN SendTestBuf[stepCount: buf.stepCount, stepControl: LOOPHOLE[buf.steps], testData: LOOPHOLE[buf.testData]] ELSE 0; VM.Unpin[buf.testDataInterval]; VM.Unpin[buf.stepInterval]; buf.i _ NEW[ChannelVec _ buf.testData.finalI]; IF undoneSteps = 0 THEN RETURN; BEGIN expected: ChannelVecRef = NEW[ChannelVec _ ALL[FALSE]]; mask: ChannelVecRef = NEW[ChannelVec _ ALL[FALSE]]; failedStep: CARDINAL = buf.stepCount-undoneSteps; badSpot: CARDINAL _ 0; FOR j: CARDINAL IN [0..failedStep] DO badSpot _ badSpot+4*buf.steps[j].quadWdCnt +(IF buf.steps[j].checkSecond THEN 8 ELSE 0) +(IF buf.steps[j].checkFirst THEN 8 ELSE 0); ENDLOOP; IF buf.steps[failedStep].checkSecond THEN BEGIN FOR i: [0..3] IN [0..3] DO LOOPHOLE[expected, REF ChannelWordVec][i+4] _ buf.testData.t[badSpot-8+i]; LOOPHOLE[mask, REF ChannelWordVec][i+4] _ buf.testData.t[badSpot-4+i]; ENDLOOP; badSpot _ badSpot-8; END; IF buf.steps[failedStep].checkFirst THEN BEGIN FOR i: [0..3] IN [0..3] DO LOOPHOLE[expected, REF ChannelWordVec][i] _ buf.testData.t[badSpot-8+i]; LOOPHOLE[mask, REF ChannelWordVec][i] _ buf.testData.t[badSpot-4+i]; ENDLOOP; END; FOR errChannel: Channel IN Channel DO IF mask[errChannel] AND (buf.i[errChannel]#expected[errChannel]) THEN ERROR CheckFailure[checkId: failedStep+1, mask: mask, expected: expected, was: buf.i, errChannel: errChannel]; ENDLOOP; ERROR; -- SendTestQueue failed but we couldn't figure out why END; END; w: WindowRef => InternalExecuteBuffer[w.buf]; ENDCASE => ERROR IllegalOp; END; OpenBuffer: PUBLIC ENTRY PROC [ base: Tester _ NIL ] RETURNS [ Tester ] = BEGIN ENABLE UNWIND => NULL; buf: BufRef = NEW[BufDesc _ [base: IF base=NIL THEN OpenTester[] ELSE base]]; finalizeList _ CONS[buf, finalizeList]; RETURN[NEW[TesterOb _ [ writeR: BufferR, flush: FlushLocal, data: buf]]]; END; FlushError: PROC [ t: Tester ] = {ERROR IllegalOp}; WriteRError: PROC [ t: Tester, reg, value: WORD ] = {ERROR IllegalOp}; ReadIError: PROC [ t: Tester ] RETURNS [ ChannelVec ] = {ERROR IllegalOp}; WriteRRemote: PROC [ t: Tester, reg, value: WORD ] = BEGIN rt: RemoteTesterRef = NARROW[t.data]; WHILE rt.stores.length>=ChipTestRemote.regStoresMaxLength DO FlushRT[rt] ENDLOOP; rt.stores.s[rt.stores.length] _ [reg: reg, value: value]; rt.stores.length _ rt.stores.length+1; END; FlushRemote: PROC [ t: Tester ] = {FlushRT[NARROW[t.data]]}; FlushRT: PROC [ rt: RemoteTesterRef ] = BEGIN IF rt.stores.length>0 THEN BEGIN interface: ChipTestRemoteRpcControl.InterfaceRecord = rt.interface; interface.WriteRegs[rt.stores]; rt.stores.length _ 0; END; END; ReadIRemote: PROC [ t: Tester ] RETURNS [ ChannelVec ] = BEGIN rt: RemoteTesterRef = NARROW[t.data]; interface: ChipTestRemoteRpcControl.InterfaceRecord = rt.interface; FlushRT[rt]; RETURN[interface.ReadIBuf[]]; END; SyncFlusher: ENTRY PROC [ l: LIST OF REF ] = BEGIN ENABLE UNWIND => NULL; FOR rl: LIST OF REF _ l, rl.rest WHILE rl#NIL DO WITH rl.first SELECT FROM rt: RemoteTesterRef => FlushRT[rt]; ENDCASE => NULL; ENDLOOP; END; Flusher: PROC = BEGIN DO Process.Pause[Process.MsecToTicks[1000]]; SyncFlusher[finalizeList]; ENDLOOP; END; ReadILocal: PROC [ t: Tester ] RETURNS [ i: ChannelVec ] = TRUSTED BEGIN ReadR: PROC [reg: CARDINAL] RETURNS [value: WORD] = TRUSTED MACHINE CODE BEGIN PrincOps.zMISC, 5B -- input --; END; WriteRLocal[t: t, reg: control, value: LOOPHOLE[SetFirstIGroup[group: 0]]]; FOR j: WordIndex IN WordIndex DO LOOPHOLE[@i, POINTER TO ChannelWordVec][j] _ ReadR[selectedIGroup]; ENDLOOP; END; Byte: TYPE = [0..377B]; status: Byte = 0; -- input register numbers selectedIGroup: Byte = 1; FlushLocal: PROC [ t: Tester ] = {NULL}; WriteRLocal: PROC [ t: Tester, reg, value: WORD ] = BEGIN DoWriteRLocal: PROC [ value: WORD, reg: WORD ] = TRUSTED MACHINE CODE BEGIN PrincOps.zMISC, 6B -- output --; END; DoWriteRLocal[value, reg]; END; init: Byte = 0; -- output register numbers and types control: Byte = 1; JustStrobe: TYPE = MACHINE DEPENDENT RECORD [ strobe (0: 0..0): BOOL _ TRUE, unused (0: 1..15): [0..0] _ 0 ]; NoOp: JustStrobe = [strobe: FALSE]; LoadABD: TYPE = MACHINE DEPENDENT RECORD [ strobe (0: 0..0): BOOL _ FALSE, command (0: 1..2): {loadD(1), loadA(2), loadB(3)}, pinGroup (0: 3..7): [0..31] _ 0, data (0: 8..15): Byte _ 0]; LoadDelay: TYPE = MACHINE DEPENDENT RECORD [ strobe (0: 0..0): BOOL _ FALSE, clock (0: 1..4): {B(1), I(2)}, unused (0: 5..5): [0..0] _ 0, delay1 (0: 6..9): [0..17B] _ 0, delay2 (0: 10..12): [0..7B] _ 0, delay3 (0: 13..15): [0..7B] _ 0]; SetFirstIGroup: TYPE = MACHINE DEPENDENT RECORD [ strobe (0: 0..0): BOOL _ FALSE, command (0: 1..5): {selectIGroup(1)} _ selectIGroup, unused (0: 6..11): [0..0] _ 0, group (0: 12..15): [0..15] _ 0]; IsntADolphin: SIGNAL = CODE; finalizeList: LIST OF REF _ NIL; SyncFinalizer: ENTRY PROC [r: REF] = BEGIN ENABLE UNWIND => NULL; Remove: PROC [l: LIST OF REF] RETURNS [result: LIST OF REF] = BEGIN SELECT TRUE FROM l = NIL => result _ NIL; l.first = r => result _ l.rest; ENDCASE => {result _ l; l.rest _ Remove[l.rest]}; END; WITH r SELECT FROM buf: BufRef => BEGIN IF buf.testData # NIL THEN TRUSTED {VM.Free[buf.testDataInterval]; buf.testData _ NIL}; IF buf.steps # NIL THEN TRUSTED {VM.Free[buf.stepInterval]; buf.steps _ NIL}; END; ENDCASE => NULL; finalizeList _ Remove[finalizeList]; END; Finalizer: PROC [fq: SafeStorage.FinalizationQueue] = BEGIN DO r: REF = SafeStorage.FQNext[fq]; SyncFinalizer[r]; ENDLOOP; END; fq: SafeStorage.FinalizationQueue = SafeStorage.NewFQ[]; SafeStorage.EstablishFinalization[CODE[BufDesc], 1, fq ! SafeStorage.CantEstablishFinalization => SafeStorage.ReEstablishFinalization[CODE[BufDesc], 1, fq]]; SafeStorage.EstablishFinalization[CODE[RemoteTester], 1, fq ! SafeStorage.CantEstablishFinalization => SafeStorage.ReEstablishFinalization[CODE[RemoteTester], 1, fq]]; TRUSTED BEGIN Process.Detach[FORK Finalizer[fq]]; Process.Detach[FORK Flusher[]]; END; END. ÐChipTestImpl.mesa - Petit Dolphin chip tester client interface last edited by McCreight, January 24, 1984 6:51 pm Types that go in the data field of a TesterOb... Petit claims that delay greater than this will cause the pulse in the delay line to collapse due to asymmetries. turn on the strobe bit in the last command This second group of procedures is used to generate and execute buffers containing several tester steps. These buffers conform to the specifications of the Dolphin ccaKludge instruction, whose microcode is in MesaIO.mc (see Fiala). The major limitation is that with the ccaKludge instruction you cannot ask about the results of the steps (except for the last one); you must predict the results (under a mask), and step execution will halt if masked prediction and reality do not match. This is fine for testing but not so good for debugging. 130% + 2 pages 130% + 1 page NOTE: This doesn't initialize the tester. If you want to do that, call Initialize on the buffer or on the buffer's base tester first. Analyze the results and generate a CheckFailure ERROR Procedures that implement register read/write for a window (which are illegal) Procedures that implement remote tester read/write The procedures that implement a local tester on a Dolphin automatically steps to next IGroup with each read Finalization (when the next-to-last REF to something disappears) Gives back Pilot Spaces in the BufDesc before the BufDesc disappears... Module start code.. ÊF˜Jšœ?™?J˜Jšœ2™2J™šÏk ˜ Jšœœ˜"Jšœ ˜ Jšœ˜Jšœœ'˜EJšœœœœ˜Jšœ œ ˜Jšœœ˜+Jšœœ˜)Jšœ œ˜ Jšœœœ ˜šœ œ3˜DJšœ;˜;—šœœA˜IJšœ4˜4——J˜šœœœœW˜|Jšœ ˜Jšœœ ˜J˜Jš œœœœœ˜:Jš œœœœœ˜Jš œ œœœœœ)˜ašœœœ˜&Jšœ%˜%Jšœ˜—Jšœœœœ˜9Jšœœœ˜KJšœ#˜#Jšœ˜Jšœ˜—Jšœ#˜#Jšœ˜J˜J˜—šž œœœ˜7Jšœ˜ Jšœœ˜0šœ˜%Jš˜šœœœ/˜GJšœ ™ —Jšœ œ œ!˜>Jš œ œœœœœ)˜ašœœœ˜#Jšœ˜Jšœ˜—Jšœ œœœ˜2Jšœœ˜6Jšœ˜Jšœ˜Jšœ˜—Jšœ˜Jšœ˜J˜—J˜Jš ž œœœœ*œœ˜[J˜šžœœ˜)Jšœ˜ J˜šž œœ œ˜'Jšœ œœŸ ˜&Jšœ œœŸ œ˜9Jšœœ˜!Jšœœœ˜JšœŸœ˜&Jšœ˜—J˜šœœ˜šœ˜Jš˜Jšœ œ˜Jšœœœ˜"Jšœœ˜.J˜Jšœ˜Jšœ˜J˜Jšœ†™†J˜šœœ#˜7šœ%˜%Jšœ œœ˜C—Jšœ˜—J˜Jšœ˜Jšœ˜J˜Jšœœ#˜.Jšœœœ˜J™šœ5™5Jš˜Jšœœœœ˜7Jšœœœœ˜3Jšœ œ˜1Jšœ œ˜šœœœ˜%šœ*˜*Jšœœœœ˜,Jšœœœœ˜,—Jšœ˜—šœ#˜)Jš˜šœ œ˜Jšœ œ4˜JJšœœ4˜FJšœ˜—Jšœ˜Jšœ˜—šœ"˜(Jš˜šœ œ˜Jšœ œ2˜HJšœœ2˜DJšœ˜—Jšœ˜—šœœ ˜%šœœ*˜EšœD˜IJšœ$˜$——Jšœ˜—JšœŸ6˜=Jšœ˜—Jšœ˜J˜—J˜-J˜Jšœœ ˜—Jšœ˜J˜—J˜š ž œœœœœœ ˜IJš˜Jšœœœ˜Jš œœœœœœ˜MJšœœ˜'šœœ ˜Jšœ˜Jšœ˜Jšœ ˜ —Jšœ˜—J˜J˜JšœN™NJ˜Jšž œœœ ˜3J˜Jšž œœœœ ˜FJ˜Jšž œœœœ ˜JJ˜J˜J˜Jšœ2™2J˜šž œœœ˜4Jš˜Jšœœ ˜%Jšœ5œ œ˜QJšœ9˜9Jšœ&˜&Jšœ˜J˜—Jšž œœœ ˜