Skip to content

Commit 7f72325

Browse files
authored
switch all .S files to unified asm, and use a macro to setup compiler and some other misc changes (#1295)
* switch all .S files to unified asm, and use a new macro `pico_default_asm_setup` to setup compiler to help porting to other compilers. Also some minor tweaks: * switch some code to use more recent helper methods (e.g. busy_wait_at_least_n_cycles) * add documentation to host divider header (I had this ages ago and never promoted) * fixup erroneous docs about 32p32 values in all divider headers * fix some compiler warnings * rename recently added `unified_asm` macro to `pico_default_asm`
1 parent dca773f commit 7f72325

File tree

41 files changed

+377
-215
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+377
-215
lines changed

src/host/hardware_divider/include/hardware/divider.h

Lines changed: 240 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,116 +7,325 @@
77
#ifndef _HARDWARE_DIVIDER_H
88
#define _HARDWARE_DIVIDER_H
99

10-
#include "pico/types.h"
10+
#include "pico.h"
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
1115

1216
typedef uint64_t divmod_result_t;
1317

1418
static inline int __sign_of(int32_t v) {
1519
return v > 0 ? 1 : (v < 0 ? -1 : 0);
1620
}
1721

18-
// divides unsigned values a by b... (a/b) returned in low 32 bits, (a%b) in high 32 bits... results undefined for b==0
19-
static inline uint64_t hw_divider_divmod_u32(uint32_t a, uint32_t b) {
22+
/*! \brief Do an unsigned HW divide and wait for result
23+
* \ingroup hardware_divider
24+
*
25+
* Divide \p a by \p b, wait for calculation to complete, return result as a pair of 32-bit quotient/remainder values.
26+
*
27+
* \param a The dividend
28+
* \param b The divisor
29+
* \return Results of divide as a pair of 32-bit quotient/remainder values.
30+
*/
31+
static inline divmod_result_t hw_divider_divmod_u32(uint32_t a, uint32_t b) {
2032
if (!b) return (((uint64_t)a)<<32u) | (uint32_t)(-1); // todo check this
2133
return (((uint64_t)(a%b))<<32u) | (a/b);
2234
}
2335

24-
// divides signed values a by b... (a/b) returned in low 32 bits, (a%b) in high 32 bits... results undefined for b==0
25-
static inline uint64_t hw_divider_divmod_s32(int32_t a, int32_t b) {
36+
/*! \brief Do a signed HW divide and wait for result
37+
* \ingroup hardware_divider
38+
*
39+
* Divide \p a by \p b, wait for calculation to complete, return result as a pair of 32-bit quotient/remainder values.
40+
*
41+
* \param a The dividend
42+
* \param b The divisor
43+
* \return Results of divide as a pair of 32-bit quotient/remainder values.
44+
*/
45+
static inline divmod_result_t hw_divider_divmod_s32(int32_t a, int32_t b) {
2646
if (!b) return (((uint64_t)a)<<32u) | (uint32_t)(-__sign_of(a));
2747
return (((uint64_t)(a%b))<<32u) | (uint32_t)(a/b);
2848
}
2949

3050
extern __thread divmod_result_t hw_divider_result_threadlocal;
3151

52+
/*! \brief Start a signed asynchronous divide
53+
* \ingroup hardware_divider
54+
*
55+
* Start a divide of the specified signed parameters. You should wait for 8 cycles (__div_pause()) or wait for the ready bit to be set
56+
* (hw_divider_wait_ready()) prior to reading the results.
57+
*
58+
* \param a The dividend
59+
* \param b The divisor
60+
*/
3261
static inline void hw_divider_divmod_s32_start(int32_t a, int32_t b) {
3362
hw_divider_result_threadlocal = hw_divider_divmod_s32(a, b);
3463
}
3564

65+
/*! \brief Start an unsigned asynchronous divide
66+
* \ingroup hardware_divider
67+
*
68+
* Start a divide of the specified unsigned parameters. You should wait for 8 cycles (__div_pause()) or wait for the ready bit to be set
69+
* (hw_divider_wait_ready()) prior to reading the results.
70+
*
71+
* \param a The dividend
72+
* \param b The divisor
73+
*/
3674
static inline void hw_divider_divmod_u32_start(uint32_t a, uint32_t b) {
3775
hw_divider_result_threadlocal = hw_divider_divmod_u32(a, b);
3876
}
3977

40-
static inline divmod_result_t hw_divider_result_wait() {
78+
/*! \brief Return result of last asynchronous HW divide
79+
* \ingroup hardware_divider
80+
*
81+
* This function waits for the result to be ready by calling hw_divider_wait_ready().
82+
*
83+
* \return Current result. Most significant 32 bits are the remainder, lower 32 bits are the quotient.
84+
*/
85+
static inline divmod_result_t hw_divider_result_wait(void) {
4186
return hw_divider_result_threadlocal;
4287
}
4388

44-
static inline uint64_t hw_divider_result_nowait() {
89+
/*! \brief Return result of HW divide, nowait
90+
* \ingroup hardware_divider
91+
*
92+
* \note This is UNSAFE in that the calculation may not have been completed.
93+
*
94+
* \return Current result. Most significant 32 bits are the remainder, lower 32 bits are the quotient.
95+
*/
96+
static inline divmod_result_t hw_divider_result_nowait(void) {
4597
return hw_divider_result_threadlocal;
4698
}
4799

48-
inline static uint32_t to_quotient_u32(unsigned long long int r) {
100+
/*! \brief Wait for a divide to complete
101+
* \ingroup hardware_divider
102+
*
103+
* Wait for a divide to complete
104+
*/
105+
static inline void hw_divider_wait_ready(void) {}
106+
107+
108+
/*! \brief Efficient extraction of unsigned quotient from 32p32 fixed point
109+
* \ingroup hardware_divider
110+
*
111+
* \param r A pair of 32-bit quotient/remainder values.
112+
* \return Unsigned quotient
113+
*/
114+
inline static uint32_t to_quotient_u32(divmod_result_t r) {
49115
return (uint32_t) r;
50116
}
51117

52-
inline static int32_t to_quotient_s32(unsigned long long int r) {
118+
/*! \brief Efficient extraction of signed quotient from 32p32 fixed point
119+
* \ingroup hardware_divider
120+
*
121+
* \param r A pair of 32-bit quotient/remainder values.
122+
* \return Unsigned quotient
123+
*/
124+
inline static int32_t to_quotient_s32(divmod_result_t r) {
53125
return (int32_t)(uint32_t)r;
54126
}
55127

56-
inline static uint32_t to_remainder_u32(unsigned long long int r) {
128+
/*! \brief Efficient extraction of unsigned remainder from 32p32 fixed point
129+
* \ingroup hardware_divider
130+
*
131+
* \param r A pair of 32-bit quotient/remainder values.
132+
* \return Unsigned remainder
133+
*
134+
* \note On Arm this is just a 32 bit register move or a nop
135+
*/
136+
inline static uint32_t to_remainder_u32(divmod_result_t r) {
57137
return (uint32_t)(r >> 32u);
58138
}
59139

60-
inline static int32_t to_remainder_s32(unsigned long long int r) {
140+
/*! \brief Efficient extraction of signed remainder from 32p32 fixed point
141+
* \ingroup hardware_divider
142+
*
143+
* \param r A pair of 32-bit quotient/remainder values.
144+
* \return Signed remainder
145+
*
146+
* \note On arm this is just a 32 bit register move or a nop
147+
*/
148+
inline static int32_t to_remainder_s32(divmod_result_t r) {
61149
return (int32_t)(r >> 32u);
62150
}
63151

64-
static inline uint32_t hw_divider_u32_quotient_wait() {
65-
return to_quotient_u32(hw_divider_result_wait());
152+
static inline void hw_divider_pause(void) {}
153+
154+
/*! \brief Do an unsigned HW divide, wait for result, return quotient
155+
* \ingroup hardware_divider
156+
*
157+
* Divide \p a by \p b, wait for calculation to complete, return quotient.
158+
*
159+
* \param a The dividend
160+
* \param b The divisor
161+
* \return Quotient results of the divide
162+
*/
163+
static inline uint32_t hw_divider_u32_quotient(uint32_t a, uint32_t b) {
164+
return b ? (a / b) : (uint32_t)(-1);
66165
}
67166

68-
static inline uint32_t hw_divider_u32_remainder_wait() {
69-
return to_remainder_u32(hw_divider_result_wait());
167+
/*! \brief Do an unsigned HW divide, wait for result, return remainder
168+
* \ingroup hardware_divider
169+
*
170+
* Divide \p a by \p b, wait for calculation to complete, return remainder.
171+
*
172+
* \param a The dividend
173+
* \param b The divisor
174+
* \return Remainder results of the divide
175+
*/
176+
static inline uint32_t hw_divider_u32_remainder(uint32_t a, uint32_t b) {
177+
return b ? (a % b) : a;
70178
}
71179

72-
static inline int32_t hw_divider_s32_quotient_wait() {
73-
return to_quotient_s32(hw_divider_result_wait());
180+
/*! \brief Do a signed HW divide, wait for result, return quotient
181+
* \ingroup hardware_divider
182+
*
183+
* Divide \p a by \p b, wait for calculation to complete, return quotient.
184+
*
185+
* \param a The dividend
186+
* \param b The divisor
187+
* \return Quotient results of the divide
188+
*/
189+
static inline int32_t hw_divider_quotient_s32(int32_t a, int32_t b) {
190+
return to_quotient_s32(hw_divider_divmod_s32(a, b));
74191
}
75192

76-
static inline int32_t hw_divider_s32_remainder_wait() {
77-
return to_remainder_s32(hw_divider_result_wait());
193+
/*! \brief Do a signed HW divide, wait for result, return remainder
194+
* \ingroup hardware_divider
195+
*
196+
* Divide \p a by \p b, wait for calculation to complete, return remainder.
197+
*
198+
* \param a The dividend
199+
* \param b The divisor
200+
* \return Remainder results of the divide
201+
*/
202+
static inline int32_t hw_divider_remainder_s32(int32_t a, int32_t b) {
203+
return b ? (a % b) : a;
78204
}
79205

80-
static inline uint32_t hw_divider_u32_quotient(uint32_t a, uint32_t b) {
81-
return b ? (a / b) : (uint32_t)(-1);
206+
/*! \brief Return result of last asynchronous HW divide, unsigned quotient only
207+
* \ingroup hardware_divider
208+
*
209+
* This function waits for the result to be ready by calling hw_divider_wait_ready().
210+
*
211+
* \return Current unsigned quotient result.
212+
*/
213+
static inline uint32_t hw_divider_u32_quotient_wait(void) {
214+
return to_quotient_u32(hw_divider_result_wait());
82215
}
83216

84-
static inline uint32_t hw_divider_u32_remainder(uint32_t a, uint32_t b) {
85-
return b ? (a % b) : a;
217+
/*! \brief Return result of last asynchronous HW divide, signed quotient only
218+
* \ingroup hardware_divider
219+
*
220+
* This function waits for the result to be ready by calling hw_divider_wait_ready().
221+
*
222+
* \return Current signed quotient result.
223+
*/
224+
static inline int32_t hw_divider_s32_quotient_wait(void) {
225+
return to_remainder_u32(hw_divider_result_wait());
86226
}
87227

88-
static inline int32_t hw_divider_s32_quotient(int32_t a, int32_t b) {
89-
return b ? (a / b) : -__sign_of(a);
228+
/*! \brief Return result of last asynchronous HW divide, unsigned remainder only
229+
* \ingroup hardware_divider
230+
*
231+
* This function waits for the result to be ready by calling hw_divider_wait_ready().
232+
*
233+
* \return Current unsigned remainder result.
234+
*/
235+
static inline uint32_t hw_divider_u32_remainder_wait(void) {
236+
return to_quotient_s32(hw_divider_result_wait());
90237
}
91238

92-
static inline int32_t hw_divider_s32_remainder(int32_t a, int32_t b) {
93-
return b ? (a % b) : a;
239+
/*! \brief Return result of last asynchronous HW divide, signed remainder only
240+
* \ingroup hardware_divider
241+
*
242+
* This function waits for the result to be ready by calling hw_divider_wait_ready().
243+
*
244+
* \return Current remainder results.
245+
*/
246+
static inline int32_t hw_divider_s32_remainder_wait(void) {
247+
return to_remainder_s32(hw_divider_result_wait());
94248
}
95249

250+
/*! \brief Do a hardware unsigned HW divide, wait for result, return quotient
251+
* \ingroup hardware_divider
252+
*
253+
* Divide \p a by \p b, wait for calculation to complete, return quotient.
254+
*
255+
* \param a The dividend
256+
* \param b The divisor
257+
* \return Quotient result of the divide
258+
*/
96259
static inline uint32_t hw_divider_u32_quotient_inlined(uint32_t a, uint32_t b) {
97260
return hw_divider_u32_quotient(a,b);
98261
}
99262

263+
/*! \brief Do a hardware unsigned HW divide, wait for result, return remainder
264+
* \ingroup hardware_divider
265+
*
266+
* Divide \p a by \p b, wait for calculation to complete, return remainder.
267+
*
268+
* \param a The dividend
269+
* \param b The divisor
270+
* \return Remainder result of the divide
271+
*/
100272
static inline uint32_t hw_divider_u32_remainder_inlined(uint32_t a, uint32_t b) {
101273
return hw_divider_u32_remainder(a,b);
102274
}
103275

276+
/*! \brief Do a hardware signed HW divide, wait for result, return quotient
277+
* \ingroup hardware_divider
278+
*
279+
* Divide \p a by \p b, wait for calculation to complete, return quotient.
280+
*
281+
* \param a The dividend
282+
* \param b The divisor
283+
* \return Quotient result of the divide
284+
*/
104285
static inline int32_t hw_divider_s32_quotient_inlined(int32_t a, int32_t b) {
105-
return hw_divider_s32_quotient(a,b);
286+
return hw_divider_quotient_s32(a,b);
106287
}
107288

289+
/*! \brief Do a hardware signed HW divide, wait for result, return remainder
290+
* \ingroup hardware_divider
291+
*
292+
* Divide \p a by \p b, wait for calculation to complete, return remainder.
293+
*
294+
* \param a The dividend
295+
* \param b The divisor
296+
* \return Remainder result of the divide
297+
*/
108298
static inline int32_t hw_divider_s32_remainder_inlined(int32_t a, int32_t b) {
109-
return hw_divider_s32_remainder(a,b);
299+
return hw_divider_remainder_s32(a,b);
110300
}
111301

112302
typedef uint64_t hw_divider_state_t;
113303

114-
static inline void hw_divider_save_state(hw_divider_state_t *dest) {
304+
/*! \brief Save the calling cores hardware divider state
305+
* \ingroup hardware_divider
306+
*
307+
* Copy the current core's hardware divider state into the provided structure. This method
308+
* waits for the divider results to be stable, then copies them to memory.
309+
* They can be restored via hw_divider_restore_state()
310+
*
311+
* \param dest the location to store the divider state
312+
*/
313+
static inline void hw_divider_save_state(hw_divider_state_t *dest) {
115314
*dest = hw_divider_result_threadlocal;
116315
}
117316

118-
static inline void hw_divider_restore_state(hw_divider_state_t *src) {
317+
/*! \brief Load a saved hardware divider state into the current core's hardware divider
318+
* \ingroup hardware_divider
319+
*
320+
* Copy the passed hardware divider state into the hardware divider.
321+
*
322+
* \param src the location to load the divider state from
323+
*/
324+
static inline void hw_divider_restore_state(hw_divider_state_t *src) {
119325
hw_divider_result_threadlocal = *src;
120326
}
121327

328+
#ifdef __cplusplus
329+
}
330+
#endif
122331
#endif // _HARDWARE_DIVIDER_H

src/host/pico_divider/divider.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
// These functions save/restore divider state, so are safe to call from interrupts
1010
int32_t div_s32s32(int32_t a, int32_t b) {
11-
return hw_divider_s32_quotient(a, b);
11+
return hw_divider_quotient_s32(a, b);
1212
}
1313

1414
divmod_result_t divmod_s32s32(int32_t a, int32_t b) {

src/rp2_common/boot_stage2/boot2_at25sf128a.S

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,7 @@
8686
// Start of 2nd Stage Boot Code
8787
// ----------------------------------------------------------------------------
8888

89-
.syntax unified
90-
.cpu cortex-m0plus
91-
.thumb
89+
pico_default_asm_setup
9290

9391
.section .text
9492

@@ -97,10 +95,7 @@
9795
// Otherwise it will be a return address -- second stage being called as a
9896
// function by user code, after copying out of XIP region. r3 holds SSI base,
9997
// r0...2 used as temporaries. Other GPRs not used.
100-
.global _stage2_boot
101-
.type _stage2_boot,%function
102-
.thumb_func
103-
_stage2_boot:
98+
regular_func _stage2_boot
10499
push {lr}
105100

106101
// Set pad configuration:

0 commit comments

Comments
 (0)