; ======================================================================
; CS617 NUMERIC LIBRARY
; divmod_u32_u32.inc
;
; Single authoritative implementation source established from C0.
;
; Provenance:
;   ROM-independent transplant of the OM-52C C-ROM unsigned 32-bit
;   division routine at historical address &HEAC5.
;
; Public entry in this revision:
;   UDIV32NZ
;
; Contract:
;   precondition:
;       divisor != 0
;
;   input:
;       $15-$18  unsigned 32-bit dividend, low word first
;       $5-$8    unsigned 32-bit divisor, low word first
;
;   output:
;       $15-$18  unsigned 32-bit quotient
;       $10-$13  unsigned 32-bit remainder
;
;   expected:
;       dividend = quotient * divisor + remainder
;       0 <= remainder < divisor
;
; C0 accepted machine-code identity:
;   address in C0: &H0E16..&H0E76
;   length: 97 bytes
;   SHA-256 of emitted 97-byte core:
;   e229040baa4ea907de739b7dd7bed5b2316479d9f338889b2c949bf0e1410040
;
; C1 rule:
;   This include must emit exactly that same 97-byte sequence before
;   stronger behavioral testing is interpreted.
;
; #LIST is deliberate: HD61 suppresses listing output while processing
; an include unless list output is re-enabled.
; ======================================================================

#LIST

; ======================================================================
; UDIV32NZ
;
; ROM-independent transplant of the OM-52C unsigned 32-bit division core.
; Precondition: divisor in $5-$8 is nonzero.
;
; The routine deliberately preserves the donor register choreography.
; The only promoted semantic observation is that $10-$13 is exposed as
; remainder on return instead of being treated as disposable scratch.
; ======================================================================

UDIV32NZ:
        SBW     $0,$SZ

; Preserve donor temporaries/unrelated state exactly as the historical
; routine does.
        PHSM    $29,8
        PHSM    $21,3

; Working dividend/remainder = original dividend.
; Quotient = 0.
        LDM     $10,$15,4
        SBW     $15,$15
        SBW     $17,$17

D32_OUTER:
; If remainder < divisor, division is complete.
        SBCW    $12,$7
        JR      C,D32_DONE
        JR      NZ,D32_PREP
        SBCW    $10,$5
        JR      C,D32_DONE

D32_PREP:
; Candidate shifted divisor = divisor.
; Candidate quotient term = 1.
        LDM     $0,$5,4
        LDW     $19,$SY
        SBW     $21,$21

D32_SHIFT:
; Do not left-shift a divisor whose top bit is already set.
        ANC     $3,&H80
        JR      NZ,D32_APPLY

; divisor candidate <<= 1 across 32 bits
        BIUW    $0
        ROUW    $2

; quotient term <<= 1 across 32 bits
        BIUW    $19
        ROUW    $21

; Compare shifted divisor with current remainder.
        SBCW    $12,$2
        JR      C,D32_BACK
        JR      NZ,D32_SHIFT
        SBCW    $10,$SZ
        JR      NC,D32_SHIFT

D32_BACK:
; Last shift overshot: move divisor and quotient term back one bit.
        BIDW    $3
        RODW    $1
        BIDW    $22
        RODW    $20

D32_APPLY:
; quotient += term
        ADW     $15,$19
        JR      NC,D32_QHI
        ADW     $17,$SY
D32_QHI:
        ADW     $17,$21

; remainder -= shifted divisor
        SBW     $10,$SZ
        JR      NC,D32_RHI
        SBW     $12,$SY
D32_RHI:
        SBW     $12,$2
        JR      D32_OUTER

D32_DONE:
        PPSM    $19,3
        PPSM    $22,8
        RTN
