1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
; bcd16.s
; version 20060201
;
; Copyright (C) 2006 Damian Yerrick
;
; Copying and distribution of this file, with or without
; modification, are permitted in any medium without royalty provided
; the copyright notice and this notice are preserved in any source
; code copies. This file is offered as-is, without any warranty.
;
; @mssola: The memory addresses being used here have been modified so they don't
; clash with my programs (from $0x to $8x).
.p02
;; Define so you can better manage code that you want included whenever this
;; feature has been included.
BCD16_SUPPORT = 1
.exportzp bcdNum, bcdResult
.export bcdConvert
; bcdConvert
;
; Given a number in bcdNum (16-bit), converts it to 5 decimal digits
; in bcdResult. Unlike most 6502 binary-to-decimal converters, this
; subroutine doesn't use the decimal mode that was removed from the
; 2A03 variant of the 6502 processor.
;
; For each value of n from 4 to 1, it compares the number to 8*10^n,
; then 4*10^n, then 2*10^n, then 1*10^n, each time subtracting if
; possible. After finishing all the comparisons and subtractions in
; each decimal place value, it writes the digit to the output array
; as a byte value in the range [0, 9]. Finally, it writes the
; remainder to element 0.
;
; Extension to 24-bit and larger numbers is straightforward:
; Add a third bcdTable, increase BCD_BITS, and extend the
; trial subtraction.
; Constants _________________________________________________________
; BCD_BITS
; The highest possible number of bits in the BCD output. Should
; roughly equal 4 * log10(2) * x, where x is the width in bits
; of the largest binary number to be put in bcdNum.
; bcdTableLo[y], bcdTableHi[y]
; Contains (1 << y) converted from BCD to binary.
BCD_BITS = 19
; Variables _________________________________________________________
; bcdNum (input)
; Number to be converted to decimal (16-bit little endian).
; Overwritten.
; bcdResult (output)
; Decimal digits of result (5-digit little endian).
; X
; Offset of current digit being worked on.
; Y
; Offset into bcdTable*.
; curDigit
; The lower holds the digit being constructed.
; The upper nibble contains a sentinel value; when a 1 is shifted
; out, the byte is complete and should be copied to result.
; (This behavior is called a "ring counter".)
; Overwritten.
; b
; Low byte of the result of trial subtraction.
; Overwritten.
bcdNum = $80
bcdResult = $82
curDigit = $87
b = $82
;
; Completes within 670 cycles.
;
bcdConvert:
lda #$80 >> ((BCD_BITS - 1) & 3)
sta curDigit
ldx #(BCD_BITS - 1) >> 2
ldy #BCD_BITS - 5
@loop:
; Trial subtract this bit to A:b
sec
lda bcdNum
sbc bcdTableLo,y
sta b
lda bcdNum+1
sbc bcdTableHi,y
; If A:b > bcdNum then bcdNum = A:b
bcc @trial_lower
sta bcdNum+1
lda b
sta bcdNum
@trial_lower:
; Copy bit from carry into digit and pick up
; end-of-digit sentinel into carry
rol curDigit
dey
bcc @loop
; Copy digit into result
lda curDigit
sta bcdResult,x
lda #$10 ; Empty digit; sentinel at 4 bits
sta curDigit
; If there are digits left, do those
dex
bne @loop
lda bcdNum
sta bcdResult
rts
bcdTableLo:
.byt <10, <20, <40, <80
.byt <100, <200, <400, <800
.byt <1000, <2000, <4000, <8000
.byt <10000, <20000, <40000
bcdTableHi:
.byt >10, >20, >40, >80
.byt >100, >200, >400, >800
.byt >1000, >2000, >4000, >8000
.byt >10000, >20000, >40000
|