
; ------------------------------------------------------------------------
; Public candidate API. All pointers in UA=14 RAM. All calls leave UA=14.
; B9_PARSE:  $10=RAM ASCII pointer, $12=length (0..23), $14=RAM B9 dest.
;            $0=0 OK,1 SYNTAX,2 RANGE,3 LENGTH. Failure leaves dest intact.
; B9_FORMAT: $10=RAM B9 pointer, $12=RAM ASCII dest, $14=capacity >=20.
;            $0=0 OK,1 BAD_B9,3 CAPACITY; $1=length only when OK.
; B9_VALIDATE: $10=RAM B9 pointer; $0=0 valid/1 bad; $1=0 zero,
;              1 positive,2 negative only when valid.
; Not reentrant: uses B9C_* private workspace 2E40..2EC4.
; ------------------------------------------------------------------------
B9C_OUTPTR:EQU &H2EC0
B9C_INPTR: EQU &H2EC2
B9C_NLEN:  EQU &H2EC4

B9_PARSE:
        PST     UA,&H14
        LD      $16,$12
        SBC     $16,24
        JP      NC,B9P_CAPERR
        PRE     IX,B9C_OUTPTR
        STW     $14,(IX+$SX)
        PRE     IX,B9C_INPTR
        STW     $10,(IX+$SX)
        PRE     IX,B9C_NLEN
        ST      $12,(IX+$SX)
        LDW     $2,$10
        LDW     $4,B9C_TEXT
        LD      $20,$12
B9P_CPYIN:
        AN      $20,$20
        JR      Z,B9P_NUL
        PRE     IX,$2
        LD      $16,(IX+$SX)
        AN      $16,$16
        JP      Z,B9P_SYNTAX
        ADW     $2,$SY
        PRE     IX,$4
        ST      $16,(IX+$SX)
        ADW     $4,$SY
        SB      $20,$SY
        JP      B9P_CPYIN
B9P_NUL:
        PRE     IX,$4
        LD      $16,0
        ST      $16,(IX+$SX)
        CAL     B9C_PARSE
        AN      $0,$0
        JP      NZ,B9P_RET
        LDW     $2,B9C_VALUE
        PRE     IX,B9C_OUTPTR
        LDW     $4,(IX+$SX)
        LD      $20,9
B9P_CPYOUT:
        PRE     IX,$2
        LD      $16,(IX+$SX)
        ADW     $2,$SY
        PRE     IX,$4
        ST      $16,(IX+$SX)
        ADW     $4,$SY
        SB      $20,$SY
        JP      NZ,B9P_CPYOUT
        LD      $0,0
B9P_RET:
        RTN
B9P_CAPERR:
        LD      $0,3
        RTN
B9P_SYNTAX:
        LD      $0,1
        RTN

B9_FORMAT:
        PST     UA,&H14
        LD      $16,$14
        SBC     $16,20
        JP      C,B9F_CAPERR
        PRE     IX,B9C_OUTPTR
        STW     $12,(IX+$SX)
        LDW     $2,$10
        LDW     $4,B9C_VALUE
        LD      $20,9
B9F_CPYIN:
        PRE     IX,$2
        LD      $16,(IX+$SX)
        ADW     $2,$SY
        PRE     IX,$4
        ST      $16,(IX+$SX)
        ADW     $4,$SY
        SB      $20,$SY
        JP      NZ,B9F_CPYIN
        CAL     B9C_FORMAT
        AN      $0,$0
        JP      NZ,B9F_RET
        LDW     $2,B9C_FMT
        PRE     IX,B9C_OUTPTR
        LDW     $4,(IX+$SX)
        PRE     IX,B9C_FLEN
        LD      $21,(IX+$SX)
        LD      $20,$21
        AD      $20,$SY
B9F_CPYOUT:
        PRE     IX,$2
        LD      $16,(IX+$SX)
        ADW     $2,$SY
        PRE     IX,$4
        ST      $16,(IX+$SX)
        ADW     $4,$SY
        SB      $20,$SY
        JP      NZ,B9F_CPYOUT
        LD      $1,$21
        LD      $0,0
B9F_RET:
        RTN
B9F_CAPERR:
        LD      $0,3
        RTN

B9_VALIDATE:
        PST     UA,&H14
        LDW     $2,$10
        LDW     $4,B9C_VALUE
        LD      $20,9
B9V_CPYIN:
        PRE     IX,$2
        LD      $16,(IX+$SX)
        ADW     $2,$SY
        PRE     IX,$4
        ST      $16,(IX+$SX)
        ADW     $4,$SY
        SB      $20,$SY
        JP      NZ,B9V_CPYIN
        CAL     B9C_FORMAT
        AN      $0,$0
        JP      NZ,B9V_RET
        LDW     $2,B9C_VALUE
        LD      $20,9
        LD      $17,0
B9V_ZEROCHK:
        PRE     IX,$2
        LD      $16,(IX+$SX)
        OR      $17,$16
        ADW     $2,$SY
        SB      $20,$SY
        JP      NZ,B9V_ZEROCHK
        LD      $1,0
        AN      $17,$17
        JR      Z,B9V_GOOD
        LD      $1,1
        PRE     IX,B9C_BSIGN
        LD      $16,(IX+$SX)
        AN      $16,$16
        JR      Z,B9V_GOOD
        LD      $1,2
B9V_GOOD:
        LD      $0,0
B9V_RET:
        RTN

; ========================================================================
; B9_CONVERT: extracted, privately namespaced Chapter09 B9CALC converter.
; Source donor: math10_calc_b9_r001.s, 2026-10-15 r001 archive.
; All executable converter instructions preserved, with C9_* -> B9C_* labels.
; Public calling adapters below. This is a NEW, UNQUALIFIED consumer candidate.
; Bank UA=14, private SCRATCH 2E40..2EC4; one client at a time.
; No VT20, VT21, EVAL, keyboard, or math-* calls.
; ========================================================================
; ============================================================================
; CS617 / Chapter 09 / Math 1.0 / CALC first implementation candidate r001
; Application-owned decimal text <-> full thirteen-digit native B9.
;
; STATUS: UNASSEMBLED / UNEXECUTED. Host oracle is separate. Do not integrate
; into accepted ch09_main.s or alter accepted Math/Gallery/VALIDATE/DYADIC.
; UA=&H14: IX indexes RAM. This module owns tentative 2E40..2EBF RAM.
; RAM above previous 2E33 high-water REQUIRES owner/emulator qualification.
;
; B9C_PARSE:   NUL-terminated ASCII at B9C_TEXT (max 23 chars + NUL).
;             Writes B9C_VALUE only on success. $0=0 OK,1 SYNTAX,2 RANGE.
;             Grammar: [+-]? ((digits[.digits?]?)|(.digits))
;                      ([Ee][+-]?digits)?; at least one mantissa digit.
;             ASCII 'e' accepted as well as 'E'. Half-up at digit 14.
; B9C_FORMAT:  B9C_VALUE -> B9C_FMT, B9C_FMTLEN, exact 13 significant
;             B9 digits in scientific notation. $0=0 OK,1 BAD B9.
;             Zero prints '0'; nonzero prints [-]d.ddddddddddddE+NN.
; No keyboard, CALC controller, or 17-way dispatcher in this first gate.
; ============================================================================
B9C_TEXT:    EQU &H2E40  ; 24-byte NUL-terminated editor text
B9C_VALUE:   EQU &H2E60  ; committed 9-byte B9 (not overwritten on error)
B9C_FMT:     EQU &H2E70  ; 24-byte NUL-terminated formatted text
B9C_DIG:     EQU &H2E90  ; 14 unpacked significant digits (13+guard)
B9C_TMP:     EQU &H2EA0  ; nine-byte B9 transaction buffer
B9C_POS:     EQU &H2EB0  ; input offset 0..23
B9C_INT:     EQU &H2EB1  ; mantissa digits left of decimal point
B9C_FIRST:   EQU &H2EB2  ; first significant raw digit index, FF when none
B9C_NDIG:    EQU &H2EB3  ; all mantissa digits including leading zeroes
B9C_SCNT:    EQU &H2EB4  ; captured significant digits, at most 14
B9C_DOT:     EQU &H2EB5  ; decimal point encountered
B9C_STATE:   EQU &H2EB6  ; 0 mantissa, 1 explicit exponent
B9C_EDIG:    EQU &H2EB7  ; number of exponent digits
B9C_ESIGN:   EQU &H2EB8  ; 0 plus, 1 minus
B9C_EVAL:    EQU &H2EB9  ; absolute explicit exponent <=127
B9C_NEG:     EQU &H2EBA  ; mantissa negative
B9C_BIAS:    EQU &H2EBB  ; checked B9 exponent bias 1..199
B9C_FLEN:    EQU &H2EBC  ; formatted length excluding NUL
B9C_ESSET:   EQU &H2EBD  ; explicit exponent sign consumed
B9C_BSIGN:   EQU &H2EBE  ; decoded B9 sign flag
B9C_HUND:    EQU &H2EBF  ; decoded B9 biased exponent hundreds

; ------------------- transactional decimal text -> B9 ------------------------
B9C_PARSE:
        LD      $16,0
        PRE     IX,B9C_POS
        ST      $16,(IX+$SX)
        PRE     IX,B9C_INT
        ST      $16,(IX+$SX)
        PRE     IX,B9C_NDIG
        ST      $16,(IX+$SX)
        PRE     IX,B9C_SCNT
        ST      $16,(IX+$SX)
        PRE     IX,B9C_DOT
        ST      $16,(IX+$SX)
        PRE     IX,B9C_STATE
        ST      $16,(IX+$SX)
        PRE     IX,B9C_EDIG
        ST      $16,(IX+$SX)
        PRE     IX,B9C_ESIGN
        ST      $16,(IX+$SX)
        PRE     IX,B9C_EVAL
        ST      $16,(IX+$SX)
        PRE     IX,B9C_NEG
        ST      $16,(IX+$SX)
        PRE     IX,B9C_ESSET
        ST      $16,(IX+$SX)
        LD      $16,&HFF
        PRE     IX,B9C_FIRST
        ST      $16,(IX+$SX)
        PRE     IX,B9C_DIG
        LD      $20,14
        LD      $16,0
B9C_CLRDIG:
        STI     $16,(IX+$SX)
        SB      $20,$SY
        JP      NZ,B9C_CLRDIG
        LDW     $2,B9C_TEXT
B9C_NEXT:
        PRE     IX,B9C_POS
        LD      $18,(IX+$SX)
        SBC     $18,24
        JP      NC,B9C_BADSY  ; must see a NUL by byte 23
        PRE     IX,$2
        LD      $16,(IX+$SX)
        AN      $16,$16
        JP      Z,B9C_FINISH
        ADW     $2,$SY
        LD      $17,$16
        SBC     $17,&H30
        JP      C,B9C_NONDIG
        SBC     $17,&H3A
        JP      NC,B9C_NONDIG
        SB      $17,&H30
        JP      B9C_DIGIT
B9C_NONDIG:
        SBC     $16,&H2B   ; '+'
        JP      Z,B9C_PLUS
        SBC     $16,&H2D   ; '-'
        JP      Z,B9C_MINUS
        SBC     $16,&H2E   ; '.'
        JP      Z,B9C_POINT
        SBC     $16,&H45   ; 'E'
        JP      Z,B9C_EXPMARK
        SBC     $16,&H65   ; 'e'
        JP      Z,B9C_EXPMARK
        JP      B9C_BADSY
B9C_PLUS:
        PRE     IX,B9C_STATE
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      Z,B9C_MANTSIGN
        JP      B9C_EXP_SIGN
B9C_MINUS:
        PRE     IX,B9C_STATE
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      Z,B9C_MANTSIGN
        JP      B9C_EXP_SIGN
B9C_MANTSIGN:
        PRE     IX,B9C_POS
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      NZ,B9C_BADSY
        LD      $0,$16
        SBC     $0,&H2D
        JP      NZ,B9C_ADV
        PRE     IX,B9C_NEG
        LD      $0,1
        ST      $0,(IX+$SX)
        JP      B9C_ADV
B9C_EXP_SIGN:
        PRE     IX,B9C_EDIG
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      NZ,B9C_BADSY
        PRE     IX,B9C_ESSET
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      NZ,B9C_BADSY
        LD      $0,1
        ST      $0,(IX+$SX)
        LD      $0,$16
        SBC     $0,&H2D
        JP      NZ,B9C_ADV
        PRE     IX,B9C_ESIGN
        LD      $0,1
        ST      $0,(IX+$SX)
        JP      B9C_ADV
B9C_POINT:
        PRE     IX,B9C_STATE
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      NZ,B9C_BADSY
        PRE     IX,B9C_DOT
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      NZ,B9C_BADSY
        LD      $0,1
        ST      $0,(IX+$SX)
        JP      B9C_ADV
B9C_EXPMARK:
        PRE     IX,B9C_STATE
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      NZ,B9C_BADSY
        PRE     IX,B9C_NDIG
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      Z,B9C_BADSY
        PRE     IX,B9C_STATE
        LD      $0,1
        ST      $0,(IX+$SX)
        JP      B9C_ADV
B9C_DIGIT:
        PRE     IX,B9C_STATE
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      NZ,B9C_EXP_DIGIT
; Record first nonzero position BEFORE incrementing raw digit count.
        PRE     IX,B9C_FIRST
        LD      $0,(IX+$SX)
        SBC     $0,&HFF
        JP      NZ,B9C_MANT_N
        AN      $17,$17
        JP      Z,B9C_MANT_N
        PRE     IX,B9C_NDIG
        LD      $0,(IX+$SX)
        PRE     IX,B9C_FIRST
        ST      $0,(IX+$SX)
B9C_MANT_N:
        PRE     IX,B9C_DOT
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      NZ,B9C_MANT_RAW
        PRE     IX,B9C_INT
        LD      $0,(IX+$SX)
        AD      $0,$SY
        ST      $0,(IX+$SX)
B9C_MANT_RAW:
        PRE     IX,B9C_NDIG
        LD      $0,(IX+$SX)
        AD      $0,$SY
        ST      $0,(IX+$SX)
        PRE     IX,B9C_FIRST
        LD      $0,(IX+$SX)
        SBC     $0,&HFF
        JP      Z,B9C_ADV
        PRE     IX,B9C_SCNT
        LD      $0,(IX+$SX)
        SBC     $0,14
        JP      NC,B9C_ADV
        LD      $18,$0
        AD      $0,$SY
        ST      $0,(IX+$SX)
        LDW     $4,B9C_DIG
        LDW     $12,0
        LD      $12,$18
        ADW     $4,$12
        PRE     IX,$4
        ST      $17,(IX+$SX)
        JP      B9C_ADV
B9C_EXP_DIGIT:
        PRE     IX,B9C_EDIG
        LD      $0,(IX+$SX)
        AD      $0,$SY
        ST      $0,(IX+$SX)
; Safe base-10 exponent accumulation (signed <=127). Before x10,
; cap old value at 12, then reject any resulting value >127.
        PRE     IX,B9C_EVAL
        LD      $0,(IX+$SX)
        SBC     $0,13
        JP      NC,B9C_RANGE
        LD      $18,$0
        AD      $0,$0
        AD      $18,$18
        AD      $18,$18
        AD      $18,$18
        AD      $0,$18
        AD      $0,$17
        SBC     $0,128
        JP      NC,B9C_RANGE
        ST      $0,(IX+$SX)
        JP      B9C_ADV
B9C_ADV:
        PRE     IX,B9C_POS
        LD      $0,(IX+$SX)
        AD      $0,$SY
        ST      $0,(IX+$SX)
        JP      B9C_NEXT
B9C_FINISH:
        PRE     IX,B9C_NDIG
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      Z,B9C_BADSY
        PRE     IX,B9C_STATE
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      Z,B9C_CHECKZERO
        PRE     IX,B9C_EDIG
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      Z,B9C_BADSY
B9C_CHECKZERO:
        PRE     IX,B9C_FIRST
        LD      $0,(IX+$SX)
        SBC     $0,&HFF
        JP      Z,B9C_ZERO
; Actual biased exponent, signed 16-bit arithmetic: 100+INT-FIRST-1+/-EXP.
; Normalized B9 supports only bias 1..199 (actual E -99..+99).
        LDW     $2,100
        LDW     $4,0
        PRE     IX,B9C_INT
        LD      $4,(IX+$SX)
        ADW     $2,$4
        PRE     IX,B9C_FIRST
        LD      $4,(IX+$SX)
        SBW     $2,$4
        LDW     $4,1
        SBW     $2,$4
        LDW     $4,0
        PRE     IX,B9C_EVAL
        LD      $4,(IX+$SX)
        PRE     IX,B9C_ESIGN
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      NZ,B9C_EXPSUB
        ADW     $2,$4
        JP      B9C_EXPCHECK
B9C_EXPSUB:
        SBW     $2,$4
B9C_EXPCHECK:
        LDW     $4,1
        SBCW    $2,$4
        JP      C,B9C_RANGE
        LDW     $4,200
        SBCW    $2,$4
        JP      NC,B9C_RANGE
        PRE     IX,B9C_BIAS
        ST      $2,(IX+$SX)
; Half-up decimal rounding, using captured 14th digit (guard).
        PRE     IX,B9C_DIG+13
        LD      $0,(IX+$SX)
        SBC     $0,5
        JP      C,B9C_PACK
        LD      $18,12
B9C_ROUND:
        LDW     $4,B9C_DIG
        LDW     $12,0
        LD      $12,$18
        ADW     $4,$12
        PRE     IX,$4
        LD      $16,(IX+$SX)
        SBC     $16,9
        JP      NZ,B9C_ROUND_INC
        LD      $16,0
        ST      $16,(IX+$SX)
        AN      $18,$18
        JP      Z,B9C_ROUND_OVER
        SB      $18,$SY
        JP      B9C_ROUND
B9C_ROUND_INC:
        AD      $16,$SY
        ST      $16,(IX+$SX)
        JP      B9C_PACK
B9C_ROUND_OVER:
        PRE     IX,B9C_DIG
        LD      $16,1
        ST      $16,(IX+$SX)
        PRE     IX,B9C_BIAS
        LD      $16,(IX+$SX)
        AD      $16,$SY
        SBC     $16,200
        JP      NC,B9C_RANGE
        ST      $16,(IX+$SX)
B9C_PACK:
        LDW     $2,B9C_DIG+12
        LDW     $4,B9C_TMP
        LD      $20,6
B9C_PACKPAIR:
        PRE     IX,$2
        LD      $16,(IX+$SX)
        SBW     $2,$SY
        PRE     IX,$2
        LD      $17,(IX+$SX)
        SBW     $2,$SY
        AD      $17,$17
        AD      $17,$17
        AD      $17,$17
        AD      $17,$17
        OR      $16,$17
        PRE     IX,$4
        ST      $16,(IX+$SX)
        ADW     $4,$SY
        SB      $20,$SY
        JP      NZ,B9C_PACKPAIR
        PRE     IX,B9C_DIG
        LD      $16,(IX+$SX)
        PRE     IX,B9C_TMP+6
        ST      $16,(IX+$SX)
        PRE     IX,B9C_BIAS
        LD      $18,(IX+$SX)
        LD      $19,0
        SBC     $18,100
        JP      C,B9C_TENS
        SB      $18,100
        LD      $19,1
B9C_TENS:
        LD      $17,0
B9C_TENLOOP:
        SBC     $18,10
        JP      C,B9C_EXPWRITE
        SB      $18,10
        AD      $17,&H10
        JP      B9C_TENLOOP
B9C_EXPWRITE:
        OR      $17,$18
        PRE     IX,B9C_TMP+7
        ST      $17,(IX+$SX)
        PRE     IX,B9C_NEG
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      Z,B9C_POSITIVE
        AD      $19,5
B9C_POSITIVE:
        PRE     IX,B9C_TMP+8
        ST      $19,(IX+$SX)
        JP      B9C_COMMIT
B9C_ZERO:
        PRE     IX,B9C_TMP
        LD      $20,9
        LD      $16,0
B9C_ZEROLOOP:
        STI     $16,(IX+$SX)
        SB      $20,$SY
        JP      NZ,B9C_ZEROLOOP
B9C_COMMIT:
        LDW     $2,B9C_TMP
        LDW     $4,B9C_VALUE
        LD      $20,9
B9C_COPY:
        PRE     IX,$2
        LD      $16,(IX+$SX)
        ADW     $2,$SY
        PRE     IX,$4
        ST      $16,(IX+$SX)
        ADW     $4,$SY
        SB      $20,$SY
        JP      NZ,B9C_COPY
        LD      $0,0
        RTN
B9C_BADSY:
        LD      $0,1
        RTN
B9C_RANGE:
        LD      $0,2
        RTN

; ---------------------- exact B9 -> display text -----------------------------
; B9C_FORMAT does not mutate B9C_VALUE. Packed BCD and sign/exponent
; validity are checked before producing the final success code.
B9C_FORMAT:
        LD      $0,0
        LDW     $2,B9C_VALUE
        LD      $20,9
B9C_SCANZERO:
        PRE     IX,$2
        LD      $16,(IX+$SX)
        OR      $0,$16
        ADW     $2,$SY
        SB      $20,$SY
        JP      NZ,B9C_SCANZERO
        AN      $0,$0
        JP      Z,B9C_FMTZERO
        PRE     IX,B9C_VALUE+8
        LD      $18,(IX+$SX)
        LD      $19,$18
        SBC     $19,5
        JP      C,B9C_FMTPLUS
        SB      $18,5
        PRE     IX,B9C_BSIGN
        LD      $0,1
        ST      $0,(IX+$SX)
        JP      B9C_FMTBIAS
B9C_FMTPLUS:
        PRE     IX,B9C_BSIGN
        LD      $0,0
        ST      $0,(IX+$SX)
B9C_FMTBIAS:
        SBC     $18,2
        JP      NC,B9C_FMTBAD
        PRE     IX,B9C_HUND
        ST      $18,(IX+$SX)
        PRE     IX,B9C_VALUE+7
        LD      $17,(IX+$SX)
        LD      $18,$17
        AN      $18,&H0F
        SBC     $18,10
        JP      NC,B9C_FMTBAD
        DID     $17
        AN      $17,&H0F
        SBC     $17,10
        JP      NC,B9C_FMTBAD
        LD      $16,$17
        LD      $17,$18
        LD      $18,0
B9C_FMTTEN:
        AN      $16,$16
        JP      Z,B9C_FMTTENOK
        AD      $18,10
        SB      $16,$SY
        JP      B9C_FMTTEN
B9C_FMTTENOK:
        AD      $18,$17
        PRE     IX,B9C_HUND
        LD      $19,(IX+$SX)
        AN      $19,$19
        JP      Z,B9C_FMTB1
        AD      $18,100
B9C_FMTB1:
        AN      $18,$18
        JP      Z,B9C_FMTBAD
        SBC     $18,200
        JP      NC,B9C_FMTBAD
        PRE     IX,B9C_BIAS
        ST      $18,(IX+$SX)
; Significant digit 0 is B9C_VALUE+6 low nibble, followed by each
; pair's high nibble then low nibble from bytes +5,+4,...,+0.
        PRE     IX,B9C_VALUE+6
        LD      $16,(IX+$SX)
        LD      $17,$16
        AN      $17,&HF0
        JP      NZ,B9C_FMTBAD
        AN      $16,&H0F
        JP      Z,B9C_FMTBAD
        SBC     $16,10
        JP      NC,B9C_FMTBAD
        PRE     IX,B9C_DIG
        ST      $16,(IX+$SX)
        LDW     $2,B9C_VALUE+5
        LDW     $4,B9C_DIG+1
        LD      $20,6
B9C_UNPACK:
        PRE     IX,$2
        LD      $16,(IX+$SX)
        LD      $17,$16
        DID     $16
        AN      $16,&H0F
        SBC     $16,10
        JP      NC,B9C_FMTBAD
        AN      $17,&H0F
        SBC     $17,10
        JP      NC,B9C_FMTBAD
        PRE     IX,$4
        ST      $16,(IX+$SX)
        ADW     $4,$SY
        PRE     IX,$4
        ST      $17,(IX+$SX)
        ADW     $4,$SY
        SBW     $2,$SY
        SB      $20,$SY
        JP      NZ,B9C_UNPACK
; Build sign, 1 integer digit, decimal point, 12 fractional digits,
; E, sign, 2-digit signed decimal exponent; terminate explicitly.
        LDW     $4,B9C_FMT
        PRE     IX,B9C_BSIGN
        LD      $0,(IX+$SX)
        AN      $0,$0
        JP      Z,B9C_FMTFIRST
        LD      $16,&H2D
        CAL     B9C_EMIT
B9C_FMTFIRST:
        PRE     IX,B9C_DIG
        LD      $16,(IX+$SX)
        AD      $16,&H30
        CAL     B9C_EMIT
        LD      $16,&H2E
        CAL     B9C_EMIT
        LDW     $2,B9C_DIG+1
        LD      $20,12
B9C_FMTFRAC:
        PRE     IX,$2
        LD      $16,(IX+$SX)
        AD      $16,&H30
        CAL     B9C_EMIT
        ADW     $2,$SY
        SB      $20,$SY
        JP      NZ,B9C_FMTFRAC
        LD      $16,&H45
        CAL     B9C_EMIT
        PRE     IX,B9C_BIAS
        LD      $18,(IX+$SX)
        SBC     $18,100
        JP      C,B9C_FMTNEGEXP
        SB      $18,100
        LD      $16,&H2B
        JP      B9C_FMTEXPSIGN
B9C_FMTNEGEXP:
        LD      $0,100
        SB      $0,$18
        LD      $18,$0
        LD      $16,&H2D
B9C_FMTEXPSIGN:
        CAL     B9C_EMIT
        LD      $17,0
B9C_FMTEXP10:
        SBC     $18,10
        JP      C,B9C_FMTEXP1
        SB      $18,10
        AD      $17,$SY
        JP      B9C_FMTEXP10
B9C_FMTEXP1:
        LD      $16,$17
        AD      $16,&H30
        CAL     B9C_EMIT
        LD      $16,$18
        AD      $16,&H30
        CAL     B9C_EMIT
        LD      $16,0
        CAL     B9C_EMIT
; Subtract NUL from stored count; length excludes terminator.
        LDW     $2,B9C_FMT
        SBW     $4,$2
        SBW     $4,$SY
        PRE     IX,B9C_FLEN
        ST      $4,(IX+$SX)
        LD      $0,0
        RTN
B9C_FMTZERO:
        PRE     IX,B9C_FMT
        LD      $16,&H30
        STI     $16,(IX+$SX)
        LD      $16,0
        ST      $16,(IX+$SX)
        PRE     IX,B9C_FLEN
        LD      $16,1
        ST      $16,(IX+$SX)
        LD      $0,0
        RTN
B9C_FMTBAD:
        LD      $0,1
        RTN
B9C_EMIT:
        PRE     IX,$4
        ST      $16,(IX+$SX)
        ADW     $4,$SY
        RTN
