; ;Jim Eccleston July 19 1980 ; ;Allen Mar August 8, 1980 - added 'label + offset' ; so COM file can be generated without DDT.COM ; Thanks to Bill Precht and Ward Christensen ; who used it in his 'PMMIBYE2' remote CP/M ; program... ; ; ;********************************************************************** ;* * ;* W O R M T E S T * ;* * ;* A serious flaw exists in most memory test routines when * ;* applied to Z-80 systems. A board can be tested for hours * ;* and never drop a bit, then when it's loaded with a program * ;* fail instantly. The problem is that access timing on a * ;* Z-80 instruction fetch (the M-1 cycle) is significantly * ;* more critical than on a simple read cycle. No matter how * ;* fancy a normal memory test gets, it never makes demands * ;* on memory speed that an actual program does. The only way * ;* to check this memory for full speed operation is to * ;* actually run a program in it. Wormtest does just that. ;* vide The M-1 Worm. P.C. July 73 * ;* * ;********************************************************************** ; ; The first few lines relocate the program down to low memory ; ; There are two parts to the test program. The larger ; portion consists of service routines, but the Worm ; itself consists of a short 12 byte routine that ; upon initialization breaks away from the main body ; and crawls up through memory space giving a running ; travelogue as he goes. If he stops talking, you know ; something bad happened, and where. ; The Worm acts as the main program loop. It manipulates ; two test bytes and calls two subroutines. One of the ; subroutines reports the location of the worm and detects ; and reports any errors in the test bytes. The other sub- ; routine shifts the Worm up in memory one location and ; adjusts the return to begin execution for another loop. ; There are seven instruction fetches per loop, with the ; data manipulation instructions in complementary pairs ; to ensure full speed testing on both ones and zeroes. ; The instruction RST 7 is embedded in the Worm in non- ; executable locations as traps in case a memory error ; causes the program counter to get out of sync. The Worm ; leaves behind a slime-trail of FF's as it travels. Any ; execution of a trap is reported and the trap subroutine ; attempts to return execution back to the worm. ; The error reports indicate which data byte was bad and ; what the erroneous value was.A "D" indicates that bits ; were dropped, while a "P" indicates that bits were ; picked. A trap error is flagged by a "T" followed by ; the address. Upon execution the Worm will immediately ; start reporting its location (by address) ; Bad memory will trash the program or else trigger the ; error repots. No memory looks like a string of FF's ; and a sequential string of traps will be reported. ; When ROM is hit, execution of the ROM program will begin, ; so if you have the Morrows Disk Controller you will know ; your memory is ok when the system re-boots. ; ; ; (The following in is no longer true with this version) ; You may find you need to use DDT to produce the .COM file ; because of the ORG at 0008H ; ; org 0100h ; ; Move routine relocates WORM program down to 08H ; start lxi d,dest ;Destination address lxi h,source ;Source address mvi b,pend-source+1 ;Number of bytes to move loop mov a,m ;Get byte stax d ;Put byte inx h ;Bump up source adr. inx d ;Bump up destination adr. dcr b ;Decrease byte count jnz loop ;Do again if not zero count lxi sp,stack ;Set up stack pointer lxi b,data ;Set up data pointer ; ;No, these are not the Pointer sisters jmp worm ; dest equ 08h ;destination ; source equ $ offset equ dest-source ;reloc amount ; ; org 08h ;Start of relocated code dw 0ffffh dw 0ffffh dw 0ffffh dw 0ffffh ;Rst 7s ; ; movwrm equ $+offset pop h ;Get address of worm + 1 mov d,h ;Duplicate address in d mov e,l ;and e regs. dcx d ;Set DE to last address of worm mvi b,0ch ;Set length of worm getwrm equ $+offset ldax d ;;Get byte of worm mov m,a ;Move it up one location dcx d ;Adjust pointers dcx h dcr b mov a,b cpi 00 jnz getwrm lxi b,data ;Restore data pointer inx h ;HL to start of worm inx h pchl ;Return to worm rst 7 ;RST 7 ; ; rptadr equ $+offset cpi 0ffh ;Check for dropped bit error jnz errdrp mov a,b cpi 00h ;Check for picked bit error jnz errpik jmp rptad2 ;Show the address rst 7 rst 7 ;Trap ; ; trap equ $+offset mvi a,54h ;Print a "T" call output mvi a,20h ;Print a " " call output pop h ;Recover address dcx h ;Adjust address call adout ;Print the address inx h ;Adjust address pchl ;Return ; ; rptad2 equ $+offset pop h ;Recover address ; ; NOP THIS IF YOU HAVE A SLOW TERMINAL ; call adout ;Print address ; ; UNLESS YOU REALLY LIKE SEEING THAT ADDRESS !! ; inx h ;Adjust return address inx h inx h pchl ;Return ; ; errdrp equ $+offset mvi b,44h ;Show it's dropped bit(s) jmp errprt ;Print error message ; ; errpik equ $+offset mvi b,50h ;Show it's picked bit(s) ; ; errprt equ $+offset mov c,a ;Save error data mvi a,2ah ;Print "*" call output mvi a,20h ;Print " " call output mov a,b ;Print type of error call output mvi a,20h ;Print " " call output mov a,c ;Get error data call bowcl ;Print and end line jmp rptad2 ;Now try for address and return ; ; adout equ $+offset push h ;Save address mov a,h call bytout ;Its nybble time mov a,l call bowcl ;Same with cr/lf pop h ;Restore address ret ; ; bytout equ $+offset push psw ;Save A rrc ;Shift nybble rrc rrc rrc call nybout ;Nybble out 1 pop psw ;Restore A call nybout ;Nybble out 2 ret ; ; bowcl equ $+offset call bytout mvi a,0Dh ;C/R time call output mvi a,0Ah ;LF time call output ret ; ; nybout equ $+offset ani 0fh ;Strip high nibble cpi 0ah ;Divide alpha v numeric jm isnum ;If numeric adi 07h ;Add alpha offset isnum equ $+offset adi 30h ;Add numeric offset call output ret ; ; ************************************************ ; * * ; * Insert Your DIRECT Console Output Call Here * ; * * ; * * ; * unless you want to use cp/m calls till crash * ; ************************************************ ; output equ $+offset push b ;save bc push psw lp equ $+offset in 72h ani 02h jz lp pop psw out 73h pop b ret ; ; data equ $+offset db 00 ; ; ds 20 stack equ $+offset-1 ; ; worm equ $+offset rst 7 ;Trap ldax b ;Move data to A; start of worm push psw ;Push test data onto stack mvi a,0ffh ;Move second test byte to A pop b ;Pop first test byte into B rst 5 ;call "rptadr" rst 7 ;Trap rst 7 rst 7 nop ;"rptadr" return location rst 2 ;call "movwrm" ; pend equ $ ;program end ; end 0100h