@@ -43,6 +43,144 @@ intrinsics! {
4343
4444 ( ( rem as u64 ) << 32 ) | ( div as u64 )
4545 }
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+ }
46184}
47185
48186intrinsics ! {
0 commit comments