-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfbcd.as
166 lines (153 loc) · 3.49 KB
/
fbcd.as
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
; long _fbcd(x, exp, buf)
; double x;
; int * exp;
; char * buf;
; split x into mantissa and decimal exponent parts
; return value is the (long) mantissa part, exponent part is
; stored in *exp as two's complement. Mantissa is stored into buf
; as an ascii string.
argx equ 6 ;offset of x argument
argexp equ 10 ;offset of exp argument
argbuf equ 12 ;offset of buf argument
exptmp equ -1 ;offset of exp temp byte
sgntmp equ -2 ;offset of sign byte
NDIG equ 8 ;number of decimal digits
global __fbcd, rcsv, cret, flmul, negmant,lldiv,llmod
psect text
hasfrac:
ld c,0 ;zero number
ld a,e ;check low 8 bits
or a
jr nz,1f ;non zero bit in low 8 bits
ld c,8 ;bump count
ld a,d ;check next 8 bits
or a ;is there a bit there?
jr nz,1f ;yup
ld c,16
ld a,h ;now check next 8 bits
1:
rra ;shift bottom bit out
jr c,2f ;found a bit!
inc c ;increment count
jr 1b ;and loop
2:
ld a,h ;get exponent
res 7,a ;clear sign bit - should be zero anyway
sub 64+24 ;normalize - remove bias
add a,c ;add in bit position
ret ;return with value in a and flags set
__fbcd:
call rcsv ;get x into hlde, exp into bc
dec sp ;make room for exponent
dec sp ;and sign flag
xor a
ld (ix+exptmp),a ;zero it
ld (ix+sgntmp),a
ld (bc),a ;and the returned exp value
ex de,hl ;put hi word into hl as required
ld a,h ;check for zero exponent
and 7Fh ;zero exponent means 0.0
jp nz,1f ;return if x == 0.0
ld l,a ;zero mantissa just in case
ld e,a
ld d,a
ld h,a ;and sign/exponent
jp sbcd ;return with mantissa = 0, exponent = 0
1:
res 7,h ;test mantissa sign
2:
call hasfrac ;any fractional part?
jp m,1f ;negative if there is fractional part
push hl ;put x on stack
push de
ld hl,(tenth+2)
ld de,(tenth)
call flmul ;returns with value in hlde
inc (ix+exptmp) ;increment exponent
jr 2b ;now check again
1:
push hl
push de ;pass x as argument
ld hl,(ten+2)
ld de,(ten)
call flmul ;multiply it
dec (ix+exptmp) ;and decrement exponent
call hasfrac ;check for fractional part
jp m,1b ;loop if still fractional
ld a,h ;get exponent
ld h,0 ;zero top byte
sub 64+24 ;offset exponent
2:
or a ;check for zero
jr z,3f ;return if finished
jp p,4f
srl l ;shift l down
rr d ;rotate the rest
rr e
inc a ;increment count
jr 2b
4:
sla e
rl d
rl l
rl h
dec a
jr 2b
3:
ld a,(ix+exptmp)
ld c,(ix+argexp) ;get exp pointer
ld b,(ix+argexp+1)
ld (bc),a ;store exponent
inc bc
rla
sbc a,a
ld (bc),a ;sign extend it
bit 0,(ix+sgntmp) ;test sign
jp z,sbcd ;return if no negation needed
push hl ;push hi word
ld hl,0 ;get a zero
or a ;reset carry
sbc hl,de ;do low subtraction
ex de,hl ;put into de again
ld hl,0 ;get another zero
pop bc ;get hi word
sbc hl,bc ;subtract again
sbcd: ;now store as ascii
ld c,(ix+argbuf)
ld b,(ix+argbuf+1)
push bc
pop iy
ld bc,NDIG
add iy,bc ;point to end of buffer
ld b,c
ld (iy+0),0 ;null terminate
push hl
push de ;save return value
1:
push bc ;save count
push hl ;save value
push de
ld bc,0
push bc ;pass 10 on stack
ld bc,10
push bc
call llmod
ld a,e ;get remainder
add a,'0' ;asciize
dec iy
ld (iy+0),a
pop de
pop hl ;restore value
ld bc,0 ;now divide by 10
push bc
ld bc,10
push bc
call lldiv
pop bc ;restore count
djnz 1b ;loop if more to do
pop de
pop hl
jp cret ;all done
psect data
ten: deff 10.0
tenth: deff 0.1