@@ -43,6 +43,144 @@ intrinsics! {
43
43
44
44
( ( rem as u64 ) << 32 ) | ( div as u64 )
45
45
}
46
+
47
+ /// Returns unsigned 8-bit `n / d` and `n % d`.
48
+ ///
49
+ /// Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function.
50
+ #[ naked]
51
+ pub unsafe extern "C" fn __udivmodqi4( ) {
52
+ // Derived from: https://github.com/gcc-mirror/gcc/blob/95f10974a9190e345776604480a2df0191104308/libgcc/config/avr/lib1funcs.S#L1365
53
+
54
+ // r25: remainder
55
+ // r24: dividend, quotient
56
+ // r22: divisor
57
+ // r23: loop counter
58
+ core:: arch:: naked_asm!(
59
+ "clr r25" , // clear remainder
60
+ "ldi r23, 8" , // init loop counter
61
+ "lsl r24" , // shift dividend
62
+ "rol r25" , // shift dividend into remainder
63
+ "cp r25, r22" , // compare remainder & divisor
64
+ "brcs 2" , // remainder <= divisor
65
+ "sub r25, r22" , // restore remainder
66
+ "rol r24" , // shift dividend (with CARRY)
67
+ "dec r23" , // decrement loop counter
68
+ "brne -14" ,
69
+ "com r24" , // complement result (C flag was complemented in loop)
70
+ "ret" ,
71
+ ) ;
72
+ }
73
+
74
+ /// Returns signed 8-bit `n / d` and `n % d`.
75
+ ///
76
+ /// Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function.
77
+ #[ naked]
78
+ pub unsafe extern "C" fn __divmodqi4( ) {
79
+ // Derived from: https://github.com/gcc-mirror/gcc/blob/95f10974a9190e345776604480a2df0191104308/libgcc/config/avr/lib1funcs.S#L1385
80
+
81
+ // r25: remainder
82
+ // r24: dividend, quotient
83
+ // r22: divisor
84
+ // r23: loop counter
85
+ core:: arch:: naked_asm!(
86
+ "bst r24, 7" , // store sign of dividend
87
+ "mov r0, r24" ,
88
+ "eor r0, r22" , // r0.7 is sign of result
89
+ "sbrc r24, 7" ,
90
+ "neg r24" , // dividend negative : negate
91
+ "sbrc r22, 7" ,
92
+ "neg r22" , // divisor negative : negate
93
+ // TODO: "call" => instruction requires a CPU feature not currently enabled
94
+ // TODO: gcc checks for __AVR_HAVE_JMP_CALL__
95
+ "rcall __udivmodqi4" , // do the unsigned div/mod
96
+ "brtc 2" ,
97
+ "neg r25" , // correct remainder sign
98
+ "sbrc r0,7" ,
99
+ "neg r24" , // correct result sign
100
+ "ret" ,
101
+ ) ;
102
+ }
103
+
104
+ /// Returns unsigned 16-bit `n / d` and `n % d`.
105
+ ///
106
+ /// Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function.
107
+ #[ naked]
108
+ pub unsafe extern "C" fn __udivmodhi4( ) {
109
+ // Derived from: https://github.com/gcc-mirror/gcc/blob/95f10974a9190e345776604480a2df0191104308/libgcc/config/avr/lib1funcs.S#L1427
110
+
111
+ // r26: remainder (low)
112
+ // r27: remainder (high)
113
+ // r24: dividend (low)
114
+ // r25: dividend (high)
115
+ // r22: divisor (low)
116
+ // r23: divisor (high)
117
+ // r21: loop counter
118
+ core:: arch:: naked_asm!(
119
+ "sub r26, r26" ,
120
+ "sub r27, r27" , // clear remainder and carry
121
+ "ldi r21, 17" , // init loop counter
122
+ "rjmp .+14" , // jump to entry point
123
+ "rol r26" , // shift dividend into remainder
124
+ "rol r27" ,
125
+ "cp r26, r22" , // compare remainder & divisor
126
+ "cpc r27, r23" ,
127
+ "brcs .+4" , // remainder < divisor
128
+ "sub r26, r22" , // restore remainder
129
+ "sbc r27, r23" ,
130
+ "rol r24" , // shift dividend (with CARRY)
131
+ "rol r25" ,
132
+ "dec r21" , // decrement loop counter
133
+ "brne .-22" ,
134
+ "com r24" ,
135
+ "com r25" ,
136
+ // TODO: "movw" => instruction requires a CPU feature not currently enabled
137
+ // TODO: gcc checks for __AVR_HAVE_MOVW__
138
+ "mov r22, r24" ,
139
+ "mov r23, r25" ,
140
+ "mov r24, r26" ,
141
+ "mov r25, r27" ,
142
+ "ret" ,
143
+ ) ;
144
+ }
145
+
146
+ /// Returns signed 16-bit `n / d` and `n % d`.
147
+ ///
148
+ /// Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function.
149
+ #[ naked]
150
+ pub unsafe extern "C" fn __divmodhi4( ) {
151
+ // Derived from: https://github.com/gcc-mirror/gcc/blob/95f10974a9190e345776604480a2df0191104308/libgcc/config/avr/lib1funcs.S#L1457
152
+
153
+ // r26: remainder (low)
154
+ // r27: remainder (high)
155
+ // r24: dividend (low)
156
+ // r25: dividend (high)
157
+ // r22: divisor (low)
158
+ // r23: divisor (high)
159
+ // r21: loop counter
160
+ core:: arch:: naked_asm!(
161
+ "bst r25, 7" , // store sign of dividend
162
+ "mov r0, r23" ,
163
+ "brtc .+4" ,
164
+ "com r0" , // r0.7 is sign of result
165
+ "rcall .+12" , // dividend negative : negate
166
+ "sbrc r23, 7" ,
167
+ "rcall .+16" , // divisor negative : negate
168
+ // TODO: "call" => instruction requires a CPU feature not currently enabled
169
+ // TODO: gcc checks for __AVR_HAVE_JMP_CALL__
170
+ "rcall __udivmodhi4" , // do the unsigned div/mod
171
+ "sbrc r0, 7" ,
172
+ "rcall .+10" , // correct remainder sign
173
+ "brtc .+14" ,
174
+ "com r25" , // correct dividend/remainder sign
175
+ "neg r24" ,
176
+ "sbci r25, 0xFF" ,
177
+ "ret" ,
178
+ "com r23" , // correct divisor/result sign
179
+ "neg r22" ,
180
+ "sbci r23, 0xFF" ,
181
+ "ret" ,
182
+ ) ;
183
+ }
46
184
}
47
185
48
186
intrinsics ! {
0 commit comments