; Recursive grid iterator
; By and (c) Neil A Carson, RiscBSD kernel team, 1995 A.D.

R0  RN 0
R1  RN 1
R2  RN 2
R3  RN 3
R4  RN 4
R5  RN 5
R6  RN 6
R7  RN 7
R8  RN 8
R9  RN 9
R10 RN 10
R11 RN 11
R12 RN 12
R13 RN 13
R14 RN 14
R15 RN 15

pc  RN 15
lr  RN 14
sp  RN 13

x	RN	0
y	RN	1
s	RN	2
bx	RN	3
by	RN	4
bs	RN	5
cl1	RN	6
cl2	RN	7
cl3	RN	8
cl4	RN	9
maxiter	RN	10
scr	RN	11
tmp	RN	12
tmp2	RN	14

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	IMPORT	iterate

;
; Macro to get or put a pixel from/to the screen, and to iterate if
; necessary.
;

	MACRO
$label	GetVal	$reg
	;
	; Calculate pixel offset => tmp
	;
	ADD	tmp, scr, by, ASL #9		; tmp = scr + by * 512
	ADD	tmp, tmp, by, ASL #7		; tmp += by * 128
	ADD	tmp, tmp, bx			; tmp += bx
	LDRB	$reg, [tmp]			; $reg = pixel value

	;
	; Is the result 0 or something else?
	;
	CMP	$reg, #0			; is the pixel black?

	;
	; If it is, then iterate it, otherwise use it
	;
	STMEQFD	sp!, {R0}			; Preserve R0
	BLEQ	iterate			; Iterate

	CMP	$reg, #0			; Re-do compare
	MOVEQ	$reg, R0			; $reg = result
	LDMEQFD	sp!, {R0}			; Restore R0 if needed
	STREQB	$reg, [tmp]			; Store result

	MEND

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;
; Proc. to fill a square (at bx, by, size bs) reasonably quickly.
; Simply uses STRB as this will do the trick reasonably fast. We can trash
; any registers we want here (apart from sp!) as this is called just before
; we return for good.
;

height	RN	0
length	RN	1
addr	RN	2
togo	RN	3
colour	RN	6

FilSqr
	MOV	height, bs				; Height = height
	MOV	length, bs				; Length = length

	ADD	addr, scr, by, ASL #9
	ADD	addr, addr, by, ASL #7
	ADD	addr, addr, bx
FilSqr1							; For each row...
	MOV	togo, length
FilSqr2
		STRB	colour, [addr], #1
		SUB	togo, togo, #1
		CMP	togo, #0
		BLT	FilSqr3

		STRB	colour, [addr], #1
		SUB	togo, togo, #1
		CMP	togo, #0
		BLT	FilSqr3

		STRB	colour, [addr], #1
		SUB	togo, togo, #1
		CMP	togo, #0
		BLT	FilSqr3

		STRB	colour, [addr], #1
		SUB	togo, togo, #1
		CMP	togo, #0
		BGE	FilSqr2

FilSqr3
	ADD	addr, addr, #640
	SUB	addr, addr, length
	SUB     addr, addr, #1
	SUB	height, height, #1			; Another row down
	CMP	height, #0				; Re-do if needed
	BGE	FilSqr1

	LDMFD	sp!, {r0-r12, pc}			; Return to caller

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;
; Pointer to the start of the screen memory
;
screen
	DCD	0
;
; Maximum possible iterations
;
maxiters
	DCD	128

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;
; Iterate a square of the Mandelbrot set. This code calls itsenf recursively.
; extern void iterate_square(x, y, s, bx, by, bs)
;

	EXPORT	iterate_square
iterate_square
	STMFD	sp!, {r0-r12, lr}		; Preserve all regs.
	LDR	scr, screen			; Get screen pointer

	;
	; Get ready to iterate any points needed
	;
	LDR	maxiter, maxiters		; Load max. iterations

	;
	; Get cl1
	;
	GetVal	cl1				; Get cl1

	;
	; Get cl2
	;
	ADD	bx, bx, bs
	ADD	x, x, s
	GetVal	cl2				; Get cl2

	;
	; Get cl4
	;
	ADD	by, by, bs
	ADD	y, y, s
	GetVal	cl4				; Get cl4


	;
	; Get cl3 - do this hear to minimise adds/subs.
	;
	SUB	bx, bx, bs
	SUB	x, x, s
	GetVal	cl3				; get cl3


	;
	; If cl1, cl2, cl3 and cl4 are equal, then go home.
	;
	CMP	cl1, cl2			; cl1 == cl2?
	CMPEQ	cl3, cl4			; cl3 == cl4?
	CMPEQ	cl1, cl3			; cl1 == cl3?
	SUBEQ	by, by, bs			; Reset by
	BEQ	FilSqr				; Fill the square in and
						; this will return too.

	;
	; If we are at a size of 1, then go home too.
	;
	CMP	bs, #1				; bs == 1?
	LDMLEFD	sp!, {r0-r12, pc}		; Return if so

	;
	; They weren't equal. So subdivide into four further, *smaller*
	; squares, and call ourselves until the cows come home.
	;

	;
	; Reset y and by
	;
	SUB	by, by, bs
	SUB	y, y, s

	MOV	s, s, ASR #1			; s = s / 2
	MOV	bs, bs, ASR #1			; bs = bs / 2

	;
	; First square
	;
	BL	iterate_square			; Call ourselves

	;
	; Second square
	;
	ADD	x, x, s
	ADD	bx, bx, bs
	BL	iterate_square			; Call ourselves

	;
	; Fourth square
	;
	ADD	y, y, s
	ADD	by, by, bs
	BL	iterate_square			; Call ourselves

	;
	; Third square
	;
	SUB	x, x, s
	SUB	bx, bx, bs
	BL	iterate_square			; Call ourselves

	;
	; Finish up
	;
	LDMFD	sp!, {r0-r12, pc}

	END
