home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
memtest
/
memtest1.lbr
/
MEMTEST1.AQM
/
MEMTEST1.ASM
Wrap
Assembly Source File
|
1985-02-09
|
15KB
|
594 lines
;******************************************************************************
;MEMTEST1.ASM for CP/M-80. Written by Len Moskowitz and released to the
;public domain. October 1984
;
; MEMTEST is a memory test program. It tests memory with
; twelve different patterns of bits. It does each test addressed
; both forwards and backwards through memory.
; The twelve patterns are:
;
; Bit 76543210
; ------------
; Pattern 0. 00000000 (00h, All zeros)
; 1. 00000001 (01h)___
; 2. 00000010 (02h) |
; 3. 00000100 (04h) |
; 4. 00001000 (08h) | "Walking Ones" or
; 5. 00010000 (10h) | "Barber Pole" pattern
; 6. 00100000 (20h) |
; 7. 01000000 (40h) |
; 8. 10000000 (80h)__|
; 9. 01010101 (55h, Even alternating ones)
; 10. 10101010 (AAh, Odd alternating ones)
; 11. 11111111 (FFh, All ones)
;
; Before the test begins, the program tells you where it resides
; so that you can avoid overwriting it. You are then prompted for
; whether you want screen updates and for the first and last addresses
; of the memory block to be tested. Screen updates cause the program
; to run much, much slower than without updates. If you choose updates,
; the screen will show the current address being tested and the pattern
; being used. The program expects the addresses to be in Hex
; (radix 16) format. A control C aborts the program.
; For each pattern, the first memory location is written to and
; then read from. The value read from memory is compared to the test
; pattern. If they are identical, the test proceeds to the next memory
; location. If they are not the same, the address that failed is
; displayed along with the current test pattern and the erroneous value
; that the memory location contained. You are given a choice of
; continuing or quitting.
; When all the locations are tested, the test goes on to the next
; pattern. When all twelve patterns have been tested using forward
; addressing (from low address to high address), the twelve are then
; repeated using backward addressing (high address to low address).
; If the test completes without mishap, a message confirms this and
; the program exits to CP/M (provided you haven't overwritten it with
; the test) via a jump to location 0000.
; I have provided for I/O using either the standard BDOS calls
; or direct console I/O via routines internal to MEMTST. This version
; has the internal routines commented out so that the casual user can
; run it without change. If you wish to make this test able to
; check all memory except for the block where it resides, all console
; I/O should be done using the internal routines. To activate them,
; comment out the BDOS subroutines and remove the comment semicolons
; from the internal subroutines. You also must change the
; "instatusport", "outstatusport", "inreadymask", "outreadymask",
; "indataport", and "outdataport" equates to reflect your system
; requirements.
; If you use the BDOS calls, take pains not to ask MEMTST to test
; the locations where the BDOS and BIOS reside. You can find the
; address of the BDOS by looking at locations 0006 and 0007 for a
; standard CP/M installation. (Location 0005 is the "jump to BDOS" call
; address.) Testing these locations will result in an overwrittten
; operating system and you'll have to reboot to bring the system back up.
; Also be sure not to ask to test the memory where MEMTST resides.
; For 64K of memory, the test takes approximately 75 seconds to
; complete on a 4 megaHertz Z80A system with no wait states with no
; screen updates. With screen updates on, the test takes 20 Hours!
; I therefore recommend you run without screen updates if you're testing
; any block sized over 0200h. If an error occurs, probe that area
; with updates on.
; A shortcoming of any test program of this type is that it can't
; test the worst case memory access timing required for instruction
; fetch operations. If you find you have problems that this program does
; not isolate, try using WORM (of which the current version is WORM21),
; which is available via many RCPM systems. It checks for access
; timing sensitivity but does not do exhaustive pattern testing. Between
; the two programs you're likely to uncover any memory problems you might
; have.
;
; Len Moskowitz
; Fair Lawn, N.J.
; October 1984
;
;11Nov84 Renamed MEMTST10.ASM to MEMTEST1 to avoid confusion
; with MEMTST11.ASM written by J. Kravitz, 08Dec76.
; Ken Stritzel, Flanders, NJ RCPM
;
;******************************************************************************
;
;****************
;***** Equates *
;****************
cpm: equ 0000h ;jump to CP/M address
bdos: equ 0005h ;jump to BDOS address
conout: equ 02h ;BDOS console out function code
conin: equ 01h ;BDOS console in function code
constat: equ 0bh ;BDOS get console status code
tpa: equ 0100h ;CP/M programs start at this address
cr: equ 0dh ;ASCII carriage return
lf: equ 0ah ;ASCII line feed
controlc: equ 03h ;ASCII control C
del: equ 7fh ;ASCII delete
no: equ 0
yes equ 0ffh
; Change the following equates to match your system if you are using the
; internal I/O subroutines. If you are using the CP/M BDOS calls you may
; leave these as is.
outdataport: equ 0
indataport: equ 0
outstatusport: equ 1
instatusport: equ 1
outreadymask: equ 01
inreadymask: equ 02
memtst: org tpa
; Tell him where this program resides so he can avoid it during the test.
lxi sp,stacktop
lxi h,offlimits
call print
lxi h,repeat
mov c,h
call unpack
mov c,l
call unpack
lxi h,andmessage
call print
lxi h,endprogram
mov c,h
call unpack
mov c,l
call unpack
mvi a,'.'
call sout
; Ask him if he wants the screen updated continuously, and store his
; answer in "screenupdate".
lxi h,screenupdateQ
call print
call sin
cpi 'Y'
jz setupdateyes
cpi 'y'
jz setupdateyes
cpi cr
jz setupdateyes
setupdateno: mvi a,no
sta screenupdate
jmp locationprompt
setupdateyes: mvi a,yes
sta screenupdate
; This section does initialization and gets the starting and ending
; locations from the fellow at the keyboard.
locationprompt: lxi h,enterfirst
call print
call loca
shld startloc
lxi h,enterlast
call print
call loca
call crlf
mov e,l
mov d,h
inx d
mvi a,0
lxi h,step
mov m,a
inx h
mov m,a
lhld startloc
mov c,a
mov b,a
; This is the core of the memory test routine. The section from
; "repeat" to "doit" does the screen update if requested.
repeat: lda screenupdate
cpi no
jz doit
push b
push h
lxi h,currentaddress
call print
pop h
push h
mov c,h
call unpack
mov c,l
call unpack
lxi h,currentpattern
call print
pop h
pop b
push b
push h
mov c,b
call unpack
mvi a,cr
call sout
pop h
pop b
; The next four lines do the memory test
doit: mov m,b ;move the pattern to memory
mov a,m ;move it back to A
cmp b ;compare it back to the pattern
jnz error ;jump if they don't match
; Check if he wants to exit and get the next test location ready.
reenter: call consolestatus ;check if he pressed a key
jz nocontrolc ;if not jump around the next few lines
call sin ;if he did, take the character in
;SIN exits if it was control C
nocontrolc: lda step ;check the "backward" flag
ani 80h ;if it's set
jnz backwards ; jump around the forward code
inx h ;we're going forward so increment HL
jmp compareend ; and jump around the backward code
backwards: dcx h ;we're going backward so decrement HL
; This section checks the next address to be tested with the end
; location. If we haven't hit the end location yet, we loop to repeat.
; If we have hit it we fall through.
compareend: mov a,l
cmp e
jnz repeat
mov a,h
cmp d
jnz repeat
; See if we've completed the last pattern. If we have, then jump
; to "checkforback" to see if we've done the backward addressing yet.
; If this is not the last pattern, go onto the next one by incrementing
; the step counter in register C and STEP (which holds the step and the
; "backward" flag.
checkstep: mvi a,0bh
cmp c
jz checkforback
inr c
lda screenupdate
cpi no
jz noupdate
call crlf
noupdate: lxi h,step
mvi a,80h
ana m
jz backflagnotset
mvi a,80h
ora c
mov m,a
jmp setnewpattern
backflagnotset: mov m,c
; Check what step we're going to do and set the new pattern accordingly.
setnewpattern: mvi a,1
cmp c
jnz not1
mvi b,1
jmp loadpattern
not1: mvi a,9h
cmp c
jnz not9
mvi b,0aah
jmp loadpattern
not9: jnc lessthan9
mvi a,0ah
cmp c
jnz not10mustbe11
mvi b,55h
jmp loadpattern
not10mustbe11: mvi b,0ffh
jmp loadpattern
lessthan9: mov a,b
rlc
mov b,a
loadpattern: lxi h,pattern
mov m,b
lhld startloc
jmp repeat
; We get to this next section when we've completed the last pattern. If
; the "backward" flag (bit 7 of STEP) is not set, it sets it, swaps the
; starting and ending locations and starts the background addressing
; cycle. If the flag was set, we're done so we exit via ENDOK
checkforback: lda screenupdate
cpi no
jz updateno
call crlf
updateno: lda step
ani 80h
jnz endok
mvi a,80h
sta step
lxi h,startloc
mov e,m
inx h
mov d,m
dcx d
lhld endloc
shld startloc
mvi a,0
mov c,a
mov b,a
jmp repeat
; ENDOK prints the message "OK" and exits to CP/M.
endok: call crlf
mvi a,'O'
call sout
mvi a,'K'
call sout
jmp cpm
; ERROR prints the address of the memory cell that read back erroneous
; data, the expected pattern and the bad data. It then offers you
; the choice of continuing or exiting to CP/M.
error: call crlf
mov d,a
push psw
push b
push d
push h
lxi h,errorat
call print
pop h
push h
mov c,h
call unpack
mov c,l
call unpack
lxi h,patternis
call print
mov c,b
call unpack
lxi h,memoryvalue
call print
mov c,d
call unpack
call crlf
lxi h,continueQ
call print
call sin
cpi 'Y'
jz setuptorepeat
cpi 'y'
jz setuptorepeat
cpi cr
jz setuptorepeat
jmp cpm
setuptorepeat: mvi a,cr
call sout
pop h
pop d
pop b
pop psw
jmp reenter
;****************
;***** MESSAGES *
;****************
;
errorat: db ' *** Error at location : ',0
patternis: db ' Pattern is : ',0
memoryvalue: db ' Memory value is : ',0
continueQ db 'Continue? (Y/N) : ',0
enterfirst: db cr,lf,'Enter first address : ',0
enterlast: db cr,lf,'Enter last address : ',0
currentaddress: db 'Current address : ',0
currentpattern: db ' Current pattern : ',0
screenupdateQ: db cr,lf,'Screen updates? (Runs much slower with updates'
db ') (Y/N) : ',0
offlimits: db cr,lf,'The core of this program resides between ',0
andmessage: db ' and ',0
;*******************
;***** SUBROUTINES *
;*******************
; CONSOLESTATUS checks to see if a key was pressed. If a key was
; pressed, the A register will contain 0FFh. Otherwise it will have
; 00h.
; ***** BDOS I/O routine
consolestatus: push b
push d
push h
mvi c,constat
call bdos
ora a
pop h
pop d
pop b
ret
; ***** Internal I/O routine
;
;consolestatus: in instatusport
; ani inreadymask
; jz notready
; mvi a,0ffh
; ret
; notready:mvi a,0
; ret
;
;
; CRLF prints a carriage return and a line feed. Preserves all
; registers.
crlf: push psw
xra a
adi cr
call sout
adi lf
call sout
pop psw
ret
; HXTOASCI converts the lower nibble of the value in the A register
; into an ASCII numeric or alphabetic character. It expects the most
; significant nibble to be zeroed.
hxtoasci: cpi 0ah
jc numeric
sui 9
adi 40h
ret
numeric:adi 30h
ret
; PRINT prints the string pointed to by registers HL until a zero
; (0h) is encountered.
;
print: mov a,m
cpi 0
rz
print1: call sout
inx h
mov a,m
cpi 0
jnz print1
ret
; SIN gets one character from the console and echoes it back to the
; console. Character ends up in register A.
;
; ***** BDOS I/O version
sin: push b
push d
push h
mvi c,conin
call bdos
cpi controlc
jz cpm
pop h
pop d
pop b
ret
; ***** Internal I/O version
;sin: in instatusport
; ani inreadymask
; jz sin
; in indataport
; cpi controlc
; jz cpm
; push psw
; call sout
; pop psw
; ret
; SOUT outputs whatever is the A register to the console. Returns with
; register A cleared to zero.
;
; ***** BDOS I/O version
sout: push b
push d
push h
mov e,a
mvi c,conout
call bdos
pop h
pop d
pop b
xra a
ret
; ***** Internal I/O version
;sout: push psw
; sout1: in outstatusport
; ani outreadymask
; jz sout1
; pop psw
; out outdataport
; xra a
; ret
; UNPACK takes what ever is in register C (which is supposed to be
; an address or memory pattern), unpacks it into two hex digits,
; converts them to ASCII and outputs them to the console. Modifies
; A register only.
unpack: mov a,c
ani 0f0h
rrc
rrc
rrc
rrc
call hxtoasci
call sout
mov a,c
ani 0fh
call hxtoasci
call sout
ret
;***************
;***** STORAGE *
;***************
; Storage goes here. The subroutines after this section can be written
; over by MEMTST if you want to test those locations. They are only
; used in the initialization section at the top of the program.
screenupdate ds 1
endloc: ds 2
startloc: ds 2
step: ds 1
pattern: ds 1
stack: ds 32
stacktop: equ $
endprogram: equ $
; LOCA takes four ASCII characters in from the console (expecting them
; to be 0-9 or A-F), converts them to hex, packs them into two bytes,
; and stores them in "endloc" and registers HL.
loca: call sin
call pack
mov h,c
call sin
call pack
mov l,c
shld endloc
ret
; PACK expects an ASCII character in register A. If it's an alphabetic
; character (A-F) it converts it to a hex digit in the range of A hex
; to F hex. If it is a number it just strips off the most significant
; nibble leaving a hex digit in the range from 0 to 9.
pack: cpi 41h
jc label8
adi 09h
label8: ani 0fh
add a
add a
add a
add a
mov c,a
call sin
cpi del
jnz norubout
adi ' '
call sout
call sin
jmp pack
norubout: cpi 41h
jc label9
adi 09h
label9: ani 0fh
add c
mov c,a
ret