;***********************************************************************
; MICROCOSM ASSOCIATES "SUPER MEMORY DIAGNOSTIC" VERSION 1.01  (C) 1979
;***********************************************************************
;
;DONATED TO THE "SIG/M" CP/M USER'S GROUP BY:
;KELLY SMITH, MICROCOSM ASSOCIATES
;3055 WACO AVENUE
;SIMI VALLEY, CALIFORNIA, 93065
;(805) 527-9321 (MODEM, CP/M-NET (TM))
;(805) 527-0518 (VERBAL)
;
;
;
	ORG	0100H
;
;
;
	DI			;DISABLE INTERRUPTS
	LXI	SP,STACK	;SET THE STACK POINTER
	JMP	INIT		;INITIALIZE
;
;
;
;
;
;
;DEFINE CONSOLE I/O PARAMETERS FOR ALTAIR 2SI/O BOARD
;
CCTRL	EQU	010H	;CONSOLE COMMAND/STATUS PORT
CDATA	EQU	011H	;CONSOLE DATA PORT
CRRDY	EQU	001H	;RECEIVER READY BIT
CTRDY	EQU	002H	;TRANSMITTER READY BIT
;
;
;
;SUBROUTINE TO CONVERT TWO HEX CHARACTERS TO ONE BYTE
;
NBL:	SUI	'0'
	RC
	ADI	0E9H
	RC
	ADI	6
	JP	NIO
	ADI	7
	RC
NIO:	ADI	10
	ORA	A
	RET
;
;
;
;SUBROUTINE TO CONVERT A BYTE TO TWO HEX CHARACTERS
;
LBYTE:	PUSH	PSW
	RRC
	RRC
	RRC
	RRC
	ANI	0FH
	CALL	HXDA
	POP	PSW
	ANI	0FH
	JMP	HXDA
;
;
;
HXDA:	CPI	10
	JM	CNO
	ADI	7
CNO:	ADI	30H
	MOV	C,A
	JMP	CO
;
;
;
;CONSOLE INPUT ROUTINE
;
CI:	IN	CCTRL
	ANI	CRRDY
	JZ	CI
	IN	CDATA
	ANI	7FH
	RET
;
;
;
CRLF:	MVI	C,0DH
	CALL	CO
	MVI	C,0AH
	JMP	CO
;
;
;
CONO:	CALL	BYTEO
	CALL	CRLF
	RET
;
;
;
CONI:	PUSH	B
	CALL	BYTEC
	POP	B
	RET
;
;
;
;CONSOLE OUTPUT ROUTINE
;
CO:	IN	CCTRL
	ANI	CTRDY
	JZ	CO
	MOV	A,C
	OUT	CDATA
	RET
;
;
;
INIT:	LXI	H,01000H	;SET DELAY COUNT FOR 6850 SETTLE TIME
DELAY:	DCX	H
	MOV	A,H
	ORA	L
	JNZ	DELAY
	MVI	A,003H	;RESET 6850 ACIA
	OUT	CCTRL
	MVI	A,015H
	OUT	CCTRL
	LXI	H,MSGN
	CALL	MSG
TOP:	LXI	H,MSG7	;OUTPUT "TOP OF MEMORY=" TO CONSOLE
	CALL	MSG
	LXI	H,00FFFH	;SET BASE ADDRESS OF TEST RAM -1
FIND:	INX	H	;EXAMINE EACH BYTE
	MOV	A,M
	CMA
	MOV	M,A
	CMP	M
	JZ	FIND
	DCX	H
	CALL	HLOUT
	LXI	H,QTMSG	;OUTPUT "MEMORY QUALIFICATION TEST
			; IS IN PROGRESS" TO CONSOLE
	CALL	MSG
	LXI	H,01000H	;SET MEMORY "BOTTOM" ADDRESS
	SHLD	MBOT
	LXI	H,0C000H	;SET MEMORY "TOP" ADDRESS
	SHLD	MTOP
	LXI	H,TEST	;SAVE "FUNKY RETURN" ADDRESS
	SHLD	MTEST
	JMP	RNDSL	;GO DO RANDOM PATTERNS TEST ON 16K BYTE MEMORY
TEST:	LXI	SP,STACK	;RE-SET THE STACK
	JMP	MEMTS
;
;
;
MNTR:	LXI	SP,STACK
	CALL	CRLF
	MVI	C,'-'	;OUTPUT PROMPT (- CHARACTER)
	CALL	CO
	CALL	CECHO	;ECHO KEY-BOARD INPUT OUT TO CONSOLE
	CPI	'M'
	JZ	MEM	;JUMP TO MEMORY DISPLAY/ALTER,IF "M"
	CPI	'G'
	JZ	GO	;JUMP TO GO TO MEMORY ADDRESS,IF "G"
	CPI	'T'
	JZ	MEMTS	;JUMP TO MEMORY TEST START,IF "T"
LER:	CALL	CRLF	;KEEP IT NEAT
	MVI	C,'?'	;LINE INPUT ERROR,OUTPUT "?" TO CONSOLE
	CALL	CO
	JMP	MNTR
;
;
;
CECHO:	CALL	CI
	MOV	C,A
	CALL	CO
	RET
;
;
;
GO:	LXI	H,MSG2	;OUTPUT "GO ADDRESS=" TO CONSOLE
	CALL	MSG
	CALL	PARAM
	CALL	CRLF
	PCHL
;
;
;
PARAM:	LXI	H,0
PARM1:	CALL	CECHO
	CPI	0DH
	RZ
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	JC	LER
	CALL	NBL
	JC	LER
	ORA	L
	MOV	L,A
	JMP	PARM1
;
;
;
BYTEC:	CALL	CECHO
BYTC1:	CALL	NBL
	JC	LER
	RLC
	RLC
	RLC
	RLC
	PUSH	PSW
	CALL	CECHO
	CALL	NBL
	JC	LER
	POP	B
	ORA	B
	RET
;
;
;
BYTEO:	PUSH	PSW
	CALL	BYTO1
	MOV	C,A
	CALL	CO
	POP	PSW
	CALL	BYTO2
	MOV	C,A
	JMP	CO
BYTO1:	RRC
	RRC
	RRC
	RRC
BYTO2:	ANI	0FH
	CPI	0AH
	JM	BYTO3
	ADI	7
BYTO3:	ADI	30H
	RET
;
;
;
HLCO:	CALL	CRLF
HLOUT:	MOV	A,H
	CALL	BYTEO
	MOV	A,L
	CALL	BYTEO
	RET
;
;
;
DSPYM:	CALL	HLCO
	MVI	C,'='
	CALL	CO
	MOV	A,M
	CALL	BYTEO
	MVI	C,20H
	CALL	CO
	RET
;
;
;
MEM:	LXI	H,MSG1	;OUTPUT "MEMORY ADDRESS=" TO CONSOLE
	CALL	MSG
	CALL	PARAM
MEM1:	CALL	DSPYM
	CALL	CECHO
	CPI	00DH
	JZ	MNTR
	CPI	020H
	JZ	MEM9
	CPI	05EH
	JZ	MEM10
	CALL	BYTC1
	MOV	M,A
	CMP	M
	JZ	MEM9
	MVI	C,' '
	CALL	CO
	MVI	C,'E'
	CALL	CO
MEM9:	INX	H
	JMP	MEM1
MEM10:	DCX	H
	JMP	MEM1
;
;
;
;KEY-BOARD INTERRUPT ROUTINE,KEYED WITH "SPACE-BAR"
;
KBINT:	IN	CCTRL
	ANI	CRRDY
	RZ
	IN	CDATA
	ANI	07FH	;MASK-OFF PARITY BIT
	CPI	020H	;GOT A "SPACE-BAR"?
	JZ	MNTR	;GO TO COMMAND MONITOR,IF SO 
	RET
;
;
;
SP5:	MVI	C,20H
	CALL	CO
SP4:	MVI	C,20H
	CALL	CO
SP3:	MVI	C,20H
	CALL	CO
SP2:	MVI	C,20H
	CALL	CO
SP1:	MVI	C,20H
	CALL	CO
	RET
;
;
;
;
;
;
MSGN:	DB	71,0DH,0AH,'MICROCOSM ASSOCIATES "SUPER MEMORY DIAGNOSTIC"'
	DB	' VERSION 1.01  (C) 1979'
;
MSG1:	DB	14,'EMORY ADDRESS='
;
MSG2:	DB	10,'O ADDRESS='
;
MSG7:	DB	17,0DH,0AH,0AH,'TOP OF MEMORY='
;
QTMSG:	DB	43,0DH,0AH,0AH,'MEMORY QUALIFICATION TEST IS IN PROGRESS'
;
AMMSG:	DB	39,0DH,0AH,0AH,'TEST MEMORY IN "AUTO" MODE (Y OR N)?'
;
DFMSG:	DB	47,0DH,0AH,0AH,'TEST "ALL","SELECT",OR "MONITOR" (A,S OR M)?'
;
TPMSG:	DB	20,' TEST IS IN PROGRESS'
;
TMSG:	DB	17,0DH,0AH,0AH,'TESTING MEMORY'
;
FMSG:	DB	6,',FROM '
;
TOMSG:	DB	4,' TO '
;
PSMSG:	DB	7,0DH,0AH,'PASS='
;
ERMSG:	DB	15,', TOTAL ERRORS='
;
PTSG:	DB	25,0DH,0AH,'GALLOPING PATTERNS TEST'
;
RFMSG:	DB	25,0DH,0AH,'STATIC CHECK CYCLE TEST'
;
CKMSG:	DB	25,0DH,0AH,'CHECKING DATA RETENTION'
;
CLMSG:	DB	24,0DH,0AH,'GALLOPING COLUMNS TEST'
;
RDMSG:	DB	22,0DH,0AH,'RANDOM PATTERNS TEST'
;
SATSG:	DB	23,0DH,0AH,'WRITE SATURATION TEST'
;
WMSG:	DB	23,0DH,0AH,'WALKING PATTERNS TEST'
;
NDMSG:	DB	27,0DH,0AH,0AH,'NO MEMORY BLOCKS DROPPED'
;
DMMSG:	DB	27,0DH,0AH,0AH,'DROPPED MEMORY BLOCK(S)='
;
LMMSG:	DB	22,0DH,0AH,0AH,'LOW MEMORY ADDRESS='
;
HMMSG:	DB	22,0DH,0AH,'HIGH MEMORY ADDRESS='
;
NAMSG:	DB	24,0DH,0AH,'INVALID MEMORY ADDRESS'
;
OPMSG:	DB	20,0DH,0AH,0AH,'TEST OPTIONS ARE:'
;
TMSG1:	DB	30,0DH,0AH,0DH,0AH,'01-GALLOPING PATTERNS TEST'
;
TMSG2:	DB	27,0DH,0AH,'02-GALLOPING COLUMNS TEST'
;
TMSG3:	DB	26,0DH,0AH,'03-WALKING PATTERNS TEST'
;
TMSG4:	DB	25,0DH,0AH,'04-RANDOM PATTERNS TEST'
;
TMSG5:	DB	26,0DH,0AH,'05-WRITE SATURATION TEST'
;
TMSG6:	DB	28,0DH,0AH,'06-STATIC CHECK CYCLE TEST'
;
TMSGN:	DB	44,0DH,0AH,0AH,'ENTER TEST NUMBER (01,02,03,04,05 OR 06)='
;
EPMSG:	DB	24,0DH,0AH,0AH,'ENTER PATTERN(00-FF)='
;
REMSG:	DB	29,0DH,0AH,'RETENTION ERROR AT ADDRESS='
;
EXMSG:	DB	31,0DH,0AH,'EXPECTED "00" DATA,READ BACK '
;
MRER1:	DB	20,0DH,0AH,'ERROR AT ADDRESS=',0
;
MRER2:	DB	12,'  READ BACK '
;
MRER3:	DB	11,' ,EXPECTED '
;
MRER4:	DB	27,0DH,0AH,'LAST ADDRESS WRITTEN WAS '
;
MRER5:	DB	14,20H,',PATTERN WAS '
;
MRER6:	DB	26,0DH,0AH,'ERROR READING OTHER CELL'
;
MRER7:	DB	25,0DH,0AH,'ERROR READING TEST CELL'
;
MRER8:	DB	12,0DH,0AH,'TEST CELL='
;
MRER9:	DB	13,', OTHER CELL='
;
MER10:	DB	18,20H,20H,'PATTERN STORED=',0
;
MER11:	DB	16,20H,20H,'PATTERN READ=',0
;
MER12:	DB	19,0DH,0AH,'BIT(S) IN ERROR=',0
;
;
;
;
;
MSG:	PUSH	PSW
	PUSH	B
	MOV	B,M
	INX	H
MSGA:	MOV	C,M
	CALL	CO
	INX	H
	DCR	B
	JNZ	MSGA
	POP	B
	POP	PSW
	RET
;
;
;
;
;
;
;ROUTINE TO FIND ALL 4K MEMORY BLOCKS AVAILABLE TO SYSTEM
;
MEMTS:	LXI	H,00000H	;CLEAR THE PASS AND ERROR COUNTERS
	SHLD	PCTR
	SHLD	ECTR
	LXI	B,MBUF	;POINT TO MEMORY BUFFER
	MVI	E,1	;SET-UP BASE RAM 1ST 4K BYTE TEST ADDRESS
STAAD:	MOV	A,E
	STAX	B	;SAVE IT IN BUFFER
	INX	B
INC4K:	MVI	A,00BH	;INCREMENT TO NEXT 4K MEMORY BLOCK,STOP IF ALL
			; MEMORY BLOCKS TRIED,FOR 16 K BYTE MEMORY
	INR	E	;BUMP FOR NEXT MEMORY BLOCK
	CMP	E	;ALL DONE?
	JP	STAAD	;IF NOT,GO TEST THIS NEW MEMORY BLOCK 
	MVI	A,080H	;YES,TAG WITH "END" IN BUFFER
	STAX	B
AUT:	LXI	H,AMMSG	;OUTPUT "TEST MEMORY IN "AUTO" MODE (Y OR N)?"
	CALL	MSG
	CALL	CECHO	;GET THE ANSWER 
	CPI	'Y'
	JZ	AUTO	;DO AUTO MODE,IF YES
	CPI	'N'
	JZ	SELCT	;LET OPERATOR SELECT,IF NO
	JMP	AUT	;OOPS...GAVE HIM TWO CHOICES,AND HE PICKED THIRD 
AUTO:	CALL	KBINT	;CHECK FOR KEY-BOARD INTERRUPT
	LXI	H,DROP	;SET-UP DROP LIST POINTER
	SHLD	DROPP	;SET DROP LIST POINTER TO START
	XRA	A	;CLEAR DROP COUNT AND ERROR FLAG
	DCX	H
	MOV	M,A
	DCX	H
	MOV	M,A
AUTO0:	LXI	H,MBUF	;POINT TO MEMORY BUFFER
	SHLD	MEMPT	;SAVE MEMORY POINTER FOR LOOPING
AUTO1:	LDA	ERFLG	;GET ERROR FLAG,TO SEE IF WE DROP MEMORY
			; BLOCK JUST TESTED OR NOT 
	ORA	A
	JZ	AUTO3	;IF NOT ZERO,DROP THIS BLOCK FROM TEST 
	LHLD	DROPP	;POINT TO NEXT DROP LIST SLOT
	XCHG
	LHLD	BLKST	;GET MEMORY BLOCK START ADDRESS
	XCHG		;AND NOW WE HAVE H&L REGS.AS DROP LIST POINTER,
			; AND D&E REGS. AS THE BLOCK START 
	MOV	M,E	;SAVE LOW BYTE OF BLOCK START
	INX	H
	MOV	M,D	;SAVE HIGH BYTE OF BLOCK START
	INX	H	;GET H&L REGS. TO POINT TO NEXT DROP LIST SLOT 
	SHLD	DROPP	;SAVE THE NEW POINTER
	LXI	H,DROPC	;+1 TO THE DROP COUNT
	INR	M
	LHLD	MEMPT	;GET THE MEMORY BLOCK POINTER
	DCX	H	;BACK-UP TO MEMORY BLOCK JUST TESTED,AND LOG IT OUT 
	MVI	M,000H
AUTO3:	MVI	A,9	;SET ERROR DISPLAY COUNTER TO 8 PLUS 1
	STA	ERCNT
	XRA	A	;CLEAR ERROR FLAG
	STA	ERFLG
	LHLD	MEMPT	;GET MEMORY BLOCK AND BLOCK NUMBER
	MOV	A,M
	INX	H	;UPDATE AND SAVE NEW POINTER
	SHLD	MEMPT
	ORA	A	;TEST THE MEMORY BLOCK NUMBER
	JM	AUTO0	;RE-START IF "END" OF BUFFER
	JZ	AUTO3	;TRY NEXT ONE,IF DROPPED MEMORY BLOCK 
	RLC		;CONVERT MEMORY BLOCK NUMBER TO 4K BLOCK ADDRESS
	RLC
	RLC
	RLC
	MVI	L,000H	;ZERO L REG.
	MOV	H,A	;MAKE A 16 BIT BLOCK ADDRESS OUT OF THIS,
			; AND SAVE AS BLOCK STARTING ADDRESS
	SHLD	BLKST
	ADI	010H	;ADD 4K TO START
	MOV	H,A
	SHLD	MEND	;SAVE AS MEMORY BLOCK END ADDRESS +1
	LXI	H,AUTO1	;SAVE "AUTO1" FOR LOOPING ADDRESS
	SHLD	AUTOR
	LXI	H,TMSG	;OUTPUT "TESTING MEMORY " TO CONSOLE
	CALL	MSG
	LXI	H,FMSG	;OUTPUT ", FROM " TO CONSOLE
	CALL	MSG
	LHLD	BLKST	;GET THE MEMORY BLOCK STARTING ADDRESS
	CALL	HLOUT
	LXI	H,TOMSG	;OUTPUT " TO " TO CONSOLE
	CALL	MSG
	LHLD	MEND	;GET THE MEMORY ENDING ADDRESS
	CALL	HLOUT
	LXI	H,PSMSG	;OUTPUT "PASS=" TO CONSOLE
	CALL	MSG
	LHLD	PCTR	;GET THE PASS COUNTER,AND UPDATE IT
	INX	H
	SHLD	PCTR
	CALL	HLOUT
	LXI	H,ERMSG	;OUTPUT ", ERRORS TOTAL=" TO CONSOLE
	CALL	MSG
	LHLD	ECTR	;GET THE ERROR COUNTER,AND SHOW IT ALSO 
	CALL	HLOUT
	LXI	H,WRTSAT	;SAVE "NEXT TEST" ADDRESS
	SHLD	MTEST
	JMP	RANPT	;GO DO RANDOM PATTERNS MEMORY TEST
;
;
;
;ROUTINE TO DO WRITE AMPLIFIER SATURATION TEST IN "AUTO MODE"
;
WRTSAT:	LXI	SP,STACK	;SET THE STACK POINTER
	LXI	H,SATSG	;OUTPUT "WRITE SATURATION TEST" TO CONSOLE
	CALL	MSG
	LHLD	BLKST	;GET MEMORY BLOCK STARTING ADDRESS
	SHLD	MBOT	;SAVE AS MEMORY BOTTOM ADDRESS
	LHLD	MEND	;GET MEMORY BLOCK END ADDRESS
	SHLD	MTOP	;SAVE A MEMORY "TOP" ADDRESS
	MVI	B,100	;SET-UP FOR 100 WRITE SATURATION PASSES
	XRA	A	;SATURATE WITH 0'S FIRST
	CALL	SAT	;WRITE WITH PATTERN,100 TIMES
	MVI	A,0FFH	;FLIP PATTERN TO 1'S
	CALL	BAKPT	;WRITE 1 TIME ONLY
	CALL	SATRD	;DO SATURATION READ
	MVI	B,100	;AGAIN SET-UP 100 WRITE SATURATION PASSES
	MVI	A,0FFH	;NOW SATURATE WITH 1'S
	CALL	SAT	;WRITE WITH PATTERN,100 TIMES
	XRA	A	;FLIP PATTERN TO 0'S
	CALL	BAKPT	;WRITE 1 TIME ONLY
	CALL	SATRD	;DO SATURATION READ
	JMP	GAL	;GO DO "GALLOPING PATTERNS" MEMORY TEST
;
;
;
;ROUTINE TO DO WRITE SATURATION TEST IN "SELECT MODE"
;
WSATT:	MVI	B,100	;SET-UP FOR 100 WRITE SATURATION PASSES
	CALL	SAT	;WRITE WITH SELECTED PATTERN,100 TIMES
	CMA		;WRITE WITH COMPLEMENT,1 PASS
	CALL	BAKPT
	CALL	SATRD	;READ THE DATA
	LDA	TPATT	;GET SAVED TEST PATTERN
	MVI	B,100	;NOW DO COMPLEMENT 100 TIMES
	CALL	SAT	;....AND WE'RE OFF
	CMA		;WRITE WITH COMPLEMENT,1 PASS
	CALL	BAKPT
	CALL	SATRD	;READ THE DATA
	RET
;
;
;
;SUBROUTINE TO READ 1 PASS "BACKGROUND" PATTERN AS CONTAINED IN A REG.
;
SATRD:	LHLD	MTOP	;GET MEMORY "TOP" ADDRESS
	XCHG		;SWAP H&L REGS. TO D&E REGS.
	LHLD	MBOT	;TOP'S IN D&E REGS.,BOTTOM'S IN H&L REGS.
	MOV	B,A	;SAVE PATTERN IN B REG.
	STA	TPATT	;SAVE DATA PATTERN FOR POSSIBLE ERROR DISPLAY
FSTRD:	CALL	COMP	;ALL DONE?
	RZ
	MOV	A,M	;GET A BYTE FROM MEMORY
	CMP	B	;GOT A MATCH?
	CNZ	SATER	;INDICATE "WRITE SATURATION" ERROR IF NO MATCH
	INX	H	;BUMP POINTER FOR NEXT BYTE
	JMP	FSTRD	;DO FAST READ ON MORE MEMORY
;
;
;
SAT:	PUSH	PSW	;EXILE THE A REG.
	CALL	KBINT	;CHECK KEY-BOARD INTERRUPT
	POP	PSW	;BACK FROM EXILE
	PUSH	B	;SAVE PASSES ON STACK
	CALL	BAKPT	;WRITE THE "BACKGROUND" PATTERN
	POP	B	;GET PASS COUNT
	DCR	B	;DE-BUMP THE PASS COUNT
	JNZ	SAT	;CONTINUE WRITING 'TILL 100 PASSES COMPLETED
	RET
;
;
;
;SUBROUTINE TO INDICATE ERROR IN WRITE SATURATION TEST
;
SATER:	STA	ERPAT	;SAVE "BAD" BYTE
	MVI	A,0FFH	;SET ERROR FLAG
	STA	ERFLG
	PUSH	H	;SAVE BAD BYTE ADDRESS
	LHLD	ECTR	;UPDATE THE ERROR COUNTER
	INX	H
	SHLD	ECTR
	LDA	ERCNT	;DONE DISPLAYING ALL ERRORS?
	DCR	A
	JZ	PTX	;DON'T DISPLAY ANY MORE ERRORS,IF SO
	STA	ERCNT
	LXI	H,MRER1	;OUTPUT " ERROR AT ADDRESS=" TO CONSOLE
	CALL	MSG
	POP	H	;GET BAD BYTE ADDRESS,BUT DON'T
			; CHANGE THE STACK
	PUSH	H
	CALL	HLOUT
	LXI	H,MRER2	;OUTPUT "  READ BACK " TO CONSOLE
	CALL	MSG
	LDA	ERPAT	;GET ERROR PATTERN
	CALL	BYTEO	;SHOW IT
	LXI	H,MRER3	;OUTPUT " , EXPECTED " TO CONSOLE
	JMP	SATX	;DISPLAY EXPECTED DATA PATTERN AND EXIT
;
;
;
;ROUTINE TO DO STATIC CHECK CYCLE TEST IN "SELECT MODE"
;
STATT:	MVI	A,0FFH	;ALL 1'S PATTERN FOR FIRST PORTION OF TEST
	PUSH	PSW	;SAVE THE PATTERN
	CALL	BAKPT	;WRITE IT
	LXI	B,500*5	;DO 5 MINUTE DELAY "DO NOTHING"
	CALL	LOOP1
	POP	PSW	;GET PATTERN
	CALL	SATRD	;READ AFTER DELAY TIME
	XRA	A	;ALL 0'S PATTERN FOR SECOND PORTION OF TEST
	PUSH	PSW	;SAVE THE PATTERN
	CALL	BAKPT	;WRITE IT
	LXI	B,500*5	;DO 5 MINUTE DELAY "DO NOTHING"
	CALL	LOOP1
	POP	PSW	;GET PATTERN
	CALL	SATRD	;CHECK DATA AFTER 5 MINUTE DELAY
	RET
;
;
;
;ROUTINE TO DO "GALLOPING" MEMORY TEST IN 256 BYTE CHUNKS
; (MEMORY DATA WILL BE FF HEX AND THEN 00 HEX)
;
GAL:	LXI	H,PTSG	;OUTPUT "GALLOPING PATTERN MEMORY TEST" TO CONSOLE
	CALL	MSG
	LHLD	BLKST	;GET MEMORY BLOCK STARTING ADDRESS
GAL1:	SHLD	MBOT	;SAVE AS "CHUNK" START
	INR	H	;ADD 256
	MVI	L,000H	;CLEAN-UP L REG.
	SHLD	MTOP	;SAVE AS "CHUNK" END +1
	MVI	A,0FFH	;ALL ONES BACK-GROUND PATTERN
	CALL	GALPT	;TEST THE "CHUNK" WITH 1'S
	XRA	A	;ALL ZEROS BACK-GROUND PATTERN
	CALL	GALPT	;TEST THE "CHUNK" WITH 0'S
	LHLD	MEND	;GET "CHUNK" AND MEMORY BLOCK END
	CALL	COMP	;HAVE WE DONE ALL 16 "CHUNKS" IN THE MEMORY BLOCK?
	JZ	STATIC	;IF DONE,GO DO 1 MINUTE STATIC TEST
	XCHG		;OH...GO DO NEXT "CHUNK" IN SAME MEMORY BLOCK
	JMP	GAL1
;
;
;
STATIC:	LXI	H,RFMSG	;OUTPUT "STATIC CHECK CYCLE" TO CONSOLE
	CALL	MSG
	LXI	B,500
	CALL	LOOP1	;DO ONE MINUTE DELAY FOR STATIC CHECK
	LXI	H,CKMSG	;OUTPUT "CHECKING DATA RETENTION" TO CONSOLE
	CALL	MSG
	LHLD	MEND	;GET MEMORY BLOCK END
	XCHG		;SWAP TO D&E REGS.
	LHLD	BLKST	;GET MEMORY BLOCK STARTING ADDRESS
	XRA	A	;MAKE A 0'S BYTE FOR COMPARE
LOOP3:	CMP	M	;TEST "GALLOPING PATTERN" RESULT BYTE
	CNZ	RFERR	;IF IT DIDN'T SURVIVE,REPORT RETENTION ERROR 
	INX	H	;BUMP FOR NEXT TEST BYTE
	CALL	COMP	;HAVE WE CHECKED THE WHOLE MEMORY BLOCK?
	JC	LOOP3	;IF NOT,DO IT   
	LXI	H,CLMSG	;OUTPUT "GALLOPING COLUMN MEMORY TEST" TO CONSOLE
	CALL	MSG
	LHLD	BLKST	;GET MEMORY BLOCK START
	SHLD	MBOT	;SAVE IT FOR FUTURE USE IN "GALLOPING COLUMN"
	LHLD	MEND	;GET MEMORY BLOCK END
	SHLD	MTOP	;SAVE FOR FUTURE USE IN "GALLOPING COLUMN"
	MVI	A,0FFH	;SET-UP ALL ONES PATTERN
	CALL	GALCL	;DO "GALLOPING COLUMN"
	XRA	A	;SET-UP ALL ZEROS PATTERN
	CALL	GALCL	;TEST THE MEMORY BLOCK AGAIN 
;
;
;
;ROUTINE TO WALK PATTERNS THRU THE MEMORY BLOCK IN 256 BYTE "CHUNKS",
; (WRITES 1'S,WALKS 0'S,THEN WRITES 0'S,AND THEN WALKS 1'S)
;
WALK:	LXI	H,WMSG	;OUTPUT "WALKING PATTERNS MEMORY TEST" TO CONSOLE
	CALL	MSG
	LHLD	BLKST	;GET MEMORY BLOCK STARTING ADDRESS
WALK1:	SHLD	MBOT	;SAVE AS "CHUNK" STARTING ADDRESS
	INR	H	;ADD 256
	MVI	L,000H	;SCRUB L REG. 
	SHLD	MTOP	;SAVE RESULT AS "CHUNK" END +1
	MVI	A,0FFH	;MAKE AN ALL 1'S PATTERN BYTE
	CALL	WALKT	;LET'S GO FOR A WALK 
	XRA	A	;MAKE AN ALL 0'S PATTERN BYTE
	CALL	WALKT	;MAYBE WE COULD JOG FOR AWHILE?
	LHLD	MEND	;GET "CHUNK" AND BLOCK END
	CALL	COMP	;ALL THE "CHUNKS" DONE IN THE BLOCK?
	JZ	TEND	;IF ZERO,GO TO NEXT MEMORY BLOCK IN AUTO SEQUENCE
	XCHG		;NO? GET NEW "CHUNK" START ADDRESS
	JMP	WALK1	;GO TEST NEW "CHUNK"   
TEND:	CALL	CDROP	;SHOW ANY "DROPPED BLOCKS"
	LHLD	AUTOR	;GET "AUTO1" RETURN ADDRESS
	PCHL		;GO FOR IT   
;
;
;
;ROUTINE TO DO RANDOM MEMORY TEST IN "SELECT MODE"
;
RNDSL:	LHLD	MTOP	;GET OPERATOR SELECTED MEMORY "TOP" ADDRESS
	MOV	B,H	;SAVE IT IN B&C REGS.
	MOV	C,L
	DCX	B	;DE-BUMP B&C REGS. TO GET PROPER "TOP"
			; MEMORY BOUNDRY ADDRESS
	LHLD	MBOT	;GET OPERATOR SELECTED MEMORY "BOTTOM" ADDRESS
	JMP	RANST	;GO TO RANDOM PATTERNS TEST START 
;
;
;
;ROUTINE TO DO RANDOM PATTERNS MEMORY TEST IN "AUTO MODE"
;
RANPT:	LXI	H,RDMSG	;OUTPUT "RANDOM PATTERNS MEMORY TEST" TO CONSOLE
	CALL	MSG
RANMT:	LHLD	MEND	;GET MEMORY BLOCK END ADDRESS INTO B&C REGS.
	MOV	B,H
	MOV	C,L
	DCX	B	;DE-BUMP B&C REGS. TO GET PROPER BLOCK END
			; BOUNDRY ADDRESS
	DCX	B
	DCX	B
	LHLD	BLKST	;GET MEMORY BLOCK START ADDRESS INTO H&L REGS.,
			; AND D&E REGS.
RANST:	MOV	D,H
	MOV	E,L
	SPHL		;STUFF H&L REGS. INTO SP REG.
	LXI	H,1	;MAKE A STARTING "SEED" FOR FIRST RANDOM PATTERN
;
;
;
;"STORR", STORES RANDOM NUMBERS THROUGHOUT THE MEMORY TEST AREA BY
;USING RANDOM NUMBERS,CAUSING MOST PATTERN SENSITIVE AND ADDRESSING
;PROBLEMS TO BE CAUGHT.THE NUMBERS ARE STORED USING THE
;8080/8085 "PUSH" COMMAND WHICH STORES TWO ADJACENT BYTES IN THE
;FASTEST MANNER POSSIBLE.
;
STORR:	INX	SP	;BUMP STACK POINTER BY 2'S
	INX	SP
	PUSH	H	;STUFF THE RANDOM DATA BYTE INTO MEMORY
	POP	H
	LXI	H,0	;SCRUB H&L REGS.
	DAD	SP	;GET THE CURRENT TEST CELL ADDRESS
	MOV	A,C	;GET LOW BYTE OF MEMORY TOP ADDRESS
	SUB	L	;SUBTRACT LOW BYTE OF TEST CELL
	MOV	A,B	;GET HIGH BYTE OF MEMORY TOP ADDRESS,
			; AND SAVE CARRY ONLY
	SBB	H	;SUBTRACT HIGH BYTE OF TEST CELL ADDRESS
	JC	DONE1	;IF WE GOT THE CARRY,WERE DONE   
	DCX	SP	;NO,NOT DONE YET
	DCX	SP
	POP	H
	MOV	A,L	;MAKE MORE "HASH" FOR MEMORY PATTERNS
	ADD	A
	MOV	L,A
	MOV	A,H
	RAL
	MOV	H,A
	MVI	A,0
	ADC	L
	MOV	L,A
	MOV	A,H
	RLC
	RLC
	RLC
	XRA	L
	RRC
	RRC
	ANI	1
	XRA	L
	MOV	L,A
	JMP	STORR
;
;
;
;"DONE1" CHECKS THE FIRST TWO BYTES FOR ERRORS AND ALSO CHECKS
;TO SEE WHICH PASS-THROUGH THE PROGRAM IS ON.
;
DONE1:	MOV	L,E
	MOV	H,D
	MVI	A,1
	CMP	M
	JNZ	CHECK
	DCR	A
	INX	H
	CMP	M
	JNZ	ERROR
	JMP	CHKR
;
;
;
CHECK:	MVI	A,0FEH
	CMP	M
	MVI	A,1
	JNZ	ERROR
	DCR	A
	DCR	A
	INX	H
	CMP	M
	JNZ	ERROR
;
;
;
;"CHKR" GOES BACK AND CHECKS TO SEE IF WHAT IS STORED
;THROUGHOUT MEMORY,IS STILL THE SAME AS WHEN IT WAS STORED.
;
CHKR:	MOV	A,M
	RAL
	DCX	H
	MOV	A,M
	RAL
	MOV	M,A
	INX	H
	MOV	A,M
	RAL
	MOV	M,A
	INX	H
	MOV	A,C
	SUB	L
	MOV	A,B
	SBB	H
	JC	DONE2
	DCX	H
	MOV	A,M
	RLC
	RLC
	RLC
	DCX	H
	XRA	M
	RRC
	RRC
	ANI	1
	XRA	M
	INX	H
	INX	H
	CMP	M
	JNZ	ERROR
	INX	H
	MOV	A,C
	SUB	L
	MOV	A,B
	SBB	H
	JC	DONE2
	DCX	H
	DCX	H
	MOV	A,M
	INX	H
	INX	H
	CMP	M
	JNZ	ERROR
	JMP	CHKR
;
;
;
;"DONE2" CHECKS TO SEE WHICH TEST HAS JUST BEEN DONE.  IF IT WAS
;THE FIRST TEST THEN IT SETS UP TO TEST THE COMPLIMENT, ELSE IT
;SETS UP FOR THE FINAL FOUR TESTS
;
DONE2:	MOV	L,E
	MOV	H,D
	SPHL
	LXI	H,0FFFEH
	LDAX	D
	CPI	2
	JZ	STORR
	MOV	L,E
	MOV	H,D
	LXI	D,0AA55H
;
;
;
;"STOAL" STORES THE TWO BYTES IN THE D&E REGISTERS (AA HEX AND 55 HEX)
;THROUGHOUT THE TEST AREA
;
STOAL:	MOV	M,D
	INX	H
	MOV	M,E
	INX	H
	MOV	A,C
	SUB	L
	MOV	A,B
	SBB	H
	JNZ	STOAL
	LXI	H,0
	DAD	SP
;
;
;
;"CHKAL" TEST TO SEE IF THE DATA STORED THROUGHOUT MEMORY IS THE
;SAME AS THE D&E REGISTERS
;
CHKAL:	MOV	A,D
	MOV	D,E
	MOV	E,A
	CMP	M
	JNZ	ERROR
	INX	H
	MOV	A,C
	SUB	L
	MOV	A,B
	SBB	H
	JNZ	CHKAL
;
;
;
;THIS ROUTINE FINDS OUT WHICH PASS THE TEST IS ON,
;AND THEN SETS UP TO DO THE NEXT TEST
;
	LXI	H,0
	DAD	SP
	LXI	D,055AAH
	MOV	A,M
	CPI	0AAH
	JZ	STOAL
	LXI	D,0FFFFH
	CPI	055H
	JZ	STOAL
	LXI	D,0
	INR	A
	JZ	STOAL
	LHLD	MTEST	;GO DO NEXT MEMORY TEST,WERE DONE HERE 
	PCHL
;
;
;
;THIS ROUTINE PRINTS OUT WHAT IS POINTED TO IN MEMORY BY
;THE B&C REGISTERS UNTIL A ZERO BYTE IS FOUND.
;
MSGOUT:	LDAX	B
	ANA	A
	JNZ	AR1	;CHECKS FOR '0' END OF MESSAGE FLAG
	PCHL
AR1:	IN	CCTRL
	ANI	CTRDY
	JZ	AR1	;CHECK IF CONSOLE READY
	LDAX	B
	OUT	CDATA
	INX	B	;OUTPUT CHARACTER
	JMP	MSGOUT
;
;
;
;THE "ERROR" ROUTINE PRINTS OUT THAT THERE HAS BEEN AN ERROR AT
;THE ADDRESS IN THE H&L REGISTERS.IT THEN TELLS THAT THE TEST
;BYTE IS THE BYTE IN THE ACCUMULATOR AND THE ERROR BYTE IS THE
;BYTE POINTED TO BY THE H&L REGISTERS.FINALLY IT PRINTS OUT THE
;BITS THAT ARE IN DISAGREEMENT IN THE TWO BYTES.
;
ERROR:	SPHL
	MVI	A,0FFH	;SET ERROR FLAG
	STA	ERFLG
	LDA	ERCNT	;DONE SHOWING 8 ERRORS?
	DCR	A
	JZ	ER9
	STA	ERCNT
	LXI	H,ER1
	MOV	D,A
	LXI	B,MRER1	;OUTPUT "ERROR AT ADDRESS=" TO CONSOLE
	JMP	MSGOUT
;
ER1:	LXI	H,0
	DAD	SP
	MOV	B,D
	XCHG
	LXI	H,ER2
	JMP	OUTER
;
ER2:	MOV	D,E
	LXI	H,ER3
	JMP	OUTER
;
ER3:	MOV	D,B
	LXI	B,MER10	;OUTPUT "PATTERN STORED=" TO CONSOLE
	LXI	H,ER4
	JMP	MSGOUT
;
ER4:	LXI	H,ER5
	JMP	OUTER
;
ER5:	LXI	B,MER11	;OUTPUT "PATTERN READ=" TO CONSOLE
	LXI	H,ER6
	JMP	MSGOUT
;
ER6:	LXI	H,0
	DAD	SP
	MOV	E,D
	MOV	D,M
	LXI	H,ER7
	JMP	OUTER
;
ER7:	LXI	B,MER12	;OUTPUT "BITS IN ERROR=" TO CONSOLE
	LXI	H,ER8
	JMP	MSGOUT
;
ER8:	MVI	D,0
	MVI	B,1
	LXI	H,0
	DAD	SP
	MOV	A,E
	XRA	M
	MOV	E,A
;
LOP:	INR	D
	MOV	A,E
	RAR
	MOV	E,A
	JNC	NOERR
;
	DCR	B
	JZ	LOPE
LUPE:	IN	CCTRL
	ANI	CTRDY
	JZ	LUPE
	MVI	A,','
	OUT	CDATA
LOPE:	IN	CCTRL
	ANI	CTRDY
	JZ	LOPE
	MOV	A,D
	ADI	2FH
	OUT	CDATA
NOERR:	MOV	A,D
	CPI	8
	JNZ	LOP
ER9:	LHLD	ECTR	;UPDATE THE ERROR COUNTER
	INX	H
	SHLD	ECTR
	LHLD	MTEST	;RETURN
	PCHL
;
;
;
OUTER:	IN	CCTRL
	ANI	CTRDY
	JZ	OUTER
	MOV	A,D
	RLC
	RLC
	RLC
	RLC
	ANI	0FH
	CPI	0AH
	JC	OUTR1
	ADI	7
OUTR1:	ADI	'0'
	OUT	CDATA
OUTR2:	IN	CCTRL
	ANI	CTRDY
	JZ	OUTR2
	MOV	A,D
	ANI	0FH
	CPI	0AH
	JC	OUTR3
	ADI	7
OUTR3:	ADI	'0'
	OUT	CDATA
	PCHL
;
;
;
;
;
;
;ROUTINE TO SHOW THE "DROP LIST" TO THE OPERATOR
;
CDROP:	LDA	DROPC	;GET THE DROP COUNT 
	ORA	A	;DID WE LOSE ANYBODY?
	JNZ	PDROP
	LXI	H,NDMSG	;OUTPUT "NO MEMORY BLOCKS DROPPED" TO CONSOLE
	CALL	MSG
	RET
PDROP:	LXI	H,DROP	;POINT TO START OF THE DROP LIST
EDROP:	PUSH	PSW	;SAVE THE DROP COUNT
	PUSH	H	;SAVE THE DROP POINTER
	LXI	H,DMMSG	;OUTPUT "DROPPED MEMORY BLOCK(S)=" TO CONSOLE
	CALL	MSG
	POP	H	;GET THE DROP POINTER BACK
	MOV	E,M
	INX	H
	MOV	D,M
	INX	H	;WERE NOW POINTING TO THE NEXT DROP LIST SLOT
	XCHG		;GET THE ADDRESS OF THE DROPPED MEMORY BLOCK
	CALL	HLOUT
	XCHG		;SWAP'EM
	POP	PSW	;GET THE DROP COUNT
	DCR	A	;DE-BUMP IT 
	JNZ	EDROP	;DO THEM ALL 
	RET
;
;
;
;"SELECT" MODE ROUTINE (OPERATOR DEFINES ADDRESS RANGE,PATTERN,AND TEST)
;
SELCT:	MVI	A,0FFH	;SET ERROR DISPLAY COUNT TO 256
	STA	ERCNT
	LXI	H,SELCT	;MAKE A RETURN ADDRESS FOR END OF TEST
	SHLD	MTEST
MENU:	LXI	H,DFMSG	;OUTPUT "TEST "ALL","SELECT",OR "MONITOR" (Y OR N)?"
			; TO CONSOLE
	CALL	MSG
	CALL	CECHO	;GET THE ANSWER
	CPI	'A'	;"ALL" CHOSEN?
	JZ	ALL
	CPI	'S'	;"SELECT" CHOSEN?
	JZ	SEL
	CPI	'M'	;"MONITOR" CHOSEN?
	JZ	MNTR
	JMP	MENU	;OOPS...NONE OF THE ABOVE,TRY AGAIN
ALL:	LXI	H,01000H	;SET MEMORY "BOTTOM"
	SHLD	MBOT
	LXI	H,0C000H	;SET MEMORY "TOP"
	SHLD	MTOP
	JMP	SEL1	;TEST "ALL".....
SEL:	LXI	H,LMMSG	;OUTPUT "LOW MEMORY ADDRESS=" TO CONSOLE
	CALL	MSG
	CALL	PARAM	;GET IT FROM OPERATOR 
	MOV	A,H	;IS THE REQUESTED ADDRESS <1000 HEX?
	CPI	010H
	JNC	SEL0
	LXI	H,NAMSG	;OOPS...NOT ALLOWED,OUTPUT "INVALID
			; MEMORY ADDRESS" TO CONSOLE
	CALL	MSG
	JMP	SEL	;GIVE'M ANOTHER CHANCE
SEL0:	SHLD	MBOT	;SAVE IT AS MEMORY "BOTTOM" ADDRESS
	LXI	H,HMMSG	;OUTPUT "HIGH MEMORY ADDRESS=" TO CONSOLE
	CALL	MSG
	CALL	PARAM	;GET IT FROM OPERATOR
	XCHG		;SWAP TO D&E REGS.
	MOV	A,D	;GET THE HIGH BYTE OF "TOP" MEMORY ADDRESS
	LHLD	MBOT	;GET MEMORY "BOTTOM" ADDRESS
	CMP	H	;IS THE TOP < BOTTOM?
	JNC	STOTOP	;IF NOT,STORE THE "TOP" FOR SAFE KEEPING
	LXI	H,NAMSG	;ARE YOU POSSIBLY ATTEMPTING TO TRY MY PATIENCE?
	CALL	MSG
	JMP	SELCT	;TRY AGAIN,AND AGAIN,AND AGAIN,AND.......
STOTOP:	XCHG		;GET THE "TOP" BACK TO H&L REGS.
	INX	H	;GO ONE PAST THE END,AND SAVE IT
	SHLD	MTOP
SEL1:	LXI	H,OPMSG	;OUTPUT "TEST OPTIONS ARE:" TO CONSOLE
	CALL	MSG
	LXI	H,TMSG1	;OUTPUT " 01-GALLOPING PATTERNS TEST" TO CONSOLE
	CALL	MSG
	LXI	H,TMSG2	;OUTPUT " 02-GALLOPING COLUMNS TEST" TO CONSOLE
	CALL	MSG
	LXI	H,TMSG3	;OUTPUT " 03-WALKING PATTERNS TEST" TO CONSOLE
	CALL	MSG
	LXI	H,TMSG4	;OUTPUT " 04-RANDOM PATTERNS TEST" TO CONSOLE
	CALL	MSG
	LXI	H,TMSG5	;OUTPUT " 05-WRITE SATURATION TEST" TO CONSOLE
	CALL	MSG
	LXI	H,TMSG6	;OUTPUT " 06-STATIC CHECK CYCLE TEST" TO CONSOLE
	CALL	MSG
	LXI	H,TMSGN	;OUTPUT " ENTER TEST NUMBER(01,02,03,04,05 OR 06)="
	CALL	MSG
	CALL	CONI	;GET THE ANSWER 
	CPI	000H	;HMMMM....DID HE PICK 00 HEX?
	JZ	SEL1	;IF SO,START HIM ALL OVER AGAIN 
	CPI	007H	;TEST NUMBER SELECTED >6?
	JNC	SEL1	;IF YES,GIVE THE JERK ANOTHER CHANCE 
	MOV	B,A	;SAVE THE TEST NUMBER IN B REG.
	LXI	H,EPMSG	;OUTPUT "ENTER PATTERN(00-FF)=" TO CONSOLE
	CALL	MSG
	CALL	CONI	;GET THE REQUESTED PATTERN
	MOV	C,A	;SAVE IT IN C REG.
	PUSH	B	;EXILE THE TEST NUMBER
	LXI	H,TPMSG	;OUTPUT "  TEST IS IN PROGRESS" TO CONSOLE
	CALL	MSG
	POP	B	;FROM WHENCE THY CAME...
	LXI	D,SELCT	;GO BACK TO "SELECT MODE" AFTER TEST COMPLETION
	PUSH	D
	DCR	B	;ADJUST THE TEST NUMBER FOR THE TABLE JUMP
	MOV	A,B
	RLC
	ADD	B
	MOV	E,A
	MVI	D,000H	;MAKE A 16 BIT INDEX
	LXI	H,BTAB	;GET THE TABLE BASE
	MOV	A,C	;GET BACK THE SAVED PATTERN
	DAD	D	;GET H&L REGS. TO EQUAL THE ADRESS OF THE JUMP 
	PCHL		;GO FOR IT   
BTAB:	JMP	GALPT	;GO DO "GALLOPING PATTERNS TEST"
	JMP	GALCL	;GO DO "GALLOPING COLUMNS TEST"
	JMP	WALKT	;GO DO "WALKING PATTERNS TEST"
	JMP	RNDSL	;GO DO "RANDOM PATTERNS TEST"
	JMP	WSATT	;GO DO "WRITE SATURATION TEST"
	JMP	STATT	;GO DO "STATIC CHECK CYCLE TEST"
	RET		;THIS SHOULD'NT GET USED   
;
;
;
;SUBROUTINE TO INDICATE RETENTION ERROR (GALLOPING PATTERN BAD AFTER 1 MINUTE)
;
RFERR:	CMA		;MAKE ERROR FLAG NON-ZERO
	STA	ERFLG
	CMA
	PUSH	H	;SAVE ERROR BYTE ADDRESS
	LHLD	ECTR	;UPDATE THE ERROR COUNTER
	INX	H
	SHLD	ECTR
	LDA	ERCNT	;DONE DISPLAYING ALL ERRORS?
	DCR	A
	JZ	RFX
	STA	ERCNT
	LXI	H,REMSG	;OUTPUT " RETENTION ERROR AT ADDRESS="
	CALL	MSG
	POP	H	;GET THE ERROR BYTE ADDRESS
	CALL	HLOUT
	PUSH	H	;SAVE ERROR BYTE ADDRESS FOR EXIT
	CALL	MSG
	LXI	H,EXMSG	;OUTPUT "EXPECTED "00" DATA,READ BACK " TO CONSOLE
	CALL	MSG
	POP	H	;RESTORE POINTER TO BAD BYTE ADDRESS,
			; BUT DON'T CHANGE THE STACK 
	PUSH	H
	MOV	A,M	;GET THE BAD BYTE
	CALL	BYTEO	;SHOW IT 
	CALL	CRLF
RFX:	POP	H	;GET THE ERROR ADDRESS BACK FOR EXIT
	RET		;EXIT,AND CONTINUE TESTING
;
;
;
;SUBROUTINE TO INDICATE ERROR IN WALKING PATTERN
;
PTERR:	PUSH	H	;SAVE BAD BYTE ADDRESS
	LHLD	ECTR	;UPDATE THE ERROR COUNTER
	INX	H
	SHLD	ECTR
	LDA	ERCNT	;DONE DISPLAYING ERRORS?
	DCR	A
	JZ	PTX
	STA	ERCNT
	LXI	H,MRER1	;OUTPUT " ERROR AT ADDRESS=" TO CONSOLE
	CALL	MSG
	POP	H	;GET THE BAD BYTE ADDRESS ,BUT DON'T
			;CHANGE THE STACK 
	PUSH	H
	CALL	HLOUT
	LXI	H,MRER2	;OUTPUT "  READ BACK " TO CONSOLE
	CALL	MSG
	POP	H	;GET THAT ADDRESS AGAIN 
	PUSH	H
	MOV	A,M	;GET THE ERROR BYTE
	CALL	BYTEO	;SHOW IT 
	LXI	H,MRER3	;OUTPUT " , EXPECTED " TO CONSOLE
	CALL	MSG
	LDA	ERPAT	;GET THE "GOOD" DATA BYTE
	CALL	BYTEO	;SHOW IT ALSO 
	LXI	H,MRER4	;OUTPUT "LAST ADDRESS WRITTEN WAS" TO CONSOLE
	CALL	MSG
	LHLD	LASTW	;GET THE LAST ADDRESS WRITTEN
	CALL	HLOUT
	LXI	H,MRER5	;OUTPUT " PATTERN WAS " TO CONSOLE
SATX:	CALL	MSG
	LDA	TPATT	;GET THE TEST PATTERN AND OUTPUT IT TO CONSOLE
	CALL	BYTEO
	CALL	CRLF	;KEEP IT NEAT
	MVI	A,0FFH	;SET THE ERROR FLAG
	STA	ERFLG
	CALL	KBINT	;CHECK FOR KEY-BOARD INTERRUPT
PTX:	POP	H	;RESTORE THE "BAD" ADDRESS
	RET		;CONTINUE TESTING
;
;
;
;SUBROUTINE TO HANDLE ERRORS IN "GALLOPING PATTERN/COLUMN TESTS
;
ERR1:	PUSH	H
	LHLD	ECTR	;UPDATE THE ERROR COUNTER
	INX	H
	SHLD	ECTR
	LDA	ERCNT	;DONE DISPLAYING ERRORS?
	DCR	A
	JZ	COMEX
	STA	ERCNT
	LXI	H,MRER6	;OUTPUT "ERROR READING OTHER CELL" TO CONSOLE
	CALL	MSG
	POP	H
	JMP	COMER	;GO TO COMMON ERROR PROCESSING
;
;
;
ERR2:	PUSH	H
	LHLD	ECTR	;UPDATE THE ERROR COUNTER
	INX	H
	SHLD	ECTR
	LDA	ERCNT	;DONE DISPLAYING ERRORS?
	DCR	A
	JZ	COMEX
	STA	ERCNT
	LXI	H,MRER7	;OUTPUT "ERROR READING TEST CELL" TO CONSOLE
	CALL	MSG
	POP	H
COMER:	PUSH	H	;PROTECT THE INNOCENT 
	PUSH	D
	PUSH	B
	PUSH	PSW
	PUSH	H
	LHLD	ECTR	;UPDATE THE ERROR COUNTER
	INX	H
	SHLD	ECTR
	LXI	H,MRER8	;OUTPUT "TEST CELL=" TO CONSOLE
	CALL	MSG
	POP	H
	PUSH	H
	XCHG
	CALL	HLOUT
	XCHG
	POP	H
	PUSH	H
	LXI	H,MRER9	;OUTPUT ", OTHER CELL=" TO CONSOLE
	CALL	MSG
	POP	H
	CALL	HLOUT
	PUSH	H
	LXI	H,MER10	;OUTPUT "PATTERN STORED=" TO CONSOLE
	CALL	MSG
	POP	H	;BLOW-AWAY H&L REGS. TO ADJUST THE STACK 
	MOV	A,B
	CALL	BYTEO	;SHOW IT 
	LXI	H,MER11	;OUTPUT "PATTERN READ=" TO CONSOLE
	CALL	MSG
	LDA	TPATT
	CALL	BYTEO	;SHOW IT ALSO 
	CALL	CRLF	;KEEP IT NEAT
	MVI	A,0FFH	;SET THE ERROR FLAG
	STA	ERFLG
	POP	PSW	;EVERYBODY BACK FROM EXILE 
	POP	B
	POP	D
COMEX:	POP	H
	RET
;
;
;
LOOP1:	CALL	KBINT	;CHECK FOR KEY-BOARD INTERRUPT
	LXI	D,10000
LOOP2:	DCX	D
	MOV	A,D
	ORA	E
	JNZ	LOOP2
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	LOOP1
	RET
;
;
;
;ROUTINES FOR MEMORY TEST
;
GALPT:	MOV	B,A	;SAVE THE PATTERN
	CALL	BAKPT	;WRITE THE "BACKGROUND" PATTERN
GALST:	LHLD	MBOT	;GET THE TEST CELL ADDRESS
	XCHG		;SWAP FOR MEMORY TOP INTO H&L REGS.
PNCEL:	PUSH	D	;SAVE TEST CELL ADDRESS
	LHLD	MBOT	;GET ADDRESS OF OTHER CELL
	LDAX	D	;GET CONTENTS OF TEST CELL
	CMA		;FLIP IT OVER 
	STAX	D	;STORE IT BACK
GPLOP:	CALL	KBINT	;CHECK KEY-BOARD INTERRUPT
	POP	D	;GET BACK ADDRESS OF TEST CELL
	PUSH	D
	CALL	COMP	;SEE IF TEST ADDRESS EQUALS OTHER ADDRESS
	JZ	SKIP	;IF YES,SKIP TESTING 
	MOV	A,M	;GET THE OTHER CELL
	STA	TPATT	;SAVE IT JUST IN CASE IT'S WRONG   
	CMP	B	;EQUAL TO PATTERN?
	LDAX	D	;READ BACK THE TEST CELL
	CNZ	ERR1	;OOPS....REPORT THE ERROR 
	CMA		;BACK TO ORIGINAL STATE......... 
	STA	TPATT	;SAVE IT 
	CMP	B	;STILL EQUAL TO PATTERN?
	CNZ	ERR2	;OOPS....WRONG HERE ALSO 
SKIP:	INX	H	;BUMP THE OTHER ADDRESS
	XCHG		;MEMORY TO D&E REGS.
	LHLD	MTOP
	XCHG
	CALL	COMP	;AT TOP OF MEMORY BLOCK?
	JNZ	GPLOP	;IF NOT,CONTINUE "GALLOPING PATTERN" LOOP 
	POP	D	;WHOOPIE...TOP OF MEMORY BLOCK,GET BACK TEST ADDRESS
	LDAX	D	;GET THE TEST CELL
	CMA		;BACK TO ORIGINAL,AND SAVE IT
	STAX	D
	INX	D	;BUMP FOR NEXT TEST ADDRESS
	CALL	COMP	;TOP OF BLOCK YET?
	JNZ	PNCEL	;IF NOT,GET THE NEXT CELL FOR TEST 
	RET
;
;
;
GALCL:	MOV	B,A	;SAVE THE PATTERN
	CALL	BAKPT	;WRITE BACKGROUND
	LHLD	MBOT
CNCEL:	PUSH	H	;SAVE TEST CELL ADDRESS
	MOV	A,M	;GET CONTENTS OF TEST CELL
	CMA		;FLIP IT 
	MOV	M,A	;CRAM IT BACK
CLOOP:	CALL	KBINT	;CHECK FOR KEY-BOARD INTERRUPT
	MVI	E,64	;GOLLY,A DECIMAL NUMBER 
	MVI	D,000H	;SCRUB D REG.
	DAD	D
	XCHG		;NOW D&E REGS. EQUAL H&L REGS.+64 
	LHLD	MTOP
	CALL	COMP
	XCHG
	JM	CINCR	;BUMP THE TEST CELL ADDRESS IF < MEMORY TOP ADDRESS
	JZ	CINCR
	POP	D	;GET AND SAVE THE TEST CELL
	PUSH	D
	LDAX	D
	CMA		;FLIP IT 
	STA	TPATT	;SAVE IT IN CASE IT'S WRONG 
	CMP	B	;EQUAL TO,PATTERN?
	CNZ	ERR1	;IF NOT,REPORT ERROR
	MOV	A,M	;TEST OTHER CELL
	STA	TPATT	;SAVE IT 
	CMP	B	;EQUAL TO PATTERN?
	CNZ	ERR2	;IF NOT,REPORT ERROR
	JMP	CLOOP	;TRY NEXT OTHER CELL
CINCR:	POP	H	;GET TEST CELL ADDRESS
	MOV	A,M	;GET CONTENTS
	CMA		;FLIP BACK TO ORIGINAL
	MOV	M,A	;RESAVE
	CALL	INC64	;BUMP TEST ADDRESS MODULO 64
	MOV	A,M	;EQUAL TO PATTERN?
	STA	TPATT	;SAVE IT IN CASE IT'S WRONG 
	CMP	B
	CNZ	ERR1
	CALL	INC64
	MOV	A,M
	STA	TPATT
	CMP	B
	CNZ	ERR1
	CALL	INC64
	ANI	63
	RZ		;RETURN IF WRAPPED AROUND TO START ADDRESS 
	JMP	CNCEL
;
;
;
WALKT:	CALL	BAKPT	;WRITE FULL BACKGROUND PATTERN
	LHLD	MBOT	;POINT TO FIRST BYTE OF BLOCK ADDRESS
	PUSH	H	;SAVE FOR INSTANT RESET
	CMA		;FLIP BACKGROUND PATTERN FOR TEST PATTERN
	STA	TPATT	;SAVE IT 
WPAT:	CALL	KBINT	;CHECK FOR KEY-BOARD INTERRUPT
	LDA	TPATT	;GET THE TEST PATTERN
	MOV	M,A	;STUFF PATTERN INTO MEMORY
	PUSH	H	;SAVE "LAST WRITTEN" ADDRESS
	SHLD	LASTW
	INX	H
	CMA		;FLIP TO BACKGROUND PATTERN
CPAT1:	CALL	COMP	;TEST BACKGROUND PATTERN FROM "LAST WRITTEN+1",
			; TO "END OF BLOCK"
			;TESTED ALL REMAINING BACKGROUND?
	JZ	WKSET	;IF YES,GO TEST PATTERN BYTES
	CMP	M	;NO...TEST BACKGROUND BYTE 
	CNZ	PTERR	;IF BAD BYTE,REPORT ERROR
	INX	H	;BUMP THE POINTER
	JMP	CPAT1	;GO FOR MORE 
WKSET:	XCHG		;SET-UP FOR NEXT SECTION,H&L REGS. EQUAL
			; LAST ADDRESS IN BLOCK+1
	POP	D	;D&E REGS. EQUAL "LAST WRITTEN" ADDRESS
	XTHL		;H&L REGS. EQUAL FIRST ADDRESS IN BLOCK
	PUSH	D	;JAM-ON "LAST WRITTEN" TO STACK
	CMA		;GET TEST PATTERN BACK
CPAT2:	CMP	M	;TEST PATTERN BYTES FROM START OF BLOCK,
			; TO "LAST WRITTEN"
	CNZ	PTERR	;ERROR IN "WALKED" BYTE?
	CALL	COMP	;NO,THEN ARE WE DONE?
	INX	H
	JNZ	CPAT2	;GO FOR MORE IF NOT DONE YET 
	POP	H	;SET-UP FOR NEXT PATTERN BYTE,H&L REGS. EQUAL
			; "LAST WRITTEN" ADDRESS
	POP	D	;D&E REGS. EQUAL LAST ADDRESS IN BLOCK+1
	INX	H	;BUMP FOR NEXT ADDRESS TO WRITE
	CALL	COMP	;DONE THE WHOLE THING?
	RZ	
	PUSH	H	;NO,PUT A COPY OF MEMORY BOTTOM ON THE STACK
	LHLD	MBOT
	XTHL
	JMP	WPAT	;GO DO SOME MORE 
;
;
;
;SUBROUTINE TO GENERATE BACKGROUND PATTERN AS CONTAINED IN A REG.
;
BAKPT:	LHLD	MTOP
	XCHG
	LHLD	MBOT	;TOP'S IN D&E REGS.,BOTTOM'S IN H&L REGS.
BAKGR:	CALL	COMP	;WE DONE?
	RZ
	MOV	M,A	;STORE THE BACKGROUND PATTERN
	INX	H	;BUMP FOR NEXT ADDRESS
	JMP	BAKGR	;GO DO MORE 'TILL WE HIT TOP 
;
;
;
;SUBROUTINE TO INCREMENT H&L REGS. MODULO 64
;
INC64:	INX	H	;TEST FOR WRAP-AROUND
	MOV	A,L
	ANI	63
	RNZ
	MOV	A,L
	SUI	64
	MOV	L,A
	RNC
	DCR	H	;BORROW IF NEEDED 
	RET
;
;
;
;SUBROUTINE TO COMPARE H&L REGS. TO D&E REGS. FOR BLOCK COMPLETION
;
COMP:	PUSH	B
	MOV	B,A
	MOV	A,H
	SUB	D
	JNZ	COMP1
	MOV	A,L
	SUB	E
COMP1:	MOV	A,B
	POP	B
	RET
;
;
;
;STORAGE FOR VARIABLES AND STACK POINTERS
;
	DS	16	;16 BYTE STACK POINTER STORAGE AREA
STACK:	DS	000H
ERPAT:	DS	1	;STORAGE FOR ERROR PATTERN
ERFLG:	DS	1	;STORAGE FOR BLOCK ERROR FLAG
DROPC:	DS	1	;STORAGE FOR NUMBER OF "DROPPED" BLOCKS
DROP:	DS	28	;DROP BUFFER
DROPP:	DS	2	;POINTER TO NEXT FREE SLOT IN DROP LIST
MBUF:	DS	15	;MEMORY BLOCK BUFFER
	DB	080H	;TERMINATOR FOR MEMORY BLOCK BUFFER POINTER
MEMPT:	DS	2	;STORAGE FOR MEMORY BUFFER POINTER
BLKST:	DS	2	;STORAGE FOR MEMORY BLOCK START ADDRESS
MEND:	DS	2	;STORAGE FOR MEMORY BLOCK END ADDRESS
MBOT:	DS	2	;STORAGE FOR 256 "CHUNK" START ADDRESS
MTOP:	DS	2	;STORAGE FOR 256 "CHUNK" END ADDRESS
TPATT:	DS	1	;STORAGE FOR LAST PATTERN WRITTEN
LASTW:	DS	2	;STORAGE FOR LAST ADDRESS WRITTEN
MTEST:	DS	2	;STORAGE FOR MEMORY TEST POINTER
AUTOR:	DS	2	;STORAGE FOR "AUTO1" RETURN ADDRESS FOR LOOPING
PCTR:	DS	2	;STORAGE FOR "PASS" COUNTER
ECTR:	DS	2	;STORAGE FOR "ERROR" COUNTER
ERCNT:	DS	1	;STORAGE FOR ERROR DISPLAY COUNTER
;
;
;
	END
