;********************************************************************
;
;  This is the MITS memory test routine written primarily to find
;  problems with the 4K DRAM boards. It is designed to assemble
;  under Altair DOS, however, DOS is not required for operation
;  (console I/O is done directly through the 2SIO hardware).
;
;  Updated 11/21/17 by Mike Douglas for compatibility with the
;  CP/M ASM assembler and to do console I/O with hex values
;  instead of octal values. The program runs under CP/M or
;  standalone. Console I/O is done directly through the first
;  port on a 2SIO board.
;
;	DOS MEMORY TEST
;
;	A COMBINATION OF ROWPAT AND GALPAT/GALCOL
;
;********************************************************************

	ORG  0100H	;RUN ADDRESS

SETSTK:	LXI  SP,STACK
	DI
	MVI  A,3
	OUT  20Q
	MVI  A,21Q
	OUT  20Q	;INIT ACIA
;
; FIND ALL 4K BLOCKS PRESENT IN THE SYSTEM
; (BLOCK 4 TO BLOCK 15)
;
FINDEM:	LXI  B,BRDBUF	;POINT TO BOARD BUFFER
	MVI  E,4	;FIRST BLOCK TO TRY
;
; CONVERT BLOCK NUMBER TO A 16-BIT START ADDRESS
;
FIND1:	XRA  A
	MOV  L,A
	MOV  A,E	;GET BLOCK NUMBER
	RLC
	RLC
	RLC
	RLC		;...SHIFT INTO 4 MSB
	MOV  H,A	;[HL] = ADDRESS OF FIRST BYTE OF BLOCK
;
; SEE IF THE FIRST BYTE OF THE BLOCK EXISTS AS RAM
;
	MOV  A,M	;GET THE BYTE
	MOV  D,A	;SAVE IT
	CMA		;MAKE COMPLEMENT
	MOV  M,A	;TRY TO STORE COMPLEMENT
	MOV  A,M	;...AND THEN READ IT BACK
	CMA		;RESTORE TO ORIGINAL (MAYBE)
	CMP  D		;COMPARE TO KNOWN GOOD ORIGINAL
	JNZ  FIND2	;NO GOOD - TRY NEXT 4K BLOCK
;
; FOUND A RAM BOARD, SAVE BOARD (BLOCK) NUMBER IN BOARD BUFFER
;
	MOV  A,E	;GET BOARD NUMBER
	STAX B		;SAVE IN BUFFER
	INX  B		;POINT TO NEXT POSITION
;
; INCREMENT TO NEXT 4K BLOCK, STOP LOOKING IF ALL BLOCKS TRIED
;
FIND2:	MVI  A,15
	INR  E		;NEXT BLOCK NUMBER
	CMP  E		;OVER THE TOP ?
	JP   FIND1	;NO - GO TEST THIS NEW BLOCK
	MVI  A,0200Q	;YES - MARK END IN BUFFER
	STAX B
;
;
;
; ASK USER FOR CHOICE OF AUTOMATIC OR SELECTION MODE
;
MODE:	CALL PRNMSG	;PRINT "AUTO MODE (Y/N)?"
	DW   MAUTO
	CALL GETSTG	;GET ANSWER
	MVI  A,'Y'
	CMP  M		;DO THEY WANT AUTO MODE ?
	JNZ  SELECT	;NO - THEN LET THEM SELECT
;
; AUTO TEST SEQUENCE STARTS HERE
;
	LXI  H,DROPLS
	SHLD DROPPT	;SET DROP LIST POINTER TO START
	XRA  A
	DCX  H
	MOV  M,A	;CLEAR DROP COUNT
	DCX  H
	MOV  M,A	;...AND ERROR FLAG
MODE1:	LXI  H,BRDBUF	;POINT TO BOARD BUFFER
	SHLD BRDPT	;SAVE POINTER FOR LOOPING
;
; AUTO SEQUENCE MAIN LOOP
;
; CONTROL-C CAUSES AUTOMATIC DUMP OF DROP BUFFER
;
AUTO:	IN   16
	RRC
	JNC  MODE2
     	IN   17
	ANI  0177Q
	CPI  3		;GOT A CONTROL-C ?
	CZ   CDROP	;YES - SHOW WHO DIED
;
; TEST ERROR FLAG TO SEE WHETHER OR NOT WE DROP THE BLOCK JUST TESTED
;
MODE2:	LDA  ERRFLG	;GET ERROR FLAG
	ORA  A		;...AND TEST IT
	JZ   MODE3
;
; NONZERO ERROR FLAG MEANS WE DROP THIS BLOCK
;
	LHLD DROPPT	;POINT TO NEXT DROP LIST SLOT
	XCHG
	LHLD BLKST	;GET BLOCK START ADDRESS
	XCHG		;[HL] = DROP LIST POINTER, [DE] = BLOCK START
	MOV  M,E	;SAVE LOW BYTE
	INX  H
	MOV  M,D	;SAVE HIGH BYTE
	INX  H		;[HL] NOW POINTS TO NEXT DROP LIST SLOT
	SHLD DROPPT	;SAVE NEW POINTER
	LXI  H,DROPCT
	INR  M		;INCREMENT DROP COUNT
	LHLD BRDPT	;GET BOARD POINTER
	DCX  H		;BACK UP TO BOARD JUST TESTED
	MVI  M,0	;...AND LOG IT OUT
;
; GET NEXT BOARD NUMBER AND TEST FOR END OF BUFFER OR DROPPED BOARD
;
MODE3:	XRA  A
	STA  ERRFLG	;CLEAR ERROR FLAG
  	LHLD BRDPT	;GET BOARD POINTER
	MOV  A,M	;...AND BOARD NUMBER
	INX  H
	SHLD BRDPT	;UPDATE AND SAVE NEW POINTER
	ORA  A		;TEST BOARD NUMBER
	JM   MODE1	;RESTART IF END OF BUFFER
	JZ   MODE3	;TRY NEXT ONE IF DROPPED BOARD
;
; CONVERT BOARD NUMBER TO 4K BLOCK ADDRESS
;
	RLC
	RLC
	RLC
	RLC		;BOARD NUMBER TO 4 MSB
	MVI  L,0
	MOV  H,A	;MAKE A 16-BIT BLOCK ADDRESS
	SHLD BLKST	;SAVE AS BLOCK START ADDRESS
	ADI  16		;ADD 4K TO START
	MOV  H,A
	SHLD BLKEND	;SAVE AS BLOCK END ADDRESS + 1
;
; FIX STACK SO RETURNS COME TO "AUTO" TO DO NEXT BOARD
;
	LXI  H,AUTO
	PUSH H
;
; PRINT THE RANGE THAT THIS SEQUENCE TESTS
;
	CALL PRNMSG	;PRINT "TESTING "
	DW   MTRNG
	LHLD BLKST	;GET BLOCK START ADDRESS
	CALL NUMASC	;MAKE ASCII AND PRINT IT
	CALL PRNMSG	;PRINT " TO "
	DW   MFILLR
	LHLD BLKEND	;GET BLOCK END ADDRESS
	CALL NUMASC	;MAKE ASCII AND PRINT IT
;
; DO GALPAT TEST IN 256-BYTE CHUNKS
; PATTERNS ARE 377, THEN 000
;
	CALL PRNMSG	;PRINT "GALPAT"
	DW   MGALP
	LHLD BLKST	;GET BLOCK START
GAL1:	SHLD MEMBOT	;SAVE AS "CHUNK" START
	INR  H		;ADD 256
	MVI  L,0
	SHLD MEMTOP	;...AND THAT'S THE "CHUNK" END +1
	MVI  A,0377Q	;ALL ONES BACKGROUND PATTERN
	CALL GALPAT	;TEST THE "CHUNK"
	XRA  A		;ALL ZEROS BACKGROUND PATTERN
	CALL GALPAT	;TEST THE SAME CHUNK AGAIN
	LHLD BLKEND	;[DE] = "CHUNK" END, [HL] = BLOCK END
	CALL COMPAR	;DONE ALL 16 "CHUNKS" IN THE BLOCK ?
	JZ   WAIT	;YES - GO KILL TIME
	XCHG	        ;[HL] = NEW "CHUNK" START
	JMP  GAL1	;GO TEST NEW "CHUNK"
;
; WAIT HERE FOR 1 MINUTE TO CHECK REFRESH
;
WAIT:	CALL PRNMSG	;PRINT "WAITING"
	DW   MWAIT
	LXI  B,500	;NUMBER OF TIMES TO DO 120 ms LOOP
WAIT1:	LXI  D,10000	;NUMBER OF TIMES TO DO 12 us LOOP
WAIT2:	DCX  D		;2.5 us
	MOV  A,D	;2.5 us
	ORA  E		;2.0 us
	JNZ  WAIT2	;5.0 us
	DCX  B
	MOV  A,B
	ORA  C
	JNZ  WAIT1
;
; SEE IF GALPAT RESULT (ALL ZEROS) SURVIVED DELAY
;
	CALL PRNMSG	;PRINT "RECHECK"
	DW   MRCHK
	LHLD BLKEND	;GET BLOCK END
	XCHG		;...IN [DE]
	LHLD BLKST	;...AND BLOCK START IN [HL]
	XRA  A		;THE RESULT WE'RE LOOKING FOR
GAL2:	CMP  M		;TEST GALPAT RESULT BYTE
	CNZ  RFERR	;NO - REPORT REFRESH ERROR
	INX  H
	CALL COMPAR	;CHECKED WHOLE BLOCK ?
	JC   GAL2	;NO - THEN DO IT !
;
; DO GALCOL WITH ALL ONES, THEN ALL ZEROS ON THE WHOLE BLOCK
;
GC:	CALL PRNMSG	;PRINT "GALCOL"
	DW   MGALC
	LHLD BLKST	;GET BLOCK START
	SHLD MEMBOT	;SAVE FOR GALCOL
	LHLD BLKEND	;GET BLOCK END
	SHLD MEMTOP	;SAVE FOR GALCOL
	MVI  A,0377Q	;ALL ONES PATTERN
	CALL GALCOL	;DO THE TEST
	XRA  A		;ALL ZEROS PATTERN
	CALL GALCOL	;TEST THE BLOCK AGAIN
;
; WALK PATTERNS THROUGH THE BLOCK IN 256-BYTE "CHUNKS"
; FIRST WRITE ONES, WALK ZEROS, THEN WRITE ZEROS, WALK ONES
;
	CALL PRNMSG	;PRINT "WALKING PATTERNS"
	DW   MWALKS
	LHLD BLKST	;GET BLOCK START
GC1:	SHLD MEMBOT	;SAVE AS "CHUNK" START
	INR  H		;ADD 256
	MVI  L,0
	SHLD MEMTOP	;RESULT IS "CHUNK" END + 1
	MVI  A,0377Q	;GET ALL ONES BACKGROUND PATTERN
	CALL WALK	;TEST THE CHUNK
	XRA  A		;ALL ZEROS BACKGROUND PATTERN
	CALL WALK	;TEST AGAIN
	LHLD BLKEND	;[DE] = "CHUNK" END, [HL] = BLOCK END
	CALL COMPAR	;DONE ALL "CHUNKS" IN THE BLOCK ?
	RZ		;YES - GO TO NEXT BOARD IN AUTO SEQUENCE;
	XCHG		;NO  - [HL] = NEW "CHUNK" START
	JMP  GC1	;GO TEST NEW "CHUNK"
;
; THIS ROUTINE PRINTS OUT THE DROP LIST
;
CDROP:	LDA  DROPCT	;GET DROP COUNT
	ORA  A		;DID WE LOSE ANYBODY ?
	JNZ  CDROP1
	CALL PRNMSG     ;NO - THEN SAY SO !!!
	DW   NODROP
	RET
CDROP1:	CALL PRNMSG	;YES - TELL THEM WHAT THE NUMBERS MEAN
	DW   HDROP
	LXI  H,DROPLS	;POINT TO DROP LIST
CDROP2:	MOV  E,M	;GET LOW BYTE
	INX  H
	MOV  D,M
	INX  H		;[HL] NOW POINTS TO NEXT DROP LIST SLOT
	XCHG		;WE NEED ADDRESS IN [HL] FOR CALL
	CALL NUMASC
	CALL PRNMSG	;CONVERT AND PRINT ADDRESS AND DO CRLF
	DW   MCRTLF
	XCHG		;RESTORE [HL] AND [DE]
	DCR  A		;ONE LESS ADDRESS TO DISPLAY
	JNZ  CDROP2	;DO THEM ALL
	RET		;...AND THEN GO HOME
;
;
;
; THIS IS THE ENTRY POINT FOR "SELECT" MODE
; USER DEFINES ADDRESS RANGE, PATTERN, AND TEST TYPE
;
SELECT:	CALL PRNMSG	;ASK FOR LOW ADDRESS LIMIT
	DW   MLOMEM
	CALL GETSTG	;GET ANSWER
	CALL ASCNUM	;MAKE BINARY
	SHLD MEMBOT	;SAVE LOW LIMIT
	CALL PRNMSG	;ASK FOR UPPER LIMIT
	DW   MHIMEM
	CALL GETSTG	;GET ANSWER
	CALL ASCNUM	;MAKE BINARY
	MOV  A,L
	ORA  H		;UPPER LIMIT OF ZERO ?
	JZ   MODE	;YES - THEN RESTART
	INX  H		;NO  - THEN GO ONE PAST END
	SHLD MEMTOP	;...AND SAVE END+1
;
; DISPLAY TEST OPTIONS AND GET USER'S CHOICE
;
SLCT1:	CALL PRNMSG	;SHOW OPTIONS, ASK FOR CHOICE
	DW   MOPTN
	CALL GETSTG	;GET THE ANSWER
	CALL ASCNUM	;...IN BINARY
	MOV  A,L
	ORA  H		;WAS IT ZERO ?
	JZ   SELECT	;YES - GO ASK FOR LIMITS AGAIN
	MOV  A,H
	ORA  A		;TEST NUMBER > 255 ?
	JNZ  SLCT1	;YES - GIVE THE JERK ANOTHER CHANCE
	ORA  L
	CPI  4		;TEST NUMBER > 3 ?
	JNC  SLCT1	;YES - SOME PEOPLE NEVER LEARN !!
	MOV  B,A	;SAVE TEST NUMBER IF OK
;
; ASK USER TO DEFINE A PATTERN TO BE WRITTEN
;
	CALL PRNMSG	;ASK FOR PATTERN
	DW   MGTPAT
	CALL GETSTG	;GET HIS ANSWER
	CALL ASCNUM	;...IN BINARY
	MOV  C,L	;HIDE THE LOW BYTE
;
; BRANCH TO THE CHOSEN TEST
;
	LXI  D,SELECT
	PUSH D		;WE GO TO "SELECT" AT END OF TEST
	DCR  B		;ADJUST TEST NUMBER
	MOV  A,B
	RLC		;...FOR TABLE JUMP
	ADD  B
	MOV  E,A
	MVI  D,0	;MAKE A 16-BIT INDEX
	LXI  H,BTAB	;GET TABLE BASE
	MOV  A,C	;GET PATTERN READY
	DAD  D		;[HL] = ADDRESS OF JUMP
	PCHL		;BRANCH TO JUMP TO TEST
BTAB:	JMP  GALPAT
	JMP  GALCOL
	JMP  WALK
	RET		;THIS SHOULD'NT GET USED
;
;
;
;
;*********************************************************************
;
;	ERROR PROCESSING ROUTINES
;
;
; ERROR IN REFRESH (GALPAT RESULT BAD AFTER 1-MINUTE DELAY)
;
RFERR:	CMA
	STA  ERRFLG	;MAKE ERROR FLAG NONZERO
	CMA		;RESTORE [A]
      	CALL PRNMSG	;PRINT "REFRESH ERROR AT "
	DW   MRFSH	
	PUSH H		;SAVE ERROR ADDRESS FOR EXIT
	CALL NUMASC	;MAKE ASCII AND PRINT IT
	CALL PRNMSG
	DW   MRFSH2	;PRINT "EXPECTED 252, READ "
	POP  H		;RESTORE POINTER TO BAD DATA
	PUSH H		;...BUT DON'T CHANGE STACK
	MOV  L,M	;GET BAD DATA
	MVI  H,0
	CALL NUMASC	;MAKE ASCII AND PRINT IT
	CALL PRNMSG
	DW   MCRTLF	;...FOLLOWED BY CRLF
	POP  H		;GET ERROR ADDRESS BACK
	RET		;CONTINUE TESTING
;
; ERROR IN WALKING PATTERNS
;
PATERR:	CALL PRNMSG
	DW   MRER1	;PRINT "ERROR AT ADDRESS "
	PUSH H		;SAVE BAD ADDRESS
	CALL NUMASC	;CONVERT TO ASCII AND PRINT IT
	CALL PRNMSG
	DW   MRER2	;PRINT " : READ "
	POP  H		;GET BAD ADDRESS
	PUSH H		;...BUT DON'T CHANGE STACK
	MOV  L,M	;GET BAD DATA
	MVI  H,0
	CALL NUMASC	;MAKE ASCII AND PRINT
	CALL PRNMSG
	DW   MRER3	;PRINT " , EXPECTED "
	MOV  L,A	;GET GOOD DATA
	MVI  H,0
	CALL NUMASC	;MAKE ASCII AND PRINT
	LHLD LASTWR	;GET "LAST WRITTEN" ADDRESS
	CALL PRNMSG
	DW   MRER4	;PRINT "LAST ADDRESS WRITTEN WAS"
	CALL NUMASC	;CONVERT AND PRINT "LAST WRITTEN" ADDRESS
	PUSH PSW
	LDA  TPATT	;[A] = TEST PATTERN
	CALL PRNMSG
	DW   MRER5	;PRINT " PATTERN WAS "
	MVI  H,0
	MOV  L,A
	CALL NUMASC	;CONVERT AND PRINT TEST PATTERN
	MVI  A,0377Q
	STA  ERRFLG	;SET ERROR FLAG
	POP  PSW
	POP  H		;RESTORE CALLER'S [HL]  (BAD ADDRESS)
	RET		;CONTINUE TESTING
;
;
; ERROR IN GALPAT OR GALCOL
;
ERROR1:	CALL PRNMSG	;PRINT "OTHER CELL"
	DW   MERROC
	JMP  COMERR	;GO TO COMMON ERROR PROCESSING
ERROR2:	CALL PRNMSG	;PRINT "TEST CELL"
	DW   MERRTC
COMERR:	PUSH H
	PUSH D
	PUSH B
	PUSH PSW	;PROTECT THE INNOCENT
	CALL PRNMSG	;PRINT "TEST CELL = "
	DW   MTCELL
	XCHG
	CALL NUMASC
	XCHG
	CALL PRNMSG	;PRINT "OTHER CELL = "
	DW   MOCELL
	CALL NUMASC
	CALL PRNMSG	;PRINT "PATTERN STORED = "
	DW   MSTPAT
	MOV  L,B
	MVI  H,0
	CALL NUMASC
	CALL PRNMSG	;PRINT "PATTERN READ = "
	DW   MRDPAT
	MOV  L,A
	MVI  H,0
	CALL NUMASC
	CALL PRNMSG	;PRINT CRLF
	DW   MCRTLF
	MVI  A,0377Q
	STA  ERRFLG	;SET ERROR FLAG
	POP  PSW
	POP  B
	POP  D
	POP  H		;EVERYBODY BACK FROM EXILE
	RET
;
;
;
;
;*********************************************************************
;
;	THESE ARE THE ACTUAL TEST ROUTINES
;
;********************************************************************
;
; GALPAT
;
GALPAT:	MOV  B,A	;SAVE PATTERN
	CALL BAKPAT	;WRITE BACKGROUND PATTERN
GPSTRT:	LHLD MEMBOT
	XCHG		;[DE] = TEST CELL ADDRESS, [HL] = MEMTOP
GPNCEL:	PUSH D
	LHLD MEMBOT	;[HL] = ADDRESS OF OTHER CELL
	LDAX D		;GET CONTENTS OF TEST CELL
	CMA		;COMPLEMENT IT
	STAX D		;...AND STORE IT BACK
GPLOOP:	POP  D		;GET BACK ADDRESS OF TEST CELL
	PUSH D
	CALL COMPAR	;SEE IF TEST ADDRESS = OTHER ADDRESS
	JZ   GPSKIP	;YES - SKIP TESTING
	MOV  A,M	;LOAD OTHER CELL
	CMP  B		;EQUAL TO PATTERN ?
	CNZ  ERROR1	;NO - REPORT ERROR
	LDAX D		;READ BACK TEST CELL
	CMA		;BACK TO ORIGINAL STATE
	CMP  B		;EQUAL TO PATTERN ?
	CNZ  ERROR2	;NO -REPORT ERROR
GPSKIP:	INX  H		;BUMP OTHER ADDRESS
	XCHG		;[DE] = MEMTOP
	LHLD MEMTOP
	XCHG
	CALL COMPAR	;AT TOP OF BLOCK ?
	JNZ  GPLOOP	;NO - CONTINUE
	POP  D		;YES - GET BACK TEST ADDRESS
	LDAX D		;LOAD TEST CELL
	CMA		;COMPLEMENT BACK TO ORIGINAL
	STAX D		;AND STORE BACK
	INX  D		;NEXT TEST ADDRESS
	CALL COMPAR	;AT TOP OF BLOCK ?
	JNZ  GPNCEL	;NO - CONTINUE
	RET
;
;
; GALCOL
;
GALCOL:	MOV  B,A	;SAVE PATTERN
	CALL BAKPAT	;WRITE BACKGROUND
	LHLD MEMBOT
GCNCEL:	PUSH H		;SAVE TEST CELL ADDRESS
	MOV  A,M	;GET CONTENTS OF TEST CELL
	CMA		;COMPLEMENT IT
	MOV  M,A	;STORE IT BACK
GCLOOP:	MVI  E,64
	MVI  D,0
	DAD  D
	XCHG		;[DE] = [HL] + 64
	LHLD MEMTOP
	CALL COMPAR
	XCHG
	JM   GCINCR
	JZ   GCINCR	;UP TEST CELL ADDRESS IF NEW [DE] < MEMTOP
	POP  D
	PUSH D
	LDAX D		;GET TEST CELL
	CMA
	CMP  B		;IS COMPLEMENT = PATTERN ?
	CNZ  ERROR1	;NO - REPORT ERROR
	MOV  A,M	;TEST OTHER CELL
	CMP  B		;EQUAL TO PATTERN ?
	CNZ  ERROR2	;NO - REPORT ERROR
	JMP  GCLOOP	;TRY NEXT OTHER CELL
GCINCR:	POP  H		;GET TEST CELL ADDRESS
	MOV  A,M	;GET CONTENTS
	CMA		;COMPLEMENT BACK TO ORIGINAL
	MOV  M,A	;RESAVE
	CALL INCM64	;INCREMENT TEST ADDRESS MOD 64
	MOV  A,M	;EQUAL TO PATTERN ?
	CMP  B
	CNZ  ERROR1
	CALL INCM64
	MOV  A,M
	CMP  B
	CNZ  ERROR1
	CALL INCM64
	ANI  077Q	;TEST MOD 64
	RZ		;RETURN IF WRAPPED TO START ADDRESS
	JMP  GCNCEL	;ELSE DO NEXT TEST CELL
;
;
; WALKING PATTERNS
;
WALK:	CALL BAKPAT	;WRITE FULL BACKGROUND
	LHLD MEMBOT	;[HL] = FIRST BYTE OF BLOCK ADDRESS
	PUSH H		;SAVE FOR INSTANT RESET
	CMA		;COMPLEMENT OF BACKGROUND IS TEST PATTERN
	STA  TPATT	;SAVE PATTERN
;
; WRITE TEST PATTERN
;
WALK1:	MOV  M,A	;STORE TEST PATTERN
	PUSH H		;SAVE "LAST WRITTEN" ADDRESS
	SHLD LASTWR	;SAVE "LAST WRITTEN" ADDRESS
	INX  H
	CMA		;RESET [A] TO BACKGROUND PATTERN
;
; TEST BACKGROUND PATTERN FROM ("LAST WRITTEN" + 1) TO (END OF BLOCK)
;
WALK2	CALL COMPAR	;TESTED ALL REMAINING BACKGROUND ?
	JZ   WKSET	;YES - GO TEST PATTERN BYTES
	CMP  M		;NO  - TEST BACKGROUND BYTE
	CNZ  PATERR	;BAD - REPORT ERROR
	INX  H
	JMP  WALK2
;
; SET UP FOR NEXT SECTION
;
WKSET:	XCHG		;[HL] = LAST ADDRESS IN BLOCK + 1
	POP  D		;[DE] = "LAST WRITTEN" ADDRESS
	XTHL		;[HL] = FIRST ADDRESS IN BLOCK
	PUSH D		;"LAST WRITTEN" TO STACK
	CMA		;GET TEST PATTERN BACK
;
; TEST PATTERN BYTES FROM (START OF BLOCK) TO ("LAST WRITTEN")
;
WALK3:	CMP  M		;TEST A BYTE
	CNZ  PATERR	;ERROR IN WALKED TEST PATTERN
	CALL COMPAR	;TESTED ALL WRITTEN BYTES ?
	INX  H
	JNZ  WALK3	;NO - THEN DO IT !!
;
; SET UP FOR NEXT PATTERN BYTE
;
	POP  H		;[HL] = "LAST WRITTEN" ADDRESS
	POP  D		;[DE] = LAST ADDRESS IN BLOCK + 1
	INX  H		;[HL] = NEXT ADDRESS TO WRITE
	CALL COMPAR	;DONE THE WHOLE THING ?
	RZ		;YES - THAT'S ALL
	PUSH H
	LHLD MEMBOT
	XTHL		;MAKE SURE A COPY OF MEMBOT IS ON THE STACK
	JMP  WALK1
;
;
;
;**********************************************************************
;
;	SUPPORT ROUTINES
;
;*********************************************************************
;
;
; GENERATE BACKGROUND PATTERN (CONTAINED IN [A])
;
BAKPAT:	LHLD MEMTOP
	XCHG
	LHLD MEMBOT	;[HL] = MEMBOT, [DE] = MEMTOP
BACKGR:	CALL COMPAR
	RZ		;RETURN WHEN DONE
	MOV  M,A	;STORE PATTERN
	INX  H
	JMP  BACKGR
;
;
; INCREMENT [HL] MOD 64
;
INCM64:	INX  H
	MOV  A,L
	ANI  077Q	;TEST FOR WRAP-AROUND
	RNZ
	MOV  A,L	;SUBTRACT 64 TO ADJUST
	SUI  0100Q
	MOV  L,A
	RNC
	DCR  H		;BORROW IF NEEDED
	RET
;
;
; PRINT MESSAGE POINTED TO BY ADDRESS FOLLOWING CALL
;
PRNMSG:	XTHL		;GET RETURN ADDRESS
	PUSH D
	MOV  E,M
	INX  H
	MOV  D,M
	INX  H
	XCHG		;[HL] = ADDRESS OF MESSAGE
	CALL PRNSTG	;PRINT THE MESSAGE
	XCHG
	POP  D
	XTHL		;RESTORE [HL] AND RETURN ADDRESS
	RET
;
;
; PRINT STRING POINTED TO BY [HL] UNTIL NULL TERMINATOR
;
PRNSTG:	PUSH PSW
PSNEXT:	MOV  A,M	;GET A CHAR FROM THE STRING
	ORA  A		;IS IT THE TERMINATOR ?
	JZ   PSFINI	;YES - END OF STRING
	CALL PRNCHA	;NO  - PRINT IT
	INX  H		;POINT TO NEXT VICTIM
	JMP  PSNEXT	;AND GO BACK TO TRY TO PRINT
PSFINI:	POP  PSW
	RET
;
;
; PRINT A CHARACTER (ACIA, CHANNEL 20 OCTAL)
;
PRNCHA:	PUSH PSW	
PCWAIT:	IN   16		;GET STATUS
	ANI  2		;CAN WE SEND ?
	JZ   PCWAIT	;NO - WE'LL WAIT
	POP  PSW	;GET DATA BACK
	OUT  17		;...AND SEND IT
	RET
;
;
;
; READ A CHARACTER STRING INTO IOBUFR UNTIL RETURN
;
GETSTG:	PUSH PSW
GSSTRT:	LXI  H,IOBUFR	;POINT TO BUFFER
GSNEXT:	CALL GETCHA	;GET A CHARACTER
	CALL PRNCHA	;...ECHO IT
	CPI  13		;IS IT RETURN ?
	JZ   GSFINI	;YES - THAT'S ALL
	CPI  '@'	;NO  - IS IT "CLEAR BUFFER" ?
	JZ   GSSTRT	;YES - START OVER
	MOV  M,A	;NO  - PUT CHAR IN BUFFER
	INX  H		;POINT TO NEXT BUFFER POSITION
	JMP  GSNEXT	;...AND GET ANOTHER CHAR
GSFINI:	MVI  A,10	;PRINT LF
	CALL PRNCHA
	XRA  A
	MOV  M,A	;PUT ZERO TERMINATOR IN BUFFER
	POP  PSW
	LXI  H,IOBUFR	;RETURN WITH [HL] POINTING TO STRING
	RET
;
;
; GET A CHARACTER FROM ACIA, CHANNEL 20 OCTAL
;
GETCHA:	IN   16		;GET STATUS
	RRC		;ANYTHING THERE ?
	JNC  GETCHA	;NO - WAIT
	IN   17		;YES- GET IT
	ANI  0177Q	;STRIP PARITY
	RET
;
;
;
; CONVERT [HL] TO ASCII DIGIT STRING (HEX)
;
NUMASC:	PUSH B
	PUSH D
	PUSH PSW	;HIDE EVERYBODY

	LXI  D,STGNUL	;POINT TO NULL AT BUFFER END
	XRA  A
	STAX D		;MAKE SURE IT'S STILL A ZERO

	MOV  A,L	;A=LSB
	CALL NALSN	;CONVERT AND STORE LSN
	MOV  A,L	;A=LSB
	CALL NAMSN	;CONVERT AND STORE MSN

	MOV  A,H	;A=MSB
	ORA  A		;SKIP IF MSB IS ZERO
	JZ   NAEXIT

	CALL NALSN	;CONVERT AND STORE LSN
	MOV  A,H	;A=MSB
	CALL NAMSN	;CONVERT AND STORE MSN

NAEXIT:	XCHG		;[HL] = POINTER TO FIRST DIGIT
	POP  PSW
	POP  D
	POP  B		;RESTORE ALL
	JMP  PRNSTG	;PRINT THE DIGIT STRING AND EXIT	
;
; CONVERT MSN OR LSN OF A TO ASCII AND STORE AT [--D]
;	
NAMSN:	RRC		;MOVE MSN TO LSN
	RRC
	RRC
	RRC
NALSN:	ANI  0FH	;GET NIBBLE ALONE
	CPI  10		;0-9?
	JC   NASTOR	;YES
	ADI  7		;OFFSET FOR'A'-'F'
NASTOR:	ADI  '0'	;CONVERT TO ASCII
	DCX  D		;MOVE POINTER 
	STAX D		;PUT ASCII DIGIT IN BUFFER
	RET
;
;
; CONVERT ASCII DIGIT STRING TO BINARY IN [HL]
; ENTER WITH [HL] POINTING TO ASCII STRING
;
ASCNUM:	PUSH PSW
	PUSH D
	PUSH B
	XCHG		;GET POINTER TO STRING IN [DE]
	LXI  H,0	;RESULT = 0
ANLOOP:	LDAX D		;GET NEXT CHAR
	CPI  '0'
	JM   ANFINI	;STOP IF < ASCII ZERO
	SUI  '0'	;DROP ASCII BIAS
	CPI  10		;0-9?
	JC   ANSTOR	;YES
	SUI  7		;OFFSET FOR 'A'-'F'
ANSTOR:	MOV  B,A	;SAVE DIGIT
	MVI  A,16	;ASSUMED RADIX 16
	CMP  B		;QUIT IF [B] >= [A]
	JZ   ANFINI
	JC   ANFINI
	DAD  H
	DAD  H
	DAD  H
	DAD  H		;[HL] = RESULT * RADIX  (16)
	MOV  A,L
	ADD  B		;ADD IN NEW DIGIT
	MOV  L,A
	JNC  ANNCRY
	INR  H		;ADD IN CARRY IF NEEDED
ANNCRY:	INX  D
	JMP  ANLOOP	;GO DO NEXT CHAR
ANFINI:	POP  B
	POP  D
	POP  PSW	;COME ON BACK
	RET
;
;
;
; COMPARE [HL] TO [DE]
;
COMPAR:	PUSH B
	MOV  B,A
	MOV  A,H
	SUB  D
	JNZ  CPFINI
	MOV  A,L
	SUB  E
CPFINI:	MOV  A,B
	POP  B
	RET
;
;
;
;
;******************************************************************
;
;	MESSAGE STRINGS
;
;*****************************************************************
;
;
MAUTO:	DB	13,10,10,'AUTO MODE (Y/N) ? ',0
MTRNG:	DB	'TESTING ',0
MFILLR:	DB	' TO ',0
MGALP:	DB	13,10,'GALPAT / ',0
MWAIT:	DB	'WAITING / ',0
MRCHK:	DB	'RECHECK / ',0
MGALC:	DB	'GALCOL / ',0
MWALKS:	DB	'WALKING PATTERNS',13,10,0
MLOMEM:	DB	'LOW ADDRESS ? ',0
MHIMEM:	DB	'HIGH ADDRESS ? ',0
MOPTN:	DB	13,10,'TEST OPTIONS ARE:',13,10
	DB	' 1- GALPAT',13,10
	DB	' 2- GALCOL',13,10
	DB	' 3- WALKING PATTERNS',13,10,10
	DB	'ENTER TEST NUMBER: ',0
MGTPAT:	DB	'ENTER PATTERN: ',0
;
;
MERRTC:	DB	7,7,7,13,10,'ERROR READING TEST CELL',13,10,0
MERROC:	DB	7,7,7,13,10,'ERROR READING OTHER CELL',13,10,0
MTCELL:	DB	13,10,'TEST CELL = ',0
MOCELL:	DB	', OTHER CELL = ',0
MSTPAT:	DB	' BYTE STORED = ',0
MRDPAT:	DB	', BYTE READ = ',0
MCRTLF:	DB	13,10,0
MRFSH:	DB	7,7,7,13,10,'REFRESH ERROR AT ',0
MRFSH2:	DB	': EXPECTED 000, READ ',0
MRER1:	DB	7,7,7,13,10,'ERROR AT ADDRESS ',0
MRER2:	DB	': READ ',0
MRER3:	DB	', EXPECTED ',0
MRER4:	DB	13,10,'LAST BYTE WRITTEN WAS ',0
MRER5:	DB	', PATTERN WAS ',0
NODROP:	DB	13,10,'NO BOARDS DROPPED',13,10,0
HDROP:	DB	13,10,'STARTING ADDRESS(ES) OF 4K'
	DB	' BLOCK(S) DROPPED:',7,7,7,13,10,0
;
;
;
;********************************************************************
;
;	RAM STORAGE AND STACK
;
;********************************************************************
;
;
	DS   256	;STACK SPACE
;
STACK:	DS	0	;STACK JUST BELOW RAM DATA
ERRFLG:	DS	1	;BLOCK ERROR FLAG
DROPCT:	DS	1	;NUMBER OF BLOCKS DROPPED
DROPLS:	DS	28	;DROP BUFFER
DROPPT:	DS	2	;POINTER TO NEXT FREE SLOT IN 'DROPLS'
BRDBUF:	DS	15	;BOARD BUFFER
	DB	0200Q	;TERMINATOR FOR BOARD BUFFER
BRDPT:	DS	2	;BOARD BUFFER POINTER
BLKST:	DS	2	;BLOCK START ADDRESS
BLKEND:	DS	2	;BLOCK END ADDRESS
MEMBOT:	DS	2	;CHUNK START ADDRESS
MEMTOP:	DS	2	;CHUNK END ADDRESS
STGBUF:	DS	16	;BUFFER FOR NUMASC
STGNUL:	DB	0	;MARKER FOR END OF STGBUF
IOBUFR:	DS	80	;INPUT BUFFER FOR GETSTG
TPATT:	DS	1	;LAST PATTERN WRITTEN
LASTWR:	DS	2	;LAST ADDRESS WRITTEN
;
	END

