; ---- builtin functions


func_any_b_stack	.proc
		jsr  func_any_b_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_all_b_stack	.proc
		jsr  func_all_b_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_any_b_into_A	.proc
		; -- any(array),  array in P8ZP_SCRATCH_W1, num bytes in A
		sta  _cmp_mod+1		; self-modifying code
		ldy  #0
-		lda  (P8ZP_SCRATCH_W1),y
		bne  _got_any
		iny
_cmp_mod	cpy  #255		; modified
		bne  -
		lda  #0
		rts
_got_any	lda  #1
		rts
		.pend


func_all_b_into_A	.proc
		; -- all(array),  array in P8ZP_SCRATCH_W1, num bytes in A
		sta  _cmp_mod+1		; self-modifying code
		ldy  #0
-		lda  (P8ZP_SCRATCH_W1),y
		beq  _got_not_all
		iny
_cmp_mod	cpy  #255		; modified
		bne  -
		lda  #1
_got_not_all	rts
		.pend

func_any_w_into_A	.proc
		asl  a
		jmp  func_any_b_into_A
		.pend

func_any_w_stack	.proc
		asl  a
		jsr  func_any_b_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_all_w_into_A	.proc
		; -- all(warray),  array in P8ZP_SCRATCH_W1, num bytes in A
		asl  a			; times 2 because of word
		sta  _cmp_mod+1		; self-modifying code
		ldy  #0
-		lda  (P8ZP_SCRATCH_W1),y
		bne  +
		iny
		lda  (P8ZP_SCRATCH_W1),y
		bne  ++
		lda  #0
		rts
+		iny
+		iny
_cmp_mod	cpy  #255		; modified
		bne  -
		lda  #1
		rts
		.pend

func_all_w_stack	.proc
		jsr  func_all_w_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_sin8_into_A	.proc
		tay
		lda  _sinecos8,y
		rts
_sinecos8	.char  trunc(127.0 * sin(range(256+64) * rad(360.0/256.0)))
		.pend

func_sin8u_into_A	.proc
		tay
		lda  _sinecos8u,y
		rts
_sinecos8u	.byte  trunc(128.0 + 127.5 * sin(range(256+64) * rad(360.0/256.0)))
		.pend

func_sin8_stack	.proc
		tay
		lda  func_sin8_into_A._sinecos8,y
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_sin8u_stack	.proc
		tay
		lda  func_sin8u_into_A._sinecos8u,y
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_cos8_into_A	.proc
		tay
		lda  func_sin8_into_A._sinecos8+64,y
		rts
		.pend

func_cos8u_into_A	.proc
		tay
		lda  func_sin8u_into_A._sinecos8u+64,y
		rts
		.pend

func_cos8_stack	.proc
		tay
		lda  func_sin8_into_A._sinecos8+64,y
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_cos8u_stack	.proc
		tay
		lda  func_sin8u_into_A._sinecos8u+64,y
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_sin16_into_AY	.proc
		tay
		lda  _sinecos8lo,y
		pha
		lda  _sinecos8hi,y
		tay
		pla
		rts
_  :=  trunc(32767.0 * sin(range(256+64) * rad(360.0/256.0)))
_sinecos8lo     .byte  <_
_sinecos8hi     .byte  >_
		.pend

func_sin16u_into_AY	.proc
		tay
		lda  _sinecos8ulo,y
		pha
		lda  _sinecos8uhi,y
		tay
		pla
		rts
_  :=  trunc(32768.0 + 32767.5 * sin(range(256+64) * rad(360.0/256.0)))
_sinecos8ulo     .byte  <_
_sinecos8uhi     .byte  >_
		.pend


func_sin16_stack	.proc
		tay
		lda  func_sin16_into_AY._sinecos8lo,y
		sta  P8ESTACK_LO,x
		lda  func_sin16_into_AY._sinecos8hi,y
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend

func_sin16u_stack	.proc
		tay
		lda  func_sin16u_into_AY._sinecos8ulo,y
		sta  P8ESTACK_LO,x
		lda  func_sin16u_into_AY._sinecos8uhi,y
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend

func_cos16_into_AY	.proc
		tay
		lda  func_sin16_into_AY._sinecos8lo+64,y
		pha
		lda  func_sin16_into_AY._sinecos8hi+64,y
		tay
		pla
		rts
		.pend

func_cos16u_into_AY	.proc
		tay
		lda  func_sin16u_into_AY._sinecos8ulo+64,y
		pha
		lda  func_sin16u_into_AY._sinecos8uhi+64,y
		tay
		pla
		rts
		.pend

func_cos16_stack	.proc
		tay
		lda  func_sin16_into_AY._sinecos8lo+64,y
		sta  P8ESTACK_LO,x
		lda  func_sin16_into_AY._sinecos8hi+64,y
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend

func_cos16u_stack	.proc
		tay
		lda  func_sin16u_into_AY._sinecos8ulo+64,y
		sta  P8ESTACK_LO,x
		lda  func_sin16u_into_AY._sinecos8uhi+64,y
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend

abs_b_stack	.proc
	; -- push abs(A) on stack (as byte)
		jsr  abs_b_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

abs_b_into_A	.proc
	; -- A = abs(A)
		cmp  #0
		bmi  +
		rts
+		eor  #$ff
		clc
		adc  #1
		rts
		.pend

abs_w_stack	.proc
	; -- push abs(AY) on stack (as word)
		jsr  abs_w_into_AY
		sta  P8ESTACK_LO,x
		tya
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend

abs_w_into_AY	.proc
	; -- AY = abs(AY)
		cpy  #0
		bmi  +
		rts
+		eor  #$ff
		pha
		tya
		eor  #$ff
		tay
		pla
		clc
		adc  #1
		bcc  +
		iny
+		rts
		.pend

func_sign_b_into_A	.proc
		cmp  #0
		beq  _zero
		bmi  _neg
		lda  #1
_zero		rts
_neg		lda  #-1
		rts
		.pend

func_sign_b_stack	.proc
		jsr  func_sign_b_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_sign_ub_into_A	.proc
		cmp  #0
		bne  _pos
		rts
_pos		lda  #1
		rts
		.pend

func_sign_ub_stack	.proc
		jsr  func_sign_ub_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_sign_uw_into_A	.proc
		cpy  #0
		beq  _possibly_zero
_pos		lda  #1
		rts
_possibly_zero	cmp  #0
		bne  _pos
		rts
		.pend

func_sign_uw_stack	.proc
		jsr  func_sign_uw_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_sign_w_into_A	.proc
		cpy  #0
		beq  _possibly_zero
		bmi  _neg
_pos		lda  #1
		rts
_neg		lda  #-1
		rts
_possibly_zero	cmp  #0
		bne  _pos
		rts
		.pend


func_sign_w_stack	.proc
		jsr  func_sign_w_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_sqrt16_stack	.proc
		jsr  func_sqrt16_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_sqrt16_into_A	.proc
		; integer square root from  http://6502org.wikidot.com/software-math-sqrt
		sta  P8ZP_SCRATCH_W1
		sty  P8ZP_SCRATCH_W1+1
		txa
		pha
		lda  #0
		sta  P8ZP_SCRATCH_B1
		sta  P8ZP_SCRATCH_REG
		ldx  #8
-		sec
		lda  P8ZP_SCRATCH_W1+1
		sbc  #$40
		tay
		lda  P8ZP_SCRATCH_REG
		sbc  P8ZP_SCRATCH_B1
		bcc  +
		sty  P8ZP_SCRATCH_W1+1
		sta  P8ZP_SCRATCH_REG
+		rol  P8ZP_SCRATCH_B1
		asl  P8ZP_SCRATCH_W1
		rol  P8ZP_SCRATCH_W1+1
		rol  P8ZP_SCRATCH_REG
		asl  P8ZP_SCRATCH_W1
		rol  P8ZP_SCRATCH_W1+1
		rol  P8ZP_SCRATCH_REG
		dex
		bne  -
		pla
		tax
		lda  P8ZP_SCRATCH_B1
		rts
		.pend

func_rnd_stack	.proc
	; -- put a random ubyte on the estack
		jsr  math.randbyte
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_rndw_stack	.proc
	; -- put a random uword on the estack
		jsr  math.randword
		sta  P8ESTACK_LO,x
		tya
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend

func_min_ub_into_A	.proc
		; -- min(ubarray) -> A.  (array in P8ZP_SCRATCH_W1, num elements in A)
		tay
		dey
		lda  #255
		sta  P8ZP_SCRATCH_B1
-		lda  (P8ZP_SCRATCH_W1),y
		cmp  P8ZP_SCRATCH_B1
		bcs  +
		sta  P8ZP_SCRATCH_B1
+		dey
		cpy  #255
		bne  -
		lda  P8ZP_SCRATCH_B1
		rts
				.pend

func_min_ub_stack	.proc
		jsr  func_min_ub_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_min_b_into_A	.proc
		; -- min(barray) -> A.  (array in P8ZP_SCRATCH_W1, num elements in A)
		tay
		lda  #127
		sta  P8ZP_SCRATCH_B1
-		lda  (P8ZP_SCRATCH_W1),y
		clc
		sbc  P8ZP_SCRATCH_B1
		bvc  +
		eor  #$80
+		bpl  +
		lda  (P8ZP_SCRATCH_W1),y
		sta  P8ZP_SCRATCH_B1
+		dey
		cpy  #255
		bne  -
		lda  P8ZP_SCRATCH_B1
		rts
		.pend

func_min_b_stack	.proc
		jsr  func_min_b_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_min_uw_into_AY	.proc
		; -- min(uwarray) -> AY  (array in P8ZP_SCRATCH_W1, num elements in A)
		asl  a
		tay
		dey
		dey
		lda  #$ff
		sta  _result_minuw
		sta  _result_minuw+1
_loop
		iny
		lda  (P8ZP_SCRATCH_W1),y
		dey
		cmp   _result_minuw+1
		bcc  _less
		bne  _gtequ
		lda  (P8ZP_SCRATCH_W1),y
		cmp  _result_minuw
		bcs  _gtequ
_less		lda  (P8ZP_SCRATCH_W1),y
		sta  _result_minuw
		iny
		lda  (P8ZP_SCRATCH_W1),y
		sta  _result_minuw+1
		dey
_gtequ		dey
		dey
		cpy  #254
		bne  _loop
		lda  _result_minuw
		ldy  _result_minuw+1
		rts
_result_minuw	.word  0
		.pend

func_min_w_into_AY	.proc
		; -- min(warray) -> AY  (array in P8ZP_SCRATCH_W1, num elements in A)
		asl  a
		tay
		dey
		dey
		lda  #$ff
		sta  _result_minw
		lda  #$7f
		sta  _result_minw+1
_loop
		lda  (P8ZP_SCRATCH_W1),y
		cmp   _result_minw
		iny
		lda  (P8ZP_SCRATCH_W1),y
		dey
		sbc  _result_minw+1
		bvc  +
		eor  #$80
+		bpl  _gtequ
		lda  (P8ZP_SCRATCH_W1),y
		sta  _result_minw
		iny
		lda  (P8ZP_SCRATCH_W1),y
		sta  _result_minw+1
		dey
_gtequ		dey
		dey
		cpy  #254
		bne  _loop
		lda  _result_minw
		ldy  _result_minw+1
		rts
_result_minw	.word  0
		.pend

func_min_uw_stack	.proc
		jsr  func_min_uw_into_AY
		sta  P8ESTACK_LO,x
		tya
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend

func_min_w_stack	.proc
		jsr  func_min_w_into_AY
		sta  P8ESTACK_LO,x
		tya
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend

func_max_ub_into_A	.proc
		; -- max(ubarray) -> A  (array in P8ZP_SCRATCH_W1, num elements in A)
		tay
		lda  #0
		sta  P8ZP_SCRATCH_B1
-		lda  (P8ZP_SCRATCH_W1),y
		cmp  P8ZP_SCRATCH_B1
		bcc  +
		sta  P8ZP_SCRATCH_B1
+		dey
		cpy  #255
		bne  -
		lda  P8ZP_SCRATCH_B1
		rts
		.pend

func_max_ub_stack	.proc
		jsr  func_max_ub_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_max_b_into_A	.proc
		; -- max(barray) -> A  (array in P8ZP_SCRATCH_W1, num elements in A)
		tay
		lda  #-128
		sta  P8ZP_SCRATCH_B1
-		lda  (P8ZP_SCRATCH_W1),y
		sec
		sbc  P8ZP_SCRATCH_B1
		bvc  +
		eor  #$80
+		bmi  +
		lda  (P8ZP_SCRATCH_W1),y
		sta  P8ZP_SCRATCH_B1
+		dey
		cpy  #255
		bne  -
		lda  P8ZP_SCRATCH_B1
		rts
		.pend

func_max_b_stack	.proc
		jsr  func_max_b_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend

func_max_uw_into_AY	.proc
		; -- max(uwarray) -> AY  (array in P8ZP_SCRATCH_W1, num elements in A)
		asl  a
		tay
		dey
		dey
		lda  #0
		sta  _result_maxuw
		sta  _result_maxuw+1
_loop
		iny
		lda  (P8ZP_SCRATCH_W1),y
		dey
		cmp  _result_maxuw+1
		bcc  _lesseq
		bne  _greater
		lda  (P8ZP_SCRATCH_W1),y
		cmp  _result_maxuw
		bcc  _lesseq
_greater	lda  (P8ZP_SCRATCH_W1),y
		sta  _result_maxuw
		iny
		lda  (P8ZP_SCRATCH_W1),y
		sta  _result_maxuw+1
		dey
_lesseq		dey
		dey
		cpy  #254
		bne  _loop
		lda  _result_maxuw
		ldy  _result_maxuw+1
		rts
_result_maxuw	.word  0
		.pend

func_max_uw_stack	.proc
		jsr  func_max_uw_into_AY
		sta  P8ESTACK_LO,x
		tya
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend

func_max_w_into_AY	.proc
		; -- max(uwarray) -> AY  (array in P8ZP_SCRATCH_W1, num elements in A)
		asl  a
		tay
		dey
		dey
		lda  #0
		sta  _result_maxw
		lda  #$80
		sta  _result_maxw+1
_loop
		lda  (P8ZP_SCRATCH_W1),y
		cmp  _result_maxw
		iny
		lda  (P8ZP_SCRATCH_W1),y
		dey
		sbc  _result_maxw+1
		bvc  +
		eor  #$80
+		bmi  _lesseq
		lda  (P8ZP_SCRATCH_W1),y
		sta  _result_maxw
		iny
		lda  (P8ZP_SCRATCH_W1),y
		sta  _result_maxw+1
		dey
_lesseq		dey
		dey
		cpy  #254
		bne  _loop
		lda  _result_maxw
		ldy  _result_maxw+1
		rts
_result_maxw	.word  0
		.pend

func_max_w_stack	.proc
		jsr  func_max_w_into_AY
		sta  P8ESTACK_LO,x
		tya
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend

func_sum_ub_into_AY	.proc
		; -- sum(ubarray) -> AY  (array in P8ZP_SCRATCH_W1, num elements in A)
		tay
		dey
		lda  #0
		sta  P8ZP_SCRATCH_W2
		sta  P8ZP_SCRATCH_W2+1
-		lda  (P8ZP_SCRATCH_W1),y
		clc
		adc  P8ZP_SCRATCH_W2
		sta  P8ZP_SCRATCH_W2
		bcc  +
		inc  P8ZP_SCRATCH_W2+1
+		dey
		cpy  #255
		bne  -
		lda  P8ZP_SCRATCH_W2
		ldy  P8ZP_SCRATCH_W2+1
		rts
		.pend

func_sum_ub_stack	.proc
		jsr  func_sum_ub_into_AY
		sta  P8ESTACK_LO,x
		tya
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend


func_sum_b_into_AY	.proc
		; -- sum(barray) -> AY  (array in P8ZP_SCRATCH_W1, num elements in A)
		tay
		dey
		lda  #0
		sta  P8ZP_SCRATCH_W2
		sta  P8ZP_SCRATCH_W2+1
_loop		lda  (P8ZP_SCRATCH_W1),y
		pha
		clc
		adc  P8ZP_SCRATCH_W2
		sta  P8ZP_SCRATCH_W2
		; sign extend the high byte
		pla
		and  #$80
		beq  +
		lda  #$ff
+		adc  P8ZP_SCRATCH_W2+1
		sta  P8ZP_SCRATCH_W2+1
		dey
		cpy  #255
		bne  _loop
		lda  P8ZP_SCRATCH_W2
		ldy  P8ZP_SCRATCH_W2+1
		rts
		.pend

func_sum_b_stack	.proc
		jsr  func_sum_b_into_AY
		sta  P8ESTACK_LO,x
		tya
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend

func_sum_uw_into_AY	.proc
		; -- sum(uwarray) -> AY  (array in P8ZP_SCRATCH_W1, num elements in A)
		asl  a
		tay
		dey
		dey
		lda  #0
		sta  P8ZP_SCRATCH_W2
		sta  P8ZP_SCRATCH_W2+1
-		lda  (P8ZP_SCRATCH_W1),y
		iny
		clc
		adc  P8ZP_SCRATCH_W2
		sta  P8ZP_SCRATCH_W2
		lda  (P8ZP_SCRATCH_W1),y
		adc  P8ZP_SCRATCH_W2+1
		sta  P8ZP_SCRATCH_W2+1
		dey
		dey
		dey
		cpy  #254
		bne  -
		lda  P8ZP_SCRATCH_W2
		ldy  P8ZP_SCRATCH_W2+1
		rts
		.pend

func_sum_uw_stack	.proc
		jsr  func_sum_uw_into_AY
		sta  P8ESTACK_LO,x
		tya
		sta  P8ESTACK_HI,x
		dex
		rts
		.pend


func_sum_w_into_AY = func_sum_uw_into_AY
func_sum_w_stack = func_sum_uw_stack


func_sort_ub	.proc
		; 8bit unsigned sort
		; sorting subroutine coded by mats rosengren (mats.rosengren@esa.int)
		; input:  address of array to sort in P8ZP_SCRATCH_W1, length in S
		; first, put pointer BEFORE array
		sta  P8ZP_SCRATCH_B1
		lda  P8ZP_SCRATCH_W1
		bne  +
		dec  P8ZP_SCRATCH_W1+1
+		dec  P8ZP_SCRATCH_W1
_sortloop	ldy  P8ZP_SCRATCH_B1		;start of subroutine sort
		lda  (P8ZP_SCRATCH_W1),y	;last value in (what is left of) sequence to be sorted
		sta  P8ZP_SCRATCH_REG		;save value. will be over-written by largest number
		jmp  _l2
_l1		dey
		beq  _l3
		lda  (P8ZP_SCRATCH_W1),y
		cmp  P8ZP_SCRATCH_W2+1
		bcc  _l1
_l2		sty  P8ZP_SCRATCH_W2	;index of potentially largest value
		sta  P8ZP_SCRATCH_W2+1	;potentially largest value
		jmp  _l1
_l3		ldy  P8ZP_SCRATCH_B1		;where the largest value shall be put
		lda  P8ZP_SCRATCH_W2+1	;the largest value
		sta  (P8ZP_SCRATCH_W1),y	;put largest value in place
		ldy  P8ZP_SCRATCH_W2	;index of free space
		lda  P8ZP_SCRATCH_REG		;the over-written value
		sta  (P8ZP_SCRATCH_W1),y	;put the over-written value in the free space
		dec  P8ZP_SCRATCH_B1		;end of the shorter sequence still left
		bne  _sortloop			;start working with the shorter sequence
		rts
		.pend


func_sort_b	.proc
		; 8bit signed sort
		; sorting subroutine coded by mats rosengren (mats.rosengren@esa.int)
		; input:  address of array to sort in P8ZP_SCRATCH_W1, length in A
		; first, put pointer BEFORE array
		sta  P8ZP_SCRATCH_B1
		lda  P8ZP_SCRATCH_W1
		bne  +
		dec  P8ZP_SCRATCH_W1+1
+		dec  P8ZP_SCRATCH_W1
_sortloop	ldy  P8ZP_SCRATCH_B1		;start of subroutine sort
		lda  (P8ZP_SCRATCH_W1),y	;last value in (what is left of) sequence to be sorted
		sta  P8ZP_SCRATCH_REG		;save value. will be over-written by largest number
		jmp  _l2
_l1		dey
		beq  _l3
		lda  (P8ZP_SCRATCH_W1),y
		cmp  P8ZP_SCRATCH_W2+1
		bmi  _l1
_l2		sty  P8ZP_SCRATCH_W2	;index of potentially largest value
		sta  P8ZP_SCRATCH_W2+1	;potentially largest value
		jmp  _l1
_l3		ldy  P8ZP_SCRATCH_B1		;where the largest value shall be put
		lda  P8ZP_SCRATCH_W2+1	;the largest value
		sta  (P8ZP_SCRATCH_W1),y	;put largest value in place
		ldy  P8ZP_SCRATCH_W2	;index of free space
		lda  P8ZP_SCRATCH_REG		;the over-written value
		sta  (P8ZP_SCRATCH_W1),y	;put the over-written value in the free space
		dec  P8ZP_SCRATCH_B1		;end of the shorter sequence still left
		bne  _sortloop			;start working with the shorter sequence
		rts
		.pend


func_sort_uw	.proc
		; 16bit unsigned sort
		; sorting subroutine coded by mats rosengren (mats.rosengren@esa.int)
		; input:  address of array to sort in P8ZP_SCRATCH_W1, length in A
		; first: subtract 2 of the pointer
		asl  a
		sta  P8ZP_SCRATCH_B1
		lda  P8ZP_SCRATCH_W1
		sec
		sbc  #2
		sta  P8ZP_SCRATCH_W1
		bcs  _sort_loop
		dec  P8ZP_SCRATCH_W1+1
_sort_loop	ldy  P8ZP_SCRATCH_B1    	;start of subroutine sort
		lda  (P8ZP_SCRATCH_W1),y    ;last value in (what is left of) sequence to be sorted
		sta  _work3          		;save value. will be over-written by largest number
		iny
		lda  (P8ZP_SCRATCH_W1),y
		sta  _work3+1
		dey
		jmp  _l2
_l1		dey
		dey
		beq  _l3
		iny
		lda  (P8ZP_SCRATCH_W1),y
		dey
		cmp  P8ZP_SCRATCH_W2+1
		bne  +
		lda  (P8ZP_SCRATCH_W1),y
		cmp  P8ZP_SCRATCH_W2
+		bcc  _l1
_l2		sty  _work1          		;index of potentially largest value
		lda  (P8ZP_SCRATCH_W1),y
		sta  P8ZP_SCRATCH_W2          ;potentially largest value
		iny
		lda  (P8ZP_SCRATCH_W1),y
		sta  P8ZP_SCRATCH_W2+1
		dey
		jmp  _l1
_l3		ldy  P8ZP_SCRATCH_B1           ;where the largest value shall be put
		lda  P8ZP_SCRATCH_W2          ;the largest value
		sta  (P8ZP_SCRATCH_W1),y      ;put largest value in place
		iny
		lda  P8ZP_SCRATCH_W2+1
		sta  (P8ZP_SCRATCH_W1),y
		ldy  _work1         		 ;index of free space
		lda  _work3          		;the over-written value
		sta  (P8ZP_SCRATCH_W1),y      ;put the over-written value in the free space
		iny
		lda  _work3+1
		sta  (P8ZP_SCRATCH_W1),y
		dey
		dec  P8ZP_SCRATCH_B1           ;end of the shorter sequence still left
		dec  P8ZP_SCRATCH_B1
		bne  _sort_loop           ;start working with the shorter sequence
		rts
_work1	.byte  0
_work3	.word  0
		.pend


func_sort_w	.proc
		; 16bit signed sort
		; sorting subroutine coded by mats rosengren (mats.rosengren@esa.int)
		; input:  address of array to sort in P8ZP_SCRATCH_W1, length in A
		; first: subtract 2 of the pointer
		asl  a
		sta  P8ZP_SCRATCH_B1
		lda  P8ZP_SCRATCH_W1
		sec
		sbc  #2
		sta  P8ZP_SCRATCH_W1
		bcs  _sort_loop
		dec  P8ZP_SCRATCH_W1+1
_sort_loop	ldy  P8ZP_SCRATCH_B1    	;start of subroutine sort
		lda  (P8ZP_SCRATCH_W1),y    ;last value in (what is left of) sequence to be sorted
		sta  _work3          		;save value. will be over-written by largest number
		iny
		lda  (P8ZP_SCRATCH_W1),y
		sta  _work3+1
		dey
		jmp  _l2
_l1		dey
		dey
		beq  _l3
		lda  (P8ZP_SCRATCH_W1),y
		cmp  P8ZP_SCRATCH_W2
		iny
		lda  (P8ZP_SCRATCH_W1),y
		dey
		sbc  P8ZP_SCRATCH_W2+1
		bvc  +
		eor  #$80
+		bmi  _l1
_l2		sty  _work1          		;index of potentially largest value
		lda  (P8ZP_SCRATCH_W1),y
		sta  P8ZP_SCRATCH_W2          ;potentially largest value
		iny
		lda  (P8ZP_SCRATCH_W1),y
		sta  P8ZP_SCRATCH_W2+1
		dey
		jmp  _l1
_l3		ldy  P8ZP_SCRATCH_B1           ;where the largest value shall be put
		lda  P8ZP_SCRATCH_W2          ;the largest value
		sta  (P8ZP_SCRATCH_W1),y      ;put largest value in place
		iny
		lda  P8ZP_SCRATCH_W2+1
		sta  (P8ZP_SCRATCH_W1),y
		ldy  _work1         		 ;index of free space
		lda  _work3          		;the over-written value
		sta  (P8ZP_SCRATCH_W1),y      ;put the over-written value in the free space
		iny
		lda  _work3+1
		sta  (P8ZP_SCRATCH_W1),y
		dey
		dec  P8ZP_SCRATCH_B1           ;end of the shorter sequence still left
		dec  P8ZP_SCRATCH_B1
		bne  _sort_loop           ;start working with the shorter sequence
		rts
_work1	.byte  0
_work3	.word  0
		.pend


func_reverse_b	.proc
		; --- reverse an array of bytes (in-place)
		; inputs:  pointer to array in P8ZP_SCRATCH_W1, length in A
_index_right = P8ZP_SCRATCH_W2
_index_left = P8ZP_SCRATCH_W2+1
_loop_count = P8ZP_SCRATCH_REG
		sta  _loop_count
		lsr  _loop_count
		sec
		sbc  #1
		sta  _index_right
		lda  #0
		sta  _index_left
_loop		ldy  _index_right
		lda  (P8ZP_SCRATCH_W1),y
		pha
		ldy  _index_left
		lda  (P8ZP_SCRATCH_W1),y
		ldy  _index_right
		sta  (P8ZP_SCRATCH_W1),y
		pla
		ldy  _index_left
		sta  (P8ZP_SCRATCH_W1),y
		inc  _index_left
		dec  _index_right
		dec  _loop_count
		bne  _loop
		rts
		.pend


func_reverse_w	.proc
		; --- reverse an array of words (in-place)
		; inputs:  pointer to array in P8ZP_SCRATCH_W1, length in A
_index_first = P8ZP_SCRATCH_W2
_index_second = P8ZP_SCRATCH_W2+1
_loop_count = P8ZP_SCRATCH_REG
		pha
		asl  a     ; *2 because words
		sec
		sbc  #2
		sta  _index_first
		lda  #0
		sta  _index_second
		pla
		lsr  a
		pha
		sta  _loop_count
		; first reverse the lsbs
_loop_lo	ldy  _index_first
		lda  (P8ZP_SCRATCH_W1),y
		pha
		ldy  _index_second
		lda  (P8ZP_SCRATCH_W1),y
		ldy  _index_first
		sta  (P8ZP_SCRATCH_W1),y
		pla
		ldy  _index_second
		sta  (P8ZP_SCRATCH_W1),y
		inc  _index_second
		inc  _index_second
		dec  _index_first
		dec  _index_first
		dec  _loop_count
		bne  _loop_lo
		; now reverse the msbs
		dec  _index_second
		inc  _index_first
		inc  _index_first
		inc  _index_first
		pla
		sta  _loop_count
_loop_hi	ldy  _index_first
		lda  (P8ZP_SCRATCH_W1),y
		pha
		ldy  _index_second
		lda  (P8ZP_SCRATCH_W1),y
		ldy  _index_first
		sta  (P8ZP_SCRATCH_W1),y
		pla
		ldy  _index_second
		sta  (P8ZP_SCRATCH_W1),y
		dec  _index_second
		dec  _index_second
		inc  _index_first
		inc  _index_first
		dec  _loop_count
		bne  _loop_hi

		rts
		.pend


func_exit	.proc
		; -- immediately exit the program with a return code in the A register
		ldx  orig_stackpointer
		txs
		rts		; return to original caller
		.pend


func_read_flags_stack	.proc
		; -- put the processor status register on the stack
		php
		pla
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend


func_memset	.proc
	; note: clobbers A,Y
		txa
		pha
		lda  _arg_address
		sta  P8ZP_SCRATCH_W1
		lda  _arg_address+1
		sta  P8ZP_SCRATCH_W1+1
		ldx  _arg_numbytes
		ldy  _arg_numbytes+1
		lda  _arg_bytevalue
		jsr  memset
		pla
		tax
		rts
_arg_address	.word  0
_arg_numbytes	.word  0
_arg_bytevalue	.byte  0
		.pend


func_memsetw	.proc
	; note: clobbers A,Y
		txa
		pha
		lda  _arg_address
		sta  P8ZP_SCRATCH_W1
		lda  _arg_address+1
		sta  P8ZP_SCRATCH_W1+1
		lda  _arg_numwords
		sta  P8ZP_SCRATCH_W2
		lda  _arg_numwords+1
		sta  P8ZP_SCRATCH_W2+1
		lda  _arg_wordvalue
		ldy  _arg_wordvalue+1
		jsr  memsetw
		pla
		tax
		rts
_arg_address	.word  0
_arg_numwords	.word  0
_arg_wordvalue	.word  0
		.pend


func_memcopy	.proc
	; memcopy of any number of bytes, note: clobbers A,Y
		stx  P8ZP_SCRATCH_REG
		lda  _arg_from
		sta  P8ZP_SCRATCH_W1
		lda  _arg_from+1
		sta  P8ZP_SCRATCH_W1+1
		lda  _arg_to
		sta  P8ZP_SCRATCH_W2
		lda  _arg_to+1
		sta  P8ZP_SCRATCH_W2+1

		ldy  #0
		ldx  _arg_numbytes+1
		beq  _remain
-		lda  (P8ZP_SCRATCH_W1),y	; move a page at a time
		sta  (P8ZP_SCRATCH_W2),y
		iny
		bne  -
		inc  P8ZP_SCRATCH_W1+1
		inc  P8ZP_SCRATCH_W2+1
		dex
		bne  -
_remain		ldx  _arg_numbytes
		beq  _done
-		lda (P8ZP_SCRATCH_W1),y		; move the remaining bytes
		sta (P8ZP_SCRATCH_W2),y
		iny
		dex
		bne  -

_done		ldx  P8ZP_SCRATCH_REG
		rts

_arg_from	.word  0
_arg_to		.word  0
_arg_numbytes	.word  0
		.pend


func_memcopy255	.proc
	; fast memcopy of up to 255 bytes, note: clobbers A,Y
	;  note: also uses the _arg variables from regular func_memcopy
		stx  P8ZP_SCRATCH_REG
		lda  func_memcopy._arg_from
		sta  P8ZP_SCRATCH_W1
		lda  func_memcopy._arg_from+1
		sta  P8ZP_SCRATCH_W1+1
		lda  func_memcopy._arg_to
		sta  P8ZP_SCRATCH_W2
		lda  func_memcopy._arg_to+1
		sta  P8ZP_SCRATCH_W2+1
		ldx  func_memcopy._arg_numbytes
		ldy  #0
-		lda  (P8ZP_SCRATCH_W1), y
		sta  (P8ZP_SCRATCH_W2), y
		iny
		dex
		bne  -
		ldx  P8ZP_SCRATCH_REG
		rts
		.pend


func_leftstr	.proc
		; leftstr(source, target, length)
		lda  _arg_source
		ldy  _arg_source+1
		sta  P8ZP_SCRATCH_W1
		sty  P8ZP_SCRATCH_W1+1
		lda  _arg_target
		ldy  _arg_target+1
		sta  P8ZP_SCRATCH_W2
		sty  P8ZP_SCRATCH_W2+1
		ldy  _arg_length
		lda  #0
		sta  (P8ZP_SCRATCH_W2),y
		cpy  #0
		bne  _loop
		rts
_loop		dey
		lda  (P8ZP_SCRATCH_W1),y
		sta  (P8ZP_SCRATCH_W2),y
		cpy  #0
		bne  _loop
+		rts

_arg_source	.word  0
_arg_target	.word  0
_arg_length	.byte  0
		.pend


func_rightstr	.proc
		; rightstr(source, target, length)
		lda  _arg_source
		ldy  _arg_source+1
		jsr  func_strlen_into_A
		sec
		sbc  _arg_length
		sta  P8ZP_SCRATCH_B1
		lda  _arg_source
		ldy  _arg_source+1
		sta  P8ZP_SCRATCH_W1
		sty  P8ZP_SCRATCH_W1+1
		lda  _arg_target
		ldy  _arg_target+1
		sta  P8ZP_SCRATCH_W2
		sty  P8ZP_SCRATCH_W2+1
		ldy  #0
		sty  P8ZP_SCRATCH_REG
-		ldy  P8ZP_SCRATCH_B1
		lda  (P8ZP_SCRATCH_W1),y
		inc  P8ZP_SCRATCH_B1
		ldy  P8ZP_SCRATCH_REG
		sta  (P8ZP_SCRATCH_W2),y
		inc  P8ZP_SCRATCH_REG
		cmp  #0
		bne  -
		rts

_arg_source	.word  0
_arg_target	.word  0
_arg_length	.byte  0
		.pend


func_strlen_into_A		.proc
	; -- put length of 0-terminated string in A/Y into A
		sta  P8ZP_SCRATCH_W1
		sty  P8ZP_SCRATCH_W1+1
		ldy  #0
-		lda  (P8ZP_SCRATCH_W1),y
		beq  +
		iny
		bne  -
+		tya
		rts
		.pend

func_strlen_stack	.proc
		jsr  func_strlen_into_A
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend


func_substr	.proc
		; substr(source, target, start, length)
		lda  _arg_source
		ldy  _arg_source+1
		sta  P8ZP_SCRATCH_W1
		sty  P8ZP_SCRATCH_W1+1
		lda  _arg_target
		ldy  _arg_target+1
		sta  P8ZP_SCRATCH_W2
		sty  P8ZP_SCRATCH_W2+1
		ldy  _arg_length
		lda  _arg_start
		sta  P8ZP_SCRATCH_B1

		; adjust src location
		clc
		lda  P8ZP_SCRATCH_W1
		adc  P8ZP_SCRATCH_B1
		sta  P8ZP_SCRATCH_W1
		bcc  +
		inc  P8ZP_SCRATCH_W1+1
+		lda  #0
		sta  (P8ZP_SCRATCH_W2),y
		jmp  _startloop
-		lda  (P8ZP_SCRATCH_W1),y
		sta  (P8ZP_SCRATCH_W2),y
_startloop	dey
		cpy  #$ff
		bne  -
		rts

_arg_source	.word  0
_arg_target	.word  0
_arg_start	.byte  0
_arg_length	.byte  0
		.pend


func_strcmp	.proc
		; -- compare 2 strings -> A
		lda  _arg_s2
		ldy  _arg_s2+1
		sta  P8ZP_SCRATCH_W2
		sty  P8ZP_SCRATCH_W2+1
		lda  _arg_s1
		ldy  _arg_s1+1
		jmp  strcmp_mem
_arg_s1		.word  0
_arg_s2		.word  0
		.pend

func_strcmp_stack	.proc
		jsr	func_strcmp
		sta  P8ESTACK_LO,x
		dex
		rts
		.pend
