;************************************************
;* divu16x8 (unsigned)
;*
;* Input : dividend_hi / dividend_lo, divisor (zeropage)
;* Output: quotient (zeropage + X), remainder (zeropage + A)
;*
;* Trash: a,x,y
;*
;* Zeropage defines
;*
;* dividend_lo
;* dividend_hi
;* divisor
;* quotient
;* remainder
;* sign_flags    ; used by signed variant only
;*
;************************************************

divu16x8
        jsr	divu16x8_core
        ldx	quotient
        lda	remainder
        rts

;************************************************
;* divs16x8 (signed)
;*
;* Input : dividend_hi / dividend_lo, divisor (zeropage)
;* Output: quotient (zeropage + X), remainder (zeropage + A)
;*
;* Trash: a,x,y
;*
;************************************************

divs16x8
        lda	#0
        sta	sign_flags

        ; normalize dividend
        lda	dividend_hi
        bpl	@dividend_positive
        jsr	negate_dividend
        lda	sign_flags
        eor	#$01              ; toggle quotient sign
        ora	#$02              ; remainder sign matches original dividend
        sta	sign_flags
@dividend_positive

        ; normalize divisor
        lda	divisor
        bpl	@divisor_positive
        jsr	negate_divisor
        lda	sign_flags
        eor	#$01              ; toggle quotient sign once more
        sta	sign_flags
@divisor_positive

        jsr	divu16x8_core

        ; apply quotient sign if needed
        lda	sign_flags
        and	#$01
        beq	@quotient_ready
        lda	quotient
        eor	#$FF
        clc	
        adc	#1
        sta	quotient
@quotient_ready

        ; apply remainder sign if needed (matches original dividend)
        lda	sign_flags
        and	#$02
        beq	@remainder_ready
        lda	remainder
        eor	#$FF
        clc	
        adc	#1
        sta	remainder
@remainder_ready

        ldx     quotient
        lda     remainder
        rts

;------------------------------------------------
; Shared unsigned 16/8 division core
;
; dividend_hi:dividend_lo / divisor -> quotient, remainder

; remainder accumulates in zeropage; divisor assumed non-zero

divu16x8_core
        lda	#0
        sta	quotient
	
        lda	dividend_hi
        beq	@check_lo
        tax	
        lda	MSB_LEN,x
        clc	
        adc	#8
        tay	
        bne	@init_loop

@check_lo
        lda	dividend_lo
        tax	
        lda	MSB_LEN,x
        tay	
        beq	@zero_result

@init_loop
        lda	#0          ; remainder lives in A for the loop
@bitloop	
        asl	dividend_lo
        rol	dividend_hi
        rol	
        cmp	divisor
        bcc	@rotate
        sbc	divisor
@rotate
        rol	quotient
        dey	
        bne	@bitloop
        sta	remainder
        rts	

@zero_result
        lda	#0
        sta	remainder
        rts	

;------------------------------------------------
; Helpers
;
; negate_dividend: dividend = -dividend (16-bit)
; negate_divisor : divisor  = -divisor  (8-bit)

negate_dividend
        lda	dividend_lo
        eor	#$FF
        clc	
        adc	#1
        sta	dividend_lo
        lda	dividend_hi
        eor	#$FF
        adc	#0
        sta	dividend_hi
        rts	

negate_divisor
        lda	divisor
        eor	#$FF
        clc	
        adc	#1
        sta	divisor
        rts	

; Leading-bit length table for 8-bit values (0..255)

MSB_LEN .byte   $00,$01,$02,$02,$03,$03,$03,$03,$04,$04,$04,$04,$04,$04,$04,$04
        .byte   $05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05,$05
        .byte   $06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06
        .byte   $06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06,$06
        .byte   $07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07
        .byte   $07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07
        .byte   $07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07
        .byte   $07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07,$07
        .byte   $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08
        .byte   $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08
        .byte   $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08
        .byte   $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08
        .byte   $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08
        .byte   $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08
        .byte   $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08
        .byte   $08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08,$08
