;MEMR           SEP 3, 1979
       Page 0
VERS    EQU     19      ;X.X
;
;
;Diss-assembly of Delta Products memory test program
;Written by D. Rasmussen January 1, 1979
;
;Extensively re-written and new tests added by Larry Alkoff
;
;Additional changes by Bill Bolton
;
;********************************************
;       FIX LIST BY WFB
;********************************************
;15/JULY/81     V19-OPTIONAL CONOUT VIA BDOS/BIOS
;                   AND NEW COMMAND LINE ARGUMENT
;                   TEST, COMMENT TEXT UPDATED
;14/JULY/81     V18-CONOUT VIA BDOS
;14/JULY/81     V17-MESSAGES CORRECTED
;
;********************************************
;       FIX LIST by LBA
;********************************************
;9/3    V16-MISC CLEANUP
;6/11   V15-BUGF ANI 7FH IN HEATH CRTIN
;5/25   V14-MSGS, RANGE LIMITS, FIX S.B. TEST
;5/19   V13-CONDX FOR MONITOR I/O
;5/18   V12-IMPROVE WALKING BIT AND CHECKERBOARD TEST
;5/15   V11-BUGF CONO PRESERVE REGS
;       AND DEFAULT END ADDR (DEFEND) NOW JUST BELOW BIOS
;5/13/79 V0-OBJECT CODE AND SOURCE LISTING
;       GIVEN TO LA BY HEAD OF DELTA PRODUCTS
;       AT SAN FRANCISCO COMPUTER FAIR.
;
;********************************************
;       INFORMATION ABOUT THIS TEST
;********************************************
;
;       This memory test will use default address
;if starting and ending address questions
;are answered with a "CR".
;Memory test can be terminated by a "SP".
;
;Command line arguments are accepted as follows -
;       '-' start of argument string
;       'B' console output via BDOS (for spooling or printing)
;       'R' random number test only
;
;The arguments may be given separately or together,
;i.e. -B, -R, -BR, -RB, or even -B -R
;The default upper test boundary address is modifed
;to the bottom of the BDOS if the B option is given.
;
;       This test is designed to display the most common
;problems first and most uncommon ones last.
;The test never finishes by itself.
;The operator may terminate by pressing the
;space bar at any time.
;Generally memory chip failures will be found within 5 seconds.
;The test takes about 3 minutes to run all
;phases in a 32k board.
;       To completely test for all address open and short
;combinations, the test should be run over a 4K boundry.
;Then run the test over the full range. There are some
;subtle things that get missed if you only run the
;test over the full range and not 4K at a time.
;       The test falls into a random numbers test at the end
;of the first phase and will stay there until
;a space bar is pressed.
;If the memory board passes these tests and will
;run for an hour on the random numbers test
;without a problem, look elsewhere for your troubles.
;
;
;The following tests are performed:
;
;FAST COMPLEMENT:
;This is a test of ALL MEMORY starting at 0
;and testing to memtop (except its own loop).
;Pick up each byte, complement and try to store.
;Quickly test if properly complemented
;and restore original byte.
;
;STUCK BIT:
;1. Fills test area with 0FFH and checks for 0FFH.
;2. Then fills test area with 0's and tests for 0's.
;3. Then re-fills with 0FFH and tests
;   just in case the bit was originally high in (1.).
;
;ADJACENT BIT SHORTED:
;Sets a single bit in all bytes high.
;This checks if a bit is shorted to the
;ones on each side.
;The test repeats 8 times, rotating
;the test bit from LSB to MSB.
;
;CHECKERBOARD:
;Fill memory with 0AAH, 55H pattern and check.
;This forms an alternating "checkerboard".
;Then reverse the pattern and re-check.
;
;WALKING BIT TEST:
;Fill memory with one bit set for each byte.
;The bit rotates at memory increases.
;For example, byte 1 has bit 1 set, byte 2 bit 2 etc.
;Then memory is checked for the proper pattern.
;This is repeated 8 times, rotating the bit each time.
;Then, the whole procedure is repeated rotating
;the opposite way.
;
;ADDRESS SHORTED:
;Fills all memory with 55H then writes an 0AAH
;at 0 (or the lowest memory tested).
;It then tests the rest of memory for 55H's.
;Then it clears location of the 0AAH and
;writes it into location 1.
;Then does same with location 2,4,8,etc setting
;a new address bit high each time and testing all of memory.
;If any address bit is shorted to another,
;the test will find an 0AAH in another location
;than the place it wrote one.
;This test takes the most time and is run last.
;
;RANDOM NUMBERS:
;A random number routine generates an 8 bit number
;pattern and writes it through all test memory.
;It then re-inserts the same seed to the routine
;and test reads the memory. A new seed is generated
;and the exercise is repeated with a new pattern.
;This goes on and on reporting each loop through
;until terminated with the space bar.
;
;
;********************************************
;       SWITCHES
;********************************************
;
TRUE    EQU     0FFFFH
FALSE   EQU     NOT TRUE
;
NOCHEK  EQU     FALSE           ;NO RANGE CHECKING
HEATH   EQU     FALSE
CRAM    EQU     4200H AND HEATH ;CP/M RAM BASE (0=STANDARD)
;
;       PICK ONE I/O ROUTINE
;
CPMIO   EQU     TRUE            ;I/O VIA CP/M, WARM BOOT EXIT
LAPIO   EQU     FALSE           ;I/O VIA LAPPLE
H84CRT  EQU     FALSE           ;HEATH ROUTINE
;
;********************************************
;       EQUATES
;********************************************
;
DEFST   EQU     500H            ;DEFAULT STARTING ADDR (INCLUSIVE)
DEFEND  EQU     0F5FFH          ;DEFAULT ENDING ADDR (INCLUSIVE)
TPA     EQU     CRAM+100H
STACK   EQU     CRAM+100H       ;STACK
RETRYS  EQU     18              ;# OF RETRYS
ENDADD  EQU     STACK-2         ;ENDING ADDRESS
MEM     EQU     STACK-4         ;STARTING ADDRESS
MEMTOPL EQU     STACK-6         ;STORE TOP OF MEMORY
COUNT   EQU     STACK-7         ;STORAGE FOR RETRY COUNT
TESTBYTE EQU    STACK-8         ;STORAGE
TBUF    EQU     CRAM+82H        ;OR STACK-9 IF NOT CP/M TBUFF
SEED    EQU     STACK-11
SEEDST  EQU     STACK-13
TEMP    EQU     STACK-15
WBOOT   EQU     CRAM+0          ;WARM BOOT ENTRY
BDOS    EQU     CRAM+5          ;BDOS ENTRY
CR      EQU     0DH
LF      EQU     0AH
BD$OFF  EQU     -7              ;OFFSET TO BELOW BDOS
BI$OFF  EQU     -4              ;OFFSET TO BELOW BIOS
;
;********************************************
;       START OF PROGRAM
;********************************************
;
       ORG     TPA
;
START:  JMP     START2
;
JEXIT:  JMP     MONIT
JCONI:  JMP     CONIN           ;JUMPS MAY BE PATCHED
JCONS:  JMP     CONST
JCONO:  JMP     CONOUT
;
;********************************************
;       MAIN LOOP
;********************************************
;
START2:
       LXI     SP,STACK-16
       CALL    INIT
       MVI     A,RETRYS        ;SET RETRY COUNT
       STA     COUNT
       LXI     D,SIG   ;SIGN ON
       CALL    PMSG    ;PRINT IT
       CALL    CRLF
       CALL    CRLF
       LDA     BDOS$FLAG
       ORA     A               ;BIOS OUTPUT
       JNZ     BDOS$1          ;NO
       LXI     D,BIOSMSG
       CALL    PMSG
       LXI     D,LOCMSG
       CALL    PMSG
       LHLD    WBOOT+1 ;GET LOCATION OF BIOS ENTRY
       LXI     D,BI$OFF+1 ;OFFSET TO START OF BIOS
       DAD     D
       MVI     L,0
       JMP     GO$ON$1
;
BDOS$1:
       LXI     D,BDOSMSG
       CALL    PMSG
       LXI     D,LOCMSG
       CALL    PMSG
       LHLD    BDOS+1  ;GET LOCATION OF BDOS ENTRY
       LXI     D,BD$OFF+1 ;OFFSET TO START OF BDOS
       DAD     D
       MVI     L,0
GO$ON$1:
       CALL    PHL     ;PRINT LOCATION OF BIOS
       LXI     D,MEMSG
       CALL    PMSG
       CALL    MEMTOP  ;FIND TOP OF MEMORY
       SHLD    MEMTOPL ;AND SAVE
       CALL    PHL     ;AND PRINT IT
       LXI     D,SPMSG
       CALL    PMSG
       LXI     D,XPMSG ;EXPLAIN
       CALL    PMSG
       LDA     BDOS$FLAG
       ORA     A       ;BIOS OUTPUT?
       JNZ     BDOS$4  ;NO
       LXI     D,BIOSMSG
       JMP     GO$ON$4
;
BDOS$4:
       LXI     D,BDOSMSG
GO$ON$4:
       CALL    PMSG
       CALL    CRLF
       LXI     D,SMSG  ;STARTING ADDR MSG
       CALL    PMSG    ;PRINT IT
LOWER0:                 ;GET STARTING ADDRESS
       CALL    GETADD  ;INPUT ADDR FROM CONIN
       JNC     LOWER2  ;NC MEANS ADDR ENTERED
       LXI     H,LASTB ;CY=CR GIVES DEFAULT
       PUSH    H
       CALL    PHL     ;PRINT DEFAULT ADDR
       POP     H
LOWER2:
       IF HEATH OR NOCHEK
       SHLD MEM ! JMP UPPER0   ;NO CHECKING
       ENDIF
       XCHG            ;ST ADDR TO DE
       LXI     H,LASTB ;TOP OF THIS PROGRAM
       CALL    HILO    ;MUST BE BELOW
       XCHG            ;STARTING ADDR
       SHLD    MEM     ;SAVE STARTING ADDR
       JNC     UPPER0  ;LOWER ADDR IS OK, GET UPPER
       LXI     D,LOWMSG
       CALL    PMSG    ;SAY TOO LOW
       LXI     H,LASTB
       CALL    PHL     ;SAY LOWEST OK ADDR
       JMP     LOWER0
UPPER0:                 ;GET ENDING ADDR
       LXI     D,EMSG  ;ENDING ADDR MSG
       CALL    PMSG
       CALL    GETADD  ;GET ENDING ADDR FROM KEYBOARD
       JNC     UPPER2  ;NC MEANS ADDR ENTERED
       LDA     BDOS$FLAG
       ORA     A       ;BIOS OUTPUT ?
       JNZ     BDOS$2  ;NO
       LHLD    WBOOT+1
       LXI     D,BI$OFF ;ESTABLISH DEFAULT ADDRESS
       JMP     GO$ON$2
;
BDOS$2:
       LHLD    BDOS+1  ;CY=CR MEANS DEFAULT
       LXI     D,BD$OFF ;ESTABLISH DEFAULT END ADDR
GO$ON$2:
       DAD     D       ;JUST BELOW BIOS OR BDOS
       PUSH    H
       CALL    PHL     ;PRINT DEFAULT ADDR
       POP     H
UPPER2:
       XCHG            ;END ADDR TO DE
       IF HEATH OR NOCHEK
       JMP     UPPERX  ;NO CHECKING
       ENDIF
       LHLD    MEM     ;GET START ADDR
       INX     H
       CALL    HILO    ;ERROR,END ADDR MUST
       JNC     UPPERX  ;BE ABOVE START ADDR
       LXI     D,UPPMSG
       CALL    PMSG
       JMP     UPPER0  ;TRY AGAIN
;
UPPERX:
       XCHG            ;END ADDR
       SHLD    ENDADD  ;SAVE ENDING ADDR
       SHLD    SEED    ;USE AS SEED ALSO
       LXI     D,CTUMSG        ;CONTINUE?
       CALL    PMSG
WAIT:
       CALL    CSTAT   ;WAIT FOR RESPONSE
       ORA     A
       JZ      WAIT
RESTART:
       CALL    CSTAT   ;SEE IF ABORT
       CALL    CRLF
       LDA     RAND$FLAG
       ORA     A       ;DO RANDOM TEST ONLY ?
       JNZ     RTEST   ;YES, GO DO RANDOM NUMBERS
;
;********************************************
;       DO FAST COMPLEMENT TEST - ALL MEMORY
;********************************************
;
       LXI     D,FCTST
       CALL    PMSG    ;PRINT FAST COMP TEST
       IF NOT HEATH
       LXI     H,0     ;START AT 0
       ENDIF
       IF HEATH
       LXI     H,2000H
       ENDIF
       LXI D,FCTEST-1  ;AND STOP AT LOOP
       CALL    FCTEST  ;DO TEST
       LHLD    MEMTOPL ;NOW TEST
       XCHG            ;TO MEMTOP
       LXI     H,FCLPX ;STARTING HERE
       CALL    FCTEST
;
;********************************************
;       DO BIT STUCK TEST
;********************************************
       LXI     D,BSTST
       CALL    PMSG    ;PRINT TEST
       MVI     B,0FFH  ;FF TEST START
       CALL    TESTW   ;WRITE TEST BYTE
       CALL    TESTR   ;CHECK TEST BYTE
       MVI     B,0     ;ZEROS TEST
       CALL    TESTW   ;WRITE TEST BYTE 0
       CALL    TESTR   ;TEST
       MVI     B,0FFH  ;BACK HI TEST
       CALL    TESTW   ;WRITE TEST BYTE 0FFH
       CALL    TESTR   ;TEST
;
;********************************************
;       DO SHORTED BIT TEST
;********************************************
       LXI     D,SBTST
       CALL    PMSG    ;PRINT BIT SHORT TEST
       MVI     A,1     ;ROTATE BIT TEST
LOOP2:  MOV     B,A     ;MAKE TEST BYTE
       CALL    ROTTST  ;DO TEST
       JNC     LOOP2   ;DONE WITH 8 BITS?
;
;********************************************
;       DO CHECKERBOARD TEST
;********************************************
       LXI     D,CBTST
       CALL    PMSG    ;PRINT CHECKBOARD TEST
       MVI     B,55H
       CALL    CBTEST
       MVI     B,0AAH
       CALL    CBTEST
;
;********************************************
;       DO WALKING BIT TEST
;********************************************
       LXI     D,WBLTST
       CALL    PMSG    ;PRINT WALKING BIT LEFT
       MVI     B,80H
WALL:   CALL    WALKL   ;DO TEST, SAVES B
       MOV     A,B
       RLC             ;NEXT SEED BIT
       MOV     B,A
       CPI     80H     ;DONE IF
       JNZ     WALL
       LXI     D,WBRTST
       CALL    PMSG    ;PRINT WALKING BIT RIGHT
       MVI     B,1
WALR:   CALL    WALKR   ;DO TEST, SAVES B
       MOV     A,B
       RRC             ;NEXT SEED BIT
       MOV     B,A
       CPI     1       ;DONE IF
       JNZ     WALR
;
;********************************************
;       DO ADDRESS LINE TEST
;********************************************
       LXI     D,ALTST
       CALL    PMSG    ;PRINT ADDR LINE TEST
       MVI     B,055H  ;TEST BYTE
       CALL    ADTEST  ;TEST
       MVI     B,0AAH  ;TEST BYTE
       CALL    ADTEST  ;TEST
;
;********************************************
;       DO RANDOM NUMBER TEST
;********************************************
RTEST:  LXI     D,RNTST
       CALL    PMSG
       MVI     C,'1'
RANDLP: PUSH    B
       CALL    RNDW    ;DO RANDOM # TEST
       CALL    SPACE
       POP     B
       CALL    CONO
       INR     C
       MVI     A,'9'
       CMP     C
       JNZ     RANDLP  ;CONTINUE RANDOM NR TEST
;
       LXI     D,MSGOK ;POINT AT TEST COMPLETE MSG
       CALL    PMSG
       JMP     RESTART ;START TEST AGAIN WITH OLD PARAMETERS
;
;********************************************
;       FINISHED WITH MAIN LOOP
;********************************************
;
ERROR:                  ;PRINT ERROR LOCATIONS
       PUSH    B
       PUSH    D
       PUSH    H
       PUSH    PSW     ;SAVE ALL REGS
       CALL    CRLF
       LXI     D,MSG1
       LDA     COUNT
       CPI     RETRYS
       CZ      PMSG    ;PRINT LABELS
       CALL    PHL     ;PRINT HL REG
       MOV     D,B     ;GET SHOULD BE DATA
       CALL    CNVT    ;PRINT HEX
       MOV     A,B
       CALL    CNVTB
       POP     PSW
       PUSH    PSW
       MOV     D,A     ;GET WAS DATA
       CALL    CNVT    ;PRINT HEX
       POP     PSW
       CALL    CNVTB
       LDA     COUNT   ;GET ERROR COUNT
       DCR     A       ;ONE LESS
       STA     COUNT   ;PUT BACK COUNT
       JNZ     MORET
       LXI     D,CTUMSG
       CALL    PMSG
       CALL    GETADD  ;SEE IF STOP OR CONTINUE
       MVI     A,RETRYS
       STA     COUNT   ;RESET COUNT
MORET:  POP     H       ;GET ALL REGS BACK
       POP     D       ;AND CONTINUE TEST
       POP     B
       RET
;
PHL:                    ;PRINT HL REGISTER
       MOV     D,H
       CALL    CNVT    ;MAKE ADDR OF ERROR ASCII
       MOV     D,L
       CALL    CNVT
       CALL    TAB
       RET
;
PMSG:           ;PRINT STRING POINTED BY DE
       CALL    CSTAT   ;POSS ABORT AT EVERY PMSG
PMSGLP: LDAX    D       ;GET BYTE TO PRINT
       ORA     A       ;END OF TEXT?
       RZ
       MOV     C,A     ;CONVENTION
       CALL    CONO    ;GOTO OUTPUT
       INX     D
       JMP     PMSGLP
;
FCTEST:                 ;COMPLEMENT BYTE AND RESTORE
       MOV A,M ! CMA
       MOV     M,A     ;VERY FAST CHANGE
       MOV     B,A     ;SAVE COMPLEMENTED BYTE
       MOV     C,M     ;SEE WHAT GOT STORED
       MOV A,B ! CMA   ;ORIG BYTE
       MOV     M,A     ;ALWAYS RESTORED
FCLPX:  MOV A,C ! CMP B ;DID IT COMPLEMENT?
       CNZ     ERROR
       INX H ! CALL HILO
       JNC     FCTEST  ;DO MORE
       RET             ;DONE
;
LOAD:                   ;GET ADDRESSES TO TEST
       CALL    CSTAT   ;POSS ABORT AT EVERY LOAD
       LHLD    ENDADD  ;GET ENDING ADDR
       XCHG            ;INTO DE
       LHLD    MEM     ;GET STARTING ADDR
       RET
;
TESTW:                  ;FILL MEMORY WITH TEST BYTE
       CALL    LOAD
WLOOP:  MOV     M,B     ;PUT TEST BYTE IN MEMORY
       INX H ! CALL HILO
       JNC     WLOOP
       RET
;
TESTR:          ;READ AND COMPARE MEMORY TO TEST BYTE
       LHLD    MEM
TESTADR:
       XCHG
       LHLD    ENDADD  ;GET STARTING ADDR
       XCHG
RLOOP:  MOV A,M ! CMP B ;CHECK BYTE
       CNZ     ERROR
       INX H ! CALL HILO
       JNC     RLOOP
       RET
;
CBTEST:                 ;CHECKERBOARD TEST
       CALL    LOAD
CBWLP:  MOV     M,B     ;B HAS TEST BYTE
       INX H ! CALL HILO
       JC      CBR     ;TIME TO READ
       MOV A,B ! CMA   ;55H BECOMES 0AAH
       MOV     M,A     ;STORE COMPLEMENT
       INX H ! CALL HILO
       JNC     CBWLP
CBR:                    ;READ AND TEST CHECKERBOARD
       CALL    LOAD
CBRLP:  MOV A,M ! CMP B ;CHECK BYTE
       CNZ     ERROR
       INX H ! CALL HILO
       RC              ;DONE
       MOV A,B ! CMA ! MOV B,A
       MOV A,M ! CMP B ;CHECK BYTE
       CNZ     ERROR
       MOV A,B ! CMA ! MOV B,A
       INX H ! CALL HILO
       JNC     CBRLP
       RET
;
CSTAT:          ;CONSOLE ABORT (SAVES ALL REGS)
       PUSH H ! PUSH D ! PUSH B
       CALL    JCONS   ;SEE IF KEY STRUCK
       ORA     A       ;SET FLAGS
       JZ      NOKEY
       CALL    JCONI   ;GET KEY
       CPI     ' '     ;EXIT IF SPACE
       JZ      RETURN
       CPI     3       ;OR ^C
       JZ      RETURN
       CPI     18H     ;^X
       JZ      START   ;RE-START TEST
NOKEY:  POP B ! POP D ! POP H
       RET
;
CNVT:                   ;CONVERT REG D TO HEX ASCII
       MOV     A,D
       RRC             ;GET HIGH NIBBLE
       RRC
       RRC
       RRC
       ANI     00FH
       CALL    CNV     ;MAKE NIBBLE ASCII
       MVI     A,00FH
       ANA     D       ;GET LOW NIBBLE
       CALL    CNV     ;MAKE NIBBLE ASCII
       RET
;
CNV:    ADI     030H
       CPI     03AH
       JM      DONE
       ADI     007H
DONE:   MOV     C,A
       CALL    CONO
       RET
;
ROTTST:                 ;ROTATE TEST
       PUSH    PSW
       CALL    TESTW
       POP     PSW
       PUSH    PSW
       CALL    TESTR
       POP     PSW
       RLC
       RET
;
WALKL:          ;LEFT WALKING BIT TEST
       PUSH    B       ;SAVE SEED
       CALL    LOAD
WLSTOR: MOV     A,B     ;GET BYTE
       RLC             ;ROTATE LEFT
       MOV     B,A     ;AND RESAVE IN B
       MOV     M,A     ;TO MEMORY
       INX H ! CALL HILO
       JNC     WLSTOR
       CALL    LOAD
       POP B ! PUSH B  ;GET SEED BIT
WLTST:  MOV     A,B     ;NOW CHECK
       RLC
       MOV     B,A
       MOV A,M ! CMP B ;CHECK BYTE
       CNZ     ERROR
       INX H ! CALL HILO
       JNC     WLTST
       POP     B       ;ORIG SEED
       RET             ;DONE
;
WALKR:          ;RIGHT WALKING BIT TEST
       PUSH    B       ;SAVE SEED
       CALL    LOAD
WRSTOR: MOV     A,B     ;GET BYTE
       RRC             ;ROTATE RIGHT
       MOV     B,A     ;AND RESAVE IN B
       MOV     M,A     ;TO MEMORY
       INX H ! CALL HILO
       JNC     WRSTOR
       CALL    LOAD
       POP B ! PUSH B  ;GET SEED BIT
WRTST:  MOV     A,B     ;NOW CHECK
       RRC
       MOV     B,A
       MOV     A,M     ;CHECK BYTE
       CMP     B
       CNZ     ERROR
       INX H ! CALL HILO
       JNC     WRTST
       POP     B       ;ORIG SEED
       RET             ;DONE
;
ADTEST:                 ;ADDRESS SHORTED TEST
       CALL    TESTW   ;FILL MEMORY WITH TEST BYTE
       MOV     A,B
       STA     TESTBYTE        ;SAVE TEST BYTE
       CALL    LOAD
       CMA
       MOV     M,A
       INX     H
       CALL    TESTADR
       LXI     B,1     ;START ADDR LSB ON
LOOP4:  LHLD    MEM
       DAD     B
       RC              ;ROLLED OVER 65K
       MOV     A,D     ;GET TEST ADDR
       SUB     H       ;PAST END?
       RC              ;KEEP GOING IF NO CARRY
       JNZ     INXHA
       MOV     A,E
       SUB     L
       RC
INXHA:  LDA     TESTBYTE
       PUSH    B
       MOV     B,A
       CMA             ;INVERT BITS
       MOV     M,A     ;WRITE TO TEST MEMORY
       INX H ! CALL HILO
       JC      OVERFL
       CALL    TESTADR ;TEST
       POP     H
       DAD     H
       RC
       MOV     B,H
       MOV     C,L
       JMP     LOOP4
;
OVERFL: POP     B
       RET
;
GETBYT: CALL    CHAR
       RZ
       CPI     ' '     ;EXIT IF SPACE
       JZ      RETURN
       CPI     3       ;^C
       JZ      RETURN
       CPI     18H     ;^X
       JZ      START
       CALL    ATOH
       JP      REENTER
       RRC
       RRC
       RRC
       RRC
       MOV     E,A
       PUSH    D
       CALL    CHAR
       POP     D
       JZ      REENTER
       CALL    ATOH
       JP      REENTER
       ORA     E
       RET
;
CHAR:   CALL    JCONI
       CPI     CR
       STC             ;SET CY FLAG (MAYBE CR)
       RZ
       PUSH    PSW
       MOV     C,A
       CALL    CONO
       POP     PSW
       RET
;
ATOH:   SUI     030H
       JM      BAD
       CPI     00AH
       RM
       SUI     007H
       CPI     00AH
       JM      BAD
       CPI     010H
       RM
BAD:    XRA     A       ;SET ZERO FLAG
       RET
;
REENTER:
       POP     H       ;FIX STACK
       LXI     D,IEMSG
       CALL    PMSG
GETADD:                 ;INPUT 4 HEX VALUES FROM CONSOLE
       CALL    GETBYT
       RC
       MOV     H,A
       SHLD    TEMP
       CALL    GETBYT
       LHLD    TEMP
       MOV     L,A
       RET
;
CNVTB:                  ;PRINT REG A IN BINAR
       MOV     E,A     ;SAVE A
       MVI     D,2     ;TWO SPACES
       CALL    TLOP
       MVI     B,2     ;NIBBLE COUNT
P
NIBB:   MVI     D,4
ALLBIT: MOV     A,E     ;RESTORE A
       RAL
       MOV     E,A
       MVI     C,030H  ;0
       JNC     ZERO
       MVI     C,031H  ;1
ZERO:   CALL    CONO
       DCR     D
       JNZ     ALLBIT
       CALL    SPACE   ;PRINT SPACE
       DCR     B
       JNZ     PNIBB
TAB:    MVI     D,004H
TLOP:   CALL    SPACE
       DCR     D
       JNZ     TLOP
       RET
;
CRLF:   MVI C,CR ! CALL CONO
       MVI C,LF ! JMP CONO
;
SPACE:  MVI     C,020H
CONO:   PUSH B ! PUSH D ! PUSH H
       LDA     BDOS$FLAG
       ORA     A       ;BIOS OUTPUT ?
       JNZ     BDOS$3  ;NO
       CALL    JCONO   ;YES
       JMP     GO$ON$3
;
BDOS$3:
       MOV     E,C
       MVI     C,2
       CALL    BDOS
GO$ON$3:
       POP H ! POP D ! POP B
       RET
;
;RANGE TESTING ROUTINE - CY SET IF RANGE EXCEEDED
;  IF   HL=DE   THEN NC AND Z SET
;  IF   HL<=DE  THEN NC
;  IF   HL>DE   THEN CY AND NZ
;  IF   HL=0    THEN CY AND Z SET
HILOX:  INX     H       ;INCREMENT PNTR, CHECK RANGE
HILO:
       MOV A,H ! ORA L
       STC ! RZ        ;TEST HL=0
       MOV A,E ! SUB L ;DE-HL
       MOV A,D ! SBB H
       RET
;
RNDW:                   ;WRITE RANDOM NUMBERS
       LHLD    SEED    ;GET SEED
       SHLD    SEEDST  ;SAVE IT FOR LATER
       CALL    LOAD
RNDWL:  CALL    RND
       MOV     M,B
       INX H ! CALL HILO
       JNC     RNDWL
;
RNDR:                   ;CHECK AND READ RANDOM NUMBERS
       LHLD    SEEDST  ;START WITH SAME SEED
       SHLD    SEED    ;PASS SEED TO GENERATOR
       CALL    LOAD    ;GET TEST ADDR
RNDRL:  CALL    RND
       MOV     A,M
       CMP     B
       CNZ     ERROR
       INX H ! CALL HILO
       JNC     RNDRL
       RET             ;TEST DONE
;
RND:                    ;GENERATE RANDOM NR FROM SEED
       PUSH    H
       LHLD    SEED
       MOV     A,L
       XRA     H
       MOV     B,A
       RLC
       MOV     L,A
       ADD     H
       MOV     H,A
       SHLD    SEED
       POP     H
       RET
;
RETURN:
       LXI     SP,STACK-16     ;FIX STACK
       JMP     JEXIT
;
MEMTOP:                 ;FIND TOP OF MEMORY
       IF NOT HEATH
       LXI     H,100H-1
       ENDIF
       IF HEATH
       LXI     H,2000H-1
       ENDIF
MEMLOOP:
       INR     H
       JZ      FOUND   ;ABOVE 64K BOUNDRY
       MOV     B,M     ;GET MEMORY BYTE
       MOV     A,M     ;AND IN A
       CMA
       MOV     M,A     ;STORE COMP
       MOV     C,M     ;GET BACK COMP BYTE
       CMP     C       ;DID IT STORE OK?
       MOV     M,B     ;PUT BACK ORIG
       JZ      MEMLOOP
FOUND:  DCR     H       ;FOUND IT
       RET             ;HL=MEMTOP
;
;********************************************
;       MESSAGE AREA
;********************************************
SIG:    DB      CR,LF
       DB      'MEMRS Memory Test - Version '
       DB      VERS/10+30H, '.', VERS MOD 10+30H
       DB      0
BIOSMSG:DB      'BIOS',0
BDOSMSG:DB      'BDOS',0
LOCMSG: DB      ' located at ',0
MEMSG:  DB      ' Top of memory at ',0
SPMSG:  DB      CR,LF
       DB      'Press "SP" or "^C" to warm boot at any time'
       DB      CR,LF
       DB      'or "^X" to restart test from beginning. ',0
XPMSG:  DB      CR,LF
       DB      'Response of "CR" gives default test range'
       DB      CR,LF
       DB      'which starts above this program and ends at ',0
MSG1:   DB      'LOCATION  SHOULD BE           WAS'
       DB      CR,LF,0
CTUMSG: DB      CR,LF
       DB      '"CR" to continue test - "SP", "^C" to quit,'
       DB      ' "^X" to restart.',0
MSGOK:  DB      CR,LF
       DB      'Test series complete', 0
SMSG:   DB      CR,LF
       DB      'Starting address (Hex or "CR") ',0
EMSG:   DB      CR,LF
       DB      'Ending address   (Hex or "CR") ',0
IEMSG:  DB      CR,LF
       DB      'Input error - Retype 4 hex digits ',0
FCTST:  DB      CR,LF
       DB      'Non-destructive test of ALL MEMORY starting at '
       IF NOT HEATH
       DB      '0 ',0
       ENDIF
       IF HEATH
       DB      '2000H ',0
       ENDIF
BSTST:  DB      CR,LF
       DB      'Bit stuck high or low test ',0
SBTST:  DB      CR,LF
       DB      'Adjacent bits shorted test ',0
CBTST:  DB      CR,LF
       DB      'Checkerboard (55AAH pattern) test ',0
WBLTST: DB      CR,LF
       DB      'Walking bit left test ',0
WBRTST: DB      CR,LF
       DB      'Walking bit right test ',0
ALTST:  DB      CR,LF
       DB      'Address line test ',0
RNTST:  DB      CR,LF
       DB      'Random number test - Cycle: ',0
LOWMSG: DB      CR,LF
       DB      'Re-enter, starting address must be at least ',0
UPPMSG: DB      CR,LF
       DB      'Re-enter, ending address too low',0
;
;
;********************************************
;       INSERT CUSTOM INITIALIZATION AND I/O ROUTINES HERE
;********************************************
;
       IF CPMIO        ;THESE ROUTINES CP/M USERS
MONIT   EQU     WBOOT
CONST   EQU     6       ;CONSOLE STATUS TO REG A
CONIN   EQU     9       ;CONSOLE CHAR TO REG A
CONOUT  EQU     0CH     ;CHAR FROM REG C TO CONSOLE
;
INIT:                   ;SET HI ORDER ADDR BYTES
       LDA     WBOOT+2
       STA     JCONS+2
       STA     JCONI+2
       STA     JCONO+2
       JMP     INIT1
       ENDIF
;
       IF LAPIO        ;USES LAPPLE MONITOR
MONIT   EQU     0D000H
CONST   EQU     0D012H
CONIN   EQU     0D003H
CONOUT  EQU     0D009H
INIT:   JMP     INIT1   ;NO INIT NEEDED
       ENDIF
;
       IF H84CRT
MONIT   EQU     WBOOT
INIT:   JMP     INIT1
CONST   EQU     $
CRTST:  IN H84ST ! ANI 1
       MVI A,0 ! RZ ! CMA ! RET
CONIN   EQU     $
CRTIN:  IN H84ST ! RAR ! JNC CRTIN
       IN H84IO ! ANI 7FH ! RET
CONOUT  EQU     $
CRTOUT: IN H84ST ! ANI 20H ! JZ CRTOUT
       MOV A,C ! OUT H84IO ! RET
H84ST   EQU     0EDH
H84IO   EQU     0E8H
       ENDIF
;
INIT1:
       LXI     H,TBUF  ;POINT TO COMMAND LINE
       MOV     A,M     ;GET FIRST BYTE
       CPI     '-'     ;OPTION CHARACTER ?
       JNZ     DEFAULT ;NO
CLOOP:
       INX     H       ;POINT TO NEXT BYTE
       MOV     A,M
       CPI     00      ;END OF COMMAND LINE ?
       RZ              ;YES
       CPI     'B'     ;BDOS OUTPUT ?
       CZ      SET$BDOS ;YES
       CPI     'R'     ;RANDOM TEST ONLY ?
       CZ      SET$RAND ;YES
       JMP     CLOOP   ;NO
;
DEFAULT:
       XRA     A
       STA     BDOS$FLAG       ;BIOS OUTPUT
       STA     RAND$FLAG       ;FULL TEST
       RET
;
SET$BDOS:
       MVI     A,TRUE          ;BDOS OUTPUT
       STA     BDOS$FLAG
       RET
;
SET$RAND:
       MVI     A,TRUE          ;RANDOM NUMBER TEST ONLY
       STA     RAND$FLAG
       RET
;
;********************************************
;
BDOS$FLAG       DB      0       ;BDOS OUTPUT FLAG
RAND$FLAG       DB      0       ;RANDOM TEST FLAG
;
LASTB   EQU     $       ;END OF PROGRAM
;
       END     START