Skip to content

Commit 8be1247

Browse files
committed
Implemented dtof in assembly
1 parent 9e250a3 commit 8be1247

File tree

8 files changed

+405
-248
lines changed

8 files changed

+405
-248
lines changed

src/crt/dtof.src

Lines changed: 218 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,218 @@
1-
assume adl=1
2-
3-
section .text
4-
5-
public __dtof
6-
7-
__dtof:
8-
; f64_ret_f32
9-
push af, iy, bc, de, hl
10-
call ___f64_to_f32
11-
pop af
12-
ld a, e
13-
pop de
14-
ld e, a
15-
pop bc, iy, af
16-
ret
17-
18-
extern ___f64_to_f32
1+
assume adl=1
2+
3+
section .text
4+
5+
public __dtof
6+
7+
private __dtof_helper
8+
__dtof_helper:
9+
; Moving this block of code to be behind __dtof ensures that
10+
; __dtof.ret_copysign can always be reached by jr in all paths.
11+
.overflow:
12+
; carry is set here
13+
pop hl
14+
; A = $10
15+
add a, c ; attempts to overflow the low 4 bits of the exponent
16+
rl b ; (0x7F << 1) | 1 if the input is inf/NaN
17+
inc b ; B will only be zero if the input was inf/NaN
18+
jr nz, .not_inf_nan
19+
20+
; carry is cleared
21+
adc hl, hl
22+
jr nz, .has_payload
23+
ld a, e
24+
rla
25+
and a, $3F
26+
jr z, .no_payload
27+
.has_payload:
28+
set 5, e ; ensure that NaN stays NaN
29+
.no_payload:
30+
ld a, c
31+
push de
32+
pop bc
33+
ld l, 5
34+
call __lshru
35+
push bc
36+
pop hl
37+
.finish_inf_nan:
38+
ld a, $7F
39+
jr __dtof.ret_copysign
40+
.not_inf_nan:
41+
; return infinity
42+
ld hl, $800000
43+
jr .finish_inf_nan
44+
45+
; Convert BC:UDE:UHL F64 to E:UHL F32
46+
; Rounding: round to nearest with ties to even
47+
; Behaviour:
48+
; Underflow: Returns signed zero. No signals raised.
49+
; Subnormal: No signals raised.
50+
; Rounded to Infinity: No signals raised.
51+
; Overflow: Returns signed infinity. No signals raised.
52+
; Signaling NaN: Quiet bit preserved. No signals raised.
53+
; Quiet NaN: Quiet bit preserved. No signals raised.
54+
; NaN Payloads: Copies the most significant payload bits. The LSB of mantissa is set if payload bits were discarded/truncated out.
55+
__dtof:
56+
bit 7, b
57+
push af ; preserve A and signbit
58+
push bc
59+
push de
60+
push hl
61+
res 7, b
62+
ld hl, -$3810
63+
add.s hl, bc
64+
jr nc, .maybe_subnormal
65+
ld hl, -$47F0 ; $FFB810
66+
ld a, l ; ld a, $10
67+
add.s hl, bc
68+
jr c, __dtof_helper.overflow
69+
; result is normal or rounds to infinity
70+
; calculate new exponent
71+
; we only need the low 8 bits of the exponent
72+
add hl, hl
73+
add hl, hl
74+
add hl, hl
75+
add hl, hl
76+
; offset = -$380 - -$47F = $FF = -1 ; therefore decrement
77+
; H = exponent + 1
78+
ld l, 29 ; f64_mant_bits - f32_mant_bits = 52 - 23 = 29
79+
ex (sp), hl ; (SP) = exponent/shift, HL = lo24
80+
81+
; clear exponent
82+
dec a ; ld a, $0F
83+
and a, c
84+
ld c, a
85+
xor a, a
86+
ld b, a
87+
; test round bit
88+
bit 4, e
89+
jr z, .round_down
90+
; test guard bit
91+
ld a, e
92+
and a, $20
93+
jr nz, .round_up
94+
; test sticky bits
95+
inc a ; make A non-zero
96+
adc hl, hl
97+
jr nz, .round_up
98+
ld a, e
99+
rla
100+
and a, $1F
101+
.round_up:
102+
.round_down:
103+
call __llshru
104+
or a, a
105+
jr z, .no_round
106+
inc hl ; does not overflow
107+
.no_round:
108+
pop af ; a = exponent + 1, flags = 29 = ---5H3V-C
109+
sbc a, b ; decremenet exponent and clear carry
110+
rra
111+
jr nc, .even_exponent
112+
ld bc, $800000
113+
add hl, bc ; the result might be rounded to infinity here
114+
adc a, c ; adc a, 0 ; wont overflow
115+
.even_exponent:
116+
.subnormal_no_round:
117+
.ret_copysign:
118+
pop de
119+
ld e, a
120+
pop bc
121+
pop af
122+
ret z
123+
set 7, e
124+
ret
125+
126+
.ret_zero:
127+
; carry is cleared
128+
pop hl
129+
xor a, a
130+
sbc hl, hl
131+
jr .ret_copysign
132+
133+
.maybe_subnormal:
134+
ld hl, -$3690
135+
add.s hl, bc
136+
jr nc, .ret_zero
137+
; calculate shift
138+
; A = (uint8_t)((BC - $3690) >> 4)
139+
; A = (uint8_t)((HL << 4) >> 8)
140+
add hl, hl
141+
add hl, hl
142+
add hl, hl
143+
add hl, hl
144+
; Shift = -A + 4 + 24
145+
ld a, 4 + 24
146+
sub a, h
147+
; maximum shift = 24 + 4 + 25 = 24 + 29 = 53
148+
; minimum shift = 24 + 4 + 1 = 24 + 5 = 29
149+
ld b, a
150+
ld e, a ; store shift amount
151+
xor a, a
152+
; calculate sticky bits
153+
sbc hl, hl
154+
inc hl ; ld hl, 1
155+
.shift_loop:
156+
add hl, hl
157+
adc a, a
158+
djnz .shift_loop
159+
; carry won't be set
160+
; set C:UDE to A:UHL
161+
; shift by an additional 24 bits
162+
dec hl
163+
jr z, .the_set_bit_is_in_hl
164+
dec a
165+
.the_set_bit_is_in_hl:
166+
ld c, a
167+
ld a, e ; restore shift amount
168+
ex de, hl
169+
scf
170+
sbc hl, hl
171+
; BC:UDE:UHL = 1 << shift
172+
; (SP) = X
173+
call __lland
174+
call __llcmpzero
175+
pop hl
176+
; DE and BC are swapped here
177+
pop bc
178+
pop de
179+
push de
180+
push bc
181+
182+
; clear exponent and include the implicit mantissa bit
183+
ld d, 0
184+
jr z, .no_sticky_bits
185+
inc d
186+
.no_sticky_bits:
187+
188+
ld l, a ; L = shift
189+
ld a, e
190+
and a, $0F
191+
or a, $10
192+
193+
call __lshru
194+
xor a, a ; subnormal exponent
195+
; HL = BC >> 1
196+
scf
197+
sbc hl, hl ; ld hl, -1
198+
add hl, sp
199+
push bc
200+
srl (hl)
201+
pop hl
202+
rr h
203+
rr l ; round bit shifted out
204+
205+
jr nc, .subnormal_no_round
206+
dec d
207+
jr z, .subnormal_round_up
208+
bit 0, l
209+
jr z, .subnormal_no_round
210+
.subnormal_round_up:
211+
inc hl ; wont overflow, but may become FLT_MIN
212+
; .subnormal_no_round:
213+
jr .ret_copysign
214+
215+
extern __lland
216+
extern __llcmpzero
217+
extern __llshru
218+
extern __lshru

src/softfloat/f64_to_f32.c

Lines changed: 0 additions & 88 deletions
This file was deleted.

src/softfloat/include/specialize.h

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,7 @@ void softfloat_f32UIToCommonNaN( uint_fast32_t uiA, struct commonNaN *zPtr );
145145
| Converts the common NaN pointed to by 'aPtr' into a 32-bit floating-point
146146
| NaN, and returns the bit pattern of this value as an unsigned integer.
147147
*----------------------------------------------------------------------------*/
148-
#if 0
149148
uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr );
150-
#else
151-
/** only used by f64_to_f32 currently */
152-
static inline uint_fast32_t softfloat_commonNaNToF32UI( const struct commonNaN *aPtr )
153-
{
154-
return (uint_fast32_t) aPtr->sign<<31 | 0x7FC00000 | aPtr->v64>>41;
155-
}
156-
#endif
157149

158150
/*----------------------------------------------------------------------------
159151
| Interpreting 'uiA' and 'uiB' as the bit patterns of two 32-bit floating-
@@ -186,20 +178,7 @@ bool softfloat_isSigNaNF64UI(uint64_t a) __attribute__((__const__, __nothrow__,
186178
| location pointed to by 'zPtr'. If the NaN is a signaling NaN, the invalid
187179
| exception is raised.
188180
*----------------------------------------------------------------------------*/
189-
#if 0
190181
void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr );
191-
#else
192-
/** only used by f64_to_f32 currently */
193-
static inline void softfloat_f64UIToCommonNaN( uint_fast64_t uiA, struct commonNaN *zPtr )
194-
{
195-
if ( softfloat_isSigNaNF64UI( uiA ) ) {
196-
softfloat_raiseFlags( softfloat_flag_invalid );
197-
}
198-
zPtr->sign = uiA>>63;
199-
zPtr->v64 = uiA<<12;
200-
zPtr->v0 = 0;
201-
}
202-
#endif
203182

204183
/*----------------------------------------------------------------------------
205184
| Converts the common NaN pointed to by 'aPtr' into a 64-bit floating-point

0 commit comments

Comments
 (0)