Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1186 | savelij | 1 | ; FLOAT.INC |
2 | ;****************************************************************************** |
||
3 | ;* Gleitkommabibliothek fuer TLCS 900 * |
||
4 | ;* * |
||
5 | ;* Originale fuer den 68000 aus mc, bis auf die Quadratwurzel aus c't * |
||
6 | ;* Portierung auf TLCS 900 von Alfred Arnold, Oktober 1993 * |
||
7 | ;* * |
||
8 | ;* Routine Funktion Eingabe Ausgabe Stack Laenge Zeit/14MHz * |
||
9 | ;* * |
||
10 | ;* fadd Addition XWA+XHL XWA 12 Byte 194 Byte 60 us * |
||
11 | ;* fsub Subtraktion XWA-XHL XWA 12 Byte 7 Byte 65 us * |
||
12 | ;* fmul Multiplikation XWA*XHL XWA 20 Byte 218 Byte 70 us * |
||
13 | ;* fdiv Division XWA/XHL XWA 20 Byte 147 Byte 300 us * |
||
14 | ;* fmul2 Mult. mit 2er-Potenz XWA*(2^BC) XWA 6 Byte 99 Byte 20 us * |
||
15 | ;* fitof Int-->Float XWA XWA 4 Byte 41 Byte 90 us * |
||
16 | ;* fftoi Float-->Int XWA XWA 2 Byte 72 Byte 20 us * |
||
17 | ;* fsqrt Quadratwurzel XWA XWA 16 Byte 192 Byte 220 us * |
||
18 | ;* fftoa Float-->ASCII XWA (XHL),BC ~38 Byte 228 Byte ~4500 us * |
||
19 | ;* fatof ASCII-->Float (XHL),BC XWA,[BC] ~40 Byte 260 Byte ~2300 us * |
||
20 | ;* * |
||
21 | ;* - Wollen Sie einzelne Routinen entfernen, so beachten Sie, dass fsub Teile * |
||
22 | ;* aus fadd und fdiv Teile aus fmul verwendet ! * |
||
23 | ;* - Gleitkommaformat ist IEEE Single (32 Bit) * |
||
24 | ;* - Integerwerte bei fmul2, fitof und fftoi sind vorzeichenbehaftet * |
||
25 | ;* - Der Prozessor muss sich im Maximum-Modus befinden * |
||
26 | ;* - Da die Routinen lokale Labels verwenden, ist mindestens AS 1.39 erfor- * |
||
27 | ;* derlich * |
||
28 | ;* - Die Ausfuehrungszeiten koennen je nach Operand streuen, insbesondere bei * |
||
29 | ;* den Konvertierungsfunktionen * |
||
30 | ;* - MACROS.INC muss vorher eingebunden werden * |
||
31 | ;****************************************************************************** |
||
32 | |||
33 | ;------------------------------------------------------------------------------ |
||
34 | ; gemeinsamer Anfang, Makros |
||
35 | |||
36 | shifta macro op,dest ; Schieben, falls evtl. A>=16 |
||
37 | push a ; A wird zerschossen |
||
38 | bit 4,a ; Akku im Bereich 16..31 ? |
||
39 | jr z,smaller |
||
40 | op 16,dest ; dann einmal gross schieben |
||
41 | smaller: push f ; Carry erhalten |
||
42 | and a,15 ; obere Bits plaetten |
||
43 | jr z,fertig |
||
44 | pop f ; evtl. Rest verarbeiten |
||
45 | op a,dest |
||
46 | jr ende ; Carry schon gut |
||
47 | fertig: pop f |
||
48 | ende: pop a ; A zurueck |
||
49 | endm |
||
50 | |||
51 | section FloatLib |
||
52 | |||
53 | ;------------------------------------------------------------------------------ |
||
54 | ; Konstanten |
||
55 | |||
56 | Ld10: dd ld(10) ; Konversionskonstanten |
||
57 | One: dd 1.0 |
||
58 | Half: dd 0.5 |
||
59 | Ten: dd 10.0 |
||
60 | Tenth: dd 3dcccccdh ; =0.1, aber die Rundung auf manchen |
||
61 | ; Systemen variiert (damit Test nicht |
||
62 | ; scheitert) |
||
63 | |||
64 | Bias equ 127 |
||
65 | MaxExpo equ 255 |
||
66 | Comma equ '.' |
||
67 | |||
68 | ;------------------------------------------------------------------------------ |
||
69 | ; Addition: XWA=XWA+XHL |
||
70 | |||
71 | proc fadd |
||
72 | |||
73 | push xbc ; andere Register retten |
||
74 | push xde |
||
75 | push xhl |
||
76 | |||
77 | ld xde,xwa ; Operand 1 nach XDE verschieben |
||
78 | rlc 1,xde ; Vorzeichen der Operanden nach Bit 0 |
||
79 | rlc 1,xhl |
||
80 | ld xbc,xde ; Differenz bilden |
||
81 | sub xbc,xhl |
||
82 | jr nc,NoSwap ; evtl. vertauschen, so dass |
||
83 | ld xwa,xhl ; groessere in XDE |
||
84 | ld xhl,xde |
||
85 | ld xde,xwa |
||
86 | NoSwap: ld qa,e ; Vorzeichen 1 ausmaskieren |
||
87 | and qa,1 ; (=Ergebnis Vorzeichen) |
||
88 | bit 0,c ; gleiches Vorzeichen ? |
||
89 | jr z,NoSub |
||
90 | set 1,qa ; dann Subtraktion vormerken |
||
91 | |||
92 | NoSub: sub xbc,xbc ; XBC initialisieren |
||
93 | rlc 8,xde ; Exponent 1 rausholen |
||
94 | ld c,e |
||
95 | or e,e ; falls <>0, implizite 1 einbauen |
||
96 | scc nz,e |
||
97 | rrc 1,xde |
||
98 | ld e,0 ; Bit 0..7 wieder plaetten |
||
99 | |||
100 | rlc 8,xhl ; dito Exponent 2 extrahieren |
||
101 | ld qc,l |
||
102 | or l,l |
||
103 | scc nz,l |
||
104 | rrc 1,xhl |
||
105 | ld l,0 |
||
106 | |||
107 | ; Zwischenstand: |
||
108 | ; - Mantissen linksbuendig inkl. impliziter Eins in XDE und XHL |
||
109 | ; - Exponent 1 in BC, Exponent 2 in QBC |
||
110 | ; - Ergebnisvorzeichen in QA, Bit 0 |
||
111 | ; - Subtraktionsflag in QA, Bit 1 |
||
112 | |||
113 | ld wa,bc ; Exponentendifferenz berechnen |
||
114 | sub wa,qbc |
||
115 | cp wa,24 ; >24, d.h. Zahl 2 vernachlaessigbar gegen Zahl 1 |
||
116 | jr gt,Round ; ja, Ergebnis ist groessere Zahl |
||
117 | shifta srl,xhl ; ansonsten Mantisse 2 entspr. anpassen |
||
118 | |||
119 | Add: bit 1,qa ; subtrahieren ? |
||
120 | jr nz,Subtract ; ja--> |
||
121 | add xde,xhl ; nein, Mantissen addieren |
||
122 | jr nc,Round ; kein Ueberlauf, runden |
||
123 | rr 1,xde ; ansonsten Ueberlauf einschieben... |
||
124 | inc bc ; ...und Exponent korrigieren |
||
125 | jr Round ; normal weiter runden |
||
126 | |||
127 | Subtract: sub xde,xhl ; Mantissen subtrahieren |
||
128 | jr z,Zero ; falls Null, Gesamtergebnis 0 |
||
129 | jr m,Round ; fuehrende 1 noch da: zum Runden |
||
130 | Normalize: or bc,bc ; Exponent bereits Null ? |
||
131 | jr z,Round ; dann denormales Ergebnis |
||
132 | dec bc ; ansonsten Mantisse eins rauf, Exponent |
||
133 | sll 1,xde ; eins runter |
||
134 | jr p,Normalize ; solange, bis Eins auftaucht |
||
135 | |||
136 | Round: add xde,80h ; Rundung auf Bit hinter Mantisse |
||
137 | jr nc,NoOver |
||
138 | rr 1,xde ; Bei Ueberlauf korrigieren |
||
139 | inc bc |
||
140 | NoOver: ld e,0 ; Mantissenrest plaetten |
||
141 | or xde,xde ; insgesamt 0 ? |
||
142 | jr z,Zero ; dann Ergebnis 0 |
||
143 | cp bc,MaxExpo ; Exponentenueberlauf ? |
||
144 | jr lt,NoEOver |
||
145 | ld bc,MaxExpo ; ja: Unendlich: Exponent=Maximum |
||
146 | sub xde,xde ; Mantisse=0 |
||
147 | jr Denormal |
||
148 | |||
149 | NoEOver: or bc,bc ; Exponent 0 ? |
||
150 | jr z,Denormal ; ja, denormal |
||
151 | sll 1,xde ; fuehrende Eins nicht speichern |
||
152 | Denormal: ld e,c ; Exponenten einbauen |
||
153 | rrc 8,xde ; nach oben schieben |
||
154 | rr 1,qa ; Vorzeichen einbauen |
||
155 | rr 1,xde |
||
156 | |||
157 | Zero: ld xwa,xde ; Ergebnis in Akku |
||
158 | |||
159 | pop xhl ; Register zurueck |
||
160 | pop xde |
||
161 | pop xbc |
||
162 | |||
163 | ret |
||
164 | |||
165 | endp |
||
166 | |||
167 | ;------------------------------------------------------------------------------ |
||
168 | ; Subtraktion: XWA=XWA-XHL |
||
169 | |||
170 | proc fsub |
||
171 | |||
172 | xor qh,80h ; Vorzeichen 2 drehen |
||
173 | jp fadd ; ansonsten wie Addition |
||
174 | |||
175 | endp |
||
176 | |||
177 | ;------------------------------------------------------------------------------ |
||
178 | ; Multiplikation: XWA=XWA*XHL |
||
179 | |||
180 | proc fmul |
||
181 | |||
182 | public MulRound:Parent,MulZero:Parent,MulResult:Parent |
||
183 | public DivError:Parent |
||
184 | |||
185 | push xbc ; Register retten |
||
186 | push xde |
||
187 | push xhl |
||
188 | push xix |
||
189 | push xiy |
||
190 | |||
191 | ld xiy,xwa ; Op1 kopieren |
||
192 | xor xiy,xhl ; Ergebnisvorzeichen bestimmen |
||
193 | |||
194 | ex wa,qwa ; Registerhaelften Op1 vertauschen |
||
195 | ld xde,xwa ; Op1 ab sofort in XDE |
||
196 | and de,7fh ; Exponent und Vz. behandeln |
||
197 | and wa,7f80h ; Exponent maskieren |
||
198 | jr z,Denorm1 ; gleich Null-->Op1 denormal |
||
199 | set 7,de ; ansonsten implizite Eins einbauen |
||
200 | sub wa,80h ; Bias kompensieren |
||
201 | Denorm1: |
||
202 | ex hl,qhl ; Op2 genauso behandeln |
||
203 | ld xbc,xhl |
||
204 | and hl,7fh |
||
205 | and bc,7f80h |
||
206 | jr z,Denorm2 |
||
207 | set 7,hl |
||
208 | sub bc,80h |
||
209 | Denorm2: |
||
210 | add bc,wa ; Exponenten addieren |
||
211 | srl 7,bc ; richtig positionieren |
||
212 | sub bc,Bias-3 ; Bias-3 abziehen |
||
213 | cp bc,-24 ; totaler Unterlauf ? |
||
214 | jr lt,MulZero ; dann Ergebnis 0 |
||
215 | |||
216 | ld wa,de ; beide oberen Haelften multiplizieren |
||
217 | mul xwa,hl |
||
218 | ex wa,qwa ; Ergebnis in oberer Haelfte lagern |
||
219 | ld wa,de ; obere Haelfte Op1 retten |
||
220 | ex de,qde ; untere Haelfte Op1 holen |
||
221 | ld ix,hl ; untere Haelfte Op1 * obere Op2 |
||
222 | mul xix,de |
||
223 | ex hl,qhl ; untere Op1 * untere Op2 |
||
224 | mul xde,hl |
||
225 | ex de,qde ; obere Op1 * untere Op2 |
||
226 | mul xhl,wa |
||
227 | |||
228 | ld wa,de ; Teile aufaddieren |
||
229 | add xwa,xix |
||
230 | add xwa,xhl |
||
231 | jr z,MulResult ; Mantisse Null, Ergebnis Null |
||
232 | jr m,MulRound |
||
233 | |||
234 | or bc,bc ; Exponent negativ ? |
||
235 | jr m,Unterlauf ; ggfs. Unterlauf behandeln |
||
236 | |||
237 | Nor: or bc,bc ; Exponent Null ? |
||
238 | jr z,MulRound ; ja-->zum Runden |
||
239 | rl 1,xde ; nein, Mantisse eins nachschieben |
||
240 | rl 1,xwa |
||
241 | dec bc ; und Exponent runter |
||
242 | or xwa,xwa ; fuehrende Eins da ? |
||
243 | jr p,Nor ; nein, weiterschieben |
||
244 | |||
245 | MulRound: add xwa,80h ; Rundung |
||
246 | jr nc,NoROver ; dabei Ueberlauf ? |
||
247 | rr 1,xwa ; ja: Mantisse & Exponent korrigieren |
||
248 | inc bc |
||
249 | NoROver: cp bc,MaxExpo ; Exponentenueberlauf ? |
||
250 | jr lt,NoEOver |
||
251 | DivError: ld bc,MaxExpo ; dann unendlich einstellen |
||
252 | sub xwa,xwa |
||
253 | jr Denormal |
||
254 | |||
255 | NoEOver: or bc,bc ; Exponent 0 ? |
||
256 | jr z,Denormal |
||
257 | sll 1,xwa ; fuehrende 1 loeschen |
||
258 | |||
259 | Denormal: ld a,c ; Exponent einbauen |
||
260 | rrc 8,xwa ; hochschieben |
||
261 | rl 1,xiy ; Vorzeichen einbauen |
||
262 | rr 1,xwa |
||
263 | |||
264 | MulResult: pop xiy |
||
265 | pop xix |
||
266 | pop xhl |
||
267 | pop xde |
||
268 | pop xbc |
||
269 | |||
270 | ret |
||
271 | |||
272 | MulZero: sub xwa,xwa ; Null erzeugen |
||
273 | jr MulResult |
||
274 | |||
275 | Unterlauf: cp bc,-24 ; totaler Unterlauf ? |
||
276 | jr le,MulZero ; dann Null |
||
277 | neg bc ; sonst umbauen |
||
278 | ld xde,xwa ; dazu Akku freimachen |
||
279 | sub wa,wa ; Endexponent |
||
280 | ex wa,bc ; ist 0 |
||
281 | shifta srl,xde ; Mantisse herunterschieben |
||
282 | ld xwa,xde ; Ergebnis zurueck nach XWA |
||
283 | jr MulRound ; zurueck mit Exponent 0 |
||
284 | |||
285 | endp |
||
286 | |||
287 | ;------------------------------------------------------------------------------ |
||
288 | ; Division: XWA=XWA/XHL |
||
289 | |||
290 | proc fdiv |
||
291 | |||
292 | push xbc ; Register retten (muss gleich zu fmul sein) |
||
293 | push xde |
||
294 | push xhl |
||
295 | push xix |
||
296 | push xiy |
||
297 | |||
298 | ld xiy,xwa ; Op1 kopieren |
||
299 | xor xiy,xhl ; Ergebnisvorzeichen bestimmen |
||
300 | |||
301 | ex wa,qwa ; Vorbehandlung wie bei fmul |
||
302 | ld xde,xwa |
||
303 | and de,7fh |
||
304 | and wa,7f80h |
||
305 | jr z,Denorm1 |
||
306 | set 7,de |
||
307 | sub wa,80h |
||
308 | Denorm1: |
||
309 | ex hl,qhl |
||
310 | ld xbc,xhl |
||
311 | and hl,7fh |
||
312 | and bc,7f80h |
||
313 | jr z,Denorm2 |
||
314 | set 7,hl |
||
315 | sub bc,80h |
||
316 | Denorm2: |
||
317 | sub wa,bc ; Exponentendifferenz bilden |
||
318 | ld bc,wa ; muс in BC liegen |
||
319 | sra 7,bc ; richtig positionieren |
||
320 | add bc,Bias ; Bias addieren |
||
321 | cp bc,-24 ; totaler Unterlauf ? |
||
322 | jr lt,MulZero ; ja, Ergebnis Null |
||
323 | |||
324 | ex hl,qhl ; Format 0fff ... ffff 0000 0000 |
||
325 | or xhl,xhl ; Ergebnis unendlich ? |
||
326 | jrl z,DivError |
||
327 | sll 7,xhl |
||
328 | ex de,qde ; dito Divident |
||
329 | or xde,xde ; falls Null, Ergebnis Null |
||
330 | jrl z,MulZero |
||
331 | sll 7,xde |
||
332 | |||
333 | NormLoop: bit 14,qhl ; Divisor normalisiert ? |
||
334 | jr nz,Normal |
||
335 | inc bc ; nein, Exponent RAUF (ist Ergebnisexponent) |
||
336 | sll 1,xhl |
||
337 | jr NormLoop |
||
338 | |||
339 | Normal: sub xwa,xwa ; Ergebnisquotient vorbesetzen |
||
340 | add bc,25 ; Exponent nicht groesser als 0 |
||
341 | |||
342 | Loop: ld xix,xde ; Divident zwischenspeichern |
||
343 | sub xde,xhl ; probeweise abziehen |
||
344 | ccf ; Carry drehen |
||
345 | jr c,IsOne ; ungedrehter Carry=1: Divisor paсt |
||
346 | ld xde,xix ; ansonsten zurueckkopieren |
||
347 | IsOne: rl 1,xwa ; Ergebnisbit einschieben |
||
348 | sll 1,xde ; Divident verschieben |
||
349 | dec bc ; Exponent runter |
||
350 | or bc,bc |
||
351 | jr z,Denorm ; falls Null, denormalisieren |
||
352 | bit 8,qwa ; fuehrende Eins da ? |
||
353 | jr z,Loop ; nein, weiterrechnen |
||
354 | |||
355 | Denorm: sll 7,xwa ; Mantisse positionieren |
||
356 | jrl z,MulResult ; Ergebnis 0 ? |
||
357 | jrl MulRound ; ansonsten zum Runden |
||
358 | |||
359 | endp |
||
360 | |||
361 | ;----------------------------------------------------------------------------- |
||
362 | ; Multiplikation mit Zweierpotenz: XWA=XWA*2^BC |
||
363 | |||
364 | proc fmul2 |
||
365 | |||
366 | push bc ; Register retten |
||
367 | push xde |
||
368 | |||
369 | ld xde,xwa ; Vorzeichen merken |
||
370 | sll 1,xwa ; Vorzeichen rausschieben |
||
371 | jr z,Zero ; falls Null, Ergebnis Null |
||
372 | rlc 8,xwa ; Exponent nach unten... |
||
373 | sub de,de ; und in DE packen |
||
374 | add e,a |
||
375 | jr z,Denorm ; falls denormalisiert.. |
||
376 | or bc,bc ; Multiplikation oder Division ? |
||
377 | jr m,Divide ; (neg. Exponent=Division) |
||
378 | |||
379 | add de,bc ; Exponent addieren |
||
380 | cp de,MaxExpo ; Ueberlauf ? |
||
381 | jr ge,Over ; ja, Ergebnis unendlich |
||
382 | Result: ld a,e ; Ergebnisexponent einbauen |
||
383 | rrc 8,xwa ; Exponent nach oben |
||
384 | rl 1,xde ; Vorzeichen einschieben |
||
385 | rr 1,xwa |
||
386 | |||
387 | Zero: pop xde ; Register zurueck |
||
388 | pop bc |
||
389 | ret |
||
390 | |||
391 | Over: ld de,MaxExpo ; Ergebnis unendlich |
||
392 | sub xwa,xwa |
||
393 | jr Result |
||
394 | |||
395 | Divide: add de,bc ; Exponentensumme bilden |
||
396 | jr gt,Result ; >0, keine Sonderbehandlung |
||
397 | scf ; ansonsten 1 explizit fБr |
||
398 | rr 1,xwa ; denormale Zahl machen |
||
399 | DDenorm: or de,de ; Exponent=0 ? |
||
400 | jr z,Result ; ja, Ergebnis einfach denormal |
||
401 | srl 1,xwa ; ansonsten weiter denormalisieren |
||
402 | jr z,Zero ; dabei totaler Unterlauf->Null |
||
403 | inc de ; Exponent korrigieren |
||
404 | jr DDenorm |
||
405 | DDDenorm: add de,bc ; Exponentensumme bilden |
||
406 | jr DDenorm |
||
407 | |||
408 | Denorm: or bc,bc ; Multiplikation oder Division ? |
||
409 | jr m,DDDenorm |
||
410 | sub a,a ; alten Exponenten loeschen |
||
411 | Norm: sll 1,xwa ; normalisieren... |
||
412 | jr c,Stop ; bis fuehrende Eins da |
||
413 | dec bc ; oder 2. Exponent 0 |
||
414 | or bc,bc |
||
415 | jr nz,Norm |
||
416 | jr Result ; Multiplikator kompl. fuer Normalisierung draufgegangen |
||
417 | Stop: add de,bc ; Rest addieren |
||
418 | jr Result ; alles andere schon o.k. |
||
419 | |||
420 | endp |
||
421 | |||
422 | ;------------------------------------------------------------------------------ |
||
423 | ; LongInt-->Float : XWA-->XWA |
||
424 | |||
425 | proc fitof |
||
426 | |||
427 | push xbc ; Register retten |
||
428 | |||
429 | or xwa,xwa ; Null ? |
||
430 | jr z,Result ; dann Ergebnis Null |
||
431 | scc m,qc ; Vorzeichen nach QC, Bit 0 |
||
432 | jr p,Positive |
||
433 | cpl wa ; falls negativ,drehen |
||
434 | cpl qwa |
||
435 | inc xwa |
||
436 | Positive: ld bc,Bias+32 ; Exponent vorbesetzen |
||
437 | Shift: dec bc ; Mantisse verschieben |
||
438 | sll 1,xwa |
||
439 | jr nc,Shift |
||
440 | ld a,c ; Exponent einbauen |
||
441 | rrc 8,xwa ; Exponent nach oben |
||
442 | rr 1,qc ; Vorzeichen einbauen |
||
443 | rr 1,xwa |
||
444 | |||
445 | Result: pop xbc ; Register zurueck |
||
446 | ret |
||
447 | |||
448 | endp |
||
449 | |||
450 | ;------------------------------------------------------------------------------ |
||
451 | ; Float-->LongInt : XWA-->XWA |
||
452 | |||
453 | proc fftoi |
||
454 | |||
455 | push bc ; Register retten |
||
456 | |||
457 | rl 1,xwa ; Vorzeichen in Carry |
||
458 | scc c,b ; in B merken |
||
459 | |||
460 | rlc 8,xwa ; Exponent nach unten |
||
461 | ld c,a ; in C legen |
||
462 | sub c,Bias ; Bias abziehen |
||
463 | |||
464 | jr m,Zero ; neg. Exponent -> Zahl<0 -> Ergebnis 0 |
||
465 | cp c,31 ; Ueberlauf ? |
||
466 | jr ge,Over |
||
467 | |||
468 | scf ; fuehrende Eins einschieben |
||
469 | rr 1,xwa |
||
470 | sub a,a ; Exponent loeschen |
||
471 | |||
472 | Shift: srl 1,xwa ; jetzt schieben, bis Ergebnis stimmt |
||
473 | inc c |
||
474 | cp c,31 |
||
475 | jr ne,Shift |
||
476 | |||
477 | srl 1,b ; negieren ? |
||
478 | jr nc,Positive |
||
479 | cpl wa ; ggfs. negieren |
||
480 | cpl qwa |
||
481 | inc xwa |
||
482 | |||
483 | Positive: pop bc ; Register zurueck |
||
484 | ret |
||
485 | |||
486 | Zero: sub xwa,xwa ; Ergebnis 0 |
||
487 | jr Positive |
||
488 | |||
489 | Over: ld xwa,7fffffffh ; Ueberlauf: Maxint zurueckgeben |
||
490 | srl 1,b ; negativ ? |
||
491 | jr nc,Positive |
||
492 | cpl wa ; ja, neg. Maximum zurueckgeben |
||
493 | cpl qwa |
||
494 | jr Positive |
||
495 | |||
496 | endp |
||
497 | |||
498 | ;------------------------------------------------------------------------------ |
||
499 | ; Quadratwurzel: XWA=SQRT(XWA) |
||
500 | |||
501 | proc fsqrt |
||
502 | |||
503 | push xbc ; Register retten |
||
504 | push xde |
||
505 | push xhl |
||
506 | push xix |
||
507 | |||
508 | ld xix,xwa ; Argument retten |
||
509 | or xix,xix ; Zahl negativ ? |
||
510 | jrl m,DomainError ; dann geht es nicht |
||
511 | |||
512 | ex ix,qix ; MSW holen |
||
513 | and xix,7f80h ; Exponent isolieren |
||
514 | jrl z,Zero ; keine Behandlung denormaler Zahlen |
||
515 | |||
516 | and xwa,7fffffh ; Mantisse isolieren |
||
517 | sub ix,7fh*80h ; Bias vom Exponenten entfernen |
||
518 | bit 7,ix ; Exponent ungerade ? |
||
519 | res 7,ix |
||
520 | jr z,EvenExp |
||
521 | add xwa,xwa ; ja: Mantisse verdoppeln |
||
522 | add xwa,1000000h-800000h ; impl. Eins dazu |
||
523 | EvenExp: ; erste Iteration ohne impl. Eins |
||
524 | sra 1,ix ; Exponent/2 mit Vorzeichen |
||
525 | add ix,7fh*80h ; Bias wieder dazu |
||
526 | ex ix,qix ; neuen Exponenten in QIX aufheben |
||
527 | sll 7,xwa ; x ausrichten |
||
528 | ld xde,40000000h ; xroot nach erster Iteration |
||
529 | ld xhl,10000000h ; m2=2 << (MaxBit-1) |
||
530 | Loop10: ld xbc,xwa ; xx2 = x |
||
531 | Loop11: sub xbc,xde ; xx2 -= xroot |
||
532 | srl 1,xde ; xroot = xroot/2 |
||
533 | sub xbc,xhl ; x2 -= m2 |
||
534 | jr m,DontSet1 |
||
535 | ld xwa,xbc ; x = xx2 |
||
536 | or xde,xhl ; xroot += m2 |
||
537 | srl 2,xhl ; m2 = m2/4 |
||
538 | jr nz,Loop11 |
||
539 | jr WABCSame |
||
540 | DontSet1: srl 2,xhl ; m2 = m2/4 |
||
541 | jr nz,Loop10 ; 15* abarbeiten |
||
542 | ; Bit 22..8 |
||
543 | ld xbc,xwa ; 17. Iteration separat |
||
544 | WABCSame: sub xbc,xde |
||
545 | rrc 1,xde ; mitsamt Carry... |
||
546 | ex de,qde ; auf neues Alignment umstellen |
||
547 | sub xbc,1 ; Carry von 0-$4000: x2 -= m2 |
||
548 | jr m,DontSet7 |
||
549 | or xbc,-40000000h ; 0-$4000: x2 -= m2, Teil 2 |
||
550 | ld xwa,xbc |
||
551 | or de,4000h ; xroot += m2 |
||
552 | DontSet7: ex wa,qwa ; x auf neues Alignment umstellen |
||
553 | ld hl,1000h ; m2 - obere Haelfte schon 0 |
||
554 | Loop20: ld xbc,xwa ; xx2 = x |
||
555 | Loop21: sub xbc,xde ; xx2 -= xroot |
||
556 | srl 1,xde ; xroot = xroot/2 |
||
557 | sub xbc,xhl ; x2 -= m2 |
||
558 | jr m,DontSet2 |
||
559 | ld xwa,xbc ; x = xx2 |
||
560 | or xde,xhl ; xroot += m2 |
||
561 | srl 2,xhl ; m2 = m2/4 |
||
562 | jr nz,Loop21 |
||
563 | jr Finish |
||
564 | DontSet2: srl 2,xhl ; m2 = m2/4 |
||
565 | jr nz,Loop20 ; 7* abarbeiten |
||
566 | |||
567 | Finish: sub xwa,xde ; Aufrunden notwendig ? |
||
568 | jr ule,NoInc |
||
569 | inc xde ; wenn ja, durchfuehren |
||
570 | NoInc: res 7,qde ; impl. Eins loeschen |
||
571 | or xde,xix |
||
572 | ld xwa,xde ; Ergebnis in XWA |
||
573 | jr End |
||
574 | |||
575 | DomainError: ld xwa,0ffc00000h ; -NAN zurueckgeben |
||
576 | jr End |
||
577 | |||
578 | Zero: sub xwa,xwa ; Ergebnis 0 |
||
579 | |||
580 | End: pop xix ; Register zurueck |
||
581 | pop xhl |
||
582 | pop xde |
||
583 | pop xbc |
||
584 | ret |
||
585 | |||
586 | endp |
||
587 | |||
588 | ;------------------------------------------------------------------------------ |
||
589 | ; Unterroutine Zehnerpotenz bilden: XWA=10.0^BC |
||
590 | |||
591 | section fPot10 ; nicht mit proc, da private Funktion |
||
592 | public fPot10:Parent |
||
593 | fPot10: |
||
594 | |||
595 | push xbc ; Register retten |
||
596 | push xhl |
||
597 | |||
598 | ld xwa,(One) ; Ausgangspunkt fuers Multiplizieren |
||
599 | ld xhl,(Ten) ; zu benutzende Potenz |
||
600 | or bc,bc ; negative Potenz ? |
||
601 | jr p,IsPos |
||
602 | ld xhl,(Tenth) ; dann eben Zehntel multiplizieren |
||
603 | neg bc ; fuer Schleife immer positiv |
||
604 | IsPos: |
||
605 | or bc,bc ; Noch weiter multiplizieren ? |
||
606 | jr z,End |
||
607 | bit 0,bc ; Restpotenz ungerade ? |
||
608 | jr z,IsEven |
||
609 | call fmul ; ja: einzeln multiplizieren |
||
610 | IsEven: srl 1,bc ; naechste Stelle |
||
611 | push xwa ; neue Potenz berechnen |
||
612 | ld xwa,xhl |
||
613 | call fmul ; durch quadrieren |
||
614 | ld xhl,xwa |
||
615 | pop xwa |
||
616 | jr IsPos ; weiter nach Einsen suchen |
||
617 | |||
618 | End: pop xhl ; Register zurueck |
||
619 | pop xbc |
||
620 | ret |
||
621 | |||
622 | endsection |
||
623 | |||
624 | ;------------------------------------------------------------------------------ |
||
625 | ; Unterroutine Zahl dezimal wandeln |
||
626 | |||
627 | section fOutDec |
||
628 | public fOutDec:Parent |
||
629 | fOutDec: |
||
630 | |||
631 | push xwa ; Register retten |
||
632 | push xbc |
||
633 | push de |
||
634 | push xhl |
||
635 | |||
636 | bit 15,qwa ; negativ ? |
||
637 | jr z,IsPos |
||
638 | ld (xix+),'-' ; ja: vermerken... |
||
639 | cpl wa ; ...und Zweierkomplement |
||
640 | cpl qwa |
||
641 | inc xwa |
||
642 | jr GoOn |
||
643 | IsPos: bit 7,c ; Pluszeichen ausgeben ? |
||
644 | jr nz,GoOn |
||
645 | ld (xix+),'+' |
||
646 | GoOn: res 7,c ; Plusflag loeschen |
||
647 | ld qbc,0 ; Nullflag und Zaehler loeschen |
||
648 | |||
649 | InLoop: ld xhl,0 ; Division vorbereiten |
||
650 | ld e,32 ; 32 Bit-Division |
||
651 | DivLoop: sll 1,xwa ; eins weiterschieben |
||
652 | rl 1,xhl |
||
653 | srl 1,xwa ; fuer nachher |
||
654 | sub xhl,10 ; passt Divisor hinein ? |
||
655 | jr nc,DivOK |
||
656 | add xhl,10 ; nein, zuruecknehmen... |
||
657 | scf ; im Ergebnis 0 einschieben |
||
658 | DivOK: ccf ; neues Ergebnisbit |
||
659 | rl 1,xwa ; Ergebnis in XWA einschieben... |
||
660 | djnz e,DivLoop |
||
661 | |||
662 | add l,'0' ; ASCII-Offset addieren |
||
663 | bit 1,qb ; schon im Nullbereich ? |
||
664 | jr z,NormVal |
||
665 | ld l,b ; ja, dann gewuenschtes Leerzeichen |
||
666 | NormVal: push l ; auf LIFO legen |
||
667 | inc qc ; ein Zeichen mehr |
||
668 | or xwa,xwa ; Quotient Null ? |
||
669 | scc z,qb |
||
670 | jr nz,InLoop ; wenn nicht Null, auf jeden Fall weiter |
||
671 | cp c,qc ; ansonsten nur, falls min. Stellenzahl |
||
672 | jr ugt,InLoop ; noch nicht erreicht |
||
673 | |||
674 | OutLoop: pop a ; jetzt Zeichen umgekehrt ablegen |
||
675 | ld (xix+),a |
||
676 | djnz qc,OutLoop |
||
677 | |||
678 | pop xhl ; Register zurueck |
||
679 | pop de |
||
680 | pop xbc |
||
681 | pop xwa |
||
682 | |||
683 | ret |
||
684 | |||
685 | endsection |
||
686 | |||
687 | ;------------------------------------------------------------------------------ |
||
688 | ; Gleitkomma nach ASCII wandeln: |
||
689 | ; In: Zahl in XWA |
||
690 | ; Zeiger auf Speicher in XHL |
||
691 | ; max. Anzahl Nachkommastellen in C |
||
692 | ; B/Bit 0 setzen, falls Mantissen-Pluszeichen unerwuenscht |
||
693 | ; B/Bit 1 setzen, falls Exponenten-Pluszeichen unerwuenscht |
||
694 | ; B/Bit 2..4 = Stellenzahl Exponent |
||
695 | ; B/Bit 5 setzen, falls Nullen am Ende der Mantisse unerwuenscht |
||
696 | ; Out: Zahl abgelegter Zeichen (exkl. NUL am Ende) in BC |
||
697 | ; (XHL) = gebildeter String |
||
698 | |||
699 | proc fftoa |
||
700 | |||
701 | push xix ; Register retten |
||
702 | push xhl |
||
703 | push de |
||
704 | push xbc |
||
705 | push xwa |
||
706 | |||
707 | ld xix,xhl ; Zeiger auf Speicher kopieren |
||
708 | ld de,bc ; Parameter sichern |
||
709 | |||
710 | ld xhl,xwa ; Zahl auf die Zerlegebank bringen |
||
711 | res 15,qwa ; Vorzeichen hier nicht mehr gebraucht |
||
712 | |||
713 | ld c,'+' ; Annahme positiv |
||
714 | sll 1,xhl ; Vorzeichen in Carry bringen |
||
715 | jr c,IsNeg ; Minuszeichen immer erforderlich... |
||
716 | bit 0,d ; ...Pluszeichen optional |
||
717 | jr nz,NoMantSgn |
||
718 | jr WrMantSgn |
||
719 | IsNeg: ld c,'-' ; ja |
||
720 | WrMantSgn: ld (xix+),c ; Mantissenvorzeichen ablegen |
||
721 | NoMantSgn: |
||
722 | ld c,qh ; Exponenten herausholen... |
||
723 | extz bc ; ...auf 16 Bit erweitern... |
||
724 | sll 8,xhl ; ...und in Quelle loeschen |
||
725 | |||
726 | cp bc,MaxExpo ; Sonderwert (INF/NAN) ? |
||
727 | jrl z,SpecialVals ; ja--> |
||
728 | |||
729 | or bc,bc ; Zahl denormal ? |
||
730 | jr nz,IsNormal ; nein, normal weiter |
||
731 | or xhl,xhl ; bei kompl. Null auch ueberspringen |
||
732 | jr z,IsNull |
||
733 | Normalize: sll 1,xhl ; ja: solange zaehlen, bis 1 erscheint |
||
734 | jr c,IsNormal |
||
735 | dec bc |
||
736 | jr Normalize |
||
737 | IsNormal: sub bc,Bias ; Bias abziehen |
||
738 | IsNull: |
||
739 | push xwa ; fuer folgendes Zahl retten |
||
740 | ld wa,bc ; Zweierexponenten in Float wandeln |
||
741 | exts xwa |
||
742 | call fitof |
||
743 | ld xhl,(Ld10) ; in Dezimalexponenten wandeln |
||
744 | call fdiv |
||
745 | or xwa,xwa ; Zahl negativ ? |
||
746 | jr p,NoCorr |
||
747 | ld xhl,(One) ; dann nocheinmal korrigieren wg. |
||
748 | call fsub ; unterer Gaussklammer |
||
749 | NoCorr: call fftoi ; Den Ausflug in Float beenden |
||
750 | ld qbc,wa ; den Zehnerexponenten retten |
||
751 | ld bc,wa |
||
752 | call fPot10 ; von diesem Exponenten Zehnerpotenz |
||
753 | ld xhl,xwa ; bilden |
||
754 | pop xwa ; alte Zahl zurueck |
||
755 | call fdiv ; Teilen: Ergebnis ist Zahl zwischen |
||
756 | Again: ld xhl,xwa ; 1.0 und 9.9999..., diese retten |
||
757 | call fftoi ; Vorkommastelle berechnen |
||
758 | cp a,10 ; doch etwas drueber ? |
||
759 | jr ult,NoRoundErr |
||
760 | ld xwa,xhl ; ja, dann noch einmal zehnteln |
||
761 | ld xhl,(Tenth) |
||
762 | call fmul |
||
763 | inc qbc |
||
764 | jr Again |
||
765 | NoRoundErr: add a,'0' ; diese nach ASCII wandeln... |
||
766 | ld (xix+),a ; ...und ablegen |
||
767 | sub a,'0' ; wieder rueckgaengig machen |
||
768 | cp e,0 ; gar keine Nachkommastellen ? |
||
769 | jr eq,NoComma |
||
770 | ld (xix+),Comma ; Dezimalpunkt ausgeben |
||
771 | call fitof ; in ganze Gleitkommazahl wandeln |
||
772 | call fsub ; Differenz bilden |
||
773 | chg 15,qwa ; war verkehrtherum... |
||
774 | ld xhl,xwa ; nach XHL verschieben, weil XWA gebraucht |
||
775 | ld c,e ; Zehnerpotenz fuer Skalierung ausrechnen |
||
776 | extz bc ; auf 16 Bit aufblasen |
||
777 | call fPot10 ; Skalierungswert berechnen |
||
778 | call fmul ; hochmultiplizieren |
||
779 | ld xhl,(Half) ; Rundung |
||
780 | call fadd |
||
781 | call fftoi ; diese herausziehen |
||
782 | ld b,'0' ; n-stellig mit Vornullen ausgeben |
||
783 | ld c,e |
||
784 | set 7,c ; kein Pluszeichen! |
||
785 | call fOutDec |
||
786 | bit 5,d ; Nullen am Ende abraeumen ? |
||
787 | jr nz,CleanZeros |
||
788 | NoComma: |
||
789 | ld a,d ; falls Minimalstellenzahl Exponent=0 |
||
790 | and a,00011100b ; und Exponent=0, vergessen |
||
791 | or a,qb |
||
792 | or a,qc |
||
793 | jr z,End |
||
794 | |||
795 | ld (xix+),'E' ; Exponenten ausgeben |
||
796 | ld wa,qbc |
||
797 | exts xwa |
||
798 | ld b,'0' ; evtl. vornullen... |
||
799 | ld c,d ; Bit 1-->Bit 7 |
||
800 | rrc 2,c |
||
801 | and c,87h ; Bits ausmaskieren |
||
802 | call fOutDec |
||
803 | |||
804 | End: pop xwa ; Register zurueck |
||
805 | pop xbc |
||
806 | pop de |
||
807 | pop xhl |
||
808 | ld (xix),0 ; NUL-Zeichen im String nicht vergessen |
||
809 | sub xix,xhl ; Stringlaenge berechnen |
||
810 | ld bc,ix |
||
811 | pop xix |
||
812 | |||
813 | ret |
||
814 | |||
815 | SpecialVals: or xde,xde ; Ist die Mantisse Null ? |
||
816 | jr nz,IsNAN |
||
817 | ldw (xix+),'NI' ; ja: INF einschreiben |
||
818 | ld (xix+),'F' |
||
819 | jr End |
||
820 | IsNAN: ldw (xix+),'AN' ; nein: NAN einschreiben |
||
821 | ld (xix+),'N' |
||
822 | jr End |
||
823 | |||
824 | CleanZeros: cp (xix-1),'0' ; steht da eine Null am Ende ? |
||
825 | jr nz,CleanNoZero ; nein, Ende |
||
826 | dec xix ; ja: Zaehler runter, so dass Ueber- |
||
827 | jr CleanZeros ; schrieben wird und neuer Versuch |
||
828 | CleanNoZero: cp (xix-1),Comma ; evtl. Komma entfernbar ? |
||
829 | jr nz,NoComma ; nein--> |
||
830 | dec xix ; ja: noch ein Zeichen weniger |
||
831 | jr NoComma |
||
832 | |||
833 | endp |
||
834 | |||
835 | ;------------------------------------------------------------------------------ |
||
836 | ; ASCII nach Gleitkomma wandeln: |
||
837 | ; In: Zeiger auf String (ASCIIZ) in XHL |
||
838 | ; Out: XWA = Ergebnis bzw. fehlerhafte Stelle |
||
839 | ; CY = 0, falls fehlerfrei |
||
840 | |||
841 | proc fatof |
||
842 | |||
843 | push xbc ; Register retten |
||
844 | push xde |
||
845 | push xhl |
||
846 | push xix |
||
847 | |||
848 | ld xix,xhl ; Zeiger nach XIX |
||
849 | ld qbc,01 ; Phase 1 (Mantisse), noch kein Vorzeichen |
||
850 | ld xde,(Ten) ; in der Mantisse mit 10 hochmultiplizieren |
||
851 | ld xhl,0 ; Mantisse vorbelegen |
||
852 | ld bc,0 ; Exponent vorbelegen |
||
853 | |||
854 | ReadLoop: ld a,(xix+) ; ein neues Zeichen holen |
||
855 | extz wa ; auf 32 Bit aufblasen |
||
856 | extz xwa |
||
857 | |||
858 | cp a,0 ; Endezeichen ? |
||
859 | jrl eq,Combine ; ja, alles zusammen |
||
860 | |||
861 | cp a,' ' ; Leerzeichen ignorieren |
||
862 | jr eq,ReadLoop |
||
863 | |||
864 | cp a,'+' ; Pluszeichen gnadenhalber zugelassen |
||
865 | jr ne,NoPlus ; ist aber nur ein Dummy |
||
866 | bit 0,qb ; schon ein Vorzeichen dagewesen ? |
||
867 | jrl nz,Error ; dann Fehler |
||
868 | set 0,qb ; ansonsten einfach setzen |
||
869 | jr ReadLoop |
||
870 | NoPlus: |
||
871 | cp a,'-' ; Minuszeichen bewirkt schon eher etwas |
||
872 | jr ne,NoMinus |
||
873 | bit 0,qb ; darf auch nur einmal auftreten |
||
874 | jrl nz,Error |
||
875 | set 0,qb |
||
876 | cp qc,1 ; je nach Phase anderes Flag setzen |
||
877 | jr ne,MinPhase3 |
||
878 | set 1,qb ; bei Mantisse Bit 1... |
||
879 | jr ReadLoop |
||
880 | MinPhase3: set 2,qb ; bei Exponent Bit 2 |
||
881 | jr ReadLoop |
||
882 | NoMinus: |
||
883 | cp a,'.' ; Umschaltung zu Phase 2 (Nachkomma) ? |
||
884 | jr ne,NoPoint |
||
885 | cp qc,1 ; bish. Phase muss eins sein |
||
886 | jrl ne,Error |
||
887 | ld qc,2 ; neue Phase eintragen |
||
888 | set 0,qb ; Nachkomma darf kein Vorzeichen haben |
||
889 | ld xde,(Tenth) ; im Nachkomma durch 10 teilen |
||
890 | jr ReadLoop |
||
891 | NoPoint: |
||
892 | cp a,'e' ; kleines und grosses E zulassen |
||
893 | jr eq,IsE |
||
894 | cp a,'E' |
||
895 | jr ne,NoE |
||
896 | IsE: cp qc,3 ; vorherige Phase muss 1 oder 2 sein |
||
897 | jr eq,Error |
||
898 | ld qc,3 ; vermerken |
||
899 | res 0,qb ; Vorzeichen wieder zugelassen |
||
900 | jr ReadLoop |
||
901 | NoE: |
||
902 | sub a,'0' ; jetzt nur noch 0..9 zugelassen |
||
903 | jr c,Error |
||
904 | cp a,9 |
||
905 | jr ugt,Error |
||
906 | set 0,qb ; nach Ziffern kein Vorzeichen mehr zulassen |
||
907 | |||
908 | cp qc,1 ; Phase 1 (Mantisse) : |
||
909 | jr ne,NoPhase1 |
||
910 | push xwa ; Zeichen retten |
||
911 | ld xwa,xde ; bish. Mantisse * 10 |
||
912 | call fmul |
||
913 | ld xhl,xwa |
||
914 | pop xwa ; Zahl nach Float wandeln |
||
915 | call fitof |
||
916 | call fadd ; dazuaddieren |
||
917 | ld xhl,xwa ; Mantisse zuruecklegen |
||
918 | jrl ReadLoop |
||
919 | NoPhase1: |
||
920 | cp qc,2 ; Phase 2 (Nachkomma) : |
||
921 | jr ne,NoPhase2 |
||
922 | call fitof ; Stelle nach Float wandeln |
||
923 | push xhl ; Mantisse retten |
||
924 | ld xhl,xde ; Stelle mit Zehnerpotenz skalieren |
||
925 | call fmul |
||
926 | pop xhl ; zur Mantisse addieren |
||
927 | call fadd |
||
928 | push xwa ; Zwischenergebnis retten |
||
929 | ld xwa,xde ; nДchste Skalierungspotenz ausrechnen |
||
930 | ld xhl,(Tenth) |
||
931 | call fmul |
||
932 | ld xde,xwa ; alles wieder zurueck |
||
933 | pop xhl |
||
934 | jrl ReadLoop |
||
935 | NoPhase2: |
||
936 | mul bc,10 ; Exponent heraufmultiplizieren |
||
937 | add bc,wa |
||
938 | cp bc,45 ; Minimum ist 1e-45 |
||
939 | jr ugt,Error |
||
940 | jrl ReadLoop |
||
941 | |||
942 | Combine: bit 2,qb ; Exponent negativ ? |
||
943 | jr z,ExpPos |
||
944 | neg bc |
||
945 | ExpPos: call fPot10 ; Zehnerpotenz des Exponenten bilden |
||
946 | call fmul ; mit Mantisse kombinieren |
||
947 | bit 1,qb ; Mantisse negativ ? |
||
948 | jr z,ManPos |
||
949 | set 15,qwa |
||
950 | ManPos: rcf ; Ende ohne Fehler |
||
951 | |||
952 | pop xix ; Register zurueck |
||
953 | pop xhl |
||
954 | pop xde |
||
955 | pop xbc |
||
956 | ret |
||
957 | |||
958 | Error: ld xwa,xix ; Endzeiger laden |
||
959 | pop xix |
||
960 | pop xhl |
||
961 | sub xwa,xhl ; rel. Position des fehlerhaften Zeichens berechnen |
||
962 | pop xde |
||
963 | pop xbc |
||
964 | scf ; Ende mit Fehler |
||
965 | ret |
||
966 | |||
967 | endp |
||
968 | |||
969 | ;------------------------------------------------------------------------------ |
||
970 | ; gemeinsames Ende |
||
971 | |||
972 | endsection |
||
973 |