An implementation of the Double Dabble algorithm for converting a number to an ASCII decimal representation was previously disclosed.
It has since been streamlined and generalized to handle numbers in sizes of one, two and four bytes.
This is the code for the 6502:
. 00199 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
. 00200 ;
. 00201 ; Format - Convert a number to ASCII decimal
. 00202 ;
. 00203 ; Input:
. 00204 ; The first bytes of Dabble = the number to convert
. 00205 ; Byt1 = number of bits to convert
. 00206 ; Byt2 = number of bytes to convert
. 00207 ; Byt3 = number of packed BCD bytes in result
. 00208 ;
. 00209 ; Output:
. 00210 ; Output string with length byte starting at Out+1
. 00211 ;
. 00212 ; Uses:
. 00213 ; Byt0
. 00214 ; Byt4
. 00215 ;
. 00216 ; Note:
. 00217 ; Implemented with the Double Dabble algorithm:
. 00218 ;
. 00219 ; https://en.wikipedia.org/wiki/Double_dabble
. 00220 ;
.0C27 00221 Format:
.0C27 A9 00 [2] 00222 lda #0 ; Clear the BCD digits
.0C29 A6 24 [3] 00223 ldx Byt2
.0C2B A4 25 [3] 00224 ldy Byt3
. 00225
.0C2D 00226 Format0:
.0C2D 95 2B [4] 00227 sta Dabble,X
.0C2F E8 [2] 00228 inx
.0C30 88 [2] 00229 dey
.0C31 D0 FA (0C2D) [2/3] 00230 bne Format0
. 00231
.0C33 18 [2] 00232 clc ; Determine index of BCD digits
.0C34 A5 25 [3] 00233 lda Byt3 ; BCD digits are big endian order
.0C36 65 24 [3] 00234 adc Byt2 ; Index := Num number bytes + Num BCD bytes - 1
.0C38 E9 00 [2] 00235 sbc #0
.0C3A 85 26 [3] 00236 sta Byt4
. 00237
.0C3C 00238 Format1:
.0C3C A6 26 [3] 00239 ldx Byt4 ; Index to BCD digits
.0C3E A4 25 [3] 00240 ldy Byt3 ; Number of bytes in converted BCD
. 00241
.0C40 00242 Format2:
.0C40 B5 2B [4] 00243 lda Dabble,X ; Isolate lower nybble
.0C42 29 0F [2] 00244 and #$F
.0C44 C9 05 [2] 00245 cmp #4+1 ; If greater than 4, add 3
.0C46 90 03 (0C4B) [2/3] 00246 blo FormatLoNotGT4
. 00247
.0C48 18 [2] 00248 clc
.0C49 69 03 [2] 00249 adc #3
. 00250
.0C4B 00251 FormatLoNotGT4:
.0C4B 85 22 [3] 00252 sta Byt0 ; Stash new lower nybble
. 00253
.0C4D B5 2B [4] 00254 lda Dabble,X ; Isolate upper nybble
.0C4F 29 F0 [2] 00255 and #$F0
.0C51 C9 50 [2] 00256 cmp #$40+$10 ; If greater than 4, add 3
.0C53 90 03 (0C58) [2/3] 00257 blo FormatHiNotGT4
. 00258
.0C55 18 [2] 00259 clc
.0C56 69 30 [2] 00260 adc #$30
. 00261
.0C58 00262 FormatHiNotGT4:
.0C58 05 22 [3] 00263 ora Byt0 ; Combine nybbles
.0C5A 95 2B [4] 00264 sta Dabble,X
. 00265
.0C5C CA [2] 00266 dex
.0C5D 88 [2] 00267 dey ; More BCD digits to check?
.0C5E D0 E0 (0C40) [2/3] 00268 bne Format2
. 00269
.0C60 06 2B [5] 00270 asl Dabble ; Shift the number left one bit
.0C62 A2 01 [2] 00271 ldx #1
.0C64 A4 24 [3] 00272 ldy Byt2
.0C66 88 [2] 00273 dey
.0C67 F0 06 (0C6F) [2/3] 00274 beq Format3 ; No additional bytes
. 00275
.0C69 00276 FormatShiftNumber:
.0C69 36 2B [6] 00277 rol Dabble,X ; Shift the rest of the number
.0C6B E8 [2] 00278 inx
.0C6C 88 [2] 00279 dey
.0C6D D0 FA (0C69) [2/3] 00280 bne FormatShiftNumber
. 00281
.0C6F 00282 Format3:
.0C6F A6 26 [3] 00283 ldx Byt4 ; Shift the BCD digits left one bit
.0C71 A4 25 [3] 00284 ldy Byt3
. 00285
.0C73 00286 FormatShiftBCD:
.0C73 36 2B [6] 00287 rol Dabble,X
.0C75 CA [2] 00288 dex
.0C76 88 [2] 00289 dey
.0C77 D0 FA (0C73) [2/3] 00290 bne FormatShiftBCD
. 00291
.0C79 C6 23 [5] 00292 dec Byt1 ; More bits to process?
.0C7B D0 BF (0C3C) [2/3] 00293 bne Format1
. 00294
.0C7D A4 24 [3] 00295 ldy Byt2 ; Index converted BCD
.0C7F A2 00 [2] 00296 ldx #0 ; And the output string
. 00297
.0C81 00298 Format4:
.0C81 B9 002B [4/5] 00299 lda Dabble,Y ; Isolate upper digit
.0C84 29 F0 [2] 00300 and #$F0
.0C86 D0 04 (0C8C) [2/3] 00301 bne FormatEmitHi
. 00302
.0C88 E0 00 [2] 00303 cpx #0 ; Leading zero?
.0C8A F0 0A (0C96) [2/3] 00304 beq FormatSkipHi
. 00305
.0C8C 00306 FormatEmitHi:
.0C8C 4A [2] 00307 lsr A ; Shift into lower nybble
.0C8D 4A [2] 00308 lsr A
.0C8E 4A [2] 00309 lsr A
.0C8F 4A [2] 00310 lsr A
. 00311
.0C90 18 [2] 00312 clc ; Convert to ASCII numeral
.0C91 69 30 [2] 00313 adc #'0'
.0C93 E8 [2] 00314 inx
.0C94 95 29 [4] 00315 sta Out+1,X
. 00316
.0C96 00317 FormatSkipHi:
.0C96 B9 002B [4/5] 00318 lda Dabble,Y ; Isolate lower digit
.0C99 29 0F [2] 00319 and #$F
.0C9B D0 04 (0CA1) [2/3] 00320 bne FormatEmitLo
. 00321
.0C9D E0 00 [2] 00322 cpx #0 ; Leading zero?
.0C9F F0 06 (0CA7) [2/3] 00323 beq FormatSkipLo
. 00324
.0CA1 00325 FormatEmitLo:
.0CA1 18 [2] 00326 clc ; Convert to ASCII numeral
.0CA2 69 30 [2] 00327 adc #'0'
.0CA4 E8 [2] 00328 inx
.0CA5 95 29 [4] 00329 sta Out+1,X
. 00330
.0CA7 00331 FormatSkipLo:
.0CA7 C8 [2] 00332 iny ; Address next pair of digits
. 00333
.0CA8 C6 25 [5] 00334 dec Byt3 ; More digits?
.0CAA D0 D5 (0C81) [2/3] 00335 bne Format4
. 00336
.0CAC 86 29 [3] 00337 stx Out+1 ; Store length of result
.0CAE 8A [2] 00338 txa
.0CAF D0 08 (0CB9) [2/3] 00339 bne FormatDone ; Check for all 0's
. 00340
.0CB1 A9 01 [2] 00341 lda #1 ; Default to "0"
.0CB3 85 29 [3] 00342 sta Out+1
.0CB5 A9 30 [2] 00343 lda #'0'
.0CB7 85 2A [3] 00344 sta Out+1+1
. 00345
.0CB9 00346 FormatDone:
.0CB9 60 [6] 00347 rts
For the 6800:
. 00180 ******************************************************************************
. 00181 *
. 00182 * Format - Convert a number to ASCII decimal
. 00183 *
. 00184 * Input:
. 00185 * The first bytes of Dabble = the number to convert
. 00186 * Int0 = number of bytes to convert
. 00187 * Byt1 = number of bits to convert
. 00188 * Byt2 = number of packed BCD bytes in result
. 00189 *
. 00190 * Output:
. 00191 * Output string with length byte starting at Out+1
. 00192 *
. 00193 * Uses:
. 00194 * Int1
. 00195 * Byt0
. 00196 *
. 00197 * Note:
. 00198 * Implemented with the Double Dabble algorithm:
. 00199 *
. 00200 * https://en.wikipedia.org/wiki/Double_dabble
. 00201 *
.020B 00202 Format
.020B 86 00 [2] 00203 ldaa #0 ; Clear the BCD digits
.020D DE 02 [4] 00204 ldx Int0
.020F D6 12 [3] 00205 ldab Byt2
. 00206
.0211 00207 Format0
.0211 A7 19 [6] 00208 staa Dabble,X
.0213 08 [4] 00209 inx
.0214 5A [2] 00210 decb
.0215 26 FA (0211) [4] 00211 bne Format0
. 00212
.0217 96 12 [3] 00213 ldaa Byt2 ; Determine index of BCD digits
.0219 9B 03 [3] 00214 adda Int0+1 ; BCD digits are big endian order
.021B 4A [2] 00215 deca ; Index := Num number bytes + Num BCD bytes - 1
.021C 97 05 [4] 00216 staa Int1+1
.021E 7F 0004 [6] 00217 clr Int1 ; Clear upper byte of index
. 00218
.0221 00219 Format1
.0221 DE 04 [4] 00220 ldx Int1 ; Index to BCD digits
.0223 D6 12 [3] 00221 ldab Byt2 ; Number of bytes in converted BCD
. 00222
.0225 00223 Format2
.0225 A6 19 [5] 00224 ldaa Dabble,X ; Isolate lower nybble
.0227 84 0F [2] 00225 anda #$F
.0229 81 05 [2] 00226 cmpa #4+1 ; If greater than 4, add 3
.022B 25 02 (022F) [4] 00227 blo FormatLoNotGT4
. 00228
.022D 8B 03 [2] 00229 adda #3
. 00230
.022F 00231 FormatLoNotGT4
.022F 97 10 [4] 00232 staa Byt0 ; Stash new lower nybble
. 00233
.0231 A6 19 [5] 00234 ldaa Dabble,X ; Isolate upper nybble
.0233 84 F0 [2] 00235 anda #$F0
.0235 81 50 [2] 00236 cmpa #$40+$10 ; If greater than 4, add 3
.0237 25 02 (023B) [4] 00237 blo FormatHiNotGT4
. 00238
.0239 8B 30 [2] 00239 adda #$30
. 00240
.023B 00241 FormatHiNotGT4
.023B 9A 10 [3] 00242 oraa Byt0 ; Combine nybbles
.023D A7 19 [6] 00243 staa Dabble,X
. 00244
.023F 09 [4] 00245 dex
.0240 5A [2] 00246 decb ; More BCD digits to check?
.0241 26 E2 (0225) [4] 00247 bne Format2
. 00248
.0243 DE 02 [4] 00249 ldx Int0 ; Address the number to convert
.0245 09 [4] 00250 dex
. 00251
.0246 68 19 [7] 00252 asl Dabble,X ; Shift the number left one bit
.0248 D6 03 [3] 00253 ldab Int0+1
.024A 5A [2] 00254 decb
.024B 27 06 (0253) [4] 00255 beq Format3 ; No additional bytes
. 00256
.024D 00257 FormatShiftNumber
.024D 09 [4] 00258 dex
.024E 69 19 [7] 00259 rol Dabble,X ; Shift the rest of the number
.0250 5A [2] 00260 decb
.0251 26 FA (024D) [4] 00261 bne FormatShiftNumber
. 00262
.0253 00263 Format3
.0253 DE 04 [4] 00264 ldx Int1 ; Shift the BCD digits left one bit
.0255 D6 12 [3] 00265 ldab Byt2
. 00266
.0257 00267 FormatShiftBCD
.0257 69 19 [7] 00268 rol Dabble,X
.0259 09 [4] 00269 dex
.025A 5A [2] 00270 decb
.025B 26 FA (0257) [4] 00271 bne FormatShiftBCD
. 00272
.025D 7A 0011 [6] 00273 dec Byt1 ; More bits to process?
.0260 26 BF (0221) [4] 00274 bne Format1
. 00275
.0262 CE 0000 [3] 00276 ldx #0 ; And the output string
.0265 DF 04 [5] 00277 stx Int1
. 00278
.0267 00279 Format4
.0267 DE 02 [4] 00280 ldx Int0 ; Index converted BCD
.0269 A6 19 [5] 00281 ldaa Dabble,X ; Isolate upper digit
.026B 84 F0 [2] 00282 anda #$F0
.026D 26 05 (0274) [4] 00283 bne FormatEmitHi
. 00284
.026F 7D 0005 [6] 00285 tst Int1+1 ; Leading zero?
.0272 27 0F (0283) [4] 00286 beq FormatSkipHi
. 00287
.0274 00288 FormatEmitHi:
.0274 44 [2] 00289 lsra ; Shift into lower nybble
.0275 44 [2] 00290 lsra
.0276 44 [2] 00291 lsra
.0277 44 [2] 00292 lsra
. 00293
.0278 8B 30 [2] 00294 adda #'0' ; Convert to ASCII numeral
.027A DE 04 [4] 00295 ldx Int1
.027C 08 [4] 00296 inx
.027D DF 04 [5] 00297 stx Int1
.027F A7 17 [6] 00298 staa Out+1,X
.0281 DE 02 [4] 00299 ldx Int0 ; Index converted BCD
. 00300
.0283 00301 FormatSkipHi:
.0283 A6 19 [5] 00302 ldaa Dabble,X ; Isolate lower digit
.0285 84 0F [2] 00303 anda #$F
.0287 26 05 (028E) [4] 00304 bne FormatEmitLo
. 00305
.0289 7D 0005 [6] 00306 tst Int1+1 ; Leading zero?
.028C 27 0B (0299) [4] 00307 beq FormatSkipLo
. 00308
.028E 00309 FormatEmitLo:
.028E 8B 30 [2] 00310 adda #'0' ; Convert to ASCII numeral
.0290 DE 04 [4] 00311 ldx Int1
.0292 08 [4] 00312 inx
.0293 DF 04 [5] 00313 stx Int1
.0295 A7 17 [6] 00314 staa Out+1,X
.0297 DE 02 [4] 00315 ldx Int0 ; Index converted BCD
. 00316
.0299 00317 FormatSkipLo:
.0299 7C 0003 [6] 00318 inc Int0+1 ; Address next pair of digits
. 00319
.029C 7A 0012 [6] 00320 dec Byt2 ; More digits?
.029F 26 C6 (0267) [4] 00321 bne Format4
. 00322
.02A1 96 05 [3] 00323 ldaa Int1+1 ; Store length of result
.02A3 97 17 [4] 00324 staa Out+1
.02A5 26 08 (02AF) [4] 00325 bne FormatDone ; Check for all 0's
. 00326
.02A7 86 01 [2] 00327 ldaa #1 ; Default to "0"
.02A9 97 17 [4] 00328 staa Out+1
.02AB 86 30 [2] 00329 ldaa #'0'
.02AD 97 18 [4] 00330 staa Out+1+1
. 00331
.02AF 00332 FormatDone
.02AF 39 [5] 00333 rts
And for the 8080:
. 00148 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
. 00149 ;
. 00150 ; Format - Convert a number to ASCII decimal
. 00151 ;
. 00152 ; Input:
. 00153 ; The first bytes of Dabble = the number to convert
. 00154 ; Int0 = number of bytes to convert
. 00155 ; Byt0 = number of bits to convert
. 00156 ; Byt1 = number of packed BCD bytes in result
. 00157 ;
. 00158 ; Output:
. 00159 ; Output string with length byte starting at Out+1
. 00160 ;
. 00161 ; Uses:
. 00162 ; Int1
. 00163 ;
. 00164 ; Note:
. 00165 ; Implemented with the Double Dabble algorithm:
. 00166 ;
. 00167 ; https://en.wikipedia.org/wiki/Double_dabble
. 00168 ;
.01F9 00169 Format:
.01F9 3A 03B7 [13] 00170 lda Byt1 ; Clear the BCD digits
.01FC 47 [5] 00171 mov B,A
.01FD AF [4] 00172 xra A
.01FE 11 03BF [10] 00173 lxi D,Dabble
.0201 2A 03A8 [16] 00174 lhld Int0
.0204 19 [10] 00175 dad D
. 00176
.0205 00177 Format0:
.0205 77 [7] 00178 mov M,A
.0206 23 [5] 00179 inx H
.0207 05 [5] 00180 dcr B
.0208 C2 0205 [10] 00181 jnz Format0
. 00182
.020B 3A 03B7 [13] 00183 lda Byt1 ; Determine address of BCD digits
.020E 5F [5] 00184 mov E,A
.020F 16 00 [7] 00185 mvi D,0
.0211 2A 03A8 [16] 00186 lhld Int0 ; BCD digits are big endian order
.0214 19 [10] 00187 dad D
.0215 11 03BE [10] 00188 lxi D,Dabble-1 ; Index := Num number bytes + Num BCD bytes - 1
.0218 19 [10] 00189 dad D
.0219 EB [4] 00190 xchg ; Keep it in DE
. 00191
.021A 00192 Format1:
.021A 3A 03B7 [13] 00193 lda Byt1 ; Number of bytes in converted BCD
.021D 47 [5] 00194 mov B,A
. 00195
.021E 6B [5] 00196 mov L,E ; Address lowest BCD byte
.021F 62 [5] 00197 mov H,D
. 00198
.0220 00199 Format2:
.0220 7E [7] 00200 mov A,M ; Isolate lower nybble
.0221 E6 0F [7] 00201 ani 0Fh
.0223 FE 05 [7] 00202 cpi 4+1 ; If greater than 4, add 3
.0225 DA 022A [10] 00203 jc FormatLoNotGT4
. 00204
.0228 C6 03 [7] 00205 adi 3
. 00206
.022A 00207 FormatLoNotGT4:
.022A 4F [5] 00208 mov C,A ; Stash new lower nybble
. 00209
.022B 7E [7] 00210 mov A,M ; Isolate upper nybble
.022C E6 F0 [7] 00211 ani 0F0h
.022E FE 50 [7] 00212 cpi 40h+10h ; If greater than 4, add 3
.0230 DA 0235 [10] 00213 jc FormatHiNotGT4
. 00214
.0233 C6 30 [7] 00215 adi 30h
. 00216
.0235 00217 FormatHiNotGT4:
.0235 B1 [4] 00218 ora C ; Combine nybbles
.0236 77 [7] 00219 mov M,A
. 00220
.0237 2B [5] 00221 dcx H
.0238 05 [5] 00222 dcr B ; More BCD digits to check?
.0239 C2 0220 [10] 00223 jnz Format2
. 00224
.023C 3A 03BF [13] 00225 lda Dabble ; Shift the number left one bit
.023F 87 [4] 00226 add A
.0240 32 03BF [13] 00227 sta Dabble
. 00228
.0243 21 03C0 [10] 00229 lxi H,Dabble+1
.0246 3A 03A8 [13] 00230 lda Int0
.0249 47 [5] 00231 mov B,A
.024A 05 [5] 00232 dcr B
.024B CA 0256 [10] 00233 jz Format3 ; No additional bytes
. 00234
.024E 00235 FormatShiftNumber:
.024E 7E [7] 00236 mov A,M ; Shift the rest of the number
.024F 17 [4] 00237 ral
.0250 77 [7] 00238 mov M,A
.0251 23 [5] 00239 inx H
.0252 05 [5] 00240 dcr B
.0253 C2 024E [10] 00241 jnz FormatShiftNumber
. 00242
.0256 00243 Format3:
.0256 3A 03B7 [13] 00244 lda Byt1 ; Shift the BCD digits left one bit
.0259 47 [5] 00245 mov B,A
.025A 6B [5] 00246 mov L,E
.025B 62 [5] 00247 mov H,D
. 00248
.025C 00249 FormatShiftBCD:
.025C 7E [7] 00250 mov A,M
.025D 17 [4] 00251 ral
.025E 77 [7] 00252 mov M,A
.025F 2B [5] 00253 dcx H
.0260 05 [5] 00254 dcr B
.0261 C2 025C [10] 00255 jnz FormatShiftBCD
. 00256
.0264 3A 03B6 [13] 00257 lda Byt0 ; More bits to process?
.0267 3D [5] 00258 dcr A
.0268 32 03B6 [13] 00259 sta Byt0
.026B C2 021A [10] 00260 jnz Format1
. 00261
.026E 11 03BF [10] 00262 lxi D,Dabble
.0271 2A 03A8 [16] 00263 lhld Int0
.0274 19 [10] 00264 dad D
.0275 3A 03B7 [13] 00265 lda Byt1
.0278 47 [5] 00266 mov B,A
. 00267
.0279 11 03BD [10] 00268 lxi D,Out+1 ; Address the output string
. 00269
.027C 0E 01 [7] 00270 mvi C,1
. 00271
.027E 00272 Format4:
.027E 7E [7] 00273 mov A,M ; Isolate upper digit
.027F E6 F0 [7] 00274 ani 0F0h
.0281 C2 0288 [10] 00275 jnz FormatEmitHi
. 00276
.0284 0D [5] 00277 dcr C ; Leading zero?
.0285 CA 0290 [10] 00278 jz FormatSkipHi
. 00279
.0288 00280 FormatEmitHi:
.0288 0F [4] 00281 rrc ; Shift into lower nybble
.0289 0F [4] 00282 rrc
.028A 0F [4] 00283 rrc
.028B 0F [4] 00284 rrc
. 00285
.028C C6 30 [7] 00286 adi '0' ; Convert to ASCII numeral
.028E 13 [5] 00287 inx D
.028F 12 [7] 00288 stax D
. 00289
.0290 00290 FormatSkipHi:
.0290 0C [5] 00291 inr C
. 00292
.0291 7E [7] 00293 mov A,M ; Isolate lower digit
.0292 E6 0F [7] 00294 ani 0Fh
.0294 C2 029B [10] 00295 jnz FormatEmitLo
. 00296
.0297 0D [5] 00297 dcr C ; Leading zero?
.0298 CA 029F [10] 00298 jz FormatSkipLo
. 00299
.029B 00300 FormatEmitLo:
.029B C6 30 [7] 00301 adi '0' ; Convert to ASCII numeral
.029D 13 [5] 00302 inx D
.029E 12 [7] 00303 stax D
. 00304
.029F 00305 FormatSkipLo:
.029F 0C [5] 00306 inr C
. 00307
.02A0 23 [5] 00308 inx H ; Address next pair of digits
. 00309
.02A1 05 [5] 00310 dcr B ; More digits?
.02A2 C2 027E [10] 00311 jnz Format4
. 00312
.02A5 79 [5] 00313 mov A,C ; Store length of result
.02A6 3D [5] 00314 dcr A
.02A7 C2 02B1 [10] 00315 jnz FormatDone ; Check for all 0's
. 00316
.02AA 3E 30 [7] 00317 mvi A,'0' ; Default to "0"
.02AC 32 03BE [13] 00318 sta Out+1+1
. 00319
.02AF 3E 01 [7] 00320 mvi A,1
. 00321
.02B1 00322 FormatDone:
.02B1 32 03BD [13] 00323 sta Out+1
. 00324
.02B4 C9 [10] 00325 ret