; WORM.ASM ver 2.1 (revised 10/9/81) ; ;Jim Eccleston July 19 1980 - program originally written ; ;Keith Petersen, W8SDZ, October 9, 1981 - fixed bug which ; caused program to print one trap error at start. ; Added REPORT conditional assembly so addresses ; won't be reported unless there is an error. ; Added equates for console ports. ; ;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 sub- ;routines. One of the subroutines reports the location of the ;worm and detects and reports any errors in the test bytes. The ;other subroutine 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 reports. 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. ; stport equ 20h ;console status port txrdy equ 04h ;console putput mask daport equ 21h ;console data port ; report equ 0 ;<--make non-zero for address reporting ; 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 jmp worm+1 ; dest equ 08h ;destination ; source equ $ offset equ dest-source ;reloc amount ; stwrm equ $+offset ;Start of relocated code (08h) 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 ; if report call adout ;Print address endif ; if not report nop ! nop ! nop ;Don't print address endif ; 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 ;save character ; lp equ $+offset in stport ;get console status ani txrdy ;ready for character? jz lp ;no, loop and wait pop psw ;get character out daport ;output to console pop b ;restore bc 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