; code: language=asm-collection tabSize=8
; Requirements:
; This function must be RELOCATABLE (only relative jumps), and use NO RAM or STACK.
; These restrictions lead to somewhat long-winded, repetative code.

;; March C- algorithm:
;;  1: (up w0) write each location bottom to top with test value
;;  2: (up r0,w1) read each location bottom to top, compare to test value, then write complement
;;  3: (up r1,w0) read each location bottom to top, compare to complement, then write test value
;;  4: (dn r0,w1) read each location top to bottom, compare to test value, then write complement
;;  5: (dn r1,w0) read each location top to bottom, compare to complement, then write test value
;;  6: (dn r0) read each location top to bottom, compare to test value

; Arguments:
;	hl = current memory position under test
;	bc = bytes remaining to test
;	iy = test data structure
; returns:
;	e = all errored bits found in this block/bank/range of memory
; destroys: a,bc,d,hl
; preserves: ix

memtestmarch2:
		ld a,0f0h		;00b0  ?????
		out (0c8h),a
		spt_ld_iya7
		out (0c5h),a		;This should be start floppy before memory test ends
		spt_ld_iya6
		out (0c0h),a		;00bf Program map B base

memtestmarch:
		xor	a
		ld	e,a			; reset error accumulator
		ld	d,a			; set the first testing value to 0

	checkabsent:					; quick test for completely missing bank
		memtest_ld_hl_base
		ld	b,h
		ld	c,1
		cpl				; A := FF
	.redo	ld	(hl),a			; write FF to base
		cpl				; A := 0
		ld	(bc),a			; write 00 to base+1
		cp	(hl)			; compare to base (should be FF, should not match)
		jr	z,.allbad		; if they match, all bits are bad, but double-check
		cp	0			; are we on the first round?
		jr	z,.redo			; yes, redo with reversed bits
		jr	mtm1
	.allbad:
		ld	e,$FF			; report all bits bad
		jr	mtm_done_bounce

	mtm1:
		memtest_loadregs
	mtm1loop:				; fill initial value upwards
		ld	(hl),d
		inc	hl
		dec	bc
		ld	a,c
		or	b
		jr	nz,mtm1loop
	mtm2:					; read value, write complement upwards
		memtest_loadregs
	mtm2loop:
		ld	a,(hl)
		cp	d			; compare to value
		jr	z, mtm2cont		; memory changed, report
		xor	d			; calculate errored bits
		or	e				
		ld	e,a			; save error bits to e
		ld	a,d			; reload a with correct value
	mtm2cont:
		cpl				; take the complement
		ld	(hl),a			; write the complement
		inc	hl
		dec	bc
		ld	a,c
		or	b
		jr	nz,mtm2loop
		
	mtm3:					; read complement, write original value upwards
		memtest_loadregs
	mtm3loop:
		ld	a,(hl)
		cpl
		cp	d			; compare to the complement
		jr	z, mtm3cont		; memory changed, report
		xor	d			; calculate errored bits
		or	e				
		ld	e,a			; save error bits to e
		ld	a,d			; reload a with correct value
	mtm3cont:
		ld	(hl),d			; fill with test value
		inc	hl
		dec	bc
		ld	a,c
		or	b
		jr	nz,mtm3loop
		jr	mtm4
	
	mtm_done_bounce:
		jr	mtm_done
	mtm1_bounce:
		jr	mtm1

	mtm4:					; read test value, write complement downwards
		memtest_loadregs
		add	hl,bc			; move to end of the test area
		dec	hl
	mtm4loop:
		ld	a,(hl)
		cp	d			; compare to value
		jr	z, mtm4cont
		xor	d			; calculate errored bits
		or	e				
		ld	e,a			; save error bits to e
		ld	a,d			; reload a with correct value
	mtm4cont:
		cpl				; take the complement
		ld	(hl),a			; write complement
		dec	hl
		dec	bc
		ld	a,c
		or	b
		jr	nz,mtm4loop

	mtm5:					; read complement, write value downwards
		memtest_loadregs
		add	hl,bc			; move to end of the test area
		dec	hl
	mtm5loop:
		ld	a,(hl)
		cpl
		cp	d
		jr	z, mtm5cont
		xor	d			; calculate errored bits
		or	e				
		ld	e,a			; save error bits to e
		ld	a,d			; reload a with correct value
	mtm5cont:
		ld	(hl),d
		dec	hl
		dec	bc
		ld	a,c
		or	b
		jr	nz,mtm5loop
	
	mtm6:					; final check that all are zero
		memtest_loadregs
		add	hl,bc			; move to end of the test area
		dec	hl
	mtm6loop:
		ld	a,(hl)
		cp	d
		jr	z,mtm6cont
		xor	d			; calculate errored bits
		or	e				
		ld	e,a			; save error bits to e
		ld	a,d			; reload a with correct value
	mtm6cont:
		dec	hl
		dec	bc
		ld	a,c
		or	b
		jr	nz,mtm6loop

	mtmredo:
		ld	a,d	
		cp	0			; if our test value is 0
		ld	d,$55
		jr	z,mtm1_bounce		; then rerun the tests with value $55

	mtm_done:
		sub	a			; set carry flag if e is nonzero
		or	e
	mtm_return:
		ret	z
		scf
		ret

memtestmarch_end equ $
;-----------------------------------------------------------------------------