Skip to content

Commit ea7a461

Browse files
ZERICO2005mateoconlechuga
authored andcommitted
Fixed __ldvrmu calling convention stability and fixed C ldiv under PREFER_OS_CRT. Created __ldivu_lremu_common to allow for custom calling conventions to be used for implementing 32-bit division/remainder.
1 parent d13be1a commit ea7a461

5 files changed

Lines changed: 105 additions & 90 deletions

File tree

src/crt/ldivu.src

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010

1111
.else
1212

13+
; REMEMBER to keep ldivu.src, lremu.src, and ldiv.src in sync with this choice
1314
.if 1
1415

1516
__ldivu:
1617
; I: EUHL=dividend, AUBC=divisor
1718
; O: euhl=EUHL/AUBC
1819
push bc
1920

20-
call __ldvrmu
21+
call __ldivu_lremu_common
2122

2223
ld a, b
2324
pop bc
@@ -26,6 +27,8 @@ __ldivu:
2627
ei
2728
ret
2829

30+
.extern __ldivu_lremu_common
31+
2932
.else
3033

3134
__ldivu:
@@ -41,8 +44,9 @@ __ldivu:
4144
pop hl
4245

4346
ret
44-
.endif
4547

4648
.extern __ldvrmu
4749

4850
.endif
51+
52+
.endif

src/crt/ldivu_lremu_common.src

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
.assume adl=1
2+
3+
.section .text
4+
5+
.global __ldivu_lremu_common
6+
.type __ldivu_lremu_common, @function
7+
8+
;;; struct u32div_t {
9+
;;; uint32_t rem;
10+
;;; uint32_t quot;
11+
;;; };
12+
;;; u32div_t _ldivu_lremu_common(uint32_t dividend, uint32_t divisor) {
13+
14+
__ldivu_lremu_common:
15+
; Similar to __ldvrmu but faster and with a different calling convention.
16+
; Note: Uses shadow registers and disables interrupts.
17+
; I: EUHL=dividend, AUBC=divisor
18+
; O: a[uhl']=EUHL%AUBC, bcu=0, b=A, c=?, euhl=EUHL/AUBC, eubc'=AUBC, zf=!IEF2
19+
20+
;;; u32div_t result;
21+
;;; result.quot = dividend;
22+
; euhl : result.quot
23+
24+
push bc
25+
26+
ld c, a ; c = A
27+
ld a, i ; a = I
28+
; pf = IEF2
29+
di
30+
31+
ld a, c ; a = A
32+
exx
33+
pop bc
34+
ld e, a ; eubc' : divisor
35+
36+
push af
37+
38+
;;; result.rem = 0;
39+
xor a, a
40+
sbc hl, hl ; auhl' : result.rem
41+
42+
;;; int i = 32;
43+
exx
44+
ld b, 32 ; b : i
45+
46+
;;; do {
47+
.L.c.loop:
48+
49+
;;; bool dividendBit = result.quot >> 31;
50+
;;; result.quot <<= 1;
51+
add hl, hl
52+
rl e
53+
;;; result.rem = (result.rem << 1) + dividendBit;
54+
exx
55+
adc hl, hl
56+
adc a, a
57+
58+
;;; bool quotBit = result.rem >= divisor;
59+
;;; result.rem -= divisor;
60+
sbc hl, bc
61+
sbc a, e
62+
63+
;;; if (!quotBit) {
64+
jr nc, .L.c.restore_skip
65+
;;; result.rem += divisor;
66+
add hl, bc
67+
adc a, e
68+
;;; }
69+
.L.c.restore_skip:
70+
71+
;;; if (quotBit) {
72+
exx
73+
jr c, .L.c.skip
74+
;;; result.quot++;
75+
inc l
76+
;;; }
77+
.L.c.skip:
78+
79+
;;; } while (--i != 0);
80+
djnz .L.c.loop
81+
82+
;;; return result;
83+
pop bc
84+
bit 2, c
85+
ret
86+
;;; }

src/crt/ldvrmu.src

Lines changed: 1 addition & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
.assume adl=1
22

33
.section .text
4-
;;; struct u32div_t {
5-
;;; uint32_t rem;
6-
;;; uint32_t quot;
7-
;;; };
8-
;;; u32div_t _ldvrmu(uint32_t dividend, uint32_t divisor) {
4+
95
.global __ldvrmu
106
.type __ldvrmu, @function
117

@@ -15,83 +11,6 @@
1511

1612
.else
1713

18-
; REMEMBER to also modify ldivu.src, lremu.src, and ldiv.src if you change this
19-
.if 1
20-
21-
__ldvrmu:
22-
; I: EUHL=dividend, AUBC=divisor
23-
; O: a[uhl']=EUHL%AUBC, bcu=0, b=A, c=?, euhl=EUHL/AUBC, eubc'=AUBC, zf=!IEF2
24-
25-
;;; u32div_t result;
26-
;;; result.quot = dividend;
27-
; euhl : result.quot
28-
29-
push bc
30-
31-
ld c, a ; c = A
32-
ld a, i ; a = I
33-
; pf = IEF2
34-
di
35-
36-
ld a, c ; a = A
37-
exx
38-
pop bc
39-
ld e, a ; eubc' : divisor
40-
41-
push af
42-
43-
;;; result.rem = 0;
44-
xor a, a
45-
sbc hl, hl ; auhl' : result.rem
46-
47-
;;; int i = 32;
48-
exx
49-
ld b, 32 ; b : i
50-
51-
;;; do {
52-
.L.c.loop:
53-
54-
;;; bool dividendBit = result.quot >> 31;
55-
;;; result.quot <<= 1;
56-
add hl, hl
57-
rl e
58-
;;; result.rem = (result.rem << 1) + dividendBit;
59-
exx
60-
adc hl, hl
61-
adc a, a
62-
63-
;;; bool quotBit = result.rem >= divisor;
64-
;;; result.rem -= divisor;
65-
sbc hl, bc
66-
sbc a, e
67-
68-
;;; if (!quotBit) {
69-
jr nc, .L.c.restore_skip
70-
;;; result.rem += divisor;
71-
add hl, bc
72-
adc a, e
73-
;;; }
74-
.L.c.restore_skip:
75-
76-
;;; if (quotBit) {
77-
exx
78-
jr c, .L.c.skip
79-
;;; result.quot++;
80-
inc l
81-
;;; }
82-
.L.c.skip:
83-
84-
;;; } while (--i != 0);
85-
djnz .L.c.loop
86-
87-
;;; return result;
88-
pop bc
89-
bit 2, c
90-
ret
91-
;;; }
92-
93-
.else
94-
9514
__ldvrmu:
9615
; I: EUHL=dividend, AUBC=divisor
9716
; O: auhl=EUHL%AUBC, euix=EUHL/AUBC, iyh=A, iyl=0
@@ -128,5 +47,3 @@ __ldvrmu:
12847
ret
12948

13049
.endif
131-
132-
.endif

src/crt/lremu.src

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@
1010

1111
.else
1212

13+
; REMEMBER to keep ldivu.src, lremu.src, and ldiv.src in sync with this choice
1314
.if 1
1415

1516
__lremu:
1617
; I: EUHL=dividend, AUBC=divisor
1718
; O: euhl=EUHL%AUBC
18-
call __ldvrmu
19+
call __ldivu_lremu_common
1920
ld e, a
2021
push de
2122
exx
@@ -26,6 +27,8 @@ __lremu:
2627
ei
2728
ret
2829

30+
.extern __ldivu_lremu_common
31+
2932
.else
3033

3134
__lremu:
@@ -41,8 +44,9 @@ __lremu:
4144
pop iy
4245
pop ix
4346
ret
44-
.endif
4547

4648
.extern __ldvrmu
4749

4850
.endif
51+
52+
.endif

src/libc/ldiv.src

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
.global _ldiv
55
.type _ldiv, @function
66

7+
; REMEMBER to keep ldivu.src, lremu.src, and ldiv.src in sync with this choice
78
.if 1
89

910
_ldiv:
@@ -27,7 +28,7 @@ _ldiv:
2728
bit 7, e
2829
call __ldivs_lrems_common
2930

30-
call __ldvrmu
31+
call __ldivu_lremu_common
3132

3233
exx
3334
ld e, a
@@ -53,6 +54,8 @@ _ldiv:
5354
.L.ei_skip:
5455
jp (hl)
5556

57+
.extern __ldivu_lremu_common
58+
5659
.else
5760

5861
_ldiv:
@@ -111,8 +114,9 @@ _ldiv:
111114
push de
112115
jp (hl)
113116

117+
.extern __ldvrmu
118+
114119
.endif
115120

116121
.extern __ldivs_lrems_common
117-
.extern __ldvrmu
118122
.extern __lneg

0 commit comments

Comments
 (0)