mirror of
https://github.com/raspberrypi/pico-sdk.git
synced 2025-03-14 04:18:33 +00:00
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`
This commit is contained in:
parent
dca773f36b
commit
7f7232541a
@ -7,7 +7,11 @@
|
||||
#ifndef _HARDWARE_DIVIDER_H
|
||||
#define _HARDWARE_DIVIDER_H
|
||||
|
||||
#include "pico/types.h"
|
||||
#include "pico.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef uint64_t divmod_result_t;
|
||||
|
||||
@ -15,108 +19,313 @@ static inline int __sign_of(int32_t v) {
|
||||
return v > 0 ? 1 : (v < 0 ? -1 : 0);
|
||||
}
|
||||
|
||||
// divides unsigned values a by b... (a/b) returned in low 32 bits, (a%b) in high 32 bits... results undefined for b==0
|
||||
static inline uint64_t hw_divider_divmod_u32(uint32_t a, uint32_t b) {
|
||||
/*! \brief Do an unsigned HW divide and wait for result
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Divide \p a by \p b, wait for calculation to complete, return result as a pair of 32-bit quotient/remainder values.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
* \return Results of divide as a pair of 32-bit quotient/remainder values.
|
||||
*/
|
||||
static inline divmod_result_t hw_divider_divmod_u32(uint32_t a, uint32_t b) {
|
||||
if (!b) return (((uint64_t)a)<<32u) | (uint32_t)(-1); // todo check this
|
||||
return (((uint64_t)(a%b))<<32u) | (a/b);
|
||||
}
|
||||
|
||||
// divides signed values a by b... (a/b) returned in low 32 bits, (a%b) in high 32 bits... results undefined for b==0
|
||||
static inline uint64_t hw_divider_divmod_s32(int32_t a, int32_t b) {
|
||||
/*! \brief Do a signed HW divide and wait for result
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Divide \p a by \p b, wait for calculation to complete, return result as a pair of 32-bit quotient/remainder values.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
* \return Results of divide as a pair of 32-bit quotient/remainder values.
|
||||
*/
|
||||
static inline divmod_result_t hw_divider_divmod_s32(int32_t a, int32_t b) {
|
||||
if (!b) return (((uint64_t)a)<<32u) | (uint32_t)(-__sign_of(a));
|
||||
return (((uint64_t)(a%b))<<32u) | (uint32_t)(a/b);
|
||||
}
|
||||
|
||||
extern __thread divmod_result_t hw_divider_result_threadlocal;
|
||||
|
||||
/*! \brief Start a signed asynchronous divide
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* 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
|
||||
* (hw_divider_wait_ready()) prior to reading the results.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
*/
|
||||
static inline void hw_divider_divmod_s32_start(int32_t a, int32_t b) {
|
||||
hw_divider_result_threadlocal = hw_divider_divmod_s32(a, b);
|
||||
}
|
||||
|
||||
/*! \brief Start an unsigned asynchronous divide
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* 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
|
||||
* (hw_divider_wait_ready()) prior to reading the results.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
*/
|
||||
static inline void hw_divider_divmod_u32_start(uint32_t a, uint32_t b) {
|
||||
hw_divider_result_threadlocal = hw_divider_divmod_u32(a, b);
|
||||
}
|
||||
|
||||
static inline divmod_result_t hw_divider_result_wait() {
|
||||
/*! \brief Return result of last asynchronous HW divide
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* This function waits for the result to be ready by calling hw_divider_wait_ready().
|
||||
*
|
||||
* \return Current result. Most significant 32 bits are the remainder, lower 32 bits are the quotient.
|
||||
*/
|
||||
static inline divmod_result_t hw_divider_result_wait(void) {
|
||||
return hw_divider_result_threadlocal;
|
||||
}
|
||||
|
||||
static inline uint64_t hw_divider_result_nowait() {
|
||||
/*! \brief Return result of HW divide, nowait
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* \note This is UNSAFE in that the calculation may not have been completed.
|
||||
*
|
||||
* \return Current result. Most significant 32 bits are the remainder, lower 32 bits are the quotient.
|
||||
*/
|
||||
static inline divmod_result_t hw_divider_result_nowait(void) {
|
||||
return hw_divider_result_threadlocal;
|
||||
}
|
||||
|
||||
inline static uint32_t to_quotient_u32(unsigned long long int r) {
|
||||
/*! \brief Wait for a divide to complete
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Wait for a divide to complete
|
||||
*/
|
||||
static inline void hw_divider_wait_ready(void) {}
|
||||
|
||||
|
||||
/*! \brief Efficient extraction of unsigned quotient from 32p32 fixed point
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* \param r A pair of 32-bit quotient/remainder values.
|
||||
* \return Unsigned quotient
|
||||
*/
|
||||
inline static uint32_t to_quotient_u32(divmod_result_t r) {
|
||||
return (uint32_t) r;
|
||||
}
|
||||
|
||||
inline static int32_t to_quotient_s32(unsigned long long int r) {
|
||||
/*! \brief Efficient extraction of signed quotient from 32p32 fixed point
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* \param r A pair of 32-bit quotient/remainder values.
|
||||
* \return Unsigned quotient
|
||||
*/
|
||||
inline static int32_t to_quotient_s32(divmod_result_t r) {
|
||||
return (int32_t)(uint32_t)r;
|
||||
}
|
||||
|
||||
inline static uint32_t to_remainder_u32(unsigned long long int r) {
|
||||
/*! \brief Efficient extraction of unsigned remainder from 32p32 fixed point
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* \param r A pair of 32-bit quotient/remainder values.
|
||||
* \return Unsigned remainder
|
||||
*
|
||||
* \note On Arm this is just a 32 bit register move or a nop
|
||||
*/
|
||||
inline static uint32_t to_remainder_u32(divmod_result_t r) {
|
||||
return (uint32_t)(r >> 32u);
|
||||
}
|
||||
|
||||
inline static int32_t to_remainder_s32(unsigned long long int r) {
|
||||
/*! \brief Efficient extraction of signed remainder from 32p32 fixed point
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* \param r A pair of 32-bit quotient/remainder values.
|
||||
* \return Signed remainder
|
||||
*
|
||||
* \note On arm this is just a 32 bit register move or a nop
|
||||
*/
|
||||
inline static int32_t to_remainder_s32(divmod_result_t r) {
|
||||
return (int32_t)(r >> 32u);
|
||||
}
|
||||
|
||||
static inline uint32_t hw_divider_u32_quotient_wait() {
|
||||
return to_quotient_u32(hw_divider_result_wait());
|
||||
}
|
||||
|
||||
static inline uint32_t hw_divider_u32_remainder_wait() {
|
||||
return to_remainder_u32(hw_divider_result_wait());
|
||||
}
|
||||
|
||||
static inline int32_t hw_divider_s32_quotient_wait() {
|
||||
return to_quotient_s32(hw_divider_result_wait());
|
||||
}
|
||||
|
||||
static inline int32_t hw_divider_s32_remainder_wait() {
|
||||
return to_remainder_s32(hw_divider_result_wait());
|
||||
}
|
||||
static inline void hw_divider_pause(void) {}
|
||||
|
||||
/*! \brief Do an unsigned HW divide, wait for result, return quotient
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Divide \p a by \p b, wait for calculation to complete, return quotient.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
* \return Quotient results of the divide
|
||||
*/
|
||||
static inline uint32_t hw_divider_u32_quotient(uint32_t a, uint32_t b) {
|
||||
return b ? (a / b) : (uint32_t)(-1);
|
||||
}
|
||||
|
||||
/*! \brief Do an unsigned HW divide, wait for result, return remainder
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Divide \p a by \p b, wait for calculation to complete, return remainder.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
* \return Remainder results of the divide
|
||||
*/
|
||||
static inline uint32_t hw_divider_u32_remainder(uint32_t a, uint32_t b) {
|
||||
return b ? (a % b) : a;
|
||||
}
|
||||
|
||||
static inline int32_t hw_divider_s32_quotient(int32_t a, int32_t b) {
|
||||
return b ? (a / b) : -__sign_of(a);
|
||||
/*! \brief Do a signed HW divide, wait for result, return quotient
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Divide \p a by \p b, wait for calculation to complete, return quotient.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
* \return Quotient results of the divide
|
||||
*/
|
||||
static inline int32_t hw_divider_quotient_s32(int32_t a, int32_t b) {
|
||||
return to_quotient_s32(hw_divider_divmod_s32(a, b));
|
||||
}
|
||||
|
||||
static inline int32_t hw_divider_s32_remainder(int32_t a, int32_t b) {
|
||||
/*! \brief Do a signed HW divide, wait for result, return remainder
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Divide \p a by \p b, wait for calculation to complete, return remainder.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
* \return Remainder results of the divide
|
||||
*/
|
||||
static inline int32_t hw_divider_remainder_s32(int32_t a, int32_t b) {
|
||||
return b ? (a % b) : a;
|
||||
}
|
||||
|
||||
/*! \brief Return result of last asynchronous HW divide, unsigned quotient only
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* This function waits for the result to be ready by calling hw_divider_wait_ready().
|
||||
*
|
||||
* \return Current unsigned quotient result.
|
||||
*/
|
||||
static inline uint32_t hw_divider_u32_quotient_wait(void) {
|
||||
return to_quotient_u32(hw_divider_result_wait());
|
||||
}
|
||||
|
||||
/*! \brief Return result of last asynchronous HW divide, signed quotient only
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* This function waits for the result to be ready by calling hw_divider_wait_ready().
|
||||
*
|
||||
* \return Current signed quotient result.
|
||||
*/
|
||||
static inline int32_t hw_divider_s32_quotient_wait(void) {
|
||||
return to_remainder_u32(hw_divider_result_wait());
|
||||
}
|
||||
|
||||
/*! \brief Return result of last asynchronous HW divide, unsigned remainder only
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* This function waits for the result to be ready by calling hw_divider_wait_ready().
|
||||
*
|
||||
* \return Current unsigned remainder result.
|
||||
*/
|
||||
static inline uint32_t hw_divider_u32_remainder_wait(void) {
|
||||
return to_quotient_s32(hw_divider_result_wait());
|
||||
}
|
||||
|
||||
/*! \brief Return result of last asynchronous HW divide, signed remainder only
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* This function waits for the result to be ready by calling hw_divider_wait_ready().
|
||||
*
|
||||
* \return Current remainder results.
|
||||
*/
|
||||
static inline int32_t hw_divider_s32_remainder_wait(void) {
|
||||
return to_remainder_s32(hw_divider_result_wait());
|
||||
}
|
||||
|
||||
/*! \brief Do a hardware unsigned HW divide, wait for result, return quotient
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Divide \p a by \p b, wait for calculation to complete, return quotient.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
* \return Quotient result of the divide
|
||||
*/
|
||||
static inline uint32_t hw_divider_u32_quotient_inlined(uint32_t a, uint32_t b) {
|
||||
return hw_divider_u32_quotient(a,b);
|
||||
}
|
||||
|
||||
/*! \brief Do a hardware unsigned HW divide, wait for result, return remainder
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Divide \p a by \p b, wait for calculation to complete, return remainder.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
* \return Remainder result of the divide
|
||||
*/
|
||||
static inline uint32_t hw_divider_u32_remainder_inlined(uint32_t a, uint32_t b) {
|
||||
return hw_divider_u32_remainder(a,b);
|
||||
}
|
||||
|
||||
/*! \brief Do a hardware signed HW divide, wait for result, return quotient
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Divide \p a by \p b, wait for calculation to complete, return quotient.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
* \return Quotient result of the divide
|
||||
*/
|
||||
static inline int32_t hw_divider_s32_quotient_inlined(int32_t a, int32_t b) {
|
||||
return hw_divider_s32_quotient(a,b);
|
||||
return hw_divider_quotient_s32(a,b);
|
||||
}
|
||||
|
||||
/*! \brief Do a hardware signed HW divide, wait for result, return remainder
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Divide \p a by \p b, wait for calculation to complete, return remainder.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
* \return Remainder result of the divide
|
||||
*/
|
||||
static inline int32_t hw_divider_s32_remainder_inlined(int32_t a, int32_t b) {
|
||||
return hw_divider_s32_remainder(a,b);
|
||||
return hw_divider_remainder_s32(a,b);
|
||||
}
|
||||
|
||||
typedef uint64_t hw_divider_state_t;
|
||||
|
||||
static inline void hw_divider_save_state(hw_divider_state_t *dest) {
|
||||
/*! \brief Save the calling cores hardware divider state
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Copy the current core's hardware divider state into the provided structure. This method
|
||||
* waits for the divider results to be stable, then copies them to memory.
|
||||
* They can be restored via hw_divider_restore_state()
|
||||
*
|
||||
* \param dest the location to store the divider state
|
||||
*/
|
||||
static inline void hw_divider_save_state(hw_divider_state_t *dest) {
|
||||
*dest = hw_divider_result_threadlocal;
|
||||
}
|
||||
|
||||
static inline void hw_divider_restore_state(hw_divider_state_t *src) {
|
||||
/*! \brief Load a saved hardware divider state into the current core's hardware divider
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Copy the passed hardware divider state into the hardware divider.
|
||||
*
|
||||
* \param src the location to load the divider state from
|
||||
*/
|
||||
static inline void hw_divider_restore_state(hw_divider_state_t *src) {
|
||||
hw_divider_result_threadlocal = *src;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // _HARDWARE_DIVIDER_H
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
// These functions save/restore divider state, so are safe to call from interrupts
|
||||
int32_t div_s32s32(int32_t a, int32_t b) {
|
||||
return hw_divider_s32_quotient(a, b);
|
||||
return hw_divider_quotient_s32(a, b);
|
||||
}
|
||||
|
||||
divmod_result_t divmod_s32s32(int32_t a, int32_t b) {
|
||||
|
@ -86,9 +86,7 @@
|
||||
// Start of 2nd Stage Boot Code
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
pico_default_asm_setup
|
||||
|
||||
.section .text
|
||||
|
||||
@ -97,10 +95,7 @@
|
||||
// Otherwise it will be a return address -- second stage being called as a
|
||||
// function by user code, after copying out of XIP region. r3 holds SSI base,
|
||||
// r0...2 used as temporaries. Other GPRs not used.
|
||||
.global _stage2_boot
|
||||
.type _stage2_boot,%function
|
||||
.thumb_func
|
||||
_stage2_boot:
|
||||
regular_func _stage2_boot
|
||||
push {lr}
|
||||
|
||||
// Set pad configuration:
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include "hardware/regs/addressmap.h"
|
||||
#include "hardware/regs/ssi.h"
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Config section
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -53,25 +55,19 @@
|
||||
// Start of 2nd Stage Boot Code
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
|
||||
.section .text
|
||||
|
||||
.global _stage2_boot
|
||||
.type _stage2_boot,%function
|
||||
.thumb_func
|
||||
_stage2_boot:
|
||||
regular_func _stage2_boot
|
||||
push {lr}
|
||||
|
||||
ldr r3, =XIP_SSI_BASE // Use as base address where possible
|
||||
|
||||
// Disable SSI to allow further config
|
||||
mov r1, #0
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// Set baud rate
|
||||
mov r1, #PICO_FLASH_SPI_CLKDIV
|
||||
movs r1, #PICO_FLASH_SPI_CLKDIV
|
||||
str r1, [r3, #SSI_BAUDR_OFFSET]
|
||||
|
||||
ldr r1, =(CTRLR0_XIP)
|
||||
@ -82,11 +78,11 @@ _stage2_boot:
|
||||
str r1, [r0]
|
||||
|
||||
// NDF=0 (single 32b read)
|
||||
mov r1, #0x0
|
||||
movs r1, #0x0
|
||||
str r1, [r3, #SSI_CTRLR1_OFFSET]
|
||||
|
||||
// Re-enable SSI
|
||||
mov r1, #1
|
||||
movs r1, #1
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// We are now in XIP mode. Any bus accesses to the XIP address window will be
|
||||
|
@ -80,25 +80,20 @@
|
||||
// Start of 2nd Stage Boot Code
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
pico_default_asm_setup
|
||||
|
||||
.section .text
|
||||
|
||||
.global _stage2_boot
|
||||
.type _stage2_boot,%function
|
||||
.thumb_func
|
||||
_stage2_boot:
|
||||
.section text
|
||||
regular_func _stage2_boot
|
||||
push {lr}
|
||||
|
||||
ldr r3, =XIP_SSI_BASE // Use as base address where possible
|
||||
|
||||
// Disable SSI to allow further config
|
||||
mov r1, #0
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// Set baud rate
|
||||
mov r1, #PICO_FLASH_SPI_CLKDIV
|
||||
movs r1, #PICO_FLASH_SPI_CLKDIV
|
||||
str r1, [r3, #SSI_BAUDR_OFFSET]
|
||||
|
||||
// On QSPI parts we usually need a 01h SR-write command to enable QSPI mode
|
||||
@ -113,7 +108,7 @@ program_sregs:
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
// Enable SSI and select slave 0
|
||||
mov r1, #1
|
||||
movs r1, #1
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
// Check whether SR needs updating
|
||||
@ -124,7 +119,7 @@ program_sregs:
|
||||
beq skip_sreg_programming
|
||||
|
||||
// Send write enable command
|
||||
mov r1, #CMD_WRITE_ENABLE
|
||||
movs r1, #CMD_WRITE_ENABLE
|
||||
str r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Poll for completion and discard RX
|
||||
@ -132,9 +127,9 @@ program_sregs:
|
||||
ldr r1, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
// Send status write command followed by data bytes
|
||||
mov r1, #CMD_WRITE_STATUS
|
||||
movs r1, #CMD_WRITE_STATUS
|
||||
str r1, [r3, #SSI_DR0_OFFSET]
|
||||
mov r0, #0
|
||||
movs r0, #0
|
||||
str r2, [r3, #SSI_DR0_OFFSET]
|
||||
|
||||
bl wait_ssi_ready
|
||||
@ -145,7 +140,7 @@ program_sregs:
|
||||
1:
|
||||
ldr r0, =CMD_READ_STATUS
|
||||
bl read_flash_sreg
|
||||
mov r1, #1
|
||||
movs r1, #1
|
||||
tst r0, r1
|
||||
bne 1b
|
||||
|
||||
@ -157,7 +152,7 @@ skip_sreg_programming:
|
||||
// bl wait_ssi_ready
|
||||
|
||||
// Disable SSI again so that it can be reconfigured
|
||||
mov r1, #0
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
#endif
|
||||
|
||||
@ -182,7 +177,7 @@ dummy_read:
|
||||
ldr r1, =(CTRLR0_ENTER_XIP)
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
mov r1, #0x0 // NDF=0 (single 32b read)
|
||||
movs r1, #0x0 // NDF=0 (single 32b read)
|
||||
str r1, [r3, #SSI_CTRLR1_OFFSET]
|
||||
|
||||
#define SPI_CTRLR0_ENTER_XIP \
|
||||
@ -197,12 +192,12 @@ dummy_read:
|
||||
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET) // SPI_CTRL0 Register
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, #1 // Re-enable SSI
|
||||
movs r1, #1 // Re-enable SSI
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
mov r1, #CMD_READ
|
||||
movs r1, #CMD_READ
|
||||
str r1, [r3, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
|
||||
mov r1, #MODE_CONTINUOUS_READ // 32-bit: 24 address bits (we don't care, so 0) and M[7:4]=1010
|
||||
movs r1, #MODE_CONTINUOUS_READ // 32-bit: 24 address bits (we don't care, so 0) and M[7:4]=1010
|
||||
str r1, [r3, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
|
||||
|
||||
// Poll for completion
|
||||
@ -218,7 +213,7 @@ dummy_read:
|
||||
// to APM mode and generate a 28-bit address phase with the extra nibble set
|
||||
// to 4'b0000).
|
||||
|
||||
mov r1, #0
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
|
||||
|
||||
// Note that the INST_L field is used to select what XIP data gets pushed into
|
||||
@ -240,7 +235,7 @@ configure_ssi:
|
||||
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET)
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, #1
|
||||
movs r1, #1
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET] // Re-enable SSI
|
||||
|
||||
// We are now in XIP mode, with all transactions using Dual I/O and only
|
||||
|
@ -4,6 +4,8 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico/asm_helper.S"
|
||||
|
||||
// Stub second stage which calls into USB bootcode, with parameters.
|
||||
// USB boot takes two parameters:
|
||||
// - A GPIO mask for activity LED -- if mask is 0, don't touch GPIOs at all
|
||||
@ -19,17 +21,12 @@
|
||||
#define ACTIVITY_LED 0
|
||||
#define BOOT_MODE USB_BOOT_MSD_AND_PICOBOOT
|
||||
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
pico_default_asm_setup
|
||||
|
||||
.section .text
|
||||
|
||||
.global _stage2_boot
|
||||
.type _stage2_boot,%function
|
||||
|
||||
.thumb_func
|
||||
_stage2_boot:
|
||||
mov r7, #0x14 // Pointer to _well_known pointer table in ROM
|
||||
regular_func _stage2_boot
|
||||
movs r7, #0x14 // Pointer to _well_known pointer table in ROM
|
||||
ldrh r0, [r7, #0] // Offset 0 is 16 bit pointer to function table
|
||||
ldrh r7, [r7, #4] // Offset 4 is 16 bit pointer to table lookup routine
|
||||
ldr r1, =('U' | ('B' << 8)) // Symbol for USB Boot
|
||||
@ -39,7 +36,7 @@ _stage2_boot:
|
||||
|
||||
mov r7, r0
|
||||
ldr r0, =(1u << ACTIVITY_LED) // Mask of which GPIO (or GPIOs) to use
|
||||
mov r1, #BOOT_MODE
|
||||
movs r1, #BOOT_MODE
|
||||
blx r7
|
||||
|
||||
dead:
|
||||
|
@ -86,9 +86,7 @@
|
||||
// Start of 2nd Stage Boot Code
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
pico_default_asm_setup
|
||||
|
||||
.section .text
|
||||
|
||||
@ -97,10 +95,7 @@
|
||||
// Otherwise it will be a return address -- second stage being called as a
|
||||
// function by user code, after copying out of XIP region. r3 holds SSI base,
|
||||
// r0...2 used as temporaries. Other GPRs not used.
|
||||
.global _stage2_boot
|
||||
.type _stage2_boot,%function
|
||||
.thumb_func
|
||||
_stage2_boot:
|
||||
regular_func _stage2_boot
|
||||
push {lr}
|
||||
|
||||
// Set pad configuration:
|
||||
|
@ -40,6 +40,8 @@
|
||||
#define PICO_FLASH_SPI_CLKDIV 4
|
||||
#endif
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// The "System Control Block" is a set of internal Cortex-M0+ control registers
|
||||
// that are memory mapped and accessed like any other H/W register. They have
|
||||
@ -69,31 +71,25 @@
|
||||
// Start of 2nd Stage Boot Code
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
.cpu cortex-m0
|
||||
.thumb
|
||||
|
||||
.org 0
|
||||
|
||||
.section .text
|
||||
|
||||
// This code will get copied to 0x20000000 and then executed
|
||||
|
||||
.global _stage2_boot
|
||||
.type _stage2_boot,%function
|
||||
.thumb_func
|
||||
_stage2_boot:
|
||||
regular_func _stage2_boot
|
||||
push {lr}
|
||||
ldr r3, =XIP_SSI_BASE // Use as base address where possible
|
||||
|
||||
// We are primarily interested in setting up Flash for DSPI XIP w/ continuous read
|
||||
|
||||
mov r1, #0
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI to allow further config
|
||||
|
||||
// The Boot ROM sets a very conservative SPI clock frequency to be sure it can
|
||||
// read the initial 256 bytes from any device. Here we can be more aggressive.
|
||||
|
||||
mov r1, #PICO_FLASH_SPI_CLKDIV
|
||||
movs r1, #PICO_FLASH_SPI_CLKDIV
|
||||
str r1, [r3, #SSI_BAUDR_OFFSET] // Set SSI Clock
|
||||
|
||||
// First we need to send the initial command to get us in to Fast Read Dual I/O
|
||||
@ -116,7 +112,7 @@ _stage2_boot:
|
||||
ldr r1, =(CTRLR0_ENTER_XIP)
|
||||
str r1, [r3, #SSI_CTRLR0_OFFSET]
|
||||
|
||||
mov r1, #0x0 // NDF=0 (single 32b read)
|
||||
movs r1, #0x0 // NDF=0 (single 32b read)
|
||||
str r1, [r3, #SSI_CTRLR1_OFFSET]
|
||||
|
||||
#define SPI_CTRLR0_ENTER_XIP \
|
||||
@ -131,18 +127,18 @@ _stage2_boot:
|
||||
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET) // SPI_CTRL0 Register
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, #1 // Re-enable SSI
|
||||
movs r1, #1 // Re-enable SSI
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET]
|
||||
|
||||
mov r1, #W25X10CL_CMD_READ_DATA_FAST_DUAL_IO // 8b command = 0xBB
|
||||
movs r1, #W25X10CL_CMD_READ_DATA_FAST_DUAL_IO // 8b command = 0xBB
|
||||
str r1, [r3, #SSI_DR0_OFFSET] // Push SPI command into TX FIFO
|
||||
mov r1, #0x0000002 // 28-bit Address for dummy read = 0x000000 + 0x2 Mode bits to set M[5:4]=10
|
||||
movs r1, #0x0000002 // 28-bit Address for dummy read = 0x000000 + 0x2 Mode bits to set M[5:4]=10
|
||||
str r1, [r3, #SSI_DR0_OFFSET] // Push Address into TX FIFO - this will trigger the transaction
|
||||
|
||||
// Now we wait for the read transaction to complete by monitoring the SSI
|
||||
// status register and checking for the "RX FIFO Not Empty" flag to assert.
|
||||
|
||||
mov r1, #SSI_SR_RFNE_BITS
|
||||
movs r1, #SSI_SR_RFNE_BITS
|
||||
00:
|
||||
ldr r0, [r3, #SSI_SR_OFFSET] // Read status register
|
||||
tst r0, r1 // RFNE status flag set?
|
||||
@ -158,7 +154,7 @@ _stage2_boot:
|
||||
// to APM mode and generate a 28-bit address phase with the extra nibble set
|
||||
// to 4'b0000).
|
||||
|
||||
mov r1, #0
|
||||
movs r1, #0
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
|
||||
|
||||
// Note that the INST_L field is used to select what XIP data gets pushed into
|
||||
@ -180,7 +176,7 @@ _stage2_boot:
|
||||
ldr r0, =(XIP_SSI_BASE + SSI_SPI_CTRLR0_OFFSET)
|
||||
str r1, [r0]
|
||||
|
||||
mov r1, #1
|
||||
movs r1, #1
|
||||
str r1, [r3, #SSI_SSIENR_OFFSET] // Re-enable SSI
|
||||
|
||||
// We are now in XIP mode, with all transactions using Dual I/O and only
|
||||
|
@ -48,7 +48,7 @@ bool clock_configure(enum clock_index clk_index, uint32_t src, uint32_t auxsrc,
|
||||
return false;
|
||||
|
||||
// Div register is 24.8 int.frac divider so multiply by 2^8 (left shift by 8)
|
||||
div = (uint32_t) (((uint64_t) src_freq << 8) / freq);
|
||||
div = (uint32_t) (((uint64_t) src_freq << CLOCKS_CLK_GPOUT0_DIV_INT_LSB) / freq);
|
||||
|
||||
clock_hw_t *clock = &clocks_hw->clk[clk_index];
|
||||
|
||||
@ -76,14 +76,9 @@ bool clock_configure(enum clock_index clk_index, uint32_t src, uint32_t auxsrc,
|
||||
if (configured_freq[clk_index] > 0) {
|
||||
// Delay for 3 cycles of the target clock, for ENABLE propagation.
|
||||
// Note XOSC_COUNT is not helpful here because XOSC is not
|
||||
// necessarily running, nor is timer... so, 3 cycles per loop:
|
||||
// necessarily running, nor is timer...:
|
||||
uint delay_cyc = configured_freq[clk_sys] / configured_freq[clk_index] + 1;
|
||||
unified_asm (
|
||||
"1: \n\t"
|
||||
"subs %0, #1 \n\t"
|
||||
"bne 1b"
|
||||
: "+r" (delay_cyc)
|
||||
);
|
||||
busy_wait_at_least_cycles(delay_cyc * 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,7 @@
|
||||
#include "hardware/regs/addressmap.h"
|
||||
#include "hardware/regs/sio.h"
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
pico_default_asm_setup
|
||||
|
||||
// tag::hw_div_s32[]
|
||||
regular_func_with_section hw_divider_divmod_s32
|
||||
|
@ -85,7 +85,7 @@ static inline void hw_divider_wait_ready(void) {
|
||||
// we use one less register and instruction than gcc which uses a TST instruction
|
||||
|
||||
uint32_t tmp; // allow compiler to pick scratch register
|
||||
unified_asm (
|
||||
pico_default_asm (
|
||||
"hw_divider_result_loop_%=:"
|
||||
"ldr %0, [%1, %2]\n\t"
|
||||
"lsrs %0, %0, #1\n\t"
|
||||
@ -177,29 +177,29 @@ static inline int32_t hw_divider_s32_remainder_wait(void) {
|
||||
/*! \brief Do a signed HW divide and wait for result
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Divide \p a by \p b, wait for calculation to complete, return result as a fixed point 32p32 value.
|
||||
* Divide \p a by \p b, wait for calculation to complete, return result as a pair of 32-bit quotient/remainder values.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
* \return Results of divide as a 32p32 fixed point value.
|
||||
* \return Results of divide as a pair of 32-bit quotient/remainder values.
|
||||
*/
|
||||
divmod_result_t hw_divider_divmod_s32(int32_t a, int32_t b);
|
||||
|
||||
/*! \brief Do an unsigned HW divide and wait for result
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* Divide \p a by \p b, wait for calculation to complete, return result as a fixed point 32p32 value.
|
||||
* Divide \p a by \p b, wait for calculation to complete, return result as a pair of 32-bit quotient/remainder values.
|
||||
*
|
||||
* \param a The dividend
|
||||
* \param b The divisor
|
||||
* \return Results of divide as a 32p32 fixed point value.
|
||||
* \return Results of divide as a pair of 32-bit quotient/remainder values.
|
||||
*/
|
||||
divmod_result_t hw_divider_divmod_u32(uint32_t a, uint32_t b);
|
||||
|
||||
/*! \brief Efficient extraction of unsigned quotient from 32p32 fixed point
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* \param r 32p32 fixed point value.
|
||||
* \param r A pair of 32-bit quotient/remainder values.
|
||||
* \return Unsigned quotient
|
||||
*/
|
||||
inline static uint32_t to_quotient_u32(divmod_result_t r) {
|
||||
@ -209,7 +209,7 @@ inline static uint32_t to_quotient_u32(divmod_result_t r) {
|
||||
/*! \brief Efficient extraction of signed quotient from 32p32 fixed point
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* \param r 32p32 fixed point value.
|
||||
* \param r A pair of 32-bit quotient/remainder values.
|
||||
* \return Unsigned quotient
|
||||
*/
|
||||
inline static int32_t to_quotient_s32(divmod_result_t r) {
|
||||
@ -219,7 +219,7 @@ inline static int32_t to_quotient_s32(divmod_result_t r) {
|
||||
/*! \brief Efficient extraction of unsigned remainder from 32p32 fixed point
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* \param r 32p32 fixed point value.
|
||||
* \param r A pair of 32-bit quotient/remainder values.
|
||||
* \return Unsigned remainder
|
||||
*
|
||||
* \note On Arm this is just a 32 bit register move or a nop
|
||||
@ -231,7 +231,7 @@ inline static uint32_t to_remainder_u32(divmod_result_t r) {
|
||||
/*! \brief Efficient extraction of signed remainder from 32p32 fixed point
|
||||
* \ingroup hardware_divider
|
||||
*
|
||||
* \param r 32p32 fixed point value.
|
||||
* \param r A pair of 32-bit quotient/remainder values.
|
||||
* \return Signed remainder
|
||||
*
|
||||
* \note On arm this is just a 32 bit register move or a nop
|
||||
@ -296,7 +296,7 @@ static inline int32_t hw_divider_remainder_s32(int32_t a, int32_t b) {
|
||||
* \ingroup hardware_divider
|
||||
*/
|
||||
static inline void hw_divider_pause(void) {
|
||||
unified_asm (
|
||||
pico_default_asm (
|
||||
"b _1_%=\n"
|
||||
"_1_%=:\n"
|
||||
"b _2_%=\n"
|
||||
|
@ -4,6 +4,7 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
// Note this file is always included by another, so does not do pico_default_asm_setup
|
||||
#include "hardware/regs/addressmap.h"
|
||||
#include "hardware/regs/sio.h"
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "hardware/exception.h"
|
||||
#include "hardware/regs/m0plus.h"
|
||||
#include "hardware/platform_defs.h"
|
||||
#include "hardware/structs/scb.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "pico/assert.h"
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "pico.h"
|
||||
#include "hardware/address_mapped.h"
|
||||
#include "hardware/regs/m0plus.h"
|
||||
|
||||
/** \file exception.h
|
||||
* \defgroup hardware_exception hardware_exception
|
||||
|
@ -244,8 +244,8 @@ void gpio_set_input_enabled(uint gpio, bool enabled) {
|
||||
}
|
||||
|
||||
void gpio_init(uint gpio) {
|
||||
sio_hw->gpio_oe_clr = 1ul << gpio;
|
||||
sio_hw->gpio_clr = 1ul << gpio;
|
||||
gpio_set_dir(gpio, GPIO_IN);
|
||||
gpio_put(gpio, 0);
|
||||
gpio_set_function(gpio, GPIO_FUNC_SIO);
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,7 @@ static inline int8_t slot_diff(struct irq_handler_chain_slot *to, struct irq_han
|
||||
int32_t result = 0xaaaa;
|
||||
// return (to - from);
|
||||
// note this implementation has limited range, but is fine for plenty more than -128->127 result
|
||||
unified_asm (
|
||||
pico_default_asm (
|
||||
"subs %1, %2\n"
|
||||
"adcs %1, %1\n" // * 2 (and + 1 if negative for rounding)
|
||||
"muls %0, %1\n"
|
||||
|
@ -6,11 +6,11 @@
|
||||
|
||||
#include "pico.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "pico/asm_helper.S"
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
#if !PICO_DISABLE_SHARED_IRQ_HANDLERS
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
.data
|
||||
.align 2
|
||||
|
@ -116,7 +116,7 @@ typedef volatile uint32_t spin_lock_t;
|
||||
*/
|
||||
#if !__has_builtin(__sev)
|
||||
__force_inline static void __sev(void) {
|
||||
unified_asm ("sev");
|
||||
pico_default_asm ("sev");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -128,7 +128,7 @@ __force_inline static void __sev(void) {
|
||||
*/
|
||||
#if !__has_builtin(__wfe)
|
||||
__force_inline static void __wfe(void) {
|
||||
unified_asm ("wfe");
|
||||
pico_default_asm ("wfe");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -139,7 +139,7 @@ __force_inline static void __wfe(void) {
|
||||
*/
|
||||
#if !__has_builtin(__wfi)
|
||||
__force_inline static void __wfi(void) {
|
||||
unified_asm ("wfi");
|
||||
pico_default_asm ("wfi");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -150,7 +150,7 @@ __force_inline static void __wfi(void) {
|
||||
* instruction will be observed before any explicit access after the instruction.
|
||||
*/
|
||||
__force_inline static void __dmb(void) {
|
||||
unified_asm ("dmb" : : : "memory");
|
||||
pico_default_asm ("dmb" : : : "memory");
|
||||
}
|
||||
|
||||
/*! \brief Insert a DSB instruction in to the code path.
|
||||
@ -161,7 +161,7 @@ __force_inline static void __dmb(void) {
|
||||
* accesses before this instruction complete.
|
||||
*/
|
||||
__force_inline static void __dsb(void) {
|
||||
unified_asm ("dsb" : : : "memory");
|
||||
pico_default_asm ("dsb" : : : "memory");
|
||||
}
|
||||
|
||||
/*! \brief Insert a ISB instruction in to the code path.
|
||||
@ -172,7 +172,7 @@ __force_inline static void __dsb(void) {
|
||||
* the ISB instruction has been completed.
|
||||
*/
|
||||
__force_inline static void __isb(void) {
|
||||
unified_asm ("isb");
|
||||
pico_default_asm ("isb");
|
||||
}
|
||||
|
||||
/*! \brief Acquire a memory fence
|
||||
@ -213,8 +213,8 @@ __force_inline static void __mem_fence_release(void) {
|
||||
*/
|
||||
__force_inline static uint32_t save_and_disable_interrupts(void) {
|
||||
uint32_t status;
|
||||
unified_asm ("mrs %0, PRIMASK" : "=r" (status)::);
|
||||
unified_asm ("cpsid i");
|
||||
pico_default_asm ("mrs %0, PRIMASK" : "=r" (status)::);
|
||||
pico_default_asm ("cpsid i");
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -224,7 +224,7 @@ __force_inline static uint32_t save_and_disable_interrupts(void) {
|
||||
* \param status Previous interrupt status from save_and_disable_interrupts()
|
||||
*/
|
||||
__force_inline static void restore_interrupts(uint32_t status) {
|
||||
unified_asm ("msr PRIMASK,%0"::"r" (status) : );
|
||||
pico_default_asm ("msr PRIMASK,%0"::"r" (status) : );
|
||||
}
|
||||
|
||||
/*! \brief Get HW Spinlock instance from number
|
||||
|
@ -4,14 +4,10 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
#include "pico/asm_helper.S"
|
||||
#include "pico/bootrom.h"
|
||||
|
||||
__pre_init __aeabi_bits_init, 00010
|
||||
pico_default_asm_setup
|
||||
|
||||
.macro bits_section name
|
||||
#if PICO_BITS_IN_RAM
|
||||
@ -21,6 +17,8 @@ __pre_init __aeabi_bits_init, 00010
|
||||
#endif
|
||||
.endm
|
||||
|
||||
__pre_init __aeabi_bits_init, 00010
|
||||
|
||||
.section .data.aeabi_bits_funcs
|
||||
.global aeabi_bits_funcs, aeabi_bits_funcs_end
|
||||
.equ BITS_FUNC_COUNT, 4
|
||||
|
@ -63,7 +63,7 @@ static uint32_t counter = 0;
|
||||
|
||||
//#define SWAP32(A) ((((A) & 0xff000000U) >> 8) | (((A) & 0xff0000U) << 8) | (((A) & 0xff00U) >> 8) | (((A) & 0xffU) << 8))
|
||||
__force_inline static uint32_t __swap16x2(uint32_t a) {
|
||||
unified_asm ("rev16 %0, %0" : "+l" (a) : : );
|
||||
pico_default_asm ("rev16 %0, %0" : "+l" (a) : : );
|
||||
return a;
|
||||
}
|
||||
#define SWAP32(a) __swap16x2(a)
|
||||
|
@ -4,17 +4,12 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "pico/asm_helper.S"
|
||||
#include "hardware/regs/addressmap.h"
|
||||
#include "hardware/divider_helper.S"
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
// PICO_CONFIG: PICO_DIVIDER_DISABLE_INTERRUPTS, Disable interrupts around division such that divider state need not be saved/restored in exception handlers, default=0, group=pico_divider
|
||||
|
||||
#include "pico/asm_helper.S"
|
||||
|
||||
// PICO_CONFIG: PICO_DIVIDER_CALL_IDIV0, Whether 32 bit division by zero should call __aeabi_idiv0, default=1, group=pico_divider
|
||||
#ifndef PICO_DIVIDER_CALL_IDIV0
|
||||
#define PICO_DIVIDER_CALL_IDIV0 1
|
||||
@ -25,6 +20,8 @@
|
||||
#define PICO_DIVIDER_CALL_LDIV0 1
|
||||
#endif
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
// PICO_CONFIG: PICO_DIVIDER_IN_RAM, Whether divider functions should be placed in RAM, default=0, group=pico_divider
|
||||
.macro div_section name
|
||||
#if PICO_DIVIDER_IN_RAM
|
||||
@ -37,11 +34,11 @@
|
||||
@ wait 8-n cycles for the hardware divider
|
||||
.macro wait_div n
|
||||
.rept (8-\n) / 2
|
||||
b 9f
|
||||
b 9f
|
||||
9:
|
||||
.endr
|
||||
.if (8-\n) % 2
|
||||
nop
|
||||
nop
|
||||
.endif
|
||||
.endm
|
||||
|
||||
|
@ -8,11 +8,9 @@
|
||||
#include "pico/bootrom/sf_table.h"
|
||||
#include "hardware/divider_helper.S"
|
||||
|
||||
__pre_init __aeabi_double_init, 00020
|
||||
pico_default_asm_setup
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
__pre_init __aeabi_double_init, 00020
|
||||
|
||||
.macro double_section name
|
||||
#if PICO_DOUBLE_IN_RAM
|
||||
|
@ -7,9 +7,7 @@
|
||||
#include "pico/asm_helper.S"
|
||||
#include "pico/bootrom/sf_table.h"
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
pico_default_asm_setup
|
||||
|
||||
wrapper_func __aeabi_dadd
|
||||
wrapper_func __aeabi_ddiv
|
||||
|
@ -17,9 +17,7 @@
|
||||
|
||||
#include "pico/asm_helper.S"
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
pico_default_asm_setup
|
||||
|
||||
.macro double_section name
|
||||
// todo separate flag for shims?
|
||||
|
@ -10,9 +10,7 @@
|
||||
|
||||
__pre_init __aeabi_float_init, 00020
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
pico_default_asm_setup
|
||||
|
||||
.macro float_section name
|
||||
#if PICO_FLOAT_IN_RAM
|
||||
|
@ -7,9 +7,7 @@
|
||||
#include "pico/asm_helper.S"
|
||||
#include "pico/bootrom/sf_table.h"
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
pico_default_asm_setup
|
||||
|
||||
wrapper_func __aeabi_fadd
|
||||
wrapper_func __aeabi_fdiv
|
||||
|
@ -7,14 +7,13 @@
|
||||
#include "pico/asm_helper.S"
|
||||
|
||||
#if PICO_FLOAT_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
#ifndef PICO_FLOAT_IN_RAM
|
||||
#define PICO_FLOAT_IN_RAM 0
|
||||
#endif
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
.macro float_section name
|
||||
// todo separate flag for shims?
|
||||
#if PICO_FLOAT_IN_RAM
|
||||
|
@ -4,12 +4,10 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
#include "pico/asm_helper.S"
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
.macro int64_section name
|
||||
#if PICO_INT64_OPS_IN_RAM
|
||||
.section RAM_SECTION_NAME(\name), "ax"
|
||||
|
@ -4,13 +4,11 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
|
||||
#include "pico/asm_helper.S"
|
||||
#include "pico/bootrom.h"
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
__pre_init __aeabi_mem_init, 00001
|
||||
|
||||
.macro mem_section name
|
||||
|
@ -75,7 +75,7 @@ bool multicore_fifo_pop_timeout_us(uint64_t timeout_us, uint32_t *out) {
|
||||
static uint32_t __attribute__((section(".stack1"))) core1_stack[PICO_CORE1_STACK_SIZE / sizeof(uint32_t)];
|
||||
|
||||
static void __attribute__ ((naked)) core1_trampoline(void) {
|
||||
unified_asm ("pop {r0, r1, pc}");
|
||||
pico_default_asm ("pop {r0, r1, pc}");
|
||||
}
|
||||
|
||||
int core1_wrapper(int (*entry)(void), void *stack_base) {
|
||||
|
@ -6,6 +6,15 @@
|
||||
|
||||
#include "pico.h"
|
||||
|
||||
# note we don't do this by default in this file for backwards comaptibility with user code
|
||||
# that may include this file, but not use unified syntax. Note that this macro does equivalent
|
||||
# setup to the pico_default_asm macro for inline assembly in C code.
|
||||
.macro pico_default_asm_setup
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
.endm
|
||||
|
||||
// do not put align in here as it is used mid function sometimes
|
||||
.macro regular_func x
|
||||
.global \x
|
||||
|
@ -335,13 +335,13 @@ extern "C" {
|
||||
#define MIN(a, b) ((b)>(a)?(a):(b))
|
||||
#endif
|
||||
|
||||
#define unified_asm(...) __asm volatile (".syntax unified\n" __VA_ARGS__)
|
||||
#define pico_default_asm(...) __asm volatile (".syntax unified\n" __VA_ARGS__)
|
||||
|
||||
/*! \brief Execute a breakpoint instruction
|
||||
* \ingroup pico_platform
|
||||
*/
|
||||
static inline void __breakpoint(void) {
|
||||
unified_asm ("bkpt #0");
|
||||
pico_default_asm ("bkpt #0");
|
||||
}
|
||||
|
||||
/*! \brief Ensure that the compiler does not move memory access across this method call
|
||||
@ -357,7 +357,7 @@ static inline void __breakpoint(void) {
|
||||
* might - even above the memory store!)
|
||||
*/
|
||||
__force_inline static void __compiler_memory_barrier(void) {
|
||||
unified_asm ("" : : : "memory");
|
||||
pico_default_asm ("" : : : "memory");
|
||||
}
|
||||
|
||||
/*! \brief Macro for converting memory addresses to 32 bit addresses suitable for DMA
|
||||
@ -443,7 +443,7 @@ static __force_inline void tight_loop_contents(void) {}
|
||||
* \return a * b
|
||||
*/
|
||||
__force_inline static int32_t __mul_instruction(int32_t a, int32_t b) {
|
||||
unified_asm ("muls %0, %1" : "+l" (a) : "l" (b) : );
|
||||
pico_default_asm ("muls %0, %1" : "+l" (a) : "l" (b) : );
|
||||
return a;
|
||||
}
|
||||
|
||||
@ -477,19 +477,15 @@ __force_inline static int32_t __mul_instruction(int32_t a, int32_t b) {
|
||||
*
|
||||
* \return the exception number if the CPU is handling an exception, or 0 otherwise
|
||||
*/
|
||||
static inline uint __get_current_exception(void) {
|
||||
static __force_inline uint __get_current_exception(void) {
|
||||
uint exception;
|
||||
unified_asm ("mrs %0, ipsr" : "=l" (exception));
|
||||
pico_default_asm ("mrs %0, ipsr" : "=l" (exception));
|
||||
return exception;
|
||||
}
|
||||
|
||||
#define WRAPPER_FUNC(x) __wrap_ ## x
|
||||
#define REAL_FUNC(x) __real_ ## x
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! \brief Helper method to busy-wait for at least the given number of cycles
|
||||
* \ingroup pico_platform
|
||||
*
|
||||
@ -505,7 +501,7 @@ static inline uint __get_current_exception(void) {
|
||||
* \param minimum_cycles the minimum number of system clock cycles to delay for
|
||||
*/
|
||||
static inline void busy_wait_at_least_cycles(uint32_t minimum_cycles) {
|
||||
unified_asm (
|
||||
pico_default_asm (
|
||||
"1: subs %0, #3\n"
|
||||
"bcs 1b\n"
|
||||
: "+r" (minimum_cycles) : : "memory"
|
||||
@ -521,6 +517,10 @@ __force_inline static uint get_core_num(void) {
|
||||
return (*(uint32_t *) (SIO_BASE + SIO_CPUID_OFFSET));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // __ASSEMBLER__
|
||||
|
||||
#define WRAPPER_FUNC_NAME(x) __wrap_##x
|
||||
|
@ -7,9 +7,7 @@
|
||||
#include "pico/asm_helper.S"
|
||||
#include "pico/bootrom/sf_table.h"
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
pico_default_asm_setup
|
||||
|
||||
wrapper_func sprintf
|
||||
wrapper_func snprintf
|
||||
|
@ -151,7 +151,7 @@ void runtime_init(void) {
|
||||
#ifndef NDEBUG
|
||||
if (__get_current_exception()) {
|
||||
// crap; started in exception handler
|
||||
unified_asm ("bkpt #0");
|
||||
__breakpoint();
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -286,7 +286,7 @@ extern void __attribute__((noreturn)) __printflike(1, 0) PICO_PANIC_FUNCTION(__u
|
||||
// Use a forwarding method here as it is a little simpler than renaming the symbol as it is used from assembler
|
||||
void __attribute__((naked, noreturn)) __printflike(1, 0) panic(__unused const char *fmt, ...) {
|
||||
// if you get an undefined reference here, you didn't define your PICO_PANIC_FUNCTION!
|
||||
unified_asm (
|
||||
pico_default_asm (
|
||||
"push {lr}\n"
|
||||
#if !PICO_PANIC_FUNCTION_EMPTY
|
||||
"bl " __XSTRING(PICO_PANIC_FUNCTION) "\n"
|
||||
|
@ -5,10 +5,11 @@
|
||||
*/
|
||||
|
||||
#include "pico.h"
|
||||
#include "pico/asm_helper.S"
|
||||
|
||||
#include "hardware/regs/m0plus.h"
|
||||
#include "hardware/regs/addressmap.h"
|
||||
#include "hardware/regs/sio.h"
|
||||
#include "pico/asm_helper.S"
|
||||
#include "pico/binary_info/defs.h"
|
||||
|
||||
#ifdef NDEBUG
|
||||
@ -17,9 +18,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
pico_default_asm_setup
|
||||
|
||||
.section .vectors, "ax"
|
||||
.align 2
|
||||
|
@ -25,7 +25,7 @@ static void stdio_semihosting_out_chars(const char *buf, int length) {
|
||||
args.buf = buf;
|
||||
args.len = length;
|
||||
|
||||
unified_asm (
|
||||
pico_default_asm (
|
||||
// r1 must contain a pointer to the arguments
|
||||
"movs r1, %[args]\n"
|
||||
// semihosting call number 0x05 = SYS_WRITE
|
||||
|
@ -1,9 +1,9 @@
|
||||
# PICO_CMAKE_CONFIG: PICO_STDIO_UART, OPTION: Globally enable stdio UART, default=1, group=pico_stdlib
|
||||
option(PICO_STDIO_UART "Globablly enable stdio UART" 1)
|
||||
option(PICO_STDIO_UART "Globally enable stdio UART" 1)
|
||||
# PICO_CMAKE_CONFIG: PICO_STDIO_USB, OPTION: Globally enable stdio USB, default=0, group=pico_stdlib
|
||||
option(PICO_STDIO_USB "Globablly enable stdio USB" 0)
|
||||
option(PICO_STDIO_USB "Globally enable stdio USB" 0)
|
||||
# PICO_CMAKE_CONFIG: PICO_STDIO_SEMIHOSTING, OPTION: Globally enable stdio semihosting, default=0, group=pico_stdlib
|
||||
option(PICO_STDIO_SEMIHOSTING "Globablly enable stdio semihosting" 0)
|
||||
option(PICO_STDIO_SEMIHOSTING "Globally enable stdio semi-hosting" 0)
|
||||
|
||||
if (NOT TARGET pico_stdlib)
|
||||
pico_add_impl_library(pico_stdlib)
|
||||
|
@ -138,6 +138,6 @@ int main(void) {
|
||||
hard_assert(recursive_mutex_try_enter(&recursive_mutex, NULL));
|
||||
hard_assert(recursive_mutex_try_enter(&recursive_mutex, NULL));
|
||||
// this should compile as we are Cortex M0+
|
||||
unified_asm ("SVC #3");
|
||||
pico_default_asm ("SVC #3");
|
||||
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ void test_random() {
|
||||
#endif
|
||||
|
||||
uint32_t __attribute__((naked)) time_32(uint32_t a, uint32_t b, uint32_t (*func)(uint32_t a, uint32_t b)) {
|
||||
unified_asm (
|
||||
pico_default_asm (
|
||||
"push {r4, r5, lr}\n"
|
||||
"ldr r4, =0xe000e018\n"
|
||||
"ldr r5, [r4]\n"
|
||||
@ -207,7 +207,7 @@ uint32_t __attribute__((naked)) time_32(uint32_t a, uint32_t b, uint32_t (*func)
|
||||
}
|
||||
|
||||
uint32_t __attribute__((naked)) time_64(uint64_t a, uint64_t b, uint64_t (*func64)(uint64_t a, uint64_t b)) {
|
||||
unified_asm (
|
||||
pico_default_asm (
|
||||
"push {r4-r6, lr}\n"
|
||||
"ldr r6, [sp, #16]\n"
|
||||
"ldr r4, =0xe000e018\n"
|
||||
|
@ -12,9 +12,9 @@
|
||||
//
|
||||
//===-
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m0plus
|
||||
.thumb
|
||||
#include "pico/asm_helper.S"
|
||||
|
||||
pico_default_asm_setup
|
||||
|
||||
.align 2
|
||||
|
||||
|
@ -518,7 +518,7 @@ int main() {
|
||||
}
|
||||
for(float x = 4294967296.f * 4294967296.f * 2.f; x>=0.5f; x/=2.f) {
|
||||
printf("f2i64 %f->%lld\n", x, (int64_t)x);
|
||||
if (x >= INT64_MAX) {
|
||||
if ((double)x >= (double)INT64_MAX) {
|
||||
// seems like there is a bug in the gcc version!
|
||||
assert(__aeabi_f2lz(x) == INT64_MAX);
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user