//MXTST.BCPL
//Microprocessor diagnostic overlay (MXTALL.BCPL also in overlay)
get "mx.d"
//FieldTest() allows any of the fields in a microinstruction to be repeatedly
//executed from the Alto and modified under mouse control for scope loops.
//The initial field value is zero, and values for all other fields are taken
//from the NOP (no-operation) microinstruction. The data pattern is
//repeatedly loaded into BR and executed. When the loop is stopped, the
//final instruction tested is left in TSTINS.
//DataTest() allows any register or memory to be tested using a data pattern
//selected from the following:
// ZEROES all 0's data
// ONES all 1's data
// CYC1 cycled 1 in word of 0's
// CYC0 cycled 0 in word of 1's
// RANDOM random data
// ALTZO alternating all-0's and all-1's
// SEQ sequential integers 0, 1, ...
// ALTGD alternates SHOULD-BE with its complement
//Whenever a TEST stops, the last value of test data is in SHOULD-BE,
//last value read back in DATA-WAS, and number of successful iterations
//prior to halting in LOOP-COUNT. Tests write data, read it back, compare,
//halt if any bits selected by BITS-CHECKED are wrong, modify the data
//under control of the pattern, and loop.
//Memory tests presently write all words in the address range being tested
//sequentially, then read and check the words sequentially. The left
//and right 18-bit half-words for LOW-HIGH control the address range,
//with the upper bound being ignored if greater than the hardware maximum
//for the memory being tested.
//MicTest(Count,A0,A1,A2,A3,A4,A5) a count of LDR addresses and one to six
//LDR addresses. If only one address is passed, then an endless repeat of
//loading BR with the selected data pattern and executing the
//selected LDR instruction takes place. If more than one address is passed,
//then the sequence is executed endlessly, the first preceded by loading
//BR with the selected data pattern and the last followed by reading
//and checking 36 bits of result. This means that to check fewer bits
//a mask left-justified in 36 bits of BITS-CHECKED should be used.
static [
STAT1 //First string on status line
STAT2 //Second string on status line
STAT3 //Number on status line
Inscnt; Ins0; Ins1; Ins2; Ins3; Ins4; Ins5
]
//Scope loop for various microinstruction fields
static [ INCact; DECact; RSHact; LSHact ]
let FieldTest() = valof
[ WssCSS("Instruction field for scope loop:")
DefField("BT",0); DefField("BC",1)
DefField("LA",2); DefField("RA",3)
DefField("PS",4); DefField("QS",5)
DefField("AF",6); DefField("BS",7)
DefField("BD",8); DefField("F1",9)
DefField("F2",10); DefField("SA",11)
QUITact = CreateAction("Abort", lv StopFldLoop,nil,0,$C-100B)
QuitF = -1
resultis FieldMenu
]
//Storage for TSTACT allocated during initialization
and DefField(str,FldX) be
[ REGACT!FldX = CreateAction(str,lv TestFld,FldX)
]
and FieldMenu(S,Nix) be
[ WsMarkA(QUITact)
test QuitF ls 0
ifso [ for I = 0 to NFLDS-1 do WsMarkA(REGACT!I) ]
ifnot
[ WsMarkA(INCact); WsMarkA(DECact)
WsMarkA(RSHact); WsMarkA(LSHact)
]
]
and StopFldLoop(S,garb,Buttons,garb1) be
[ Resets(CmdCommentStream)
WssCSS(QuitF ge 0 ? "Field iteration finished","XXX")
MaxcStopped(false)
]
and RshF(S,garb,Buttons,FldX) be
[ STAT3 = STAT3 rshift 1; ChangeField(FldX)
]
and LshF(S,garb,Buttons,FldX) be
[ STAT3 = STAT3 lshift 1; ChangeField(FldX)
]
and IncF(S,garb,Buttons,FldX) be
[ STAT3 = STAT3+1; ChangeField(FldX)
]
and DecF(S,garb,Buttons,FldX) be
[ STAT3 = STAT3-1; ChangeField(FldX)
]
//For fields, create a microinstruction which is a no-op except for the
//selected field. Begin testing with 0 in the field, modifying the value
//under mouse control. Whenever the value changes, reload PIR0-PIR3 and
//enter a loop in which CR is repeatedly loaded.
//fld is the field index, str is a status string to be displayed
//Note that TSTINS is the displacement of the instruction into LDRMEM
//while INSTST is a direct pointer to the instruction being tested
and TestFld(S,garb,Buttons,FldX) be
[ LoadDone = false //Indicate storage smashed in case of "Dump"
MoveBlock(INSTST,LDRMEM+NOP,5)
STAT2 = " "; STAT3 = 0
INCact = CreateAction("+1",lv IncF,FldX)
DECact = CreateAction("-1",lv DecF,FldX)
RSHact = CreateAction("Rshift",lv RshF,FldX)
LSHact = CreateAction("Lshift",lv LshF,FldX)
QuitF = AddToEveryTimeList(FieldLoop,FldX)
FormMenu(CmdMDFS,FormCmdmenuText); ChangeField(FldX)
]
and ChangeField(FldX) be
[ STAT3 = STAT3 & (table [ 3; 37B; 37B; 37B; 77B; 7; 37B; 37B; 37B; 77B; 17B; 377B ] ) !FldX
STAT1 = (REGACT!FldX)!0
//Args to PutField are bit1, nbits, DVec, value
PutField(table [ 0; 2; 7; 12; 17; 23; 26; 31; 36; 41; 47; 51 ] ! FldX,
table [ 2; 5; 5; 5; 6; 3; 5; 5; 5; 6; 4; 8 ] !FldX,
INSTST,STAT3)
WriteComment()
]
and FieldLoop(FldX) be XctL36(TSTINS,GOODD)
//Test of register/memory using various data patterns
and DataTest() = valof
[ STAT1 = "Testing "; STAT3 = -1
for I = 0 to NREALREGS-1 do //Skip non read-write regs
[ REGACT!I = CreateAction(REGNAM!I,lv TestReg,I) ]
for I = 0 to 1 do //IMh and IMl
[ MEMACT!I = CreateAction(MEMNAM!I,lv TestMem,I) ]
for I = 3 to 5 do //SM, DM, and MP (skipping 72-bit IM)
[ MEMACT!(I-1) = CreateAction(MEMNAM!I,lv TestMem,I) ]
for I = 7 to NREALMEMS-1 do //Skip MAIN and LDR
[ MEMACT!(I-2) = CreateAction(MEMNAM!I,lv TestMem,I) ]
GetPattern(0); resultis TestMenu
]
and TestMenu(S,Nix) be
[ WsMarkA(QUITact)
if QuitF eq -2 do
[ WssCSS("Select register or memory:")
for I = 0 to NREALREGS-1 do WsMarkA(REGACT!I)
for I = 0 to NREALMEMS-3 do WsMarkA(MEMACT!I)
]
if QuitF eq -1 do
[ for I = 0 to NPATS-1 do WsMarkA(PATACT!I) ]
]
and TestStop(S,garb,Buttons,firstact) be
[ test QuitF ge 0
ifso [ TestAborted = true ]
ifnot [ ErrorStop("XXX","") ]
]
and ErrorStop(str1,str2) be
[ Resets(CmdCommentStream)
WssCSS(str1 eq 0 ? "Data compare error testing ",str1)
WssCSS(str2)
if QuitF ge 0 do
[ RightAdjust(MASK,DMASK,TestWidth)
RightAdjust(GDATA,GOODD,TestWidth)
RightAdjust(DATA,ACTD,TestWidth)
]
MaxcStopped(false)
]
and TestReg(S,garb,Buttons,RegX) be
[ TestWidth = REGWID!RegX
LeftAdjust(MASK,DMASK,TestWidth)
QuitF = AddToEveryTimeList(TestRLp,RegX)
STAT2 = REGNAM!RegX; WriteComment()
FormMenu(CmdMDFS,FormCmdmenuText)
]
and TestRLp(RegX) be
[ for I = 1 to 100 do
[ PutRegData(RegX,GOODD); GetRegData(RegX,ACTD)
if CheckData() then ErrorStop(0,STAT2)
]
]
and TestMem(S,garb,Buttons,MemX) be
[ LoadDone = false //Indicate state smashed in case of "Dump"
TestWidth = MEMWID!MemX
LeftAdjust(MASK,DMASK,TestWidth)
STAT2 = MEMNAM!MemX; WriteComment()
QuitF = AddToEveryTimeList(selecton MemX into
[ case 9: TestSTKLp
default: TestMLp
] ,MemX)
TAVEC!0 = 0
//The left and right halves of the right-most 36 bits of the LDRMEM
//location LOW-HIGH contain the lower bound on the low address and the
//upper bound on the high address. If the low bound is greater than
//the maximum for this memory, set it to zero.
HIGHADDR = (MEMLEN!MemX)-1; LOWADDR = ADRANG!3 rshift 2
if LOWADDR gr HIGHADDR do [ LOWADDR = 0; ADRANG!3 = 0 ]
if HIGHADDR gr ADRANG!4 then HIGHADDR = ADRANG!4
FormMenu(CmdMDFS,FormCmdmenuText)
]
//LOW-HIGH doesn't affect STK
and TestSTKLp(MemX) be
[ let Vals = vec 12 //Special for STK
for I = 11 to 0 by -1 do
[ XctL12(LDNPC,GOODD); XctMic(CALL)
Vals!I = GOODD!0; NextGDATA()
]
for I = 0 to 11 do
[ XctR12(RDSTK,ACTD); GOODD!0 = Vals!I
if CheckData() then ErrorStop(0,STAT2)
XctMic(POPSTK)
]
]
and TestMLp(MemX) be
[ let SaveRX,SaveRD,SaveGD = RANDIX,RANDATA,vec 3
MoveBlock(SaveGD,GOODD,3)
for I = LOWADDR to HIGHADDR do
[ TAVEC!1 = I; PutMemData(MemX,TAVEC,GOODD); NextGDATA() ]
RANDIX = SaveRX; RANDATA = SaveRD
MoveBlock(GOODD,SaveGD,3)
for I = LOWADDR to HIGHADDR do
[ TAVEC!1 = I; GetMemData(MemX,TAVEC,ACTD)
if CheckData() then ErrorStop(0,STAT2)
]
]
and MicTMenu(S,Nix,MarkS) be
[ WsMarkA(QUITact)
if QuitF eq -1 do
[ for I = 0 to NPATS-1 do WsMarkA(PATACT!I) ]
if QuitF eq -2 do
[ LoadDone = false
QuitF = AddToEveryTimeList((Inscnt eq 1 ? RepLDR1, RepLDRn),0)
WriteComment()
]
]
//This procedure initiates "ConstructedTest". Its args are an address
//count and a vector of 1 to 6 LDR addresses. If a single address is
//passed, it is repeatedly executed from the Alto, preceded by generation
//of the selected data pattern. If more than one arg, then the sequence of
//LDR addresses is executed as a test, preceded by generation of the
//data pattern, followed by a compare of the initial data against the
//result read back. BITS-CHECKED should have a left-justified data compare
//mask.
and MicTest(count,AV) = valof
[ STAT1 = count eq 1 ? "Repeating LDR instruction",
"Repeating test sequence of LDR addresses"
STAT2 = ""; STAT3 = -1
Ins5 = AV!5; Ins4 = AV!4; Ins3 = AV!3; Ins2 = AV!2; Ins1 = AV!1; Ins0 = AV!0
Inscnt = count; TestWidth = 36; LeftAdjust(MASK,DMASK,TestWidth)
GetPattern(NREALREGS+NREALMEMS-2); resultis MicTMenu
]
and RepLDR1() be
[ for I = 1 to 100 do
[ XctL36(Ins0,GOODD); NextGDATA()
if TestAborted then ErrorStop("Halted by mouse","")
]
]
and RepLDRn() be
[ for I = 1 to 100 do
[ XctL36(Ins0,GOODD)
test Inscnt ls 3
ifso [ XctR36(Ins1,ACTD) ]
ifnot
[ XctMic(Ins1); test Inscnt ls 4
ifso [ XctR36(Ins2,ACTD) ]
ifnot
[ XctMic(Ins2); test Inscnt ls 5
ifso [ XctR36(Ins3,ACTD) ]
ifnot
[ XctMic(Ins3); test Inscnt ls 6
ifso [ XctR36(Ins4,ACTD) ]
ifnot [ XctMic(Ins4); XctR36(Ins5,ACTD) ]
]
]
]
if CheckData() then ErrorStop("Data compare error","")
]
]
//Check the 36-bit data in ACTD against GOODD using mask DMASK.
//Returns 0 on data ok with COUNT incremented and next data pattern
//in GOODD; returns 1 when a "B" is typed after reading new value for
//BBS; returns 2 on data error or anything other than "B" typed.
and CheckData() = valof
[ for I = 0 to 2 do
[ if ((GOODD!I xor ACTD!I) & DMASK!I) ne 0 then resultis true
]
//ITRCNT is equivalent to LDRMEM+COUNT
DoubleAdd(ITRCNT+3,LongOne)
if TestAborted then ErrorStop("Test halted by mouse","")
NextGDATA(); resultis false
]
and NextGDATA(Temp) be
[ switchon PATTERN into [
case 2:
case 3: [ Temp = GOODD!0 rshift 3
GOODD!0 = (GOODD!0 lshift 1) + (GOODD!1 rshift 15)
GOODD!1 = (GOODD!1 lshift 1) + (GOODD!2 rshift 15)
GOODD!2 = ((GOODD!2 lshift 1) + Temp) & 170000B; return ]
case 4: [ RANDIX = (RANDIX+1)&7
for I = 0 to 2 do
[ RANDATA = RANDATA + table [ 134134B; 054206B; 036711B
103625B; 117253B; 154737B; 041344B; 006712B
134134B; 054206B ] !RANDIX
GOODD!I = RANDATA; RANDIX = RANDIX+1
]
return
]
case 5:
case 7: [ GOODD!0 = not GOODD!0; GOODD!1 = not GOODD!1
GOODD!2 = (not (GOODD!2)) & 170000B; return ]
case 6: [ GOODD!2 = GOODD!2 + 10000B
if GOODD!2 eq 0 then DoubleAdd(GOODD,LongOne)
return ]
]
]
//Subroutine to copy a right-justified value from an 80-bit LDR address
//to a 3-word DataVec. Args are:
// (1) Pointer to 5-word LDR vector
// (2) Pointer to DataVec
// (3) Number of bits to be in DataVec
and LeftAdjust(LDRvec,DVec,Width) be
[ let Bit1 = 0
LDRvec = LDRMEM+LDRvec
Zero(DVec,3)
if Width > 32 do
[ PutField(Bit1,Width-32,DVec,LDRvec!2)
Bit1 = Bit1+Width-32; Width = 32
]
if Width > 16 do
[ PutField(Bit1,Width-16,DVec,LDRvec!3)
Bit1 = Bit1+Width-16; Width = 16
]
PutField(Bit1,Width,DVec,LDRvec!4)
]
//Subroutine to copy a left-justified DataVec of a given size to a
//right-justified 80-bit LDR location. Args are:
// (1) Pointer to 5-word LDR vector
// (2) Pointer to DataVec
// (3) Number of bits in Datavec
and RightAdjust(LDRvec,DVec,Width) be
[ let I,Bit1 = 0,80-Width
LDRvec = LDRMEM+LDRvec
Zero(LDRvec,5)
while Width > 16 do
[ PutField(Bit1,16,LDRvec,DVec!I)
I = I+1; Width = Width-16; Bit1 = Bit1+16
]
PutField(Bit1,Width,LDRvec,(DVec!I) rshift (16-Width))
]
//Display strings STAT1 and STAT2 and if STAT3 ne 177777B the
//integer STAT3 on command line
and WriteComment() be
[ Resets(CmdCommentStream); WssCSS(STAT1);
WssCSS(STAT2)
if STAT3 ne 177777B then Wos(CmdCommentStream,STAT3)
UpdateDisplay()
]