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