Subversion Repositories NedoOS

Rev

Details | Last modification | View Log

Rev Author Line No. Line
1485 alone 1
#ifndef included_f32toa
2
#define included_f32toa
3
#include "pushpop.z80"
4
#include "f32_pow10_LUT.z80"
5
#include "f32mul.z80"
6
#include "mov4.z80"
7
#include "common_str.z80"
8
 
9
;#define EXTERNAL_FORMAT_LEN                  ;Uses an external reference to get the format length
10
;#define EXTERNAL_FORMAT_LEN fmtDigits    ;Use for TI-OS
11
 
12
; Set a hard upper limit to the number of digits used
13
; This routine uses at most MAX_FORMAT_LEN+8 bytes of space
14
#ifndef MAX_FORMAT_LEN
15
#define MAX_FORMAT_LEN 8
16
#endif
17
 
18
; Set the default number of digits used. If EXTERNAL_FORMAT_LEN is defined and
19
; that value is 0 or greater than MAX_FORMAT_LEN, then FORMAT_LEN is used.
20
#ifndef FORMAT_LEN
21
#define FORMAT_LEN 6
22
#endif
23
 
24
; set the char to use for `e` notation
25
#ifndef TOK_ENG
26
#define TOK_ENG 'e'
27
#endif
28
 
29
; set the char to use for negatives
30
#ifndef TOK_NEG
31
#define TOK_NEG '-'
32
#endif
33
 
34
; set the char to use for decimal points
35
#ifndef TOK_DECIMAL
36
#define TOK_DECIMAL '.'
37
#endif
38
 
39
 
40
#define f32toa_x    scrap
41
 
42
f32toa:
43
;Inputs:
44
;   HL points to the input float
45
;   BC points to where the string gets written.
46
  call pushpop
47
  ld e,(hl)
48
  inc hl
49
  ld d,(hl)
50
  inc hl
51
  ld (f32toa_x),de
52
  ld a,(hl)
53
  ld e,a
54
  add a,a
55
  inc hl
56
  ld a,(hl)
57
  ld d,a
58
  adc a,a
59
  ld h,b
60
  ld l,c
61
  inc a
62
  jp z,f32toa_return_infnan
63
  res 7,d
64
  ld (f32toa_x+2),de
65
  jr nc,+_
66
  ld (hl),TOK_NEG    ;negative sign
67
  inc hl
68
_:
69
;DEBC is the float, A is a copy of the exponent, HL points to the next byte to write
70
  dec a
71
  jp z,f32toa_return_0
72
 
73
  push hl
74
 
75
  ld (hl),'0' ; pad one more '0' to make room for rounding (i.e. 9.999999=>10.000000)
76
  inc hl
77
 
78
  push hl
79
 
80
; approximate the base-10 exponent as floor((A-127)*log10(2))
81
; which is approximately floor((A-127)*77/256)
82
  ld h,0
83
  ld l,a
84
  ld b,h
85
  ld c,a
86
  add hl,hl ;2
87
  add hl,hl ;4
88
  add hl,hl ;8
89
  add hl,bc ;9
90
  add hl,hl ;18
91
  add hl,bc ;19
92
  add hl,hl ;38
93
  add hl,hl ;76
94
  add hl,bc ;77
95
  ; now subtract 127*77 from HL and keep the upper 8 bits of the result
96
  ld a,205
97
  add a,l
98
  ld a,217
99
  adc a,h
100
  ; A is the approximate base-10 exponent
101
;f32toa_x needs to be multipled by 10^-A
102
  push af ; save the exponent
103
  call nz,f32toa_adjust
104
;the float is now on [1, 20)
105
;Let's no work on the float as a 0.24 fixed-point value
106
;we'll first need to extract the integer component
107
  ld hl,(f32toa_x)
108
  ld de,(f32toa_x+2)
109
  ld a,e
110
  rlca
111
  scf
112
  rra
113
  ld e,a
114
  ld a,d
115
  adc a,a
116
  sub 126
117
; A is how many bits to shift out of HLE
118
  ld b,a
119
  xor a
120
f32toa_first_digit_loop:
121
  add hl,hl
122
  rl e
123
  rla
124
  djnz f32toa_first_digit_loop
125
 
126
; A is the first digit
127
  pop bc  ; B is the base-10 exponent
128
  ex (sp),hl
129
  ld d,0
130
  cp 10
131
  jr c,f32toa_first_digit_fixed
132
  inc d
133
  dec hl
134
  ld (hl),'1'
135
  inc hl
136
  sub 10
137
f32toa_first_digit_fixed:
138
  add a,'0'
139
  ld (hl),a
140
 
141
  ld a,b
142
  ex (sp),hl
143
  pop bc
144
;A is the base-10 exponent
145
;BC is where to write the digits
146
;EHL is the 0.24 fixed-point number
147
;D is 1 if we have 2 digits already, else D is 0
148
  push af
149
  call f32toa_digits
150
 
151
;BC points to the last digit. We'll want to round!
152
  ld h,b
153
  ld l,c
154
  ld a,(hl)
155
  ld (hl),0
156
  add a,5
157
  jr f32toa_round_start
158
f32toa_round_loop:
159
  dec hl
160
  inc (hl)
161
  ld a,(hl)
162
f32toa_round_start:
163
  cp '9'+1
164
  jr nc,f32toa_round_loop
165
; the string is rounded
166
  inc hl
167
  ld (hl),0
168
 
169
  ; pop the exponent off the stack and sign-extend
170
  pop af
171
  ld e,a
172
  add a,a
173
  sbc a,a
174
  ld d,a
175
  pop hl
176
  ; check if rounding caused overflow; increment exponent if so
177
  ld a,(hl)
178
  cp '0'
179
  jp z,formatstr
180
  inc de
181
  jp formatstr
182
 
183
 
184
f32toa_digits:
185
; How many digits do we need?
186
#ifdef EXTERNAL_FORMAT_LEN
187
  ; we define the number of digits externally
188
  ld a,(EXTERNAL_FORMAT_LEN)
189
 
190
  ; if A is 0, use FORMAT_LEN
191
  or a
192
  jr nz,$+4
193
  ld a,FORMAT_LEN
194
 
195
  ; if A > MAX_FORMAT_LEN, set A to MAX_FORMAT_LEN
196
  cp MAX_FORMAT_LEN
197
  jr c,$+4
198
  ld a,MAX_FORMAT_LEN
199
 
200
  ; the first digit is written.
201
  ; if we only wanted 1 digit, then A is 0 and we should stop
202
  or a
203
  ret z
204
#else
205
  ; the number of digits is not declared externally
206
  ; the first digit is written.
207
  ; if we only wanted 1 digit, then A is 0 and we should stop
208
#if FORMAT_LEN < 2
209
  ret
210
#else
211
  ld a,FORMAT_LEN
212
#endif
213
#endif
214
 
215
; we want D more digits (an extra one for rounding)
216
f32toa_digits_loop:
217
  push af
218
  call f32toa_next_digit
219
  pop af
220
f32toa_digits_start:
221
  dec a
222
  jr nz,f32toa_digits_loop
223
  ret
224
 
225
f32toa_next_digit:
226
; multiply 0.EBC by 10
227
  push bc
228
  ld b,h
229
  ld c,l
230
  ld a,e
231
  ld d,6  ;overflow digit. We shift d 3 times, that 6 turns into a 0x30 == '0'
232
 
233
  add hl,hl
234
  adc a,a
235
  rl d
236
 
237
  add hl,hl
238
  adc a,a
239
  rl d
240
 
241
  add hl,bc
242
  adc a,e
243
  jr nc,$+3
244
  inc d
245
 
246
  add hl,hl
247
  adc a,a
248
  ld e,a
249
  ld a,d
250
  adc a,a
251
 
252
  pop bc
253
  inc bc
254
  ld (bc),a
255
  ret
256
 
257
 
258
f32toa_adjust:
259
  ld hl,f32_pown10_LUT-4
260
  jr c,f32toa_pow10LUT_mul
261
  neg
262
  ld hl,f32_pow10_LUT-4
263
f32toa_pow10LUT_mul:
264
;HL points to the first entry of the LUT
265
;(f32toa_x) is the accumulator
266
;bottom 6 bits of A control which terms to multiply by
267
  ld de,f32toa_x
268
  ld b,d
269
  ld c,e
270
; process f32toa_pow10LUT_mul_sub 6 times
271
  call f32toa_pow10LUT_mul_sub3
272
f32toa_pow10LUT_mul_sub3:
273
  call f32toa_pow10LUT_mul_sub
274
  call f32toa_pow10LUT_mul_sub
275
f32toa_pow10LUT_mul_sub:
276
  inc hl
277
  inc hl
278
  inc hl
279
  inc hl
280
  rra
281
  jp c,f32mul
282
  ret
283
 
284
f32toa_return_0:
285
  ld (hl),'0'
286
  inc hl
287
  ld (hl),0
288
  ret
289
 
290
f32toa_return_infnan:
291
  rl b  ; save the sign
292
  ld a,e
293
  add a,a
294
  ld de,(f32toa_x)
295
  or d
296
  or e
297
  ex de,hl
298
  ld hl,str_NaN
299
  jr nz,f32toa_return
300
  ld hl,str_inf
301
  rr b
302
  jr nc,f32toa_return
303
  ld a,'-'
304
  ld (de),a
305
  inc de
306
f32toa_return:
307
  jp mov4
308
 
309
#include "formatstr.z80"
310
#endif