	ORG	100H
;
; UMPIRE Memory Diagnostic
; Modified to run on the Osborne Executive 1
; Does not test system bank 0.
;
;	GLW  April '84
;
WARM	EQU	0	;CP/M warm start
BDOS	EQU	5	;Basic Disk Operating System
COUNT	EQU	2AH	;number of memory bytes to test
PNTR1	EQU	40H	;address pointer 1
PNTR2	EQU	43H	;address pointer 2
STACK	EQU	0FFH	;user stack pointer
;
;	Main Program
;
	LXI	SP,STACK ;init user stack pointer
START:
	CALL	STROUT	;print sign on message
	DW	SIGNON	; string address
	CALL	HILO	;init COUNT (# bytes to test)
	LXI	B,0	; (BDOS start - Program end)
SETCNT	CALL	COMPAR
	INX	B
	JNZ	SETCNT
	MOV	H,B
	MOV	L,C
	SHLD	COUNT
;
NPASS:
	CALL	STROUT	;print "PASS "
	DW	TPASS
	LXI	H,PASS
	INR	M	;inc pass counter
	MOV	A,M
	CALL	HEXOUT	;print pass #
	CALL	TEST1	;boomerang
	CALL	TEST2	;half slow
	CALL	TEST3	;scramble
	CALL	TEST4	;spiral
	CALL	RDKEY
	JMP	NPASS	;next pass
;
;
;
; Subroutines
;
;
;	Boomerang
;
TEST1:
	CALL	STROUT	;print "TEST 1-BOOMERANG"
	DW	T10
	MVI	A,18
	STA	PNTR2	;init data table count
	LXI	H,DATA1
	SHLD	PNTR1	; and data table pointer
T100:
	LHLD	PNTR1
	MOV	C,M	; C = test byte
	INX	H
	MOV	B,M	; B = mode byte 
	INX	H
	SHLD	PNTR1	;save data table pointer
	LXI	H,PNTR2
	DCR	M	;decrement data table count
	RZ		;return to main program if done
	MVI	A,2
	ANA	B	;mode bit = 1?
	CNZ	SETHI	;yes, set HL=HI : DE=COUNT
	CZ	SETLO	; no, set HL=LO : DE=COUNT
	MVI	A,1
	ANA	B	;mode bit = 0?
	CZ	WRITE	; no, write test byte to mem range
	JZ	T100
T1ERR:
	MOV	A,M
	CMP	C	;memory = test byte?
	CNZ	ERR12	; no, print error
	MVI	A,8
	ANA	B	;mode bit = 3?
	JNZ	T102	; yes, branch
	MOV	A,C
	CMA		;no, complement and
	MOV	M,A	; write test byte
	MVI	A,4
	ANA	B	;mode bit = 2?
	JNZ	T102	; yes, branch
	MOV	M,C	;no,write normal test byte
T102:
	MVI	A,2
	ANA	B	;mode bit = 1?
	JZ	T103	; no, branch
	DCX	H
	DCX	H	;decrement address pointer
T103:
	INX	H	;increment    "       "
	DCX	D	;decrement count
	MOV	A,E
	ORA	D	;COUNT = 0?
	JNZ	T1ERR	; no, branch
	CALL	RDKEY	;key pressed?
	JZ	T100	; no, branch
	RET		;yes, return to main program
;
;	Test 1 data table
;
;              R/W     mode
;              byte    byte    pattern
DATA1:
	DB	000H,0000$0000B	; 1
	DB	000H,0000$0101B	; 2
	DB	0FFH,0000$1111B	; 3
	DB	0FFH,0000$0101B	; 4
	DB	000H,0000$1111B	; 5
	DB	000H,0000$0111B	; 6
	DB	0FFH,0000$1101B	; 7
	DB	0FFH,0000$0111B	; 8
	DB	000H,0000$1101B	; 9
	DB	000H,0000$0001B	;10
	DB	000H,0000$1011B	;11
	DB	000H,0000$0011B	;12
	DB	000H,0000$1001B	;13
	DB	0FFH,0000$0000B	;14
	DB	0FFH,0000$0001B	;15
	DB	0FFH,0000$1011B	;16
	DB	0FFH,0000$0011B	;17
	DB	0FFH,0000$1001B	;18
;
;	Half Slow
;
TEST2:
	CALL	STROUT	;print "TEST 2-HALF SLOW"
	DW	T20
	LXI	H,1	;init 'address bit' word 
	SHLD	PNTR1
T200:		      ;Next address bit
	CALL	STROUT	;print "ADDRESS BIT "
	DW	T21
	LHLD	PNTR1
	CALL	WRDOUT	;print 'address bit' word
	CALL	CRLF
	MVI	C,0
	CALL	WRITE2	;write 0's to memory to be tested
	MVI	A,20	;set test data table count
	LXI	H,DATA2	; and point to test data table
	PUSH	H
T201:		      ;Next test/mode word
	POP	H	;retrieve data table pointer
	MOV	C,M	;C = read/write test byte
	INX	H
	MOV	B,M	;B = mode byte
	INX	H
	PUSH	H	;save data table pointer
	DCR	A
	PUSH	PSW	;save table count
	CALL	SETLO	;set HL = start adr : DE = # bytes
T202:		      ;Next memory address	
	MVI	A,2
	ANA	B	;mode bit = 1?
	JNZ	T2ERR	; yes, branch
	LDA	PNTR1	;HL = 'address bit' word?
	ANA	L
	JNZ	T203
	LDA	PNTR1+1
	ANA	H
	JNZ	T203	; no, branch
	MVI	A,4
	ANA	B	;mode bit = 2?
	JNZ	T2ERR	;yes, branch
	JMP	T2NXTA	; no, branch
T203:
	MVI	A,4
	ANA	B	;mode bit = 2?
	JNZ	T2NXTA	; yes, branch
T2ERR:
	MOV	A,M
	CMP	C	;memory = test data byte?
	CNZ	ERR12	;no, output error
	MVI	A,8
	ANA	B	;mode bit = 3?
	JNZ	T2NXTA	;yes, branch
	MOV	A,C
	CMA		; no, complement
	MOV	M,A	;  and write test byte
T2NXTA:
	INX	H	;point to next address
	DCX	D	;decrement COUNT
	MOV	A,E
	ORA	D	;COUNT = 0?
	JNZ	T202	; no, test next memory address
	POP	PSW	;yes, retrieve table count
	ORA	A	;end of table?
	JNZ	T201	; no, do next subtest
	POP	H	;yes, clean up stack
	LHLD	PNTR1
	DAD	H	; address bit = address bit * 2
	SHLD	PNTR1
	MOV	A,H
	ORA	L	;all address bits tested?
	RZ		;yes, return to main program 
	CALL	RDKEY	;key pressed?
	JZ	T200	; no, do next address bit
	RET		;return to main program
;
;	Test 2 data table
;
;	       R/W    mode         Adr bit in memory adr?
;	       byte   bit:3210         yes          no 
DATA2:				
	DB	000H,0000$0000B	; 1 R/0's,W/1's	 do nothing  
	DB	0FFH,0000$1000B	; 2 Read 1's 	 do nothing
	DB	000H,0000$1100B	; 3 do nothing	 Read 0's
	DB	0FFH,0000$0000B	; 4 R/1's,W/0's	 do nothing
	DB	000H,0000$1010B	; 5 Read 0's	 Read 0's
	DB	000H,0000$0100B	; 6 do nothing	 R/0's,W/1's
	DB	000H,0000$1000B	; 7 Read 0's	 do nothing
	DB	0FFH,0000$1100B	; 8 do nothing	 Read 1's	
	DB	000H,0000$0000B	; 9 R/0's,W/1's	 do nothing
	DB	0FFH,0000$1010B	;10 Read 1's	 Read 1's
	DB	0FFH,0000$0100B	;11 do nothing   R/1's,W/0's
	DB	0FFH,0000$1000B	;12 Read 1's 	 do nothing
	DB	000H,0000$1100B	;13 do nothing	 Read 0's
	DB	000H,0000$0100B	;14 do nothing	 R/0's,W/1's
	DB	0FFH,0000$1010B	;15 Read 1's	 Read 1's
	DB	0FFH,0000$0000B	;16 R/1's,W/0's	 do nothing
	DB	000H,0000$1000B	;17 Read 0's	 do nothing	
	DB	0FFH,0000$1100B	;18 do nothing	 Read 1's
	DB	0FFH,0000$0100B	;19 do nothing	 R/1's,W/0's
	DB	000H,0000$1010B	;20 Read 0's	 Read 0's
;
;	scramble
;
TEST3:
	CALL	STROUT	;print "TEST 3-SCRAMBLE"
	DW	T40
	MVI	C,0
	CALL	WRITE2	;write 0's to memory range
	LXI	H,PNTR2
	MVI	M,40H
	LHLD	DATA3	;TPA (0100H)
	PUSH	H
T300:	POP	B
	PUSH	B
	CALL	SWAPLO	;set HL = TPA adr : BC = LOMEM
T301:	MOV	A,M	;		  : DE = COUNT	
	STAX	B	;write program code
	INX	B	; through memory
	INR	L
	DCX	D
	MOV	A,E
	ORA	D
	JNZ	T301
	CALL	RDKEY	;key pressed?
	JNZ	T303	;yes, branch
	POP	B
	MVI	A,37H
	ADD	C
	MOV	H,B
	MOV	L,A
	PUSH	H
	CALL	SWAPLO	;reset pointers
T302:	LDAX	B	;read program code
	CMP	M	; from memory
	CNZ	ERR34	; output an error
	INX	B	;update pointers
	INR	L
	DCX	D
	MOV	A,E
	ORA	D	;done?
	JNZ	T302	; no, branch
	CALL	L030B	;read KBD
	JNZ	T300	;branch if key not pressed
T303:	POP	B	;clean up stack
	RET		; and return to main program
;
;	spiral
;
TEST4:
	CALL	STROUT	;print "TEST 4-SPIRAL"
	DW	T80
	MVI	C,0
	CALL	WRITE2	;write 0's to memory
	LHLD	COUNT
	MOV	A,H
	CPI	0
	JNZ	T401
	MOV	A,L
	CPI	2	;COUNT < 2?
	RNC		; yes, return to main program
T401:	LXI	H,PNTR2
	MVI	M,40H
	LHLD	DATA3
	PUSH	H
T402:	POP	B
	PUSH	B
	CALL	L033D
T403:	MOV	A,M
	STAX	B
	INX	B
	INR	L
	MOV	A,M
	STAX	D
	DCX	D
	INR	L
	INR	L
	MOV	A,C
	XRA	E
	JNZ	T403
	XRA	B
	XRA	D
	JNZ	T403
	CALL	RDKEY
	JNZ	T405
	POP	B
	MVI	A,37H
	ADD	C
	MOV	H,B
	MOV	L,A
	PUSH	H
	CALL	L033D
T404:	LDAX	B
	CMP	M
	CNZ	ERR34
	INX	B
	INR	L
	LDAX	D
	CMP	M
	CNZ	ERR34
	DCX	D
	INR	L
	INR	L
	MOV	A,C
	XRA	E
	JNZ	T404
	XRA	B
	XRA	D
	JNZ	T404
	CALL	L030B
	JNZ	T402
T405:	POP	H
	RET
;
;
;
L030B:
	CALL	RDKEY
	XRI	1
	RZ		;return if key pressed
	LXI	H,PNTR2
	DCR	M
	RET
;
;	called by tests 1,2 & 4
;
SETLO:
	LXI	H,LOMEM
	JMP	GETCNT
;
;	called by test 1
;
SETHI:
	LHLD	BDOS+1
	DCX	H
GETCNT:	XCHG
	LHLD	COUNT
	XCHG
	RET
;
; Setup HI & LO pointers  :  called by L033D
; DE = HI memory address
; HL = LO memory address
;	
HILO:
	LHLD	BDOS+1	;BDOS start address
	XCHG
	LXI	H,LOMEM	;end of program
	RET
;
; Swap HL and BC  :  called twice by test 3
;
SWAPLO:
	CALL	SETLO
SWAPHI:
	PUSH	H	;exch HL & BC
	PUSH	B
	POP	H
	POP	B
	RET
;
; Compare : RET with Z = 1 if HL = DE
;
COMPAR:
	INX	H
	MOV	A,L
	XRA	E
	RNZ
	XRA	H
	XRA	D
	RET
;
;
;
L033D:
	CALL	HILO	;init HI & LO pointers
	CALL	SWAPHI
	DCX	D
	DCX	D
	MOV	A,C
	XRA	E
	ANI	1
	RZ
	DCX	D
	RET
;
;	called by tests 2 3 & 4
;
WRITE2:
	CALL	SETLO
;
; Write test byte (in C) to memory range
; on entry HL = PNTR1	;start address 
;	   DE = COUNT	;number of bytes to test
;
WRITE:
	MOV	M,C	;write test byte
	INX	H	;increment adr ptr
	DCX	D	;decrement range count
	MOV	A,E
	ORA	D	;count = 0?
	JNZ	WRITE	;loop til done
	RET
;
;	Output error : called by tests 3 and 4
;
ERR34:
	PUSH	H
	PUSH	D
	PUSH	B
	MOV	D,M
	CALL	SWAPHI
	MOV	C,D
	JMP	ERROUT
;
;	Output error : called by tests 1 and 2
;
ERR12:
	PUSH	H
	PUSH	D
	PUSH	B
ERROUT:
	PUSH	PSW
	XRA	C	;isolate bad bits
	PUSH	PSW
	PUSH	H
	MOV	H,B
	MOV	L,C
	PUSH	H
	CALL	STROUT	;print "TEST/MODE: "
	DW	TFBM
	POP	H
	CALL	WRDOUT	;print BC
	CALL	STROUT	;print "  ADDRESS: "
	DW	TF1
	POP	H
	CALL	WRDOUT	;print 'address'
	CALL	STROUT	;print "  BAD BITS: "
	DW	TF2
	POP	PSW
	CALL	HEXOUT	;print hex byte
	CALL	CRLF
	CALL	RDKEY
	CALL	L04CB	;04CBH
	RET
;
; Print Hex word in HL
;
WRDOUT:
	MOV	A,H
	CALL	HEXOUT	;print hex byte
	MOV	A,L
;
; Print Hex byte in A
;
HEXOUT:
	MOV	C,A
	RRC
	RRC
	RRC
	RRC
	CALL	NIBOUT
	MOV	A,C
NIBOUT:	ANI	0FH
	ADI	'0'
	CPI	':'
	JC	NIB1
	ADI	7
NIB1:	MOV	E,A
	JMP	CONOUT
;
; Output string terminated by "$"
;
STROUT:
	CALL	STR1	;move string adr to DE
	PUSH	H	;restore RET address
	MVI	A,9	;function 9
	JMP	BDOS0	;output string
STR1:
	POP	H	;point to address
	XTHL
	MOV	E,M	;move it to DE
	INX	H
	MOV	D,M
	INX	H
	RET
;
CRLF:
	CALL	STROUT
	DW	TCRLF
	RET
;
; Text Messages
;
SIGNON	DB	0DH,0AH,0DH,0AH,0DH,0AH,0DH
	DB	0AH,0DH,0AH,0DH,0AH,0DH,0AH
	DB	0DH,0AH,0DH,0AH,0DH,0AH,0DH
	DB	0AH,0DH,0AH,0DH,0AH,0DH,0AH
	DB	'User Maintenance Problem '
	DB	'Identification & Reliability '
	DB	'Enhancement',0DH,0AH
	DB	'COPYRIGHT (C) 1979, 1980 '
	DB	'by Mel Cruts',0DH,0AH,'$'
TFBM	DB	'      MODE/DATA: $'
TF1	DB	'  ADDRESS: $'
TF2	DB	'  BAD BITS: $'
TPASS	DB	'PASS $'
T10	DB	0DH,0AH,'  TEST 1-BOOMERANG',0DH,0AH,'$'
T20	DB	'  TEST 2-HALF SLOW',0DH,0AH,'$'
T21	DB	'    ADDRESS BIT $'
T40	DB	'  TEST 3-SCRAMBLE',0DH,0AH,'$'
T80	DB	'  TEST 4-SPIRAL'
TCRLF	DB	0DH,0AH,'$'
;
;	called by ERROUT
;
L04CB:
	POP	H
	POP	PSW
	POP	B
	POP	D
	XTHL
	RET
;
; Perform BDOS function
; enter with function in A : DE in HL
;
BDOS0:
	XTHL
	PUSH	H
	PUSH	D
	PUSH	B
	MOV	C,A
	CALL	BDOS
	POP	B
	POP	D
	POP	H
	XTHL
	RET
;
; Read console status
;
CONSTAT:
	LDA	DATA3
	INR	A
	STA	DATA3
	MVI	A,11
	CALL	BDOS0
	ANI	1
	RET
;
; Write console byte
;
CONOUT:
	PUSH	PSW
	MVI	A,2
	CALL	BDOS0
	POP	PSW
	RET
;
; Check for control keys K or S
;
GETKEY:
	CALL	CONIN
	ANI	7FH
	CPI	13H	;^S?	
	CZ	CONIN	; yes, call CONIN
	CPI	0BH	;^K?
	JZ	START	; yes, restart program
	RET
;
; Read byte from console 
;
CONIN:
	CALL	CONSTAT
	JZ	CONIN
	MVI	A,1
	CALL	BDOS0
	CPI	3	;^C
	RNZ		; no, return
	LHLD	STACK-3 ;yes, exit program
	SPHL
	JMP	WARM
;
RDKEY:
	CALL	CONSTAT	;key pressed?
	CNZ	GETKEY	; yes, get it  
	RET
;
;	Data storage
;
DATA3:	DW	100H
PASS	DB	0	;pass counter
;
LOMEM:	END ;of program + 1
