Skip to content

Commit ec12dca

Browse files
authored
Merge pull request #944 from boriel-basic/fix/crash_on_cast_i32_to_f
fix: crash on cast i32 to Float
2 parents 482a13a + 04b4227 commit ec12dca

5 files changed

Lines changed: 633 additions & 1 deletion

File tree

src/arch/z80/backend/common.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,9 @@ def to_float(stype: DataType) -> list[str]:
455455
elif stype == I8_t:
456456
output.append(runtime_call(RuntimeLabel.I8TOFREG))
457457
elif stype in {I16_t, I32_t, U16_t, U32_t}:
458-
output = to_long(stype)
458+
if stype in (I16_t, U16_t):
459+
output.extend(to_long(stype))
460+
459461
if stype in (I16_t, I32_t):
460462
output.append(runtime_call(RuntimeLabel.I32TOFREG))
461463
else:
Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
org 32768
2+
.core.__START_PROGRAM:
3+
di
4+
push ix
5+
push iy
6+
exx
7+
push hl
8+
exx
9+
ld hl, 0
10+
add hl, sp
11+
ld (.core.__CALL_BACK__), hl
12+
ei
13+
jp .core.__MAIN_PROGRAM__
14+
.core.__CALL_BACK__:
15+
DEFW 0
16+
.core.ZXBASIC_USER_DATA:
17+
; Defines USER DATA Length in bytes
18+
.core.ZXBASIC_USER_DATA_LEN EQU .core.ZXBASIC_USER_DATA_END - .core.ZXBASIC_USER_DATA
19+
.core.__LABEL__.ZXBASIC_USER_DATA_LEN EQU .core.ZXBASIC_USER_DATA_LEN
20+
.core.__LABEL__.ZXBASIC_USER_DATA EQU .core.ZXBASIC_USER_DATA
21+
_CLICK:
22+
DEFB 00, 00, 00, 00
23+
_TotalMinutes:
24+
DEFB 00, 00, 00, 00, 00
25+
.core.ZXBASIC_USER_DATA_END:
26+
.core.__MAIN_PROGRAM__:
27+
ld hl, (_CLICK + 2)
28+
push hl
29+
ld hl, (_CLICK)
30+
push hl
31+
ld de, 0
32+
ld hl, 20
33+
call .core.__SWAP32
34+
call .core.__DIVI32
35+
call .core.__I32TOFREG
36+
ld hl, _TotalMinutes
37+
call .core.__STOREF
38+
ld hl, 0
39+
ld b, h
40+
ld c, l
41+
.core.__END_PROGRAM:
42+
di
43+
ld hl, (.core.__CALL_BACK__)
44+
ld sp, hl
45+
exx
46+
pop hl
47+
exx
48+
pop iy
49+
pop ix
50+
ei
51+
ret
52+
;; --- end of user code ---
53+
#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/arith/div32.asm"
54+
#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/neg32.asm"
55+
push namespace core
56+
__ABS32:
57+
bit 7, d
58+
ret z
59+
__NEG32: ; Negates DEHL (Two's complement)
60+
ld a, l
61+
cpl
62+
ld l, a
63+
ld a, h
64+
cpl
65+
ld h, a
66+
ld a, e
67+
cpl
68+
ld e, a
69+
ld a, d
70+
cpl
71+
ld d, a
72+
inc l
73+
ret nz
74+
inc h
75+
ret nz
76+
inc de
77+
ret
78+
pop namespace
79+
#line 2 "/zxbasic/src/lib/arch/zx48k/runtime/arith/div32.asm"
80+
; ---------------------------------------------------------
81+
push namespace core
82+
__DIVU32: ; 32 bit unsigned division
83+
; DEHL = Dividend, Stack Top = Divisor
84+
; OPERANDS P = Dividend, Q = Divisor => OPERATION => P / Q
85+
;
86+
; Changes A, BC DE HL B'C' D'E' H'L'
87+
; ---------------------------------------------------------
88+
exx
89+
pop hl ; return address
90+
pop de ; low part
91+
ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend
92+
__DIVU32START: ; Performs D'E'H'L' / HLDE
93+
; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B)
94+
push de ; push Lowpart(Q)
95+
ex de, hl ; DE = HL
96+
ld hl, 0
97+
exx
98+
ld b, h
99+
ld c, l
100+
pop hl
101+
push de
102+
ex de, hl
103+
ld hl, 0 ; H'L'HL = 0
104+
exx
105+
pop bc ; Pop HightPart(B) => B = B'C'BC
106+
exx
107+
ld a, 32 ; Loop count
108+
__DIV32LOOP:
109+
sll c ; B'C'BC << 1 ; Output most left bit to carry
110+
rl b
111+
exx
112+
rl c
113+
rl b
114+
exx
115+
adc hl, hl
116+
exx
117+
adc hl, hl
118+
exx
119+
sbc hl,de
120+
exx
121+
sbc hl,de
122+
exx
123+
jp nc, __DIV32NOADD ; use JP inside a loop for being faster
124+
add hl, de
125+
exx
126+
adc hl, de
127+
exx
128+
dec bc
129+
__DIV32NOADD:
130+
dec a
131+
jp nz, __DIV32LOOP ; use JP inside a loop for being faster
132+
; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL
133+
push hl
134+
exx
135+
pop de
136+
ex de, hl ; D'E'H'L' = 32 bits modulus
137+
push bc
138+
exx
139+
pop de ; DE = B'C'
140+
ld h, b
141+
ld l, c ; DEHL = quotient D'E'H'L' = Modulus
142+
ret ; DEHL = quotient, D'E'H'L' = Modulus
143+
__MODU32: ; 32 bit modulus for 32bit unsigned division
144+
; DEHL = Dividend, Stack Top = Divisor (DE, HL)
145+
exx
146+
pop hl ; return address
147+
pop de ; low part
148+
ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend
149+
call __DIVU32START ; At return, modulus is at D'E'H'L'
150+
__MODU32START:
151+
exx
152+
push de
153+
push hl
154+
exx
155+
pop hl
156+
pop de
157+
ret
158+
__DIVI32: ; 32 bit signed division
159+
; DEHL = Dividend, Stack Top = Divisor
160+
; A = Dividend, B = Divisor => A / B
161+
exx
162+
pop hl ; return address
163+
pop de ; low part
164+
ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend
165+
__DIVI32START:
166+
exx
167+
ld a, d ; Save sign
168+
ex af, af'
169+
bit 7, d ; Negative?
170+
call nz, __NEG32 ; Negates DEHL
171+
exx ; Now works with H'L'D'E'
172+
ex af, af'
173+
xor h
174+
ex af, af' ; Stores sign of the result for later
175+
bit 7, h ; Negative?
176+
ex de, hl ; HLDE = DEHL
177+
call nz, __NEG32
178+
ex de, hl
179+
call __DIVU32START
180+
ex af, af' ; Recovers sign
181+
and 128 ; positive?
182+
ret z
183+
jp __NEG32 ; Negates DEHL and returns from there
184+
__MODI32: ; 32bits signed division modulus
185+
exx
186+
pop hl ; return address
187+
pop de ; low part
188+
ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend
189+
call __DIVI32START
190+
jp __MODU32START
191+
pop namespace
192+
#line 28 "arch/zx48k/cast_i32tof.bas"
193+
#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/storef.asm"
194+
push namespace core
195+
__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL)
196+
push de
197+
ex de, hl ; DE <- HL
198+
push ix
199+
pop hl ; HL <- IX
200+
add hl, de ; HL <- IX + HL
201+
pop de
202+
__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register
203+
ex af, af'
204+
ld a, (hl)
205+
inc hl
206+
ld h, (hl)
207+
ld l, a ; HL = (HL)
208+
ex af, af'
209+
__STOREF: ; Stores the given FP number in A EDCB at address HL
210+
ld (hl), a
211+
inc hl
212+
ld (hl), e
213+
inc hl
214+
ld (hl), d
215+
inc hl
216+
ld (hl), c
217+
inc hl
218+
ld (hl), b
219+
ret
220+
pop namespace
221+
#line 29 "arch/zx48k/cast_i32tof.bas"
222+
#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/swap32.asm"
223+
; Exchanges current DE HL with the
224+
; ones in the stack
225+
push namespace core
226+
__SWAP32:
227+
pop bc ; Return address
228+
ex (sp), hl
229+
inc sp
230+
inc sp
231+
ex de, hl
232+
ex (sp), hl
233+
ex de, hl
234+
dec sp
235+
dec sp
236+
push bc
237+
ret
238+
pop namespace
239+
#line 30 "arch/zx48k/cast_i32tof.bas"
240+
#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/u32tofreg.asm"
241+
push namespace core
242+
__I8TOFREG:
243+
ld l, a
244+
rlca
245+
sbc a, a ; A = SGN(A)
246+
ld h, a
247+
ld e, a
248+
ld d, a
249+
__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL)
250+
; to a Floating Point Number returned in (A ED CB)
251+
ld a, d
252+
or a ; Test sign
253+
jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned
254+
call __NEG32 ; Convert it to positive
255+
call __U32TOFREG ; Convert it to Floating point
256+
set 7, e ; Put the sign bit (negative) in the 31bit of mantissa
257+
ret
258+
__U8TOFREG:
259+
; Converts an unsigned 8 bit (A) to Floating point
260+
ld l, a
261+
ld h, 0
262+
ld e, h
263+
ld d, h
264+
__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL)
265+
; to a Floating point number returned in A ED CB
266+
PROC
267+
LOCAL __U32TOFREG_END
268+
ld a, d
269+
or e
270+
or h
271+
or l
272+
ld b, d
273+
ld c, e ; Returns 00 0000 0000 if ZERO
274+
ret z
275+
push de
276+
push hl
277+
exx
278+
pop de ; Loads integer into B'C' D'E'
279+
pop bc
280+
exx
281+
ld l, 128 ; Exponent
282+
ld bc, 0 ; DEBC = 0
283+
ld d, b
284+
ld e, c
285+
__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG
286+
exx
287+
ld a, d ; B'C'D'E' == 0 ?
288+
or e
289+
or b
290+
or c
291+
jp z, __U32TOFREG_END ; We are done
292+
srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry
293+
rr c
294+
rr d
295+
rr e
296+
exx
297+
rr e ; Shift EDCB >> 1, inserting the carry on the left
298+
rr d
299+
rr c
300+
rr b
301+
inc l ; Increment exponent
302+
jp __U32TOFREG_LOOP
303+
__U32TOFREG_END:
304+
exx
305+
ld a, l ; Puts the exponent in a
306+
res 7, e ; Sets the sign bit to 0 (positive)
307+
ret
308+
ENDP
309+
pop namespace
310+
#line 31 "arch/zx48k/cast_i32tof.bas"
311+
END
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
DIM CLICK AS LONG
2+
DIM TotalMinutes as Float
3+
4+
TotalMinutes = CLICK/20

0 commit comments

Comments
 (0)