::enabled() { return true; };
+#define DEBUG_PINS_ENABLED(p) (__debug_pin_settings::enabled())
+#endif
+#define DEBUG_PINS_SET(p, v) if (DEBUG_PINS_ENABLED(p)) gpio_set_mask((unsigned)(v)<restart_on_next = false;
+
+ i2c->hw->enable = 0;
+
+ // Configure as a fast-mode master with RepStart support, 7-bit addresses
+ i2c->hw->con =
+ I2C_IC_CON_SPEED_VALUE_FAST << I2C_IC_CON_SPEED_LSB |
+ I2C_IC_CON_MASTER_MODE_BITS |
+ I2C_IC_CON_IC_SLAVE_DISABLE_BITS |
+ I2C_IC_CON_IC_RESTART_EN_BITS;
+
+ // Set FIFO watermarks to 1 to make things simpler. This is encoded by a register value of 0.
+ i2c->hw->tx_tl = 0;
+ i2c->hw->rx_tl = 0;
+
+ // Always enable the DREQ signalling -- harmless if DMA isn't listening
+ i2c->hw->dma_cr = I2C_IC_DMA_CR_TDMAE_BITS | I2C_IC_DMA_CR_RDMAE_BITS;
+
+ // Re-sets i2c->hw->enable upon returning:
+ return i2c_set_baudrate(i2c, baudrate);
+}
+
+void i2c_deinit(i2c_inst_t *i2c) {
+ i2c_reset(i2c);
+}
+
+uint i2c_set_baudrate(i2c_inst_t *i2c, uint baudrate) {
+ invalid_params_if(I2C, baudrate == 0);
+ // I2C is synchronous design that runs from clk_sys
+ uint freq_in = clock_get_hz(clk_sys);
+
+ // TODO there are some subtleties to I2C timing which we are completely ignoring here
+ uint period = (freq_in + baudrate / 2) / baudrate;
+ uint hcnt = period * 3 / 5; // oof this one hurts
+ uint lcnt = period - hcnt;
+ // Check for out-of-range divisors:
+ invalid_params_if(I2C, hcnt > I2C_IC_FS_SCL_HCNT_IC_FS_SCL_HCNT_BITS);
+ invalid_params_if(I2C, lcnt > I2C_IC_FS_SCL_LCNT_IC_FS_SCL_LCNT_BITS);
+ invalid_params_if(I2C, hcnt < 8);
+ invalid_params_if(I2C, lcnt < 8);
+
+ i2c->hw->enable = 0;
+ // Always use "fast" mode (<= 400 kHz, works fine for standard mode too)
+ hw_write_masked(&i2c->hw->con,
+ I2C_IC_CON_SPEED_VALUE_FAST << I2C_IC_CON_SPEED_LSB,
+ I2C_IC_CON_SPEED_BITS
+ );
+ i2c->hw->fs_scl_hcnt = hcnt;
+ i2c->hw->fs_scl_lcnt = lcnt;
+ i2c->hw->fs_spklen = lcnt < 16 ? 1 : lcnt / 16;
+
+ i2c->hw->enable = 1;
+ return freq_in / period;
+}
+
+void i2c_set_slave_mode(i2c_inst_t *i2c, bool slave, uint8_t addr) {
+ invalid_params_if(I2C, addr >= 0x80); // 7-bit addresses
+ invalid_params_if(I2C, i2c_reserved_addr(addr));
+ i2c->hw->enable = 0;
+ if (slave) {
+ hw_clear_bits(&i2c->hw->con,
+ I2C_IC_CON_MASTER_MODE_BITS |
+ I2C_IC_CON_IC_SLAVE_DISABLE_BITS
+ );
+ i2c->hw->sar = addr;
+ } else {
+ hw_set_bits(&i2c->hw->con,
+ I2C_IC_CON_MASTER_MODE_BITS |
+ I2C_IC_CON_IC_SLAVE_DISABLE_BITS
+ );
+ }
+ i2c->hw->enable = 1;
+}
+
+static int i2c_write_blocking_internal(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop,
+ check_timeout_fn timeout_check, struct timeout_state *ts) {
+ invalid_params_if(I2C, addr >= 0x80); // 7-bit addresses
+ invalid_params_if(I2C, i2c_reserved_addr(addr));
+ // Synopsys hw accepts start/stop flags alongside data items in the same
+ // FIFO word, so no 0 byte transfers.
+ invalid_params_if(I2C, len == 0);
+
+ i2c->hw->enable = 0;
+ i2c->hw->tar = addr;
+ i2c->hw->enable = 1;
+
+ bool abort = false;
+ bool timeout = false;
+
+ uint32_t abort_reason;
+ size_t byte_ctr;
+
+ for (byte_ctr = 0; byte_ctr < len; ++byte_ctr) {
+ bool first = byte_ctr == 0;
+ bool last = byte_ctr == len - 1;
+
+ i2c->hw->data_cmd =
+ !!(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB |
+ !!(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
+ *src++;
+
+ do {
+ // Note clearing the abort flag also clears the reason, and this
+ // instance of flag is clear-on-read!
+ abort_reason = i2c->hw->tx_abrt_source;
+ abort = (bool) i2c->hw->clr_tx_abrt;
+ if (timeout_check) {
+ timeout = timeout_check(ts);
+ abort |= timeout;
+ }
+ tight_loop_contents();
+ } while (!abort && !(i2c->hw->status & I2C_IC_STATUS_TFE_BITS));
+
+ // Note the hardware issues a STOP automatically on an abort condition.
+ // Note also the hardware clears RX FIFO as well as TX on abort,
+ // because we set hwparam IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
+ if (abort)
+ break;
+ }
+
+ int rval;
+
+ // A lot of things could have just happened due to the ingenious and
+ // creative design of I2C. Try to figure things out.
+ if (abort) {
+ if (timeout)
+ rval = PICO_ERROR_TIMEOUT;
+ else if (!abort_reason || abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS) {
+ // No reported errors - seems to happen if there is nothing connected to the bus.
+ // Address byte not acknowledged
+ rval = PICO_ERROR_GENERIC;
+ } else if (abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_TXDATA_NOACK_BITS) {
+ // Address acknowledged, some data not acknowledged
+ rval = byte_ctr;
+ } else {
+ //panic("Unknown abort from I2C instance @%08x: %08x\n", (uint32_t) i2c->hw, abort_reason);
+ rval = PICO_ERROR_GENERIC;
+ }
+ } else {
+ rval = byte_ctr;
+ }
+
+ // nostop means we are now at the end of a *message* but not the end of a *transfer*
+ i2c->restart_on_next = nostop;
+ return rval;
+}
+
+int i2c_write_blocking(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop) {
+ return i2c_write_blocking_internal(i2c, addr, src, len, nostop, NULL, NULL);
+}
+
+int i2c_write_blocking_until(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop,
+ absolute_time_t until) {
+ timeout_state_t ts;
+ return i2c_write_blocking_internal(i2c, addr, src, len, nostop, init_single_timeout_until(&ts, until), &ts);
+}
+
+int i2c_write_timeout_per_char_us(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop,
+ uint timeout_per_char_us) {
+ timeout_state_t ts;
+ return i2c_write_blocking_internal(i2c, addr, src, len, nostop,
+ init_per_iteration_timeout_us(&ts, timeout_per_char_us), &ts);
+}
+
+static int i2c_read_blocking_internal(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop,
+ check_timeout_fn timeout_check, timeout_state_t *ts) {
+ invalid_params_if(I2C, addr >= 0x80); // 7-bit addresses
+ invalid_params_if(I2C, i2c_reserved_addr(addr));
+ invalid_params_if(I2C, len == 0);
+
+ i2c->hw->enable = 0;
+ i2c->hw->tar = addr;
+ i2c->hw->enable = 1;
+
+ bool abort = false;
+ bool timeout = false;
+ uint32_t abort_reason;
+ size_t byte_ctr;
+
+ for (byte_ctr = 0; byte_ctr < len; ++byte_ctr) {
+ bool first = byte_ctr == 0;
+ bool last = byte_ctr == len - 1;
+ while (!i2c_get_write_available(i2c))
+ tight_loop_contents();
+
+ i2c->hw->data_cmd =
+ !!(first && i2c->restart_on_next) << I2C_IC_DATA_CMD_RESTART_LSB |
+ !!(last && !nostop) << I2C_IC_DATA_CMD_STOP_LSB |
+ I2C_IC_DATA_CMD_CMD_BITS; // -> 1 for read
+
+ do {
+ abort_reason = i2c->hw->tx_abrt_source;
+ abort = (bool) i2c->hw->clr_tx_abrt;
+ if (timeout_check) {
+ timeout = timeout_check(ts);
+ abort |= timeout;
+ }
+ } while (!abort && !i2c_get_read_available(i2c));
+
+ if (abort)
+ break;
+
+ *dst++ = i2c->hw->data_cmd;
+ }
+
+ int rval;
+
+ if (abort) {
+ if (timeout)
+ rval = PICO_ERROR_TIMEOUT;
+ else if (!abort_reason || abort_reason & I2C_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK_BITS) {
+ // No reported errors - seems to happen if there is nothing connected to the bus.
+ // Address byte not acknowledged
+ rval = PICO_ERROR_GENERIC;
+ } else {
+// panic("Unknown abort from I2C instance @%08x: %08x\n", (uint32_t) i2c->hw, abort_reason);
+ rval = PICO_ERROR_GENERIC;
+ }
+ } else {
+ rval = byte_ctr;
+ }
+
+ i2c->restart_on_next = nostop;
+ return rval;
+}
+
+int i2c_read_blocking(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop) {
+ return i2c_read_blocking_internal(i2c, addr, dst, len, nostop, NULL, NULL);
+}
+
+int i2c_read_blocking_until(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop, absolute_time_t until) {
+ timeout_state_t ts;
+ return i2c_read_blocking_internal(i2c, addr, dst, len, nostop, init_single_timeout_until(&ts, until), &ts);
+}
+
+int i2c_read_timeout_per_char_us(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop,
+ uint timeout_per_char_us) {
+ timeout_state_t ts;
+ return i2c_read_blocking_internal(i2c, addr, dst, len, nostop,
+ init_per_iteration_timeout_us(&ts, timeout_per_char_us), &ts);
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_i2c/include/hardware/i2c.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_i2c/include/hardware/i2c.h
new file mode 100644
index 00000000000..2b5dca7798b
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_i2c/include/hardware/i2c.h
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_I2C_H
+#define _HARDWARE_I2C_H
+
+#include "pico.h"
+#include "pico/time.h"
+#include "hardware/structs/i2c.h"
+#include "stdio.h"
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_I2C, Enable/disable assertions in the I2C module, type=bool, default=0, group=hardware_i2c
+#ifndef PARAM_ASSERTIONS_ENABLED_I2C
+#define PARAM_ASSERTIONS_ENABLED_I2C 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file hardware/i2c.h
+ * \defgroup hardware_i2c hardware_i2c
+ *
+ * I2C Controller API
+ *
+ * The I2C bus is a two-wire serial interface, consisting of a serial data line SDA and a serial clock SCL. These wires carry
+ * information between the devices connected to the bus. Each device is recognized by a unique address and can operate as
+ * either a “transmitter” or “receiver”, depending on the function of the device. Devices can also be considered as masters or
+ * slaves when performing data transfers. A master is a device that initiates a data transfer on the bus and generates the
+ * clock signals to permit that transfer. At that time, any device addressed is considered a slave.
+ *
+ * This API allows the controller to be set up as a master or a slave using the \ref i2c_set_slave_mode function.
+ *
+ * The external pins of each controller are connected to GPIO pins as defined in the GPIO muxing table in the datasheet. The muxing options
+ * give some IO flexibility, but each controller external pin should be connected to only one GPIO.
+ *
+ * Note that the controller does NOT support High speed mode or Ultra-fast speed mode, the fastest operation being fast mode plus
+ * at up to 1000Kb/s.
+ *
+ * See the datasheet for more information on the I2C controller and its usage.
+ *
+ * \subsection i2c_example Example
+ * \addtogroup hardware_i2c
+ * \include bus_scan.c
+ */
+
+typedef struct i2c_inst i2c_inst_t;
+
+/** The I2C identifiers for use in I2C functions.
+ *
+ * e.g. i2c_init(i2c0, 48000)
+ *
+ * \ingroup hardware_i2c
+ * @{
+ */
+extern i2c_inst_t i2c0_inst;
+extern i2c_inst_t i2c1_inst;
+
+#define i2c0 (&i2c0_inst) ///< Identifier for I2C HW Block 0
+#define i2c1 (&i2c1_inst) ///< Identifier for I2C HW Block 1
+
+/** @} */
+
+// ----------------------------------------------------------------------------
+// Setup
+
+/*! \brief Initialise the I2C HW block
+ * \ingroup hardware_i2c
+ *
+ * Put the I2C hardware into a known state, and enable it. Must be called
+ * before other functions. By default, the I2C is configured to operate as a
+ * master.
+ *
+ * The I2C bus frequency is set as close as possible to requested, and
+ * the return actual rate set is returned
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \param baudrate Baudrate in Hz (e.g. 100kHz is 100000)
+ * \return Actual set baudrate
+ */
+uint _i2c_init(i2c_inst_t *i2c, uint baudrate);
+
+/*! \brief Disable the I2C HW block
+ * \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ *
+ * Disable the I2C again if it is no longer used. Must be reinitialised before
+ * being used again.
+ */
+void i2c_deinit(i2c_inst_t *i2c);
+
+/*! \brief Set I2C baudrate
+ * \ingroup hardware_i2c
+ *
+ * Set I2C bus frequency as close as possible to requested, and return actual
+ * rate set.
+ * Baudrate may not be as exactly requested due to clocking limitations.
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \param baudrate Baudrate in Hz (e.g. 100kHz is 100000)
+ * \return Actual set baudrate
+ */
+uint i2c_set_baudrate(i2c_inst_t *i2c, uint baudrate);
+
+/*! \brief Set I2C port to slave mode
+ * \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \param slave true to use slave mode, false to use master mode
+ * \param addr If \p slave is true, set the slave address to this value
+ */
+void i2c_set_slave_mode(i2c_inst_t *i2c, bool slave, uint8_t addr);
+
+// ----------------------------------------------------------------------------
+// Generic input/output
+
+struct i2c_inst {
+ i2c_hw_t *hw;
+ bool restart_on_next;
+};
+
+/*! \brief Convert I2c instance to hardware instance number
+ * \ingroup hardware_i2c
+ *
+ * \param i2c I2C instance
+ * \return Number of UART, 0 or 1.
+ */
+static inline uint i2c_hw_index(i2c_inst_t *i2c) {
+ invalid_params_if(I2C, i2c != i2c0 && i2c != i2c1);
+ return i2c == i2c1 ? 1 : 0;
+}
+
+static inline i2c_hw_t *i2c_get_hw(i2c_inst_t *i2c) {
+ i2c_hw_index(i2c); // check it is a hw i2c
+ return i2c->hw;
+}
+
+/*! \brief Attempt to write specified number of bytes to address, blocking until the specified absolute time is reached.
+ * \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \param addr Address of device to write to
+ * \param src Pointer to data to send
+ * \param len Length of data in bytes to send
+ * \param nostop If true, master retains control of the bus at the end of the transfer (no Stop is issued),
+ * and the next transfer will begin with a Restart rather than a Start.
+ * \param until The absolute time that the block will wait until the entire transaction is complete. Note, an individual timeout of
+ * this value divided by the length of data is applied for each byte transfer, so if the first or subsequent
+ * bytes fails to transfer within that sub timeout, the function will return with an error.
+ *
+ * \return Number of bytes written, or PICO_ERROR_GENERIC if address not acknowledged, no device present, or PICO_ERROR_TIMEOUT if a timeout occurred.
+ */
+int i2c_write_blocking_until(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop, absolute_time_t until);
+
+/*! \brief Attempt to read specified number of bytes from address, blocking until the specified absolute time is reached.
+ * \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \param addr Address of device to read from
+ * \param dst Pointer to buffer to receive data
+ * \param len Length of data in bytes to receive
+ * \param nostop If true, master retains control of the bus at the end of the transfer (no Stop is issued),
+ * and the next transfer will begin with a Restart rather than a Start.
+ * \param until The absolute time that the block will wait until the entire transaction is complete.
+ * \return Number of bytes read, or PICO_ERROR_GENERIC if address not acknowledged, no device present, or PICO_ERROR_TIMEOUT if a timeout occurred.
+ */
+int i2c_read_blocking_until(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop, absolute_time_t until);
+
+/*! \brief Attempt to write specified number of bytes to address, with timeout
+ * \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \param addr Address of device to write to
+ * \param src Pointer to data to send
+ * \param len Length of data in bytes to send
+ * \param nostop If true, master retains control of the bus at the end of the transfer (no Stop is issued),
+ * and the next transfer will begin with a Restart rather than a Start.
+ * \param timeout_us The time that the function will wait for the entire transaction to complete. Note, an individual timeout of
+ * this value divided by the length of data is applied for each byte transfer, so if the first or subsequent
+ * bytes fails to transfer within that sub timeout, the function will return with an error.
+ *
+ * \return Number of bytes written, or PICO_ERROR_GENERIC if address not acknowledged, no device present, or PICO_ERROR_TIMEOUT if a timeout occurred.
+ */
+static inline int i2c_write_timeout_us(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop, uint timeout_us) {
+ absolute_time_t t = make_timeout_time_us(timeout_us);
+ return i2c_write_blocking_until(i2c, addr, src, len, nostop, t);
+}
+
+int i2c_write_timeout_per_char_us(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop, uint timeout_per_char_us);
+
+/*! \brief Attempt to read specified number of bytes from address, with timeout
+ * \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \param addr Address of device to read from
+ * \param dst Pointer to buffer to receive data
+ * \param len Length of data in bytes to receive
+ * \param nostop If true, master retains control of the bus at the end of the transfer (no Stop is issued),
+ * and the next transfer will begin with a Restart rather than a Start.
+ * \param timeout_us The time that the function will wait for the entire transaction to complete
+ * \return Number of bytes read, or PICO_ERROR_GENERIC if address not acknowledged, no device present, or PICO_ERROR_TIMEOUT if a timeout occurred.
+ */
+static inline int i2c_read_timeout_us(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop, uint timeout_us) {
+ absolute_time_t t = make_timeout_time_us(timeout_us);
+ return i2c_read_blocking_until(i2c, addr, dst, len, nostop, t);
+}
+
+int i2c_read_timeout_per_char_us(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop, uint timeout_per_char_us);
+
+/*! \brief Attempt to write specified number of bytes to address, blocking
+ * \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \param addr Address of device to write to
+ * \param src Pointer to data to send
+ * \param len Length of data in bytes to send
+ * \param nostop If true, master retains control of the bus at the end of the transfer (no Stop is issued),
+ * and the next transfer will begin with a Restart rather than a Start.
+ * \return Number of bytes written, or PICO_ERROR_GENERIC if address not acknowledged, no device present.
+ */
+int i2c_write_blocking(i2c_inst_t *i2c, uint8_t addr, const uint8_t *src, size_t len, bool nostop);
+
+/*! \brief Attempt to read specified number of bytes from address, blocking
+ * \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \param addr Address of device to read from
+ * \param dst Pointer to buffer to receive data
+ * \param len Length of data in bytes to receive
+ * \param nostop If true, master retains control of the bus at the end of the transfer (no Stop is issued),
+ * and the next transfer will begin with a Restart rather than a Start.
+ * \return Number of bytes read, or PICO_ERROR_GENERIC if address not acknowledged, no device present.
+ */
+int i2c_read_blocking(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop);
+
+
+/*! \brief Determine non-blocking write space available
+ * \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \return 0 if no space is available in the I2C to write more data. If return is nonzero, at
+ * least that many bytes can be written without blocking.
+ */
+static inline size_t i2c_get_write_available(i2c_inst_t *i2c) {
+ const size_t IC_TX_BUFFER_DEPTH = 32;
+ return IC_TX_BUFFER_DEPTH - i2c_get_hw(i2c)->txflr;
+}
+
+/*! \brief Determine number of bytes received
+ * \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \return 0 if no data available, if return is nonzero at
+ * least that many bytes can be read without blocking.
+ */
+static inline size_t i2c_get_read_available(i2c_inst_t *i2c) {
+ return i2c_get_hw(i2c)->rxflr;
+}
+
+/*! \brief Write direct to TX FIFO
+ * \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \param src Data to send
+ * \param len Number of bytes to send
+ *
+ * Writes directly to the to I2C TX FIFO which us mainly useful for
+ * slave-mode operation.
+ */
+static inline void i2c_write_raw_blocking(i2c_inst_t *i2c, const uint8_t *src, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ // TODO NACK or STOP on end?
+ while (!i2c_get_write_available(i2c))
+ tight_loop_contents();
+ i2c_get_hw(i2c)->data_cmd = *src++;
+ }
+}
+
+/*! \brief Write direct to TX FIFO
+ * \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \param dst Buffer to accept data
+ * \param len Number of bytes to send
+ *
+ * Reads directly from the I2C RX FIFO which us mainly useful for
+ * slave-mode operation.
+ */
+static inline size_t i2c_read_raw_blocking(i2c_inst_t *i2c, uint8_t *dst, size_t len) {
+
+ size_t bytes_read = 0;
+
+ for (size_t i = 0; i < len; ++i) {
+
+ while (!i2c_get_read_available(i2c)) {
+ tight_loop_contents();
+ }
+
+ *dst = i2c_get_hw(i2c)->data_cmd;
+ bytes_read++;
+
+ //printf("dst %d ,", *dst);
+
+ //Check stop condition
+ int stop = (i2c->hw->raw_intr_stat & 0x00000200) >> 9;
+ if (stop && !i2c_get_read_available(i2c)) {
+ //Clear stop
+ int clear_stop = i2c_get_hw(i2c)->clr_stop_det;
+ printf("clear_stop reg: %d\n", clear_stop);
+ break;
+ } else {
+ *dst++;
+ }
+
+ }
+
+ return bytes_read;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_interp/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_interp/CMakeLists.txt
new file mode 100644
index 00000000000..d6d693fcde5
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_interp/CMakeLists.txt
@@ -0,0 +1 @@
+pico_simple_hardware_target(interp)
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_interp/include/hardware/interp.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_interp/include/hardware/interp.h
new file mode 100644
index 00000000000..18cefc53eca
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_interp/include/hardware/interp.h
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_INTERP_H
+#define _HARDWARE_INTERP_H
+
+#include "pico.h"
+#include "hardware/structs/interp.h"
+#include "hardware/regs/sio.h"
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_INTERP, Enable/disable assertions in the interpolation module, type=bool, default=0, group=hardware_interp
+#ifndef PARAM_ASSERTIONS_ENABLED_INTERP
+#define PARAM_ASSERTIONS_ENABLED_INTERP 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file hardware/interp.h
+ * \defgroup hardware_interp hardware_interp
+ *
+ * Hardware Interpolator API
+ *
+ * Each core is equipped with two interpolators (INTERP0 and INTERP1) which can be used to accelerate
+ * tasks by combining certain pre-configured simple operations into a single processor cycle. Intended
+ * for cases where the pre-configured operation is repeated a large number of times, this results in
+ * code which uses both fewer CPU cycles and fewer CPU registers in the time critical sections of the
+ * code.
+ *
+ * The interpolators are used heavily to accelerate audio operations within the SDK, but their
+ * flexible configuration make it possible to optimise many other tasks such as quantization and
+ * dithering, table lookup address generation, affine texture mapping, decompression and linear feedback.
+ *
+ * Please refer to the RP2040 datasheet for more information on the HW interpolators and how they work.
+ */
+
+#define interp0 interp0_hw
+#define interp1 interp1_hw
+
+/** \brief Interpolator configuration
+ * \defgroup interp_config interp_config
+ * \ingroup hardware_interp
+ *
+ * Each interpolator needs to be configured, these functions provide handy helpers to set up configuration
+ * structures.
+ *
+ */
+
+typedef struct {
+ uint32_t ctrl;
+} interp_config;
+
+static inline uint interp_index(interp_hw_t *interp) {
+ assert(interp == interp0 || interp == interp1);
+ return interp == interp1 ? 1 : 0;
+}
+
+/*! \brief Claim the interpolator lane specified
+ * \ingroup hardware_interp
+ *
+ * Use this function to claim exclusive access to the specified interpolator lane.
+ *
+ * This function will panic if the lane is already claimed.
+ *
+ * \param interp Interpolator on which to claim a lane. interp0 or interp1
+ * \param lane The lane number, 0 or 1.
+ */
+void interp_claim_lane(interp_hw_t *interp, uint lane);
+
+/*! \brief Claim the interpolator lanes specified in the mask
+ * \ingroup hardware_interp
+ *
+ * \param interp Interpolator on which to claim lanes. interp0 or interp1
+ * \param lane_mask Bit pattern of lanes to claim (only bits 0 and 1 are valid)
+ */
+void interp_claim_lane_mask(interp_hw_t *interp, uint lane_mask);
+
+/*! \brief Release a previously claimed interpolator lane
+ * \ingroup hardware_interp
+ *
+ * \param interp Interpolator on which to release a lane. interp0 or interp1
+ * \param lane The lane number, 0 or 1
+ */
+void interp_unclaim_lane(interp_hw_t *interp, uint lane);
+
+/*! \brief Set the interpolator shift value
+ * \ingroup interp_config
+ *
+ * Sets the number of bits the accumulator is shifted before masking, on each iteration.
+ *
+ * \param c Pointer to an interpolator config
+ * \param shift Number of bits
+ */
+static inline void interp_config_set_shift(interp_config *c, uint shift) {
+ valid_params_if(INTERP, shift < 32);
+ c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_SHIFT_BITS) |
+ ((shift << SIO_INTERP0_CTRL_LANE0_SHIFT_LSB) & SIO_INTERP0_CTRL_LANE0_SHIFT_BITS);
+}
+
+/*! \brief Set the interpolator mask range
+ * \ingroup interp_config
+ *
+ * Sets the range of bits (least to most) that are allowed to pass through the interpolator
+ *
+ * \param c Pointer to interpolation config
+ * \param mask_lsb The least significant bit allowed to pass
+ * \param mask_msb The most significant bit allowed to pass
+ */
+static inline void interp_config_set_mask(interp_config *c, uint mask_lsb, uint mask_msb) {
+ valid_params_if(INTERP, mask_msb < 32);
+ valid_params_if(INTERP, mask_lsb <= mask_msb);
+ c->ctrl = (c->ctrl & ~(SIO_INTERP0_CTRL_LANE0_MASK_LSB_BITS | SIO_INTERP0_CTRL_LANE0_MASK_MSB_BITS)) |
+ ((mask_lsb << SIO_INTERP0_CTRL_LANE0_MASK_LSB_LSB) & SIO_INTERP0_CTRL_LANE0_MASK_LSB_BITS) |
+ ((mask_msb << SIO_INTERP0_CTRL_LANE0_MASK_MSB_LSB) & SIO_INTERP0_CTRL_LANE0_MASK_MSB_BITS);
+}
+
+/*! \brief Enable cross input
+ * \ingroup interp_config
+ *
+ * Allows feeding of the accumulator content from the other lane back in to this lanes shift+mask hardware.
+ * This will take effect even if the interp_config_set_add_raw option is set as the cross input mux is before the
+ * shift+mask bypass
+ *
+ * \param c Pointer to interpolation config
+ * \param cross_input If true, enable the cross input.
+ */
+static inline void interp_config_set_cross_input(interp_config *c, bool cross_input) {
+ c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_CROSS_INPUT_BITS) |
+ (cross_input ? SIO_INTERP0_CTRL_LANE0_CROSS_INPUT_BITS : 0);
+}
+
+/*! \brief Enable cross results
+ * \ingroup interp_config
+ *
+ * Allows feeding of the other lane’s result into this lane’s accumulator on a POP operation.
+ *
+ * \param c Pointer to interpolation config
+ * \param cross_result If true, enables the cross result
+ */
+static inline void interp_config_set_cross_result(interp_config *c, bool cross_result) {
+ c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_CROSS_RESULT_BITS) |
+ (cross_result ? SIO_INTERP0_CTRL_LANE0_CROSS_RESULT_BITS : 0);
+}
+
+/*! \brief Set sign extension
+ * \ingroup interp_config
+ *
+ * Enables signed mode, where the shifted and masked accumulator value is sign-extended to 32 bits
+ * before adding to BASE1, and LANE1 PEEK/POP results appear extended to 32 bits when read by processor.
+ *
+ * \param c Pointer to interpolation config
+ * \param _signed If true, enables sign extension
+ */
+static inline void interp_config_set_signed(interp_config *c, bool _signed) {
+ c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_SIGNED_BITS) |
+ (_signed ? SIO_INTERP0_CTRL_LANE0_SIGNED_BITS : 0);
+}
+
+/*! \brief Set raw add option
+ * \ingroup interp_config
+ *
+ * When enabled, mask + shift is bypassed for LANE0 result. This does not affect the FULL result.
+ *
+ * \param c Pointer to interpolation config
+ * \param add_raw If true, enable raw add option.
+ */
+static inline void interp_config_set_add_raw(interp_config *c, bool add_raw) {
+ c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_ADD_RAW_BITS) |
+ (add_raw ? SIO_INTERP0_CTRL_LANE0_ADD_RAW_BITS : 0);
+}
+
+/*! \brief Set blend mode
+ * \ingroup interp_config
+ *
+ * If enabled, LANE1 result is a linear interpolation between BASE0 and BASE1, controlled
+ * by the 8 LSBs of lane 1 shift and mask value (a fractional number between 0 and 255/256ths)
+ *
+ * LANE0 result does not have BASE0 added (yields only the 8 LSBs of lane 1 shift+mask value)
+ *
+ * FULL result does not have lane 1 shift+mask value added (BASE2 + lane 0 shift+mask)
+ *
+ * LANE1 SIGNED flag controls whether the interpolation is signed or unsig
+ *
+ * \param c Pointer to interpolation config
+ * \param blend Set true to enable blend mode.
+*/
+static inline void interp_config_set_blend(interp_config *c, bool blend) {
+ c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_BLEND_BITS) |
+ (blend ? SIO_INTERP0_CTRL_LANE0_BLEND_BITS : 0);
+}
+
+/*! \brief Set interpolator clamp mode (Interpolator 1 only)
+ * \ingroup interp_config
+ *
+ * Only present on INTERP1 on each core. If CLAMP mode is enabled:
+ * - LANE0 result is a shifted and masked ACCUM0, clamped by a lower bound of BASE0 and an upper bound of BASE1.
+ * - Signedness of these comparisons is determined by LANE0_CTRL_SIGNED
+ *
+ * \param c Pointer to interpolation config
+ * \param clamp Set true to enable clamp mode
+ */
+static inline void interp_config_set_clamp(interp_config *c, bool clamp) {
+ c->ctrl = (c->ctrl & ~SIO_INTERP1_CTRL_LANE0_CLAMP_BITS) |
+ (clamp ? SIO_INTERP1_CTRL_LANE0_CLAMP_BITS : 0);
+}
+
+/*! \brief Set interpolator Force bits
+ * \ingroup interp_config
+ *
+ * ORed into bits 29:28 of the lane result presented to the processor on the bus.
+ *
+ * No effect on the internal 32-bit datapath. Handy for using a lane to generate sequence
+ * of pointers into flash or SRAM
+ *
+ * \param c Pointer to interpolation config
+ * \param bits Sets the force bits to that specified. Range 0-3 (two bits)
+ */
+static inline void interp_config_set_force_bits(interp_config *c, uint bits) {
+ invalid_params_if(INTERP, bits > 3);
+ // note cannot use hw_set_bits on SIO
+ c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_FORCE_MSB_BITS) |
+ (bits << SIO_INTERP0_CTRL_LANE0_FORCE_MSB_LSB);
+}
+
+/*! \brief Get a default configuration
+ * \ingroup interp_config
+ *
+ * \return A default interpolation configuration
+ */
+static inline interp_config interp_default_config() {
+ interp_config c = {0};
+ // Just pass through everything
+ interp_config_set_mask(&c, 0, 31);
+ return c;
+}
+
+/*! \brief Send configuration to a lane
+ * \ingroup interp_config
+ *
+ * If an invalid configuration is specified (ie a lane specific item is set on wrong lane),
+ * depending on setup this function can panic.
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param lane The lane to set
+ * \param config Pointer to interpolation config
+ */
+
+static inline void interp_set_config(interp_hw_t *interp, uint lane, interp_config *config) {
+ invalid_params_if(INTERP, lane > 1);
+ invalid_params_if(INTERP, config->ctrl & SIO_INTERP1_CTRL_LANE0_CLAMP_BITS &&
+ (!interp_index(interp) || lane)); // only interp1 lane 0 has clamp bit
+ invalid_params_if(INTERP, config->ctrl & SIO_INTERP0_CTRL_LANE0_BLEND_BITS &&
+ (interp_index(interp) || lane)); // only interp0 lane 0 has blend bit
+ interp->ctrl[lane] = config->ctrl;
+}
+
+/*! \brief Directly set the force bits on a specified lane
+ * \ingroup hardware_interp
+ *
+ * These bits are ORed into bits 29:28 of the lane result presented to the processor on the bus.
+ * There is no effect on the internal 32-bit datapath.
+ *
+ * Useful for using a lane to generate sequence of pointers into flash or SRAM, saving a subsequent
+ * OR or add operation.
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param lane The lane to set
+ * \param bits The bits to set (bits 0 and 1, value range 0-3)
+ */
+static inline void interp_set_force_bits(interp_hw_t *interp, uint lane, uint bits) {
+ // note cannot use hw_set_bits on SIO
+ interp->ctrl[lane] |= (bits << SIO_INTERP0_CTRL_LANE0_FORCE_MSB_LSB);
+}
+
+typedef struct {
+ io_rw_32 accum[2];
+ io_rw_32 base[3];
+ io_rw_32 ctrl[2];
+} interp_hw_save_t;
+
+/*! \brief Save the specified interpolator state
+ * \ingroup hardware_interp
+ *
+ * Can be used to save state if you need an interpolator for another purpose, state
+ * can then be recovered afterwards and continue from that point
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param saver Pointer to the save structure to fill in
+ */
+void interp_save(interp_hw_t *interp, interp_hw_save_t *saver);
+
+/*! \brief Restore an interpolator state
+ * \ingroup hardware_interp
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param saver Pointer to save structure to reapply to the specified interpolator
+ */
+void interp_restore(interp_hw_t *interp, interp_hw_save_t *saver);
+
+/*! \brief Sets the interpolator base register by lane
+ * \ingroup hardware_interp
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param lane The lane number, 0 or 1 or 2
+ * \param val The value to apply to the register
+ */
+static inline void interp_set_base(interp_hw_t *interp, uint lane, uint32_t val) {
+ interp->base[lane] = val;
+}
+
+/*! \brief Gets the content of interpolator base register by lane
+ * \ingroup hardware_interp
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param lane The lane number, 0 or 1 or 2
+ * \return The current content of the lane base register
+ */
+static inline uint32_t interp_get_base(interp_hw_t *interp, uint lane) {
+ return interp->base[lane];
+}
+
+/*! \brief Sets the interpolator base registers simultaneously
+ * \ingroup hardware_interp
+ *
+ * The lower 16 bits go to BASE0, upper bits to BASE1 simultaneously.
+ * Each half is sign-extended to 32 bits if that lane’s SIGNED flag is set.
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param val The value to apply to the register
+ */
+static inline void interp_set_base_both(interp_hw_t *interp, uint32_t val) {
+ interp->base01 = val;
+}
+
+
+/*! \brief Sets the interpolator accumulator register by lane
+ * \ingroup hardware_interp
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param lane The lane number, 0 or 1
+ * \param val The value to apply to the register
+ */
+static inline void interp_set_accumulator(interp_hw_t *interp, uint lane, uint32_t val) {
+ interp->accum[lane] = val;
+}
+
+/*! \brief Gets the content of the interpolator accumulator register by lane
+ * \ingroup hardware_interp
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param lane The lane number, 0 or 1
+ * \return The current content of the register
+ */
+static inline uint32_t interp_get_accumulator(interp_hw_t *interp, uint lane) {
+ return interp->accum[lane];
+}
+
+/*! \brief Read lane result, and write lane results to both accumulators to update the interpolator
+ * \ingroup hardware_interp
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param lane The lane number, 0 or 1
+ * \return The content of the lane result register
+ */
+static inline uint32_t interp_pop_lane_result(interp_hw_t *interp, uint lane) {
+ return interp->pop[lane];
+}
+
+/*! \brief Read lane result
+ * \ingroup hardware_interp
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param lane The lane number, 0 or 1
+ * \return The content of the lane result register
+ */
+static inline uint32_t interp_peek_lane_result(interp_hw_t *interp, uint lane) {
+ return interp->peek[lane];
+}
+
+/*! \brief Read lane result, and write lane results to both accumulators to update the interpolator
+ * \ingroup hardware_interp
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \return The content of the FULL register
+ */
+static inline uint32_t interp_pop_full_result(interp_hw_t *interp) {
+ return interp->pop[2];
+}
+
+/*! \brief Read lane result
+ * \ingroup hardware_interp
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \return The content of the FULL register
+ */
+static inline uint32_t interp_peek_full_result(interp_hw_t *interp) {
+ return interp->peek[2];
+}
+
+/*! \brief Add to accumulator
+ * \ingroup hardware_interp
+ *
+ * Atomically add the specified value to the accumulator on the specified lane
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param lane The lane number, 0 or 1
+ * \param val Value to add
+ * \return The content of the FULL register
+ */
+static inline void interp_add_accumulater(interp_hw_t *interp, uint lane, uint32_t val) {
+ interp->add_raw[lane] = val;
+}
+
+/*! \brief Get raw lane value
+ * \ingroup hardware_interp
+ *
+ * Returns the raw shift and mask value from the specified lane, BASE0 is NOT added
+ *
+ * \param interp Interpolator instance, interp0 or interp1.
+ * \param lane The lane number, 0 or 1
+ * \return The raw shift/mask value
+ */
+static inline uint32_t interp_get_raw(interp_hw_t *interp, uint lane) {
+ return interp->add_raw[lane];
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_interp/interp.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_interp/interp.c
new file mode 100644
index 00000000000..5fdad93c191
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_interp/interp.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/interp.h"
+#include "hardware/structs/sio.h"
+#include "hardware/claim.h"
+
+check_hw_size(interp_hw_t, SIO_INTERP1_ACCUM0_OFFSET - SIO_INTERP0_ACCUM0_OFFSET);
+
+check_hw_layout(sio_hw_t, interp, SIO_INTERP0_ACCUM0_OFFSET);
+
+static_assert(NUM_DMA_CHANNELS <= 16, "");
+
+static uint8_t _claimed;
+
+void interp_claim_lane(interp_hw_t *interp, uint lane) {
+ valid_params_if(INTERP, lane < 2);
+ uint bit = (interp_index(interp) << 1u) | lane;
+ hw_claim_or_assert((uint8_t *) &_claimed, bit, "Lane is already claimed");
+}
+
+void interp_claim_lane_mask(interp_hw_t *interp, uint lane_mask) {
+ valid_params_if(INTERP, lane_mask && lane_mask <= 0x3);
+ if (lane_mask & 1u) interp_claim_lane(interp, 0);
+ if (lane_mask & 2u) interp_claim_lane(interp, 1);
+}
+
+void interp_unclaim_lane(interp_hw_t *interp, uint lane) {
+ valid_params_if(INTERP, lane < 2);
+ uint bit = (interp_index(interp) << 1u) | lane;
+ hw_claim_clear((uint8_t *) &_claimed, bit);
+}
+
+void interp_save(interp_hw_t *interp, interp_hw_save_t *saver) {
+ saver->accum[0] = interp->accum[0];
+ saver->accum[1] = interp->accum[1];
+ saver->base[0] = interp->base[0];
+ saver->base[1] = interp->base[1];
+ saver->base[2] = interp->base[2];
+ saver->ctrl[0] = interp->ctrl[0];
+ saver->ctrl[1] = interp->ctrl[1];
+}
+
+void interp_restore(interp_hw_t *interp, interp_hw_save_t *saver) {
+ interp->accum[0] = saver->accum[0];
+ interp->accum[1] = saver->accum[1];
+ interp->base[0] = saver->base[0];
+ interp->base[1] = saver->base[1];
+ interp->base[2] = saver->base[2];
+ interp->ctrl[0] = saver->ctrl[0];
+ interp->ctrl[1] = saver->ctrl[1];
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_irq/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_irq/CMakeLists.txt
new file mode 100644
index 00000000000..c2182319d1c
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_irq/CMakeLists.txt
@@ -0,0 +1,6 @@
+pico_simple_hardware_target(irq)
+
+# additional sources/libraries
+
+target_sources(hardware_irq INTERFACE ${CMAKE_CURRENT_LIST_DIR}/irq_handler_chain.S)
+target_link_libraries(hardware_irq INTERFACE pico_sync)
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_irq/include/hardware/irq.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_irq/include/hardware/irq.h
new file mode 100644
index 00000000000..6075118f273
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_irq/include/hardware/irq.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_IRQ_H_
+#define _HARDWARE_IRQ_H_
+
+// These two config items are also used by assembler, so keeping separate
+// PICO_CONFIG: PICO_MAX_SHARED_IRQ_HANDLERS, Maximum Number of shared IRQ handers, default=4, advanced=true, group=hardware_irq
+#ifndef PICO_MAX_SHARED_IRQ_HANDLERS
+#define PICO_MAX_SHARED_IRQ_HANDLERS 4u
+#endif
+
+// PICO_CONFIG: PICO_DISABLE_SHARED_IRQ_HANDLERS, Disable shared IRQ handers, type=bool, default=0, group=hardware_irq
+#ifndef PICO_DISABLE_SHARED_IRQ_HANDLERS
+#define PICO_DISABLE_SHARED_IRQ_HANDLERS 0
+#endif
+
+#ifndef __ASSEMBLER__
+
+#include "pico.h"
+#include "hardware/regs/intctrl.h"
+#include "hardware/regs/m0plus.h"
+
+/** \file irq.h
+ * \defgroup hardware_irq hardware_irq
+ *
+ * Hardware interrupt handling
+ *
+ * The RP2040 uses the standard ARM nested vectored interrupt controller (NVIC).
+ *
+ * Interrupts are identified by a number from 0 to 31.
+ *
+ * On the RP2040, only the lower 26 IRQ signals are connected on the NVIC; IRQs 26 to 31 are tied to zero (never firing).
+ *
+ * There is one NVIC per core, and each core's NVIC has the same hardware interrupt lines routed to it, with the exception of the IO interrupts
+ * where there is one IO interrupt per bank, per core. These are completely independent, so for example, processor 0 can be
+ * interrupted by GPIO 0 in bank 0, and processor 1 by GPIO 1 in the same bank.
+ *
+ * \note That all IRQ APIs affect the executing core only (i.e. the core calling the function).
+ *
+ * \note You should not enable the same (shared) IRQ number on both cores, as this will lead to race conditions
+ * or starvation of one of the cores. Additionally don't forget that disabling interrupts on one core does not disable interrupts
+ * on the other core.
+ *
+ * There are three different ways to set handlers for an IRQ:
+ * - Calling irq_add_shared_handler() at runtime to add a handler for a multiplexed interrupt (e.g. GPIO bank) on the current core. Each handler, should check and clear the relevant hardware interrupt source
+ * - Calling irq_set_exclusive_handler() at runtime to install a single handler for the interrupt on the current core
+ * - Defining the interrupt handler explicitly in your application (e.g. by defining void `isr_dma_0` will make that function the handler for the DMA_IRQ_0 on core 0, and
+ * you will not be able to change it using the above APIs at runtime). Using this method can cause link conflicts at runtime, and offers no runtime performance benefit (i.e, it should not generally be used).
+ *
+ * \note If an IRQ is enabled and fires with no handler installed, a breakpoint will be hit and the IRQ number will
+ * be in r0.
+ *
+ * \section interrupt_nums Interrupt Numbers
+ *
+ * Interrupts are numbered as follows, a set of defines is available (intctrl.h) with these names to avoid using the numbers directly.
+ *
+ * IRQ | Interrupt Source
+ * ----|-----------------
+ * 0 | TIMER_IRQ_0
+ * 1 | TIMER_IRQ_1
+ * 2 | TIMER_IRQ_2
+ * 3 | TIMER_IRQ_3
+ * 4 | PWM_IRQ_WRAP
+ * 5 | USBCTRL_IRQ
+ * 6 | XIP_IRQ
+ * 7 | PIO0_IRQ_0
+ * 8 | PIO0_IRQ_1
+ * 9 | PIO1_IRQ_0
+ * 10 | PIO1_IRQ_1
+ * 11 | DMA_IRQ_0
+ * 12 | DMA_IRQ_1
+ * 13 | IO_IRQ_BANK0
+ * 14 | IO_IRQ_QSPI
+ * 15 | SIO_IRQ_PROC0
+ * 16 | SIO_IRQ_PROC1
+ * 17 | CLOCKS_IRQ
+ * 18 | SPI0_IRQ
+ * 19 | SPI1_IRQ
+ * 20 | UART0_IRQ
+ * 21 | UART1_IRQ
+ * 22 | ADC0_IRQ_FIFO
+ * 23 | I2C0_IRQ
+ * 24 | I2C1_IRQ
+ * 25 | RTC_IRQ
+ *
+ */
+
+// PICO_CONFIG: PICO_DEFAULT_IRQ_PRIORITY, Define the default IRQ priority, default=0x80, group=hardware_irq
+#ifndef PICO_DEFAULT_IRQ_PRIORITY
+#define PICO_DEFAULT_IRQ_PRIORITY 0x80
+#endif
+
+#define PICO_LOWEST_IRQ_PRIORITY 0x01
+#define PICO_HIGHEST_IRQ_PRIORITY 0xff
+
+// PICO_CONFIG: PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY, Set default shared IRQ order priority, default=0x80, group=hardware_irq
+#ifndef PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY
+#define PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY 0x80
+#endif
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_IRQ, Enable/disable assertions in the IRQ module, type=bool, default=0, group=hardware_irq
+#ifndef PARAM_ASSERTIONS_ENABLED_IRQ
+#define PARAM_ASSERTIONS_ENABLED_IRQ 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*! \brief Interrupt handler function type
+ * \ingroup hardware_irq
+ *
+ * All interrupts handlers should be of this type, and follow normal ARM EABI register saving conventions
+ */
+typedef void (*irq_handler_t)();
+
+/*! \brief Set specified interrupts priority
+ * \ingroup hardware_irq
+ *
+ * \param num Interrupt number
+ * \param hardware_priority Priority to set. Hardware priorities range from 0 (lowest) to 255 (highest) though only
+ * the top 2 bits are significant on ARM Cortex M0+. To make it easier to specify higher or lower priorities
+ * than the default, all IRQ priorities are initialized to PICO_DEFAULT_IRQ_PRIORITY by the SDK runtime at startup.
+ * PICO_DEFAULT_IRQ_PRIORITY defaults to 0x80
+ */
+void irq_set_priority(uint num, uint8_t hardware_priority);
+
+/*! \brief Enable or disable a specific interrupt on the executing core
+ * \ingroup hardware_irq
+ *
+ * \param num Interrupt number \ref interrupt_nums
+ * \param enabled true to enable the interrupt, false to disable
+ */
+void irq_set_enabled(uint num, bool enabled);
+
+/*! \brief Determine if a specific interrupt is enabled on the executing core
+ * \ingroup hardware_irq
+ *
+ * \param num Interrupt number \ref interrupt_nums
+ * \return true if the interrupt is enabled
+ */
+bool irq_is_enabled(uint num);
+
+/*! \brief Enable/disable multiple interrupts on the executing core
+ * \ingroup hardware_irq
+ *
+ * \param mask 32-bit mask with one bits set for the interrupts to enable/disable
+ * \param enabled true to enable the interrupts, false to disable them.
+ */
+void irq_set_mask_enabled(uint32_t mask, bool enabled);
+
+/*! \brief Set an exclusive interrupt handler for an interrupt on the executing core.
+ * \ingroup hardware_irq
+ *
+ * Use this method to set a handler for single IRQ source interrupts, or when
+ * your code, use case or performance requirements dictate that there should
+ * no other handlers for the interrupt.
+ *
+ * This method will assert if there is already any sort of interrupt handler installed
+ * for the specified irq number.
+ *
+ * \param num Interrupt number \ref interrupt_nums
+ * \param handler The handler to set. See \ref irq_handler_t
+ * \see irq_add_shared_handler
+ */
+void irq_set_exclusive_handler(uint num, irq_handler_t handler);
+
+/*! \brief Get the exclusive interrupt handler for an interrupt on the executing core.
+ * \ingroup hardware_irq
+ *
+ * This method will return an exclusive IRQ handler set on this core
+ * by irq_set_exclusive_handler if there is one.
+ *
+ * \param num Interrupt number \ref interrupt_nums
+ * \see irq_set_exclusive_handler
+ * \return handler The handler if an exclusive handler is set for the IRQ,
+ * NULL if no handler is set or shared/shareable handlers are installed
+ */
+irq_handler_t irq_get_exclusive_handler(uint num);
+
+/*! \brief Add a shared interrupt handler for an interrupt on the executing core
+ * \ingroup hardware_irq
+ *
+ * Use this method to add a handler on an irq number shared between multiple distinct hardware sources (e.g. GPIO, DMA or PIO IRQs).
+ * Handlers added by this method will all be called in sequence from highest order_priority to lowest. The
+ * irq_set_exclusive_handler() method should be used instead if you know there will or should only ever be one handler for the interrupt.
+ *
+ * This method will assert if there is an exclusive interrupt handler set for this irq number on this core, or if
+ * the (total across all IRQs on both cores) maximum (configurable via PICO_MAX_SHARED_IRQ_HANDLERS) number of shared handlers
+ * would be exceeded.
+ *
+ * \param num Interrupt number
+ * \param handler The handler to set. See \ref irq_handler_t
+ * \param order_priority The order priority controls the order that handlers for the same IRQ number on the core are called.
+ * The shared irq handlers for an interrupt are all called when an IRQ fires, however the order of the calls is based
+ * on the order_priority (higher priorities are called first, identical priorities are called in undefined order). A good
+ * rule of thumb is to use PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY if you don't much care, as it is in the middle of
+ * the priority range by default.
+ *
+ * \see irq_set_exclusive_handler
+ */
+void irq_add_shared_handler(uint num, irq_handler_t handler, uint8_t order_priority);
+
+/*! \brief Remove a specific interrupt handler for the given irq number on the executing core
+ * \ingroup hardware_irq
+ *
+ * This method may be used to remove an irq set via either irq_set_exclusive_handler() or
+ * irq_add_shared_handler(), and will assert if the handler is not currently installed for the given
+ * IRQ number
+ *
+ * \note This method may *only* be called from user (non IRQ code) or from within the handler
+ * itself (i.e. an IRQ handler may remove itself as part of handling the IRQ). Attempts to call
+ * from another IRQ will cause an assertion.
+ *
+ * \param num Interrupt number \ref interrupt_nums
+ * \param handler The handler to removed.
+ * \see irq_set_exclusive_handler
+ * \see irq_add_shared_handler
+ */
+void irq_remove_handler(uint num, irq_handler_t handler);
+
+/*! \brief Get the current IRQ handler for the specified IRQ from the currently installed hardware vector table (VTOR)
+ * of the execution core
+ * \ingroup hardware_irq
+ *
+ * \param num Interrupt number \ref interrupt_nums
+ * \return the address stored in the VTABLE for the given irq number
+ */
+irq_handler_t irq_get_vtable_handler(uint num);
+
+/*! \brief Clear a specific interrupt on the executing core
+ * \ingroup hardware_irq
+ *
+ * \param int_num Interrupt number \ref interrupt_nums
+ */
+static inline void irq_clear(uint int_num) {
+ *((volatile uint32_t *) (PPB_BASE + M0PLUS_NVIC_ICPR_OFFSET)) = (1u << ((uint32_t) (int_num & 0x1F)));
+}
+
+/*! \brief Force an interrupt to pending on the executing core
+ * \ingroup hardware_irq
+ *
+ * This should generally not be used for IRQs connected to hardware.
+ *
+ * \param num Interrupt number \ref interrupt_nums
+ */
+void irq_set_pending(uint num);
+
+
+/*! \brief Perform IRQ priority intiialization for the current core
+ *
+ * \note This is an internal method and user should generally not call it.
+ */
+void irq_init_priorities();
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_irq/irq.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_irq/irq.c
new file mode 100644
index 00000000000..255c00df808
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_irq/irq.c
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/irq.h"
+#include "hardware/regs/m0plus.h"
+#include "hardware/platform_defs.h"
+#include "hardware/structs/scb.h"
+
+#include "pico/mutex.h"
+#include "pico/assert.h"
+
+extern void __unhandled_user_irq();
+extern uint __get_current_exception();
+
+static inline irq_handler_t *get_vtable() {
+ return (irq_handler_t *) scb_hw->vtor;
+}
+
+static inline void *add_thumb_bit(void *addr) {
+ return (void *) (((uintptr_t) addr) | 0x1);
+}
+
+static inline void *remove_thumb_bit(void *addr) {
+ return (void *) (((uintptr_t) addr) & ~0x1);
+}
+
+static void set_raw_irq_handler_and_unlock(uint num, irq_handler_t handler, uint32_t save) {
+ // update vtable (vtable_handler may be same or updated depending on cases, but we do it anyway for compactness)
+ get_vtable()[16 + num] = handler;
+ __dmb();
+ spin_unlock(spin_lock_instance(PICO_SPINLOCK_ID_IRQ), save);
+}
+
+static inline void check_irq_param(uint num) {
+ invalid_params_if(IRQ, num >= NUM_IRQS);
+}
+
+void irq_set_enabled(uint num, bool enabled) {
+ check_irq_param(num);
+ irq_set_mask_enabled(1u << num, enabled);
+}
+
+bool irq_is_enabled(uint num) {
+ check_irq_param(num);
+ return 0 != ((1u << num) & *((io_rw_32 *) (PPB_BASE + M0PLUS_NVIC_ISER_OFFSET)));
+}
+
+void irq_set_mask_enabled(uint32_t mask, bool enabled) {
+ if (enabled) {
+ // Clear pending before enable
+ // (if IRQ is actually asserted, it will immediately re-pend)
+ *((io_rw_32 *) (PPB_BASE + M0PLUS_NVIC_ICPR_OFFSET)) = mask;
+ *((io_rw_32 *) (PPB_BASE + M0PLUS_NVIC_ISER_OFFSET)) = mask;
+ } else {
+ *((io_rw_32 *) (PPB_BASE + M0PLUS_NVIC_ICER_OFFSET)) = mask;
+ }
+}
+
+void irq_set_pending(uint num) {
+ check_irq_param(num);
+ *((io_rw_32 *) (PPB_BASE + M0PLUS_NVIC_ISPR_OFFSET)) = 1u << num;
+}
+
+#if PICO_MAX_SHARED_IRQ_HANDLERS
+// limited by 8 bit relative links (and reality)
+static_assert(PICO_MAX_SHARED_IRQ_HANDLERS >= 1 && PICO_MAX_SHARED_IRQ_HANDLERS < 0x7f, "");
+
+// note these are not real functions, they are code fragments (i.e. don't call them)
+extern void irq_handler_chain_first_slot();
+extern void irq_handler_chain_remove_tail();
+
+extern struct irq_handler_chain_slot {
+ // first 3 half words are executable code (raw vtable handler points to one slot, and inst3 will jump to next
+ // in chain (or end of chain handler)
+ uint16_t inst1;
+ uint16_t inst2;
+ uint16_t inst3;
+ union {
+ // when a handler is removed while executing, it needs an extra instruction, which overwrites
+ // the link and the priority; this is ok because no one else is modifying the chain, as
+ // the chain is effectively core local, and the user code which might still need this link
+ // disable the IRQ in question before updating, which means we aren't executing!
+ struct {
+ int8_t link;
+ uint8_t priority;
+ };
+ uint16_t inst4;
+ };
+ irq_handler_t handler;
+} irq_handler_chain_slots[PICO_MAX_SHARED_IRQ_HANDLERS];
+
+static int8_t irq_hander_chain_free_slot_head;
+#endif
+
+static inline bool is_shared_irq_raw_handler(irq_handler_t raw_handler) {
+ return (uintptr_t)raw_handler - (uintptr_t)irq_handler_chain_slots < sizeof(irq_handler_chain_slots);
+}
+
+irq_handler_t irq_get_vtable_handler(uint num) {
+ check_irq_param(num);
+ return get_vtable()[16 + num];
+}
+
+void irq_set_exclusive_handler(uint num, irq_handler_t handler) {
+ check_irq_param(num);
+#if !PICO_NO_RAM_VECTOR_TABLE
+ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_IRQ);
+ uint32_t save = spin_lock_blocking(lock);
+ __unused irq_handler_t current = irq_get_vtable_handler(num);
+ hard_assert(current == __unhandled_user_irq || current == handler);
+ set_raw_irq_handler_and_unlock(num, handler, save);
+#else
+ panic_unsupported();
+#endif
+}
+
+irq_handler_t irq_get_exclusive_handler(uint num) {
+ check_irq_param(num);
+#if !PICO_NO_RAM_VECTOR_TABLE
+ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_IRQ);
+ uint32_t save = spin_lock_blocking(lock);
+ irq_handler_t current = irq_get_vtable_handler(num);
+ spin_unlock(lock, save);
+ if (current == __unhandled_user_irq || is_shared_irq_raw_handler(current)) {
+ return NULL;
+ }
+ return current;
+#else
+ panic_unsupported();
+#endif
+}
+
+
+static uint16_t make_branch(uint16_t *from, void *to) {
+ uint32_t ui_from = (uint32_t)from;
+ uint32_t ui_to = (uint32_t)to;
+ uint32_t delta = (ui_to - ui_from - 4) / 2;
+ assert(!(delta >> 11u));
+ return 0xe000 | (delta & 0x7ff);
+}
+
+static void insert_branch_and_link(uint16_t *from, void *to) {
+ uint32_t ui_from = (uint32_t)from;
+ uint32_t ui_to = (uint32_t)to;
+ uint32_t delta = (ui_to - ui_from - 4) / 2;
+ assert(!(delta >> 11u));
+ from[0] = 0xf000 | ((delta >> 11u) & 0x7ffu);
+ from[1] = 0xf800 | (delta & 0x7ffu);
+}
+
+static inline void *resolve_branch(uint16_t *inst) {
+ assert(0x1c == (*inst)>>11u);
+ int32_t i_addr = (*inst) << 21u;
+ i_addr /= (int32_t)(1u<<21u);
+ return inst + 2 + i_addr;
+}
+
+// GCC produces horrible code for subtraction of pointers here, and it was bugging me
+static inline int8_t slot_diff(struct irq_handler_chain_slot *to, struct irq_handler_chain_slot *from) {
+ static_assert(sizeof(struct irq_handler_chain_slot) == 12, "");
+ int32_t result;
+ // return (to - from);
+ // note this implementation has limited range, but is fine for plenty more than -128->127 result
+ asm (".syntax unified\n"
+ "subs %1, %2\n"
+ "adcs %1, %1\n" // * 2 (and + 1 if negative for rounding)
+ "ldr %0, =0xaaaa\n"
+ "muls %0, %1\n"
+ "lsrs %0, 20\n"
+ : "=l" (result), "+l" (to)
+ : "l" (from)
+ :
+ );
+ return result;
+}
+
+void irq_add_shared_handler(uint num, irq_handler_t handler, uint8_t order_priority) {
+ check_irq_param(num);
+#if PICO_DISABLE_SHARED_IRQ_HANDLERS
+
+#endif
+#if PICO_NO_RAM_VECTOR_TABLE || !PICO_MAX_SHARED_IRQ_HANDLERS
+ panic_unsupported()
+#else
+ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_IRQ);
+ uint32_t save = spin_lock_blocking(lock);
+ hard_assert(irq_hander_chain_free_slot_head >= 0);
+ struct irq_handler_chain_slot *slot = &irq_handler_chain_slots[irq_hander_chain_free_slot_head];
+ int slot_index = irq_hander_chain_free_slot_head;
+ irq_hander_chain_free_slot_head = slot->link;
+ irq_handler_t vtable_handler = get_vtable()[16 + num];
+ if (!is_shared_irq_raw_handler(vtable_handler)) {
+ // start new chain
+ hard_assert(vtable_handler == __unhandled_user_irq);
+ struct irq_handler_chain_slot slot_data = {
+ .inst1 = 0xa100, // add r1, pc, #0
+ .inst2 = make_branch(&slot->inst2, irq_handler_chain_first_slot), // b irq_handler_chain_first_slot
+ .inst3 = 0xbd00, // pop {pc}
+ .link = -1,
+ .priority = order_priority,
+ .handler = handler
+ };
+ *slot = slot_data;
+ vtable_handler = (irq_handler_t)add_thumb_bit(slot);
+ } else {
+ assert(!((((uintptr_t)vtable_handler) - ((uintptr_t)irq_handler_chain_slots) - 1)%sizeof(struct irq_handler_chain_slot)));
+ struct irq_handler_chain_slot *prev_slot = NULL;
+ struct irq_handler_chain_slot *existing_vtable_slot = remove_thumb_bit(vtable_handler);
+ struct irq_handler_chain_slot *cur_slot = existing_vtable_slot;
+ while (cur_slot->priority > order_priority) {
+ prev_slot = cur_slot;
+ if (cur_slot->link < 0) break;
+ cur_slot = &irq_handler_chain_slots[cur_slot->link];
+ }
+ if (prev_slot) {
+ // insert into chain
+ struct irq_handler_chain_slot slot_data = {
+ .inst1 = 0x4801, // ldr r0, [pc, #4]
+ .inst2 = 0x4780, // blx r0
+ .inst3 = prev_slot->link >= 0 ?
+ make_branch(&slot->inst3, resolve_branch(&prev_slot->inst3)) : // b next_slot
+ 0xbd00, // pop {pc}
+ .link = prev_slot->link,
+ .priority = order_priority,
+ .handler = handler
+ };
+ // update code and data links
+ prev_slot->inst3 = make_branch(&prev_slot->inst3, slot),
+ prev_slot->link = slot_index;
+ *slot = slot_data;
+ } else {
+ // update with new chain head
+ struct irq_handler_chain_slot slot_data = {
+ .inst1 = 0xa100, // add r1, pc, #0
+ .inst2 = make_branch(&slot->inst2, irq_handler_chain_first_slot), // b irq_handler_chain_first_slot
+ .inst3 = make_branch(&slot->inst3, existing_vtable_slot), // b existing_slot
+ .link = slot_diff(existing_vtable_slot, irq_handler_chain_slots),
+ .priority = order_priority,
+ .handler = handler
+ };
+ *slot = slot_data;
+ // fixup previous head slot
+ existing_vtable_slot->inst1 = 0x4801; // ldr r0, [pc, #4]
+ existing_vtable_slot->inst2 = 0x4780; // blx r0
+ vtable_handler = (irq_handler_t)add_thumb_bit(slot);
+ }
+ }
+ set_raw_irq_handler_and_unlock(num, vtable_handler, save);
+#endif
+}
+
+void irq_remove_handler(uint num, irq_handler_t handler) {
+#if !PICO_NO_RAM_VECTOR_TABLE
+ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_IRQ);
+ uint32_t save = spin_lock_blocking(lock);
+ irq_handler_t vtable_handler = get_vtable()[16 + num];
+ if (vtable_handler != __unhandled_user_irq && vtable_handler != handler) {
+#if !PICO_DISABLE_SHARED_IRQ_HANDLERS && PICO_MAX_SHARED_IRQ_HANDLERS
+ if (is_shared_irq_raw_handler(vtable_handler)) {
+ // This is a bit tricky, as an executing IRQ handler doesn't take a lock.
+
+ // First thing to do is to disable the IRQ in question; that takes care of calls from user code.
+ // Note that a irq handler chain is local to our own core, so we don't need to worry about the other core
+ bool was_enabled = irq_is_enabled(num);
+ irq_set_enabled(num, false);
+ __dmb();
+
+ // It is possible we are being called while an IRQ for this chain is already in progress.
+ // The issue we have here is that we must not free a slot that is currently being executed, because
+ // inst3 is still to be executed, and inst3 might get overwritten if the slot is re-used.
+
+ // By disallowing other exceptions from removing an IRQ handler (which seems fair)
+ // we now only have to worry about removing a slot from a chain that is currently executing.
+
+ // Note we expect that the slot we are deleting is the one that is executing.
+ // In particular, bad things happen if the caller were to delete the handler in the chain
+ // before it. This is not an allowed use case though, and I can't imagine anyone wanting to in practice.
+ // Sadly this is not something we can detect.
+
+ uint exception = __get_current_exception();
+ hard_assert(!exception || exception == num + 16);
+
+ struct irq_handler_chain_slot *prev_slot = NULL;
+ struct irq_handler_chain_slot *existing_vtable_slot = remove_thumb_bit(vtable_handler);
+ struct irq_handler_chain_slot *to_free_slot = existing_vtable_slot;
+ int to_free_slot_index = to_free_slot - irq_handler_chain_slots;
+ while (to_free_slot->handler != handler) {
+ prev_slot = to_free_slot;
+ if (to_free_slot->link < 0) break;
+ to_free_slot = &irq_handler_chain_slots[to_free_slot->link];
+ }
+ if (to_free_slot->handler == handler) {
+ int next_slot_index = to_free_slot->link;
+ if (next_slot_index >= 0) {
+ // There is another slot in the chain, so copy that over us, so that our inst3 points at something valid
+ // Note this only matters in the exception case anyway, and it that case, we will skip the next handler,
+ // however in that case it's IRQ cause should immediately cause re-entry of the IRQ and the only side
+ // effect will be that there was potentially brief out of priority order execution of the handlers
+ struct irq_handler_chain_slot *next_slot = &irq_handler_chain_slots[next_slot_index];
+ to_free_slot->handler = next_slot->handler;
+ to_free_slot->priority = next_slot->priority;
+ to_free_slot->link = next_slot->link;
+ to_free_slot->inst3 = next_slot->link >= 0 ?
+ make_branch(&to_free_slot->inst3, resolve_branch(&next_slot->inst3)) : // b mext_>slot->next_slot
+ 0xbd00; // pop {pc}
+
+ // add old next slot back to free list
+ next_slot->link = irq_hander_chain_free_slot_head;
+ irq_hander_chain_free_slot_head = next_slot_index;
+ } else {
+ // Slot being removed is at the end of the chain
+ if (!exception) {
+ // case when we're not in exception, we physically unlink now
+ if (prev_slot) {
+ // chain is not empty
+ prev_slot->link = -1;
+ prev_slot->inst3 = 0xbd00; // pop {pc}
+ } else {
+ // chain is not empty
+ vtable_handler = __unhandled_user_irq;
+ }
+ // add slot back to free list
+ to_free_slot->link = irq_hander_chain_free_slot_head;
+ irq_hander_chain_free_slot_head = to_free_slot_index;
+ } else {
+ // since we are the last slot we know that our inst3 hasn't executed yet, so we change
+ // it to bl to irq_handler_chain_remove_tail which will remove the slot.
+ // NOTE THAT THIS TRASHES PRIORITY AND LINK SINCE THIS IS A 4 BYTE INSTRUCTION
+ // BUT THEY ARE NOT NEEDED NOW
+ insert_branch_and_link(&to_free_slot->inst3, irq_handler_chain_remove_tail);
+ }
+ }
+ } else {
+ assert(false); // not found
+ }
+ irq_set_enabled(num, was_enabled);
+ }
+#else
+ assert(false); // not found
+#endif
+ } else {
+ vtable_handler = __unhandled_user_irq;
+ }
+ set_raw_irq_handler_and_unlock(num, vtable_handler, save);
+#else
+ panic_unsupported();
+#endif
+}
+
+void irq_set_priority(uint num, uint8_t hardware_priority) {
+ check_irq_param(num);
+
+ // note that only 32 bit writes are supported
+ io_rw_32 *p = (io_rw_32 *)((PPB_BASE + M0PLUS_NVIC_IPR0_OFFSET) + (num & ~3u));
+ *p = (*p & ~(0xffu << (8 * (num & 3u)))) | (((uint32_t) hardware_priority) << (8 * (num & 3u)));
+}
+
+#if !PICO_DISABLE_SHARED_IRQ_HANDLERS && PICO_MAX_SHARED_IRQ_HANDLERS
+// used by irq_handler_chain.S to remove the last link in a handler chain after it executes
+// note this must be called only with the last slot in a chain (and during the exception)
+void irq_add_tail_to_free_list(struct irq_handler_chain_slot *slot) {
+ irq_handler_t slot_handler = (irq_handler_t) add_thumb_bit(slot);
+ assert(is_shared_irq_raw_handler(slot_handler));
+
+ int exception = __get_current_exception();
+ assert(exception);
+ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_IRQ);
+ uint32_t save = spin_lock_blocking(lock);
+ int slot_index = slot - irq_handler_chain_slots;
+ if (slot_handler == get_vtable()[exception]) {
+ get_vtable()[exception] = __unhandled_user_irq;
+ } else {
+ bool __unused found = false;
+ // need to find who points at the slot and update it
+ for(uint i=0;ilink = irq_hander_chain_free_slot_head;
+ irq_hander_chain_free_slot_head = slot_index;
+ spin_unlock(lock, save);
+}
+#endif
+
+void irq_init_priorities() {
+#if PICO_DEFAULT_IRQ_PRIORITY != 0
+ for (uint irq = 0; irq < NUM_IRQS; irq++) {
+ irq_set_priority(irq, PICO_DEFAULT_IRQ_PRIORITY);
+ }
+#endif
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_irq/irq_handler_chain.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_irq/irq_handler_chain.S
new file mode 100644
index 00000000000..6a8a4b688f3
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_irq/irq_handler_chain.S
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/platform_defs.h"
+#include "hardware/irq.h"
+
+#if !PICO_DISABLE_SHARED_IRQ_HANDLERS
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+.data
+.align 2
+
+.global irq_handler_chain_slots
+
+.global irq_handler_chain_first_slot
+.global irq_handler_chain_remove_tail
+
+//
+// These Slots make up the code and structure of the handler chains; the only external information are the VTABLE entries
+// (obviously one set per core) and a free list head. Each individual handler chain starts with the VTABLE entry I
+// pointing at the address of slot S (with thumb bit set). Thus each slot which is part of a chain is executble.
+//
+// The execution jumps (via branch instruction) from one slot to the other, then jumps to the end of chain handler.
+// The entirety of the state needed to traverse the chain is contained within the slots of the chain, which is why
+// a VTABLE entry is all that is needed per chain (rather than requiring a separarte set of head pointers)
+//
+
+irq_handler_chain_slots:
+.set next_slot_number, 1
+.rept PICO_MAX_SHARED_IRQ_HANDLERS
+ // a slot is executable and is always 3 instructions long.
+ .hword 0 // inst1 (either: ldr r0, [pc, #4] or for the FIRST slot : add r1, pc, #0 )
+ .hword 0 // inst2 ( blx r0 b irq_handler_chain_first_slot )
+
+ .hword 0 // inst3 (either: b next_slot or for the LAST pop {pc} )
+
+ // next is a single byte index of next slot in chain (or -1 to end)
+.if next_slot_number == PICO_MAX_SHARED_IRQ_HANDLERS
+ .byte 0xff
+.else
+ .byte next_slot_number
+.endif
+ // next is the 8 bit unsigned priority
+ .byte 0x00
+1:
+ // and finally the handler function pointer
+ .word 0x00000000
+ .set next_slot_number, next_slot_number + 1
+.endr
+
+irq_handler_chain_first_slot:
+ push {lr}
+ ldr r0, [r1, #4]
+ adds r1, #1
+ mov lr, r1
+ bx r0
+irq_handler_chain_remove_tail:
+ mov r0, lr
+ subs r0, #9
+ ldr r1, =irq_add_tail_to_free_list
+ blx r1
+ pop {pc}
+
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pio/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pio/CMakeLists.txt
new file mode 100644
index 00000000000..ad018690bca
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pio/CMakeLists.txt
@@ -0,0 +1,4 @@
+pico_simple_hardware_target(pio)
+
+# additional libraries
+target_link_libraries(hardware_pio INTERFACE hardware_gpio hardware_claim)
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pio/include/hardware/pio.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pio/include/hardware/pio.h
new file mode 100644
index 00000000000..68975a9777f
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pio/include/hardware/pio.h
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_PIO_H_
+#define _HARDWARE_PIO_H_
+
+#include "pico.h"
+#include "hardware/address_mapped.h"
+#include "hardware/structs/pio.h"
+#include "hardware/gpio.h"
+#include "hardware/regs/dreq.h"
+#include "hardware/pio_instructions.h"
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_PIO, Enable/disable assertions in the PIO module, type=bool, default=0, group=hardware_pio
+#ifndef PARAM_ASSERTIONS_ENABLED_PIO
+#define PARAM_ASSERTIONS_ENABLED_PIO 0
+#endif
+
+/** \file hardware/pio.h
+ * \defgroup hardware_pio hardware_pio
+ *
+ * Programmable I/O (PIO) API
+ *
+ * A programmable input/output block (PIO) is a versatile hardware interface which
+ * can support a number of different IO standards. There are two PIO blocks in the RP2040
+ *
+ * Each PIO is programmable in the same sense as a processor: the four state machines independently
+ * execute short, sequential programs, to manipulate GPIOs and transfer data. Unlike a general
+ * purpose processor, PIO state machines are highly specialised for IO, with a focus on determinism,
+ * precise timing, and close integration with fixed-function hardware. Each state machine is equipped
+ * with:
+ * * Two 32-bit shift registers – either direction, any shift count
+ * * Two 32-bit scratch registers
+ * * 4×32 bit bus FIFO in each direction (TX/RX), reconfigurable as 8×32 in a single direction
+ * * Fractional clock divider (16 integer, 8 fractional bits)
+ * * Flexible GPIO mapping
+ * * DMA interface, sustained throughput up to 1 word per clock from system DMA
+ * * IRQ flag set/clear/status
+ *
+ * Full details of the PIO can be found in the RP2040 datasheet.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static_assert(PIO_SM0_SHIFTCTRL_FJOIN_RX_LSB == PIO_SM0_SHIFTCTRL_FJOIN_TX_LSB + 1, "");
+
+/** \brief FIFO join states
+ * \ingroup hardware_pio
+ */
+enum pio_fifo_join {
+ PIO_FIFO_JOIN_NONE = 0,
+ PIO_FIFO_JOIN_TX = 1,
+ PIO_FIFO_JOIN_RX = 2,
+};
+
+enum pio_mov_status_type {
+ STATUS_TX_LESSTHAN = 0,
+ STATUS_RX_LESSTHAN = 1
+};
+
+typedef pio_hw_t *PIO;
+
+/** Identifier for the first (PIO 0) hardware PIO instance (for use in PIO functions).
+ *
+ * e.g. pio_gpio_init(pio0, 5)
+ *
+ * \ingroup hardware_pio
+ * @{
+ */
+#define pio0 pio0_hw
+/** @} */
+
+/** Identifier for the second (PIO 1) hardware PIO instance (for use in PIO functions).
+ *
+ * e.g. pio_gpio_init(pio1, 5)
+ *
+ * \ingroup hardware_pio
+ * @{
+ */
+#define pio1 pio1_hw
+/** @} */
+
+/** \brief PIO state machine configuration
+ * \defgroup sm_config sm_config
+ * \ingroup hardware_pio
+ *
+ * A PIO block needs to be configured, these functions provide helpers to set up configuration
+ * structures. See \ref pio_sm_set_config
+ *
+ */
+
+/** \brief PIO Configuration structure
+ * \ingroup sm_config
+ */
+typedef struct {
+ uint32_t clkdiv;
+ uint32_t execctrl;
+ uint32_t shiftctrl;
+ uint32_t pinctrl;
+} pio_sm_config;
+
+static inline void check_sm_param(uint sm) {
+ valid_params_if(PIO, sm < NUM_PIO_STATE_MACHINES);
+}
+
+/*! \brief Set the 'out' pins in a state machine configuration
+ * \ingroup sm_config
+ *
+ * Can overlap with the 'in', 'set' and 'sideset' pins
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param out_base 0-31 First pin to set as output
+ * \param out_count 0-32 Number of pins to set.
+ */
+static inline void sm_config_set_out_pins(pio_sm_config *c, uint out_base, uint out_count) {
+ assert(out_base < 32);
+ assert(out_count <= 32);
+ c->pinctrl = (c->pinctrl & ~(PIO_SM0_PINCTRL_OUT_BASE_BITS | PIO_SM0_PINCTRL_OUT_COUNT_BITS)) |
+ (out_base << PIO_SM0_PINCTRL_OUT_BASE_LSB) |
+ (out_count << PIO_SM0_PINCTRL_OUT_COUNT_LSB);
+}
+
+/*! \brief Set the 'set' pins in a state machine configuration
+ * \ingroup sm_config
+ *
+ * Can overlap with the 'in', 'out' and 'sideset' pins
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param set_base 0-31 First pin to set as
+ * \param set_count 0-5 Number of pins to set.
+ */
+static inline void sm_config_set_set_pins(pio_sm_config *c, uint set_base, uint set_count) {
+ assert(set_base < 32);
+ assert(set_count <= 5);
+ c->pinctrl = (c->pinctrl & ~(PIO_SM0_PINCTRL_SET_BASE_BITS | PIO_SM0_PINCTRL_SET_COUNT_BITS)) |
+ (set_base << PIO_SM0_PINCTRL_SET_BASE_LSB) |
+ (set_count << PIO_SM0_PINCTRL_SET_COUNT_LSB);
+}
+
+/*! \brief Set the 'in' pins in a state machine configuration
+ * \ingroup sm_config
+ *
+ * Can overlap with the 'out', ''set' and 'sideset' pins
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param in_base 0-31 First pin to set as input
+ */
+static inline void sm_config_set_in_pins(pio_sm_config *c, uint in_base) {
+ assert(in_base < 32);
+ c->pinctrl = (c->pinctrl & ~PIO_SM0_PINCTRL_IN_BASE_BITS) |
+ (in_base << PIO_SM0_PINCTRL_IN_BASE_LSB);
+}
+
+/*! \brief Set the 'sideset' pins in a state machine configuration
+ * \ingroup sm_config
+ *
+ * Can overlap with the 'in', 'out' and 'set' pins
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param sideset_base base pin for 'side set'
+ */
+static inline void sm_config_set_sideset_pins(pio_sm_config *c, uint sideset_base) {
+ assert(sideset_base < 32);
+ c->pinctrl = (c->pinctrl & ~PIO_SM0_PINCTRL_SIDESET_BASE_BITS) |
+ (sideset_base << PIO_SM0_PINCTRL_SIDESET_BASE_LSB);
+}
+
+/*! \brief Set the 'sideset' options in a state machine configuration
+ * \ingroup sm_config
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param bit_count Number of bits to steal from delay field in the instruction for use of side set
+ * \param optional True if the topmost side set bit is used as a flag for whether to apply side set on that instruction
+ * \param pindirs True if the side set affects pin directions rather than values
+ */
+static inline void sm_config_set_sideset(pio_sm_config *c, uint bit_count, bool optional, bool pindirs) {
+ assert(bit_count <= 32);
+ c->pinctrl = (c->pinctrl & ~PIO_SM0_PINCTRL_SIDESET_COUNT_BITS) |
+ (bit_count << PIO_SM0_PINCTRL_SIDESET_COUNT_LSB);
+
+ c->execctrl = (c->execctrl & ~(PIO_SM0_EXECCTRL_SIDE_EN_BITS | PIO_SM0_EXECCTRL_SIDE_PINDIR_BITS)) |
+ (!!optional << PIO_SM0_EXECCTRL_SIDE_EN_LSB) |
+ (!!pindirs << PIO_SM0_EXECCTRL_SIDE_PINDIR_LSB);
+}
+
+/*! \brief Set the state machine clock divider (from a floating point value) in a state machine configuration
+ * \ingroup sm_config
+ *
+ * The clock divider acts on the system clock to provide a clock for the state machine.
+ * See the datasheet for more details.
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param div The fractional divisor to be set. 1 for full speed. An integer clock divisor of n
+ * will cause the state machine to run 1 cycle in every n.
+ * Note that for small n, the jitter introduced by a fractional divider (e.g. 2.5) may be unacceptable
+ * although it will depend on the use case.
+ */
+static inline void sm_config_set_clkdiv(pio_sm_config *c, float div) {
+ uint16_t div_int = (uint16_t) div;
+ uint8_t div_frac = (uint8_t) ((div - div_int) * (1u << 8u));
+ c->clkdiv =
+ (div_frac << PIO_SM0_CLKDIV_FRAC_LSB) |
+ (div_int << PIO_SM0_CLKDIV_INT_LSB);
+}
+
+/*! \brief Set the state machine clock divider (from integer and fractional parts - 16:8) in a state machine configuration
+ * \ingroup sm_config
+ *
+ * The clock divider acts on the system clock to provide a clock for the state machine.
+ * See the datasheet for more details.
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param div_int Integer part of the divisor
+ * \param div_frac Fractional part in 1/256ths
+ * \sa sm_config_set_clkdiv
+ */
+static inline void sm_config_set_clkdiv_int_frac(pio_sm_config *c, uint16_t div_int, uint8_t div_frac) {
+ c->clkdiv =
+ (div_frac << PIO_SM0_CLKDIV_FRAC_LSB) |
+ (div_int << PIO_SM0_CLKDIV_INT_LSB);
+}
+
+/*! \brief Set the wrap addresses in a state machine configuration
+ * \ingroup sm_config
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param wrap_target the instruction memory address to wrap to
+ * \param wrap the instruction memory address after which to set the program counter to wrap_target
+ * if the instruction does not itself update the program_counter
+ */
+static inline void sm_config_set_wrap(pio_sm_config *c, uint wrap_target, uint wrap) {
+ assert(wrap < PIO_INSTRUCTION_COUNT);
+ assert(wrap_target < PIO_INSTRUCTION_COUNT);
+ c->execctrl = (c->execctrl & ~(PIO_SM0_EXECCTRL_WRAP_TOP_BITS | PIO_SM0_EXECCTRL_WRAP_BOTTOM_BITS)) |
+ (wrap_target << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB) |
+ (wrap << PIO_SM0_EXECCTRL_WRAP_TOP_LSB);
+}
+
+/*! \brief Set the 'jmp' pin in a state machine configuration
+ * \ingroup sm_config
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param pin The raw GPIO pin number to use as the source for a `jmp pin` instruction
+ */
+static inline void sm_config_set_jmp_pin(pio_sm_config *c, uint pin) {
+ assert(pin < 32);
+ c->execctrl = (c->execctrl & ~PIO_SM0_EXECCTRL_JMP_PIN_BITS) |
+ (pin << PIO_SM0_EXECCTRL_JMP_PIN_LSB);
+}
+
+/*! \brief Setup 'in' shifting parameters in a state machine configuration
+ * \ingroup sm_config
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param shift_right true to shift ISR to right, false to shift ISR to left
+ * \param autopush whether autopush is enabled
+ * \param push_threshold threshold in bits to shift in before auto/conditional re-pushing of the ISR
+ */
+static inline void sm_config_set_in_shift(pio_sm_config *c, bool shift_right, bool autopush, uint push_threshold) {
+ valid_params_if(PIO, push_threshold <= 32);
+ c->shiftctrl = (c->shiftctrl &
+ ~(PIO_SM0_SHIFTCTRL_IN_SHIFTDIR_BITS |
+ PIO_SM0_SHIFTCTRL_AUTOPUSH_BITS |
+ PIO_SM0_SHIFTCTRL_PUSH_THRESH_BITS)) |
+ (!!shift_right << PIO_SM0_SHIFTCTRL_IN_SHIFTDIR_LSB) |
+ (!!autopush << PIO_SM0_SHIFTCTRL_AUTOPUSH_LSB) |
+ ((push_threshold & 0x1fu) << PIO_SM0_SHIFTCTRL_PUSH_THRESH_LSB);
+}
+
+/*! \brief Setup 'out' shifting parameters in a state machine configuration
+ * \ingroup sm_config
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param shift_right true to shift OSR to right, false to shift OSR to left
+ * \param autopull whether autopull is enabled
+ * \param pull_threshold threshold in bits to shift out before auto/conditional re-pulling of the OSR
+ */
+static inline void sm_config_set_out_shift(pio_sm_config *c, bool shift_right, bool autopull, uint pull_threshold) {
+ valid_params_if(PIO, pull_threshold <= 32);
+ c->shiftctrl = (c->shiftctrl &
+ ~(PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_BITS |
+ PIO_SM0_SHIFTCTRL_AUTOPULL_BITS |
+ PIO_SM0_SHIFTCTRL_PULL_THRESH_BITS)) |
+ (!!shift_right << PIO_SM0_SHIFTCTRL_OUT_SHIFTDIR_LSB) |
+ (!!autopull << PIO_SM0_SHIFTCTRL_AUTOPULL_LSB) |
+ ((pull_threshold & 0x1fu) << PIO_SM0_SHIFTCTRL_PULL_THRESH_LSB);
+}
+
+/*! \brief Setup the FIFO joining in a state machine configuration
+ * \ingroup sm_config
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param join Specifies the join type. \see enum pio_fifo_join
+ */
+static inline void sm_config_set_fifo_join(pio_sm_config *c, enum pio_fifo_join join) {
+ assert(join >= 0 && join <= 2);
+ c->shiftctrl = (c->shiftctrl & ~(PIO_SM0_SHIFTCTRL_FJOIN_TX_BITS | PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS)) |
+ (join << PIO_SM0_SHIFTCTRL_FJOIN_TX_LSB);
+}
+
+/*! \brief Set special 'out' operations in a state machine configuration
+ * \ingroup sm_config
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param sticky to enable 'sticky' output (i.e. re-asserting most recent OUT/SET pin values on subsequent cycles)
+ * \param has_enable_pin true to enable auxiliary OUT enable pin
+ * \param enable_pin_index pin index for auxiliary OUT enable
+ */
+static inline void sm_config_set_out_special(pio_sm_config *c, bool sticky, bool has_enable_pin, int enable_pin_index) {
+ c->execctrl = (c->execctrl &
+ ~(PIO_SM0_EXECCTRL_OUT_STICKY_BITS | PIO_SM0_EXECCTRL_INLINE_OUT_EN_BITS |
+ PIO_SM0_EXECCTRL_OUT_EN_SEL_BITS)) |
+ (!!sticky << PIO_SM0_EXECCTRL_OUT_STICKY_LSB) |
+ (!!has_enable_pin << PIO_SM0_EXECCTRL_INLINE_OUT_EN_LSB) |
+ ((enable_pin_index << PIO_SM0_EXECCTRL_OUT_EN_SEL_LSB) & PIO_SM0_EXECCTRL_OUT_EN_SEL_BITS);
+}
+
+/*! \brief Set source for 'mov status' in a state machine configuration
+ * \ingroup sm_config
+ *
+ * \param c Pointer to the configuration structure to modify
+ * \param status_sel the status operation selector
+ * \param status_n parameter for the mov status operation (currently a bit count)
+ */
+static inline void sm_config_set_mov_status(pio_sm_config *c, enum pio_mov_status_type status_sel, uint status_n) {
+ c->execctrl = (c->execctrl
+ & ~(PIO_SM0_EXECCTRL_STATUS_SEL_BITS | PIO_SM0_EXECCTRL_STATUS_N_BITS))
+ | ((status_sel << PIO_SM0_EXECCTRL_STATUS_SEL_LSB) & PIO_SM0_EXECCTRL_STATUS_SEL_BITS)
+ | ((status_n << PIO_SM0_EXECCTRL_STATUS_N_LSB) & PIO_SM0_EXECCTRL_STATUS_N_BITS);
+}
+
+
+/*! \brief Get the default state machine configuration
+ * \ingroup sm_config
+ *
+ * Setting | Default
+ * --------|--------
+ * Out Pins | 32 starting at 0
+ * Set Pins | 0 starting at 0
+ * In Pins (base) | 0
+ * Side Set Pins (base) | 0
+ * Side Set | disabled
+ * Wrap | wrap=31, wrap_to=0
+ * In Shift | shift_direction=right, autopush=false, push_thrshold=32
+ * Out Shift | shift_direction=right, autopull=false, pull_thrshold=32
+ * Jmp Pin | 0
+ * Out Special | sticky=false, has_enable_pin=false, enable_pin_index=0
+ * Mov Status | status_sel=STATUS_TX_LESSTHAN, n=0
+ *
+ * \return the default state machine configuration which can then be modified.
+ */
+static inline pio_sm_config pio_get_default_sm_config() {
+ pio_sm_config c = {0, 0, 0};
+ sm_config_set_clkdiv_int_frac(&c, 1, 0);
+ sm_config_set_wrap(&c, 0, 31);
+ sm_config_set_in_shift(&c, true, false, 32);
+ sm_config_set_out_shift(&c, true, false, 32);
+ return c;
+}
+
+/*! \brief Apply a state machine configuration to a state machine
+ * \ingroup hardware_pio
+ *
+ * \param pio Handle to PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param config the configuration to apply
+*/
+static inline void pio_sm_set_config(PIO pio, uint sm, const pio_sm_config *config) {
+ check_sm_param(sm);
+ pio->sm[sm].clkdiv = config->clkdiv;
+ pio->sm[sm].execctrl = config->execctrl;
+ pio->sm[sm].shiftctrl = config->shiftctrl;
+ pio->sm[sm].pinctrl = config->pinctrl;
+}
+
+/*! \brief Return the instance number of a PIO instance
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \return the PIO instance number (either 0 or 1)
+ */
+static inline uint pio_get_index(PIO pio) {
+ assert(pio == pio0 || pio == pio1);
+ return pio == pio1 ? 1 : 0;
+}
+
+/*! \brief Setup the function select for a GPIO to use output from the given PIO instance
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param pin the GPIO pin whose function select to set
+ */
+static inline void pio_gpio_init(PIO pio, uint pin) {
+ assert(pio == pio0 || pio == pio1);
+ gpio_set_function(pin, pio == pio0 ? GPIO_FUNC_PIO0 : GPIO_FUNC_PIO1);
+}
+
+/*! \brief Return the DREQ to use for pacing transfers to a particular state machine
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param is_tx true for sending data to the state machine, false for received data from the state machine
+ */
+static inline uint pio_get_dreq(PIO pio, uint sm, bool is_tx) {
+ assert(pio == pio0 || pio == pio1);
+ check_sm_param(sm);
+ return sm + (is_tx ? 0 : NUM_PIO_STATE_MACHINES) + (pio == pio0 ? DREQ_PIO0_TX0 : DREQ_PIO1_TX0);
+}
+
+typedef struct pio_program {
+ const uint16_t *instructions;
+ uint8_t length;
+ int8_t origin; // required instruction memory origin or -1
+} __packed pio_program_t;
+
+/*! \brief Determine whether the given program can (at the time of the call) be loaded onto the PIO instance
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param program the program definition
+ * \return true if the program can be loaded; false if there is not suitable space in the instruction memory
+ */
+bool pio_can_add_program(PIO pio, const pio_program_t *program);
+
+/*! \brief Determine whether the given program can (at the time of the call) be loaded onto the PIO instance starting at a particular location
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param program the program definition
+ * \param offset the instruction memory offset wanted for the start of the program
+ * \return true if the program can be loaded at that location; false if there is not space in the instruction memory
+ */
+bool pio_can_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset);
+
+/*! \brief Attempt to load the program, panicking if not possible
+ * \ingroup hardware_pio
+ *
+ * \see pico_can_add_program if you need to check whether the program can be loaded
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param program the program definition
+ * \return the instruction memory offset the program is loaded at
+ */
+uint pio_add_program(PIO pio, const pio_program_t *program);
+
+/*! \brief Attempt to load the program at the specified instruction memory offset, panicking if not possible
+ * \ingroup hardware_pio
+ *
+ * \see pico_can_add_program_at_offset if you need to check whether the program can be loaded
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param program the program definition
+ * \param offset the instruction memory offset wanted for the start of the program
+ */
+void pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset);
+
+/*! \brief Remove a program from a PIO instance's instruction memory
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param program the program definition
+ * \param loaded_offset the loaded offset returned when the program was added
+ */
+void pio_remove_program(PIO pio, const pio_program_t *program, uint loaded_offset);
+
+/*! \brief Clears all of a PIO instance's instruction memory
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ */
+void pio_clear_instruction_memory(PIO pio);
+
+/*! \brief Resets the state machine to a consistent state, and configures it
+ * \ingroup hardware_pio
+ *
+ * This method:
+ * - disables the state machine (if running)
+ * - clears the FIFOs
+ * - applies the configuration
+ * - resets any internal state
+ * - jumps to the initial program location
+ *
+ * The state machine is disabled on return from this call
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param initial_pc the initial program memory offset to run from
+ * \param config the configuration to apply (or NULL to apply defaults)
+ */
+void pio_sm_init(PIO pio, uint sm, uint initial_pc, const pio_sm_config *config);
+
+/*! \brief Enable or disable a PIO state machine
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param enabled true to enable the state machine; false to disable
+ */
+static inline void pio_sm_set_enabled(PIO pio, uint sm, bool enabled) {
+ pio->ctrl = (pio->ctrl & ~(1u << sm)) | (!!enabled << sm);
+}
+
+/*! \brief Enable or disable multiple PIO state machines
+ * \ingroup hardware_pio
+ *
+ * Note that this method just sets the enabled state of the state machine;
+ * if now enabled they continue exactly from where they left off.
+ *
+ * \see pio_enable_sm_mask_in_sync if you wish to enable multiple state machines
+ * and ensure their clock dividers are in sync.
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param mask bit mask of state machine indexes to modify the enabled state of
+ * \param enabled true to enable the state machines; false to disable
+ */
+static inline void pio_set_sm_mask_enabled(PIO pio, uint32_t mask, bool enabled) {
+ pio->ctrl = (pio->ctrl & ~mask) | (enabled ? mask : 0u);
+}
+
+/*! \brief Restart a state machine with a known state
+ * \ingroup hardware_pio
+ *
+ * This method clears the ISR, shift counters, clock divider counter
+ * pin write flags, delay counter, latched EXEC instruction, and IRQ wait condition.
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ */
+static inline void pio_sm_restart(PIO pio, uint sm) {
+ pio->ctrl |= 1u << (PIO_CTRL_SM_RESTART_LSB + sm);
+}
+
+/*! \brief Restart multiple state machine with a known state
+ * \ingroup hardware_pio
+ *
+ * This method clears the ISR, shift counters, clock divider counter
+ * pin write flags, delay counter, latched EXEC instruction, and IRQ wait condition.
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param mask bit mask of state machine indexes to modify the enabled state of
+ */
+static inline void pio_restart_sm_mask(PIO pio, uint32_t mask) {
+ pio->ctrl |= (mask << PIO_CTRL_SM_RESTART_LSB) & PIO_CTRL_SM_RESTART_BITS;
+}
+
+/*! \brief Restart a state machine's clock divider (resetting the fractional count)
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ */
+static inline void pio_sm_clkdiv_restart(PIO pio, uint sm) {
+ pio->ctrl |= 1u << (PIO_CTRL_CLKDIV_RESTART_LSB + sm);
+}
+
+/*! \brief Restart multiple state machines' clock dividers (resetting the fractional count)
+ * \ingroup hardware_pio
+ *
+ * This method can be used to guarantee that multiple state machines with fractional clock dividers
+ * are exactly in sync
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param mask bit mask of state machine indexes to modify the enabled state of
+ */
+static inline void pio_clkdiv_restart_sm_mask(PIO pio, uint32_t mask) {
+ pio->ctrl |= (mask << PIO_CTRL_CLKDIV_RESTART_LSB) & PIO_CTRL_CLKDIV_RESTART_BITS;
+}
+
+/*! \brief Enable multiple PIO state machines synchronizing their clock dividers
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param mask bit mask of state machine indexes to modify the enabled state of
+ */
+static inline void pio_enable_sm_mask_in_sync(PIO pio, uint32_t mask) {
+ pio->ctrl |= ((mask << PIO_CTRL_CLKDIV_RESTART_LSB) & PIO_CTRL_CLKDIV_RESTART_BITS) |
+ ((mask << PIO_CTRL_SM_ENABLE_LSB) & PIO_CTRL_SM_ENABLE_BITS);
+}
+
+/*! \brief Return the current program counter for a state machine
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \return the program counter
+ */
+static inline uint8_t pio_sm_get_pc(PIO pio, uint sm) {
+ check_sm_param(sm);
+ return (uint8_t) pio->sm[sm].addr;
+}
+
+/*! \brief Immediately execute an instruction on a state machine
+ * \ingroup hardware_pio
+ *
+ * This instruction is executed instead of the next instruction in the normal control flow on the state machine.
+ * Subsequent calls to this method replace the previous executed
+ * instruction if it is still running. \see pio_sm_is_exec_stalled to see if an executed instruction
+ * is still running (i.e. it is stalled on some condition)
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param instr the encoded PIO instruction
+ */
+inline static void pio_sm_exec(PIO pio, uint sm, uint instr) {
+ check_sm_param(sm);
+ pio->sm[sm].instr = instr;
+}
+
+/*! \brief Determine if an instruction set by pio_sm_exec() is stalled executing
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \return true if the executed instruction is still running (stalled)
+ */
+static inline bool pio_sm_is_exec_stalled(PIO pio, uint sm) {
+ check_sm_param(sm);
+ return !!(pio->sm[sm].execctrl & PIO_SM0_EXECCTRL_EXEC_STALLED_BITS);
+}
+
+/*! \brief Immediately execute an instruction on a state machine and wait for it to complete
+ * \ingroup hardware_pio
+ *
+ * This instruction is executed instead of the next instruction in the normal control flow on the state machine.
+ * Subsequent calls to this method replace the previous executed
+ * instruction if it is still running. \see pio_sm_is_exec_stalled to see if an executed instruction
+ * is still running (i.e. it is stalled on some condition)
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param instr the encoded PIO instruction
+ */
+static inline void pio_sm_exec_wait_blocking(PIO pio, uint sm, uint instr) {
+ pio_sm_exec(pio, sm, instr);
+ while (pio_sm_is_exec_stalled(pio, sm)) tight_loop_contents();
+}
+
+/*! \brief Set the current wrap configuration for a state machine
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param wrap_target the instruction memory address to wrap to
+ * \param wrap the instruction memory address after which to set the program counter to wrap_target
+ * if the instruction does not itself update the program_counter
+ */
+static inline void pio_sm_set_wrap(PIO pio, uint sm, uint wrap_target, uint wrap) {
+ check_sm_param(sm);
+ pio->sm[sm].execctrl =
+ (pio->sm[sm].execctrl & ~(PIO_SM0_EXECCTRL_WRAP_TOP_BITS | PIO_SM0_EXECCTRL_WRAP_BOTTOM_BITS)) |
+ (wrap_target << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB) |
+ (wrap << PIO_SM0_EXECCTRL_WRAP_TOP_LSB);
+}
+
+/*! \brief Set the current 'out' pins for a state machine
+ * \ingroup sm_config
+ *
+ * Can overlap with the 'in', 'set' and 'sideset' pins
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param out_base 0-31 First pin to set as output
+ * \param out_count 0-32 Number of pins to set.
+ */
+static inline void pio_sm_set_out_pins(PIO pio, uint sm, uint out_base, uint out_count) {
+ check_sm_param(sm);
+ assert(out_base < 32);
+ assert(out_count <= 32);
+ pio->sm[sm].pinctrl = (pio->sm[sm].pinctrl & ~(PIO_SM0_PINCTRL_OUT_BASE_BITS | PIO_SM0_PINCTRL_OUT_COUNT_BITS)) |
+ (out_base << PIO_SM0_PINCTRL_OUT_BASE_LSB) |
+ (out_count << PIO_SM0_PINCTRL_OUT_COUNT_LSB);
+}
+
+
+/*! \brief Set the current 'set' pins for a state machine
+ * \ingroup sm_config
+ *
+ * Can overlap with the 'in', 'out' and 'sideset' pins
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param set_base 0-31 First pin to set as
+ * \param set_count 0-5 Number of pins to set.
+ */
+static inline void pio_sm_set_set_pins(PIO pio, uint sm, uint set_base, uint set_count) {
+ check_sm_param(sm);
+ assert(set_base < 32);
+ assert(set_count <= 5);
+ pio->sm[sm].pinctrl = (pio->sm[sm].pinctrl & ~(PIO_SM0_PINCTRL_SET_BASE_BITS | PIO_SM0_PINCTRL_SET_COUNT_BITS)) |
+ (set_base << PIO_SM0_PINCTRL_SET_BASE_LSB) |
+ (set_count << PIO_SM0_PINCTRL_SET_COUNT_LSB);
+}
+
+/*! \brief Set the current 'in' pins for a state machine
+ * \ingroup sm_config
+ *
+ * Can overlap with the 'out', ''set' and 'sideset' pins
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param in_base 0-31 First pin to set as input
+ */
+static inline void pio_sm_set_in_pins(PIO pio, uint sm, uint in_base) {
+ check_sm_param(sm);
+ assert(in_base < 32);
+ pio->sm[sm].pinctrl = (pio->sm[sm].pinctrl & ~PIO_SM0_PINCTRL_IN_BASE_BITS) |
+ (in_base << PIO_SM0_PINCTRL_IN_BASE_LSB);
+}
+
+/*! \brief Set the current 'sideset' pins for a state machine
+ * \ingroup sm_config
+ *
+ * Can overlap with the 'in', 'out' and 'set' pins
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param sideset_base base pin for 'side set'
+ */
+static inline void pio_sm_set_sideset_pins(PIO pio, uint sm, uint sideset_base) {
+ check_sm_param(sm);
+ assert(sideset_base < 32);
+ pio->sm[sm].pinctrl = (pio->sm[sm].pinctrl & ~PIO_SM0_PINCTRL_SIDESET_BASE_BITS) |
+ (sideset_base << PIO_SM0_PINCTRL_SIDESET_BASE_LSB);
+}
+
+/*! \brief Write a word of data to a state machine's TX FIFO
+ * \ingroup hardware_pio
+ *
+ * If the FIFO is full, the most recent value will be overwritten
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param data the 32 bit data value
+ */
+static inline void pio_sm_put(PIO pio, uint sm, uint32_t data) {
+ check_sm_param(sm);
+ pio->txf[sm] = data;
+}
+
+/*! \brief Read a word of data from a state machine's RX FIFO
+ * \ingroup hardware_pio
+ *
+ * If the FIFO is empty, the return value is zero.
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ */
+static inline uint32_t pio_sm_get(PIO pio, uint sm) {
+ check_sm_param(sm);
+ return pio->rxf[sm];
+}
+
+/*! \brief Determine if a state machine's RX FIFO is full
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \return true if the RX FIFO is full
+ */
+static inline bool pio_sm_is_rx_fifo_full(PIO pio, uint sm) {
+ check_sm_param(sm);
+ return (pio->fstat & (1u << (PIO_FSTAT_RXFULL_LSB + sm))) != 0;
+}
+
+/*! \brief Determine if a state machine's RX FIFO is empty
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \return true if the RX FIFO is empty
+ */
+static inline bool pio_sm_is_rx_fifo_empty(PIO pio, uint sm) {
+ check_sm_param(sm);
+ return (pio->fstat & (1u << (PIO_FSTAT_RXEMPTY_LSB + sm))) != 0;
+}
+
+/*! \brief Return the number of elements currently in a state machine's RX FIFO
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \return the number of elements in the RX FIFO
+ */
+static inline uint pio_sm_get_rx_fifo_level(PIO pio, uint sm) {
+ check_sm_param(sm);
+ int bitoffs = PIO_FLEVEL_RX0_LSB + sm * (PIO_FLEVEL_RX1_LSB - PIO_FLEVEL_RX0_LSB);
+ const uint32_t mask = PIO_FLEVEL_RX0_BITS >> PIO_FLEVEL_RX0_LSB;
+ return (pio->flevel >> bitoffs) & mask;
+}
+
+/*! \brief Determine if a state machine's TX FIFO is full
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \return true if the TX FIFO is full
+ */
+static inline bool pio_sm_is_tx_fifo_full(PIO pio, uint sm) {
+ check_sm_param(sm);
+ return (pio->fstat & (1u << (PIO_FSTAT_TXFULL_LSB + sm))) != 0;
+}
+
+/*! \brief Determine if a state machine's TX FIFO is empty
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \return true if the TX FIFO is empty
+ */
+static inline bool pio_sm_is_tx_fifo_empty(PIO pio, uint sm) {
+ check_sm_param(sm);
+ return (pio->fstat & (1u << (PIO_FSTAT_TXEMPTY_LSB + sm))) != 0;
+}
+
+/*! \brief Return the number of elements currently in a state machine's TX FIFO
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \return the number of elements in the TX FIFO
+ */
+static inline uint pio_sm_get_tx_fifo_level(PIO pio, uint sm) {
+ check_sm_param(sm);
+ unsigned int bitoffs = PIO_FLEVEL_TX0_LSB + sm * (PIO_FLEVEL_TX1_LSB - PIO_FLEVEL_TX0_LSB);
+ const uint32_t mask = PIO_FLEVEL_TX0_BITS >> PIO_FLEVEL_TX0_LSB;
+ return (pio->flevel >> bitoffs) & mask;
+}
+
+/*! \brief Write a word of data to a state machine's TX FIFO, blocking if the FIFO is full
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param data the 32 bit data value
+ */
+static inline void pio_sm_put_blocking(PIO pio, uint sm, uint32_t data) {
+ check_sm_param(sm);
+ while (pio_sm_is_tx_fifo_full(pio, sm)) tight_loop_contents();
+ pio_sm_put(pio, sm, data);
+}
+
+/*! \brief Read a word of data from a state machine's RX FIFO, blocking if the FIFO is empty
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ */
+static inline uint32_t pio_sm_get_blocking(PIO pio, uint sm) {
+ check_sm_param(sm);
+ while (pio_sm_is_rx_fifo_empty(pio, sm)) tight_loop_contents();
+ return pio_sm_get(pio, sm);
+}
+
+/*! \brief Empty out a state machine's TX FIFO
+ * \ingroup hardware_pio
+ *
+ * This method executes `pull` instructions on the state machine until the TX FIFO is empty
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ */
+void pio_sm_drain_tx_fifo(PIO pio, uint sm);
+
+/*! \brief set the current clock divider for a state machine
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param div the floating point clock divider
+ */
+static inline void pio_sm_set_clkdiv(PIO pio, uint sm, float div) {
+ check_sm_param(sm);
+ uint16_t div_int = (uint16_t) div;
+ uint8_t div_frac = (uint8_t) ((div - div_int) * (1u << 8u));
+ pio->sm[sm].clkdiv =
+ (div_frac << PIO_SM0_CLKDIV_FRAC_LSB) |
+ (div_int << PIO_SM0_CLKDIV_INT_LSB);
+}
+
+/*! \brief set the current clock divider for a state machine using a 16:8 fraction
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ * \param div_int the integer part of the clock divider
+ * \param div_frac the fractional part of the clock divider in 1/256s
+ */
+static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, uint16_t div_int, uint8_t div_frac) {
+ check_sm_param(sm);
+ pio->sm[sm].clkdiv =
+ (div_frac << PIO_SM0_CLKDIV_FRAC_LSB) |
+ (div_int << PIO_SM0_CLKDIV_INT_LSB);
+}
+
+/*! \brief Clear a state machine's TX and RX FIFOFs
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ */
+static inline void pio_sm_clear_fifos(PIO pio, uint sm) {
+ // changing the FIFO join state clears the fifo
+ check_sm_param(sm);
+ hw_xor_bits(&pio->sm[sm].shiftctrl, PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS);
+ hw_xor_bits(&pio->sm[sm].shiftctrl, PIO_SM0_SHIFTCTRL_FJOIN_RX_BITS);
+}
+
+/*! \brief Use a state machine to set a value on all pins for the PIO instance
+ * \ingroup hardware_pio
+ *
+ * This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set values on all 32 pins,
+ * before restoring the state machine's pin configuration to what it was.
+ *
+ * This method is provided as a convenience to set initial pin states, and should not be used against a state machine that is enabled.
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3) to use
+ * \param pin_values the pin values to set
+ */
+void pio_sm_set_pins(PIO pio, uint sm, uint32_t pin_values);
+
+/*! \brief Use a state machine to set a value on multiple pins for the PIO instance
+ * \ingroup hardware_pio
+ *
+ * This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set values on up to 32 pins,
+ * before restoring the state machine's pin configuration to what it was.
+ *
+ * This method is provided as a convenience to set initial pin states, and should not be used against a state machine that is enabled.
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3) to use
+ * \param pin_values the pin values to set (if the corresponding bit in pin_mask is set)
+ * \param pin_mask a bit for each pin to indicate whether the corresponding pin_value for that pin should be applied.
+ */
+void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pin_values, uint32_t pin_mask);
+
+/*! \brief Use a state machine to set the pin directions for multiple pins for the PIO instance
+ * \ingroup hardware_pio
+ *
+ * This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set pin directions on up to 32 pins,
+ * before restoring the state machine's pin configuration to what it was.
+ *
+ * This method is provided as a convenience to set initial pin directions, and should not be used against a state machine that is enabled.
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3) to use
+ * \param pin_dirs the pin directions to set - 1 = out, 0 = in (if the corresponding bit in pin_mask is set)
+ * \param pin_mask a bit for each pin to indicate whether the corresponding pin_value for that pin should be applied.
+ */
+void pio_sm_set_pindirs_with_mask(PIO pio, uint sm, uint32_t pin_dirs, uint32_t pin_mask);
+
+/*! \brief Use a state machine to set the same pin direction for multiple consecutive pins for the PIO instance
+ * \ingroup hardware_pio
+ *
+ * This method repeatedly reconfigures the target state machine's pin configuration and executes 'set' instructions to set the pin direction on consecutive pins,
+ * before restoring the state machine's pin configuration to what it was.
+ *
+ * This method is provided as a convenience to set initial pin directions, and should not be used against a state machine that is enabled.
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3) to use
+ * \param pin_base the first pin to set a direction for
+ * \param pin_count the count of consecutive pins to set the direction for
+ * \param is_out the direction to set; true = out, false = in
+ */
+void pio_sm_set_consecutive_pindirs(PIO pio, uint sm, uint pin_base, uint pin_count, bool is_out);
+
+/*! \brief Mark a state machine as used
+ * \ingroup hardware_pio
+ *
+ * Method for cooperative claiming of hardware. Will cause a panic if the state machine
+ * is already claimed. Use of this method by libraries detects accidental
+ * configurations that would fail in unpredictable ways.
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ */
+void pio_sm_claim(PIO pio, uint sm);
+
+/*! \brief Mark multiple state machines as used
+ * \ingroup hardware_pio
+ *
+ * Method for cooperative claiming of hardware. Will cause a panic if any of the state machines
+ * are already claimed. Use of this method by libraries detects accidental
+ * configurations that would fail in unpredictable ways.
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm_mask Mask of state machine indexes
+ */
+void pio_claim_sm_mask(PIO pio, uint sm_mask);
+
+/*! \brief Mark a state machine as no longer used
+ * \ingroup hardware_pio
+ *
+ * Method for cooperative claiming of hardware.
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param sm State machine index (0..3)
+ */
+void pio_sm_unclaim(PIO pio, uint sm);
+
+/*! \brief Claim a free state machine on a PIO instance
+ * \ingroup hardware_pio
+ *
+ * \param pio The PIO instance; either \ref pio0 or \ref pio1
+ * \param required if true the function will panic if none are available
+ * \return the state machine index or -1 if required was false, and none were free
+ */
+int pio_claim_unused_sm(PIO pio, bool required);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _PIO_H_
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pio/include/hardware/pio_instructions.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pio/include/hardware/pio_instructions.h
new file mode 100644
index 00000000000..757411d5e2d
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pio/include/hardware/pio_instructions.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_PIO_INSTRUCTIONS_H_
+#define _HARDWARE_PIO_INSTRUCTIONS_H_
+
+#include "pico.h"
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS, Enable/disable assertions in the PIO instructions, type=bool, default=0, group=hardware_pio
+#ifndef PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS
+#define PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum pio_instr_bits {
+ pio_instr_bits_jmp = 0x0000,
+ pio_instr_bits_wait = 0x2000,
+ pio_instr_bits_in = 0x4000,
+ pio_instr_bits_out = 0x6000,
+ pio_instr_bits_push = 0x8000,
+ pio_instr_bits_pull = 0x8080,
+ pio_instr_bits_mov = 0xa000,
+ pio_instr_bits_irq = 0xc000,
+ pio_instr_bits_set = 0xe000,
+};
+
+#ifndef NDEBUG
+#define _PIO_INVALID_IN_SRC 0x08u
+#define _PIO_INVALID_OUT_DEST 0x10u
+#define _PIO_INVALID_SET_DEST 0x20u
+#define _PIO_INVALID_MOV_SRC 0x40u
+#define _PIO_INVALID_MOV_DEST 0x80u
+#else
+#define _PIO_INVALID_IN_SRC 0u
+#define _PIO_INVALID_OUT_DEST 0u
+#define _PIO_INVALID_SET_DEST 0u
+#define _PIO_INVALID_MOV_SRC 0u
+#define _PIO_INVALID_MOV_DEST 0u
+#endif
+
+enum pio_src_dest {
+ pio_pins = 0u,
+ pio_x = 1u,
+ pio_y = 2u,
+ pio_null = 3u | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST,
+ pio_pindirs = 4u | _PIO_INVALID_IN_SRC | _PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST,
+ pio_exec_mov = 4u | _PIO_INVALID_IN_SRC | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC,
+ pio_status = 5u | _PIO_INVALID_IN_SRC | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_DEST,
+ pio_pc = 5u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC,
+ pio_isr = 6u | _PIO_INVALID_SET_DEST,
+ pio_osr = 7u | _PIO_INVALID_OUT_DEST | _PIO_INVALID_SET_DEST,
+ pio_exec_out = 7u | _PIO_INVALID_IN_SRC | _PIO_INVALID_SET_DEST | _PIO_INVALID_MOV_SRC | _PIO_INVALID_MOV_DEST,
+};
+
+inline static uint _pio_major_instr_bits(uint instr) {
+ return instr & 0xe000u;
+}
+
+inline static uint _pio_encode_instr_and_args(enum pio_instr_bits instr_bits, uint arg1, uint arg2) {
+ valid_params_if(PIO_INSTRUCTIONS, arg1 <= 0x7);
+#if PARAM_ASSERTIONS_ENABLED(PIO_INSTRUCTIONS)
+ uint32_t major = _pio_major_instr_bits(instr_bits);
+ if (major == pio_instr_bits_in || major == pio_instr_bits_out) {
+ assert(arg2 && arg2 <= 32);
+ } else {
+ assert(arg2 <= 31);
+ }
+#endif
+ return instr_bits | (arg1 << 5u) | (arg2 & 0x1fu);
+}
+
+inline static uint _pio_encode_instr_and_src_dest(enum pio_instr_bits instr_bits, enum pio_src_dest dest, uint value) {
+ return _pio_encode_instr_and_args(instr_bits, dest & 7u, value);
+}
+
+inline static uint pio_encode_delay(uint cycles) {
+ valid_params_if(PIO_INSTRUCTIONS, cycles <= 0x1f);
+ return cycles << 8u;
+}
+
+inline static uint pio_encode_sideset(uint sideset_bit_count, uint value) {
+ valid_params_if(PIO_INSTRUCTIONS, sideset_bit_count >= 1 && sideset_bit_count <= 5);
+ valid_params_if(PIO_INSTRUCTIONS, value <= (0x1fu >> sideset_bit_count));
+ return value << (13u - sideset_bit_count);
+}
+
+inline static uint pio_encode_sideset_opt(uint sideset_bit_count, uint value) {
+ valid_params_if(PIO_INSTRUCTIONS, sideset_bit_count >= 2 && sideset_bit_count <= 5);
+ valid_params_if(PIO_INSTRUCTIONS, value <= (0x1fu >> sideset_bit_count));
+ return 0x1000u | value << (12u - sideset_bit_count);
+}
+
+inline static uint pio_encode_jmp(uint addr) {
+ return _pio_encode_instr_and_args(pio_instr_bits_jmp, 0, addr);
+}
+
+inline static uint _pio_encode_irq(bool relative, uint irq) {
+ valid_params_if(PIO_INSTRUCTIONS, irq <= 7);
+ return (relative ? 0x10u : 0x0u) | irq;
+}
+
+inline static uint pio_encode_wait_gpio(bool polarity, uint pin) {
+ return _pio_encode_instr_and_args(pio_instr_bits_wait, 0u | (polarity ? 4u : 0u), pin);
+}
+
+inline static uint pio_encode_wait_pin(bool polarity, uint pin) {
+ return _pio_encode_instr_and_args(pio_instr_bits_wait, 1u | (polarity ? 4u : 0u), pin);
+}
+
+inline static uint pio_encode_wait_irq(bool polarity, bool relative, uint irq) {
+ valid_params_if(PIO_INSTRUCTIONS, irq <= 7);
+ return _pio_encode_instr_and_args(pio_instr_bits_wait, 2u | (polarity ? 4u : 0u), _pio_encode_irq(relative, irq));
+}
+
+inline static uint pio_encode_in(enum pio_src_dest src, uint value) {
+ valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_IN_SRC));
+ return _pio_encode_instr_and_src_dest(pio_instr_bits_in, src, value);
+}
+
+inline static uint pio_encode_out(enum pio_src_dest dest, uint value) {
+ valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_OUT_DEST));
+ return _pio_encode_instr_and_src_dest(pio_instr_bits_out, dest, value);
+}
+
+inline static uint pio_encode_push(bool if_full, bool block) {
+ return _pio_encode_instr_and_args(pio_instr_bits_push, (if_full ? 2u : 0u) | (block ? 1u : 0u), 0);
+}
+
+inline static uint pio_encode_pull(bool if_empty, bool block) {
+ return _pio_encode_instr_and_args(pio_instr_bits_pull, (if_empty ? 2u : 0u) | (block ? 1u : 0u), 0);
+}
+
+inline static uint pio_encode_mov(enum pio_src_dest dest, enum pio_src_dest src) {
+ valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_MOV_DEST));
+ valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_MOV_SRC));
+ return _pio_encode_instr_and_src_dest(pio_instr_bits_mov, dest, src & 7u);
+}
+
+inline static uint pio_encode_mov_not(enum pio_src_dest dest, enum pio_src_dest src) {
+ valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_MOV_DEST));
+ valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_MOV_SRC));
+ return _pio_encode_instr_and_src_dest(pio_instr_bits_mov, dest, (1u << 3u) | (src & 7u));
+}
+
+inline static uint pio_encode_mov_reverse(enum pio_src_dest dest, enum pio_src_dest src) {
+ valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_MOV_DEST));
+ valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_MOV_SRC));
+ return _pio_encode_instr_and_src_dest(pio_instr_bits_mov, dest, (2u << 3u) | (src & 7u));
+}
+
+inline static uint pio_encode_irq_set(bool relative, uint irq) {
+ return _pio_encode_instr_and_args(pio_instr_bits_irq, 0, _pio_encode_irq(relative, irq));
+}
+
+inline static uint pio_encode_irq_clear(bool relative, uint irq) {
+ return _pio_encode_instr_and_args(pio_instr_bits_irq, 2, _pio_encode_irq(relative, irq));
+}
+
+inline static uint pio_encode_set(enum pio_src_dest dest, uint value) {
+ valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_SET_DEST));
+ return _pio_encode_instr_and_src_dest(pio_instr_bits_set, dest, value);
+}
+
+inline static uint pio_encode_nop() {
+ return pio_encode_mov(pio_y, pio_y);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pio/pio.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pio/pio.c
new file mode 100644
index 00000000000..8221225196b
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pio/pio.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/claim.h"
+#include "hardware/pio.h"
+#include "hardware/pio_instructions.h"
+
+// sanity check
+check_hw_layout(pio_hw_t, sm[0].clkdiv, PIO_SM0_CLKDIV_OFFSET);
+check_hw_layout(pio_hw_t, sm[1].clkdiv, PIO_SM1_CLKDIV_OFFSET);
+check_hw_layout(pio_hw_t, instr_mem[0], PIO_INSTR_MEM0_OFFSET);
+check_hw_layout(pio_hw_t, inte0, PIO_IRQ0_INTE_OFFSET);
+check_hw_layout(pio_hw_t, txf[1], PIO_TXF1_OFFSET);
+check_hw_layout(pio_hw_t, rxf[3], PIO_RXF3_OFFSET);
+check_hw_layout(pio_hw_t, ints1, PIO_IRQ1_INTS_OFFSET);
+
+static_assert(NUM_PIO_STATE_MACHINES * NUM_PIOS <= 8, "");
+static uint8_t claimed;
+
+void pio_sm_claim(PIO pio, uint sm) {
+ check_sm_param(sm);
+ uint which = pio_get_index(pio);
+ if (which) {
+ hw_claim_or_assert(&claimed, NUM_PIO_STATE_MACHINES + sm, "PIO 1 SM %d already claimed");
+ } else {
+ hw_claim_or_assert(&claimed, sm, "PIO 0 SM %d already claimed");
+ }
+}
+
+void pio_claim_sm_mask(PIO pio, uint sm_mask) {
+ for(uint i = 0; sm_mask; i++, sm_mask >>= 1u) {
+ if (sm_mask & 1u) pio_sm_claim(pio, i);
+ }
+}
+void pio_sm_unclaim(PIO pio, uint sm) {
+ check_sm_param(sm);
+ uint which = pio_get_index(pio);
+ hw_claim_clear(&claimed, which * NUM_PIO_STATE_MACHINES + sm);
+}
+
+int pio_claim_unused_sm(PIO pio, bool required) {
+ uint which = pio_get_index(pio);
+ uint base = which * NUM_PIO_STATE_MACHINES;
+ int index = hw_claim_unused_from_range((uint8_t*)&claimed, required, base,
+ base + NUM_PIO_STATE_MACHINES - 1, "No PIO state machines are available");
+ return index >= base ? index - base : -1;
+}
+
+void pio_load_program(PIO pio, const uint16_t *prog, uint8_t prog_len, uint8_t load_offset) {
+ // instructions are only 16 bits, but instruction memory locations are spaced 32 bits apart
+ // Adjust the addresses of any jump instructions to respect load offset
+ assert(load_offset + prog_len <= PIO_INSTRUCTION_COUNT);
+
+}
+
+static_assert(PIO_INSTRUCTION_COUNT <= 32, "");
+static uint32_t _used_instruction_space[2];
+
+static int _pio_find_offset_for_program(PIO pio, const pio_program_t *program) {
+ assert(program->length < PIO_INSTRUCTION_COUNT);
+ uint32_t used_mask = _used_instruction_space[pio_get_index(pio)];
+ uint32_t program_mask = (1u << program->length) - 1;
+ if (program->origin >= 0) {
+ if (program->origin > 32 - program->length) return -1;
+ return used_mask & (program_mask << program->origin) ? -1 : program->origin;
+ } else {
+ // work down from the top always
+ for (int i = 32 - program->length; i >= 0; i--) {
+ if (!(used_mask & (program_mask << (uint) i))) {
+ return i;
+ }
+ }
+ return -1;
+ }
+}
+
+bool pio_can_add_program(PIO pio, const pio_program_t *program) {
+ uint32_t save = hw_claim_lock();
+ bool rc = -1 != _pio_find_offset_for_program(pio, program);
+ hw_claim_unlock(save);
+ return rc;
+}
+
+static bool _pio_can_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
+ assert(offset < PIO_INSTRUCTION_COUNT);
+ assert(offset + program->length <= PIO_INSTRUCTION_COUNT);
+ if (program->origin >= 0 && program->origin != offset) return false;
+ uint32_t used_mask = _used_instruction_space[pio_get_index(pio)];
+ uint32_t program_mask = (1u << program->length) - 1;
+ return !(used_mask & (program_mask << offset));
+}
+
+bool pio_can_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
+ uint32_t save = hw_claim_lock();
+ bool rc = _pio_can_add_program_at_offset(pio, program, offset);
+ hw_claim_unlock(save);
+ return rc;
+}
+
+static void _pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
+ if (!_pio_can_add_program_at_offset(pio, program, offset)) {
+ panic("No program space");
+ }
+ for (uint i = 0; i < program->length; ++i) {
+ uint16_t instr = program->instructions[i];
+ pio->instr_mem[offset + i] = pio_instr_bits_jmp != _pio_major_instr_bits(instr) ? instr : instr + offset;
+ }
+ uint32_t program_mask = (1u << program->length) - 1;
+ _used_instruction_space[pio_get_index(pio)] |= program_mask << offset;
+}
+
+// these assert if unable
+uint pio_add_program(PIO pio, const pio_program_t *program) {
+ uint32_t save = hw_claim_lock();
+ int offset = _pio_find_offset_for_program(pio, program);
+ if (offset < 0) {
+ panic("No program space");
+ }
+ _pio_add_program_at_offset(pio, program, offset);
+ hw_claim_unlock(save);
+ return offset;
+}
+
+void pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
+ uint32_t save = hw_claim_lock();
+ _pio_add_program_at_offset(pio, program, offset);
+ hw_claim_unlock(save);
+}
+
+void pio_remove_program(PIO pio, const pio_program_t *program, uint loaded_offset) {
+ uint32_t program_mask = (1u << program->length) - 1;
+ program_mask <<= loaded_offset;
+ uint32_t save = hw_claim_lock();
+ assert(program_mask == (_used_instruction_space[pio_get_index(pio)] & program_mask));
+ _used_instruction_space[pio_get_index(pio)] &= ~program_mask;
+ hw_claim_unlock(save);
+}
+
+void pio_clear_instruction_memory(PIO pio) {
+ uint32_t save = hw_claim_lock();
+ _used_instruction_space[pio_get_index(pio)] = 0;
+ for(uint i=0;iinstr_mem[i] = pio_encode_jmp(i);
+ }
+ hw_claim_unlock(save);
+}
+
+// Set the value of all PIO pins. This is done by forcibly executing
+// instructions on a "victim" state machine, sm. Ideally you should choose one
+// which is not currently running a program. This is intended for one-time
+// setup of initial pin states.
+void pio_sm_set_pins(PIO pio, uint sm, uint32_t pins) {
+ uint32_t pinctrl_saved = pio->sm[sm].pinctrl;
+ uint remaining = 32;
+ uint base = 0;
+ while (remaining) {
+ uint decrement = remaining > 5 ? 5 : remaining;
+ pio->sm[sm].pinctrl =
+ (decrement << PIO_SM0_PINCTRL_SET_COUNT_LSB) |
+ (base << PIO_SM0_PINCTRL_SET_BASE_LSB);
+ pio_sm_exec(pio, sm, pio_encode_set(pio_pins, pins & 0x1fu));
+ remaining -= decrement;
+ base += decrement;
+ pins >>= 5;
+ }
+ pio->sm[sm].pinctrl = pinctrl_saved;
+}
+
+void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pinvals, uint32_t pin_mask) {
+ uint32_t pinctrl_saved = pio->sm[sm].pinctrl;
+ while (pin_mask) {
+ uint base = __builtin_ctz(pin_mask);
+ pio->sm[sm].pinctrl =
+ (1u << PIO_SM0_PINCTRL_SET_COUNT_LSB) |
+ (base << PIO_SM0_PINCTRL_SET_BASE_LSB);
+ pio_sm_exec(pio, sm, pio_encode_set(pio_pins, (pinvals >> base) & 0x1u));
+ pin_mask &= pin_mask - 1;
+ }
+ pio->sm[sm].pinctrl = pinctrl_saved;
+}
+
+void pio_sm_set_pindirs_with_mask(PIO pio, uint sm, uint32_t pindirs, uint32_t pin_mask) {
+ uint32_t pinctrl_saved = pio->sm[sm].pinctrl;
+ while (pin_mask) {
+ uint base = __builtin_ctz(pin_mask);
+ pio->sm[sm].pinctrl =
+ (1u << PIO_SM0_PINCTRL_SET_COUNT_LSB) |
+ (base << PIO_SM0_PINCTRL_SET_BASE_LSB);
+ pio_sm_exec(pio, sm, pio_encode_set(pio_pindirs, (pindirs >> base) & 0x1u));
+ pin_mask &= pin_mask - 1;
+ }
+ pio->sm[sm].pinctrl = pinctrl_saved;
+}
+
+void pio_sm_set_consecutive_pindirs(PIO pio, uint sm, uint pin, uint count, bool is_out) {
+ assert(pin < 32u);
+ uint32_t pinctrl_saved = pio->sm[sm].pinctrl;
+ uint pindir_val = is_out ? 0x1f : 0;
+ while (count > 5) {
+ pio->sm[sm].pinctrl = (5u << PIO_SM0_PINCTRL_SET_COUNT_LSB) | (pin << PIO_SM0_PINCTRL_SET_BASE_LSB);
+ pio_sm_exec(pio, sm, pio_encode_set(pio_pindirs, pindir_val));
+ count -= 5;
+ pin = (pin + 5) & 0x1f;
+ }
+ pio->sm[sm].pinctrl = (count << PIO_SM0_PINCTRL_SET_COUNT_LSB) | (pin << PIO_SM0_PINCTRL_SET_BASE_LSB);
+ pio_sm_exec(pio, sm, pio_encode_set(pio_pindirs, pindir_val));
+ pio->sm[sm].pinctrl = pinctrl_saved;
+}
+
+void pio_sm_init(PIO pio, uint sm, uint initial_pc, const pio_sm_config *config) {
+ // Halt the machine, set some sensible defaults
+ pio_sm_set_enabled(pio, sm, false);
+
+ if (config) {
+ pio_sm_set_config(pio, sm, config);
+ } else {
+ pio_sm_config c = pio_get_default_sm_config();
+ pio_sm_set_config(pio, sm, &c);
+ }
+
+ pio_sm_clear_fifos(pio, sm);
+
+ // Clear FIFO debug flags
+ const uint32_t fdebug_sm_mask =
+ (1u << PIO_FDEBUG_TXOVER_LSB) |
+ (1u << PIO_FDEBUG_RXUNDER_LSB) |
+ (1u << PIO_FDEBUG_TXSTALL_LSB) |
+ (1u << PIO_FDEBUG_RXSTALL_LSB);
+ pio->fdebug = fdebug_sm_mask << sm;
+
+ // Finally, clear some internal SM state
+ pio_sm_restart(pio, sm);
+ pio_sm_clkdiv_restart(pio, sm);
+ pio_sm_exec(pio, sm, pio_encode_jmp(initial_pc));
+}
+
+void pio_sm_drain_tx_fifo(PIO pio, uint sm) {
+ uint instr = (pio->sm[sm].shiftctrl & PIO_SM0_SHIFTCTRL_AUTOPULL_BITS) ? pio_encode_out(pio_null, 32) :
+ pio_encode_pull(false, false);
+ while (!pio_sm_is_tx_fifo_empty(pio, sm)) {
+ pio_sm_exec(pio, sm, instr);
+ }
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pll/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pll/CMakeLists.txt
new file mode 100644
index 00000000000..37ff759639a
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pll/CMakeLists.txt
@@ -0,0 +1 @@
+pico_simple_hardware_target(pll)
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pll/include/hardware/pll.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pll/include/hardware/pll.h
new file mode 100644
index 00000000000..023e340339e
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pll/include/hardware/pll.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_PLL_H_
+#define _HARDWARE_PLL_H_
+
+#include "pico.h"
+#include "hardware/structs/pll.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file hardware/pll.h
+ * \defgroup hardware_pll hardware_pll
+ *
+ * Phase Locked Loop control APIs
+ *
+ * There are two PLLs in RP2040. They are:
+ * - pll_sys - Used to generate up to a 133MHz system clock
+ * - pll_usb - Used to generate a 48MHz USB reference clock
+ *
+ * For details on how the PLL's are calculated, please refer to the RP2040 datasheet.
+ */
+
+typedef pll_hw_t *PLL;
+
+#define pll_sys pll_sys_hw
+#define pll_usb pll_usb_hw
+
+/*! \brief Initialise specified PLL.
+ * \ingroup hardware_pll
+ * \param pll pll_sys or pll_usb
+ * \param ref_div Input clock divider.
+ * \param vco_freq Requested output from the VCO (voltage controlled oscillator)
+ * \param post_div1 Post Divider 1 - range 1-7. Must be >= post_div2
+ * \param post_div2 Post Divider 2 - range 1-7
+ */
+void pll_init(PLL pll, uint32_t ref_div, uint32_t vco_freq, uint32_t post_div1, uint8_t post_div2);
+
+/*! \brief Release/uninitialise specified PLL.
+ * \ingroup hardware_pll
+ *
+ * This will turn off the power to the specified PLL. Note this function does not currently check if
+ * the PLL is in use before powering it off so should be used with care.
+ *
+ * \param pll pll_sys or pll_usb
+ */
+void pll_deinit(PLL pll);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pll/pll.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pll/pll.c
new file mode 100644
index 00000000000..a55ed5ca88f
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pll/pll.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// For MHZ definitions etc
+#include "hardware/clocks.h"
+#include "hardware/pll.h"
+
+/// \tag::pll_init_calculations[]
+void pll_init(PLL pll, uint32_t refdiv, uint32_t vco_freq, uint32_t post_div1, uint8_t post_div2) {
+ // Turn off PLL in case it is already running
+ pll->pwr = 0xffffffff;
+ pll->fbdiv_int = 0;
+
+ uint32_t ref_mhz = XOSC_MHZ / refdiv;
+ pll->cs = refdiv;
+
+ // What are we multiplying the reference clock by to get the vco freq
+ // (The regs are called div, because you divide the vco output and compare it to the refclk)
+ uint32_t fbdiv = vco_freq / (ref_mhz * MHZ);
+/// \end::pll_init_calculations[]
+
+ // fbdiv
+ assert(fbdiv >= 16 && fbdiv <= 320);
+
+ // Check divider ranges
+ assert((post_div1 >= 1 && post_div1 <= 7) && (post_div2 >= 1 && post_div2 <= 7));
+
+ // post_div1 should be >= post_div2
+ // from appnote page 11
+ // postdiv1 is designed to operate with a higher input frequency
+ // than postdiv2
+ assert(post_div2 <= post_div1);
+
+/// \tag::pll_init_finish[]
+ // Check that reference frequency is no greater than vco / 16
+ assert(ref_mhz <= (vco_freq / 16));
+
+ // Put calculated value into feedback divider
+ pll->fbdiv_int = fbdiv;
+
+ // Turn on PLL
+ uint32_t power = PLL_PWR_PD_BITS | // Main power
+ PLL_PWR_VCOPD_BITS; // VCO Power
+
+ hw_clear_bits(&pll->pwr, power);
+
+ // Wait for PLL to lock
+ while (!(pll->cs & PLL_CS_LOCK_BITS)) tight_loop_contents();
+
+ // Set up post dividers - div1 feeds into div2 so if div1 is 5 and div2 is 2 then you get a divide by 10
+ uint32_t pdiv = (post_div1 << PLL_PRIM_POSTDIV1_LSB) |
+ (post_div2 << PLL_PRIM_POSTDIV2_LSB);
+ pll->prim = pdiv;
+
+ // Turn on post divider
+ hw_clear_bits(&pll->pwr, PLL_PWR_POSTDIVPD_BITS);
+/// \end::pll_init_finish[]
+}
+
+void pll_deinit(PLL pll) {
+ // todo: Make sure there are no sources running from this pll?
+ pll->pwr = PLL_PWR_BITS;
+}
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pwm/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pwm/CMakeLists.txt
new file mode 100644
index 00000000000..c8d34014c95
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pwm/CMakeLists.txt
@@ -0,0 +1 @@
+pico_simple_hardware_headers_only_target(pwm)
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pwm/include/hardware/pwm.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pwm/include/hardware/pwm.h
new file mode 100644
index 00000000000..4b572f7711d
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_pwm/include/hardware/pwm.h
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_PWM_H
+#define _HARDWARE_PWM_H
+
+#include "pico.h"
+#include "hardware/structs/pwm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_PWM, Enable/disable assertions in the PWM module, type=bool, default=0, group=hadrware_pwm
+#ifndef PARAM_ASSERTIONS_ENABLED_PWM
+#define PARAM_ASSERTIONS_ENABLED_PWM 0
+#endif
+
+/** \file hardware/pwm.h
+ * \defgroup hardware_pwm hardware_pwm
+ *
+ * Hardware Pulse Width Modulation (PWM) API
+ *
+ * The RP2040 PWM block has 8 identical slices. Each slice can drive two PWM output signals, or
+ * measure the frequency or duty cycle of an input signal. This gives a total of up to 16 controllable
+ * PWM outputs. All 30 GPIOs can be driven by the PWM block
+ *
+ * The PWM hardware functions by continuously comparing the input value to a free-running counter. This produces a
+ * toggling output where the amount of time spent at the high output level is proportional to the input value. The fraction of
+ * time spent at the high signal level is known as the duty cycle of the signal.
+ *
+ * The default behaviour of a PWM slice is to count upward until the wrap value (\ref pwm_config_set_wrap) is reached, and then
+ * immediately wrap to 0. PWM slices also offer a phase-correct mode, where the counter starts to count downward after
+ * reaching TOP, until it reaches 0 again.
+ *
+ * \subsection pwm_example Example
+ * \addtogroup hardware_pwm
+ * \include hello_pwm.c
+ */
+
+/** \brief PWM Divider mode settings
+ * \ingroup hardware_pwm
+ *
+ */
+enum pwm_clkdiv_mode
+{
+ PWM_DIV_FREE_RUNNING, ///< Free-running counting at rate dictated by fractional divider
+ PWM_DIV_B_HIGH, ///< Fractional divider is gated by the PWM B pin
+ PWM_DIV_B_RISING, ///< Fractional divider advances with each rising edge of the PWM B pin
+ PWM_DIV_B_FALLING ///< Fractional divider advances with each falling edge of the PWM B pin
+};
+
+enum pwm_chan
+{
+ PWM_CHAN_A = 0,
+ PWM_CHAN_B = 1
+};
+
+typedef struct {
+ uint32_t csr;
+ uint32_t div;
+ uint32_t top;
+} pwm_config;
+
+/** \brief Determine the PWM slice that is attached to the specified GPIO
+ * \ingroup hardware_pwm
+ *
+ * \return The PWM slice number that controls the specified GPIO.
+ */
+static inline uint pwm_gpio_to_slice_num(uint gpio) {
+ valid_params_if(PWM, gpio < NUM_BANK0_GPIOS);
+ return (gpio >> 1u) & 7u;
+}
+
+/** \brief Determine the PWM channel that is attached to the specified GPIO.
+ * \ingroup hardware_pwm
+ *
+ * Each slice 0 to 7 has two channels, A and B.
+ *
+ * \return The PWM channel that controls the specified GPIO.
+ */
+static inline uint pwm_gpio_to_channel(uint gpio) {
+ valid_params_if(PWM, gpio < NUM_BANK0_GPIOS);
+ return gpio & 1u;
+}
+
+/** \brief Set phase correction in a PWM configuration
+ * \ingroup hardware_pwm
+ *
+ * \param c PWM configuration struct to modify
+ * \param phase_correct true to set phase correct modulation, false to set trailing edge
+ *
+ * Setting phase control to true means that instead of wrapping back to zero when the wrap point is reached,
+ * the PWM starts counting back down. The output frequency is halved when phase-correct mode is enabled.
+ */
+static inline void pwm_config_set_phase_correct(pwm_config *c, bool phase_correct) {
+ c->csr = (c->csr & ~PWM_CH0_CSR_PH_CORRECT_BITS)
+ | (!!phase_correct << PWM_CH0_CSR_PH_CORRECT_LSB);
+}
+
+/** \brief Set clock divider in a PWM configuration
+ * \ingroup hardware_pwm
+ *
+ * \param c PWM configuration struct to modify
+ * \param div Value to divide counting rate by. Must be greater than or equal to 1.
+ *
+ * If the divide mode is free-running, the PWM counter runs at clk_sys / div.
+ * Otherwise, the divider reduces the rate of events seen on the B pin input (level or edge)
+ * before passing them on to the PWM counter.
+ */
+static inline void pwm_config_set_clkdiv(pwm_config *c, float div) {
+ c->div = (uint32_t)(div * (float)(1u << PWM_CH1_DIV_INT_LSB));
+}
+
+/** \brief Set PWM clock divider in a PWM configuration
+ * \ingroup hardware_pwm
+ *
+ * \param c PWM configuration struct to modify
+ * \param div integer value to reduce counting rate by. Must be greater than or equal to 1.
+ *
+ * If the divide mode is free-running, the PWM counter runs at clk_sys / div.
+ * Otherwise, the divider reduces the rate of events seen on the B pin input (level or edge)
+ * before passing them on to the PWM counter.
+ */
+static inline void pwm_config_set_clkdiv_int(pwm_config *c, uint div) {
+ c->div = div << PWM_CH1_DIV_INT_LSB;
+}
+
+/** \brief Set PWM counting mode in a PWM configuration
+ * \ingroup hardware_pwm
+ *
+ * \param c PWM configuration struct to modify
+ * \param mode PWM divide/count mode
+ *
+ * Configure which event gates the operation of the fractional divider.
+ * The default is always-on (free-running PWM). Can also be configured to count on
+ * high level, rising edge or falling edge of the B pin input.
+ */
+static inline void pwm_config_set_clkdiv_mode(pwm_config *c, enum pwm_clkdiv_mode mode) {
+ valid_params_if(PWM, mode >= PWM_DIV_FREE_RUNNING && mode <= PWM_DIV_B_FALLING);
+ c->csr = (c->csr & ~PWM_CH0_CSR_DIVMODE_BITS)
+ | (mode << PWM_CH0_CSR_DIVMODE_LSB);
+}
+
+/** \brief Set output polarity in a PWM configuration
+ * \ingroup hardware_pwm
+ *
+ * \param c PWM configuration struct to modify
+ * \param a true to invert output A
+ * \param b true to invert output B
+ */
+static inline void pwm_config_set_output_polarity(pwm_config *c, bool a, bool b) {
+ c->csr = (c->csr & ~(PWM_CH0_CSR_A_INV_BITS | PWM_CH0_CSR_B_INV_BITS))
+ | ((!!a << PWM_CH0_CSR_A_INV_LSB) | (!!b << PWM_CH0_CSR_B_INV_LSB));
+}
+
+/** \brief Set PWM counter wrap value in a PWM configuration
+ * \ingroup hardware_pwm
+ *
+ * Set the highest value the counter will reach before returning to 0. Also known as TOP.
+ *
+ * \param c PWM configuration struct to modify
+ * \param wrap Value to set wrap to
+ */
+static inline void pwm_config_set_wrap(pwm_config *c, uint16_t wrap) {
+ c->top = wrap;
+}
+
+/** \brief Initialise a PWM with settings from a configuration object
+ * \ingroup hardware_pwm
+ *
+ * Use the \ref pwm_get_default_config() function to initialise a config structure, make changes as
+ * needed using the pwm_config_* functions, then call this function to set up the PWM.
+ *
+ * \param slice_num PWM slice number
+ * \param c The configuration to use
+ * \param start If true the PWM will be started running once configured. If false you will need to start
+ * manually using \ref pwm_set_enabled() or \ref pwm_set_mask_enabled()
+ */
+static inline void pwm_init(uint slice_num, pwm_config *c, bool start) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ pwm_hw->slice[slice_num].csr = 0;
+
+ pwm_hw->slice[slice_num].ctr = PWM_CH0_CTR_RESET;
+ pwm_hw->slice[slice_num].cc = PWM_CH0_CC_RESET;
+ pwm_hw->slice[slice_num].top = c->top;
+ pwm_hw->slice[slice_num].div = c->div;
+ pwm_hw->slice[slice_num].csr = c->csr | (!!start << PWM_CH0_CSR_EN_LSB);
+}
+
+/** \brief Get a set of default values for PWM configuration
+ * \ingroup hardware_pwm
+ *
+ * PWM config is free running at system clock speed, no phase correction, wrapping at 0xffff,
+ * with standard polarities for channels A and B.
+ *
+ * \return Set of default values.
+ */
+static inline pwm_config pwm_get_default_config() {
+ pwm_config c = {0, 0, 0};
+ pwm_config_set_phase_correct(&c, false);
+ pwm_config_set_clkdiv_int(&c, 1);
+ pwm_config_set_clkdiv_mode(&c, PWM_DIV_FREE_RUNNING);
+ pwm_config_set_output_polarity(&c, false, false);
+ pwm_config_set_wrap(&c, 0xffffu);
+ return c;
+}
+
+/** \brief Set the current PWM counter wrap value
+ * \ingroup hardware_pwm
+ *
+ * Set the highest value the counter will reach before returning to 0. Also known as TOP.
+ *
+ * \param slice_num PWM slice number
+ * \param wrap Value to set wrap to
+ */
+static inline void pwm_set_wrap(uint slice_num, uint16_t wrap) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ pwm_hw->slice[slice_num].top = wrap;
+}
+
+/** \brief Set the current PWM counter compare value for one channel
+ * \ingroup hardware_pwm
+ *
+ * Set the value of the PWM counter compare value, for either channel A or channel B
+ *
+ * \param slice_num PWM slice number
+ * \param chan Which channel to update. 0 for A, 1 for B.
+ * \param level new level for the selected output
+ */
+static inline void pwm_set_chan_level(uint slice_num, uint chan, uint16_t level) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ hw_write_masked(
+ &pwm_hw->slice[slice_num].cc,
+ level << (chan ? PWM_CH0_CC_B_LSB : PWM_CH0_CC_A_LSB),
+ chan ? PWM_CH0_CC_B_BITS : PWM_CH0_CC_A_BITS
+ );
+}
+
+/** \brief Set PWM counter compare values
+ * \ingroup hardware_pwm
+ *
+ * Set the value of the PWM counter compare values, A and B
+ *
+ * \param slice_num PWM slice number
+ * \param level_a Value to set compare A to. When the counter reaches this value the A output is deasserted
+ * \param level_b Value to set compare B to. When the counter reaches this value the B output is deasserted
+ */
+static inline void pwm_set_both_levels(uint slice_num, uint16_t level_a, uint16_t level_b) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ pwm_hw->slice[slice_num].cc = (level_b << PWM_CH0_CC_B_LSB) | (level_a << PWM_CH0_CC_A_LSB);
+}
+
+/** \brief Helper function to set the PWM level for the slice and channel associated with a GPIO.
+ * \ingroup hardware_pwm
+ *
+ * Look up the correct slice (0 to 7) and channel (A or B) for a given GPIO, and update the corresponding
+ * counter-compare field.
+ *
+ * This PWM slice should already have been configured and set running. Also be careful of multiple GPIOs
+ * mapping to the same slice and channel (if GPIOs have a difference of 16).
+ *
+ * \param gpio GPIO to set level of
+ * \param level PWM level for this GPIO
+ */
+static inline void pwm_set_gpio_level(uint gpio, uint16_t level) {
+ valid_params_if(PWM, gpio < NUM_BANK0_GPIOS);
+ pwm_set_chan_level(pwm_gpio_to_slice_num(gpio), pwm_gpio_to_channel(gpio), level);
+}
+
+/** \brief Get PWM counter
+ * \ingroup hardware_pwm
+ *
+ * Get current value of PWM counter
+ *
+ * \param slice_num PWM slice number
+ * \return Current value of PWM counter
+ */
+static inline int16_t pwm_get_counter(uint slice_num) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ return (pwm_hw->slice[slice_num].ctr);
+}
+
+/** \brief Set PWM counter
+ * \ingroup hardware_pwm
+ *
+ * Set the value of the PWM counter
+ *
+ * \param slice_num PWM slice number
+ * \param c Value to set the PWM counter to
+ *
+ */
+static inline void pwm_set_counter(uint slice_num, uint16_t c) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ pwm_hw->slice[slice_num].ctr = c;
+}
+
+/** \brief Advance PWM count
+ * \ingroup hardware_pwm
+ *
+ * Advance the phase of a running the counter by 1 count.
+ *
+ * This function will return once the increment is complete.
+ *
+ * \param slice_num PWM slice number
+ */
+static inline void pwm_advance_count(uint slice_num) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ hw_set_bits(&pwm_hw->slice[slice_num].csr, PWM_CH0_CSR_PH_ADV_BITS);
+ while (pwm_hw->slice[slice_num].csr & PWM_CH0_CSR_PH_ADV_BITS) {
+ tight_loop_contents();
+ }
+}
+
+/** \brief Retard PWM count
+ * \ingroup hardware_pwm
+ *
+ * Retard the phase of a running counter by 1 count
+ *
+ * This function will return once the retardation is complete.
+ *
+ * \param slice_num PWM slice number
+ */
+static inline void pwm_retard_count(uint slice_num) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ hw_set_bits(&pwm_hw->slice[slice_num].csr, PWM_CH0_CSR_PH_RET_BITS);
+ while (pwm_hw->slice[slice_num].csr & PWM_CH0_CSR_PH_RET_BITS) {
+ tight_loop_contents();
+ }
+}
+
+/** \brief Set PWM clock divider using an 8:4 fractional value
+ * \ingroup hardware_pwm
+ *
+ * Set the clock divider. Counter increment will be on sysclock divided by this value, taking in to account the gating.
+ *
+ * \param slice_num PWM slice number
+ * \param integer 8 bit integer part of the clock divider
+ * \param fract 4 bit fractional part of the clock divider
+ */
+static inline void pwm_set_clkdiv_int_frac(uint slice_num, uint8_t integer, uint8_t fract) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ valid_params_if(PWM, fract >= 0 && slice_num <= 16);
+ pwm_hw->slice[slice_num].div = (integer << PWM_CH0_DIV_INT_LSB) | (fract << PWM_CH0_DIV_FRAC_LSB);
+}
+
+/** \brief Set PWM clock divider
+ * \ingroup hardware_pwm
+ *
+ * Set the clock divider. Counter increment will be on sysclock divided by this value, taking in to account the gating.
+ *
+ * \param slice_num PWM slice number
+ * \param divider Floating point clock divider, 1.f <= value < 256.f
+ */
+static inline void pwm_set_clkdiv(uint slice_num, float divider) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ valid_params_if(PWM, divider >= 1.f && divider < 256.f);
+ uint8_t i = (uint8_t)divider;
+ uint8_t f = (uint8_t)((divider - i) * (0x01 << 4));
+ pwm_set_clkdiv_int_frac(slice_num, i, f);
+}
+
+/** \brief Set PWM output polarity
+ * \ingroup hardware_pwm
+ *
+ * \param slice_num PWM slice number
+ * \param a true to invert output A
+ * \param b true to invert output B
+ */
+static inline void pwm_set_output_polarity(uint slice_num, bool a, bool b) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ hw_write_masked(&pwm_hw->slice[slice_num].csr, !!a << PWM_CH0_CSR_A_INV_LSB | !!b << PWM_CH0_CSR_B_INV_LSB,
+ PWM_CH0_CSR_A_INV_BITS | PWM_CH0_CSR_B_INV_BITS);
+}
+
+
+/** \brief Set PWM divider mode
+ * \ingroup hardware_pwm
+ *
+ * \param slice_num PWM slice number
+ * \param mode Required divider mode
+ */
+static inline void pwm_set_clkdiv_mode(uint slice_num, enum pwm_clkdiv_mode mode) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ valid_params_if(PWM, mode >= PWM_DIV_FREE_RUNNING && mode <= PWM_DIV_B_FALLING);
+ hw_write_masked(&pwm_hw->slice[slice_num].csr, mode << PWM_CH0_CSR_DIVMODE_LSB, PWM_CH0_CSR_DIVMODE_BITS);
+}
+
+/** \brief Set PWM phase correct on/off
+ * \ingroup hardware_pwm
+ *
+ * \param slice_num PWM slice number
+ * \param phase_correct true to set phase correct modulation, false to set trailing edge
+ *
+ * Setting phase control to true means that instead of wrapping back to zero when the wrap point is reached,
+ * the PWM starts counting back down. The output frequency is halved when phase-correct mode is enabled.
+ */
+static inline void pwm_set_phase_correct(uint slice_num, bool phase_correct) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ hw_write_masked(&pwm_hw->slice[slice_num].csr, phase_correct << PWM_CH0_CSR_PH_CORRECT_LSB, PWM_CH0_CSR_PH_CORRECT_BITS);
+}
+
+/** \brief Enable/Disable PWM
+ * \ingroup hardware_pwm
+ *
+ * \param slice_num PWM slice number
+ * \param enabled true to enable the specified PWM, false to disable
+ */
+static inline void pwm_set_enabled(uint slice_num, bool enabled) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ hw_write_masked(&pwm_hw->slice[slice_num].csr, !!enabled << PWM_CH0_CSR_EN_LSB, PWM_CH0_CSR_EN_BITS);
+}
+
+/** \brief Enable/Disable multiple PWM slices simultaneously
+ * \ingroup hardware_pwm
+ *
+ * \param mask Bitmap of PWMs to enable/disable. Bits 0 to 7 enable slices 0-7 respectively
+ */
+static inline void pwm_set_mask_enabled(uint32_t mask) {
+ pwm_hw->en = mask;
+}
+
+/*! \brief Enable PWM instance interrupt
+ * \ingroup hardware_pwm
+ *
+ * Used to enable a single PWM instance interrupt
+ *
+ * \param slice_num PWM block to enable/disable
+ * \param enabled true to enable, false to disable
+ */
+static inline void pwm_set_irq_enabled(uint slice_num, bool enabled) {
+ valid_params_if(PWM, slice_num >= 0 && slice_num < NUM_PWM_SLICES);
+ if (enabled) {
+ hw_set_bits(&pwm_hw->inte, 1u << slice_num);
+ } else {
+ hw_clear_bits(&pwm_hw->inte, 1u << slice_num);
+ }
+}
+
+/*! \brief Enable multiple PWM instance interrupts
+ * \ingroup hardware_pwm
+ *
+ * Use this to enable multiple PWM interrupts at once.
+ *
+ * \param slice_mask Bitmask of all the blocks to enable/disable. Channel 0 = bit 0, channel 1 = bit 1 etc.
+ * \param enabled true to enable, false to disable
+ */
+static inline void pwm_set_irq_mask_enabled(uint32_t slice_mask, bool enabled) {
+ valid_params_if(PWM, slice_mask < 256);
+ if (enabled) {
+ hw_set_bits(&pwm_hw->inte, slice_mask);
+ } else {
+ hw_clear_bits(&pwm_hw->inte, slice_mask);
+ }
+}
+
+/*! \brief Clear single PWM channel interrupt
+ * \ingroup hardware_pwm
+ *
+ * \param slice_num PWM slice number
+ */
+static inline void pwm_clear_irq(uint slice_num) {
+ pwm_hw->intr = 1u << slice_num;
+}
+
+/*! \brief Get PWM interrupt status, raw
+ * \ingroup hardware_pwm
+ *
+ * \return Bitmask of all PWM interrupts currently set
+ */
+static inline int32_t pwm_get_irq_status_mask() {
+ return pwm_hw->ints;
+}
+
+/*! \brief Force PWM interrupt
+ * \ingroup hardware_pwm
+ *
+ * \param slice_num PWM slice number
+ */
+static inline void pwm_force_irq(uint slice_num) {
+ pwm_hw->intf = 1u << slice_num;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_resets/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_resets/CMakeLists.txt
new file mode 100644
index 00000000000..0b314573e60
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_resets/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(hardware_resets INTERFACE)
+target_include_directories(hardware_resets INTERFACE include)
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_resets/include/hardware/resets.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_resets/include/hardware/resets.h
new file mode 100644
index 00000000000..fab604bdaeb
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_resets/include/hardware/resets.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_RESETS_H
+#define _HARDWARE_RESETS_H
+
+#include "pico.h"
+#include "hardware/structs/resets.h"
+
+/** \file hardware/resets.h
+ * \defgroup hardware_resets hardware_resets
+ *
+ * Hardware Reset API
+ *
+ * The reset controller allows software control of the resets to all of the peripherals that are not
+ * critical to boot the processor in the RP2040.
+ *
+ * \subsubsection reset_bitmask
+ * \addtogroup hardware_resets
+ *
+ * Multiple blocks are referred to using a bitmask as follows:
+ *
+ * Block to reset | Bit
+ * ---------------|----
+ * USB | 24
+ * UART 1 | 23
+ * UART 0 | 22
+ * Timer | 21
+ * TB Manager | 20
+ * SysInfo | 19
+ * System Config | 18
+ * SPI 1 | 17
+ * SPI 0 | 16
+ * RTC | 15
+ * PWM | 14
+ * PLL USB | 13
+ * PLL System | 12
+ * PIO 1 | 11
+ * PIO 0 | 10
+ * Pads - QSPI | 9
+ * Pads - bank 0 | 8
+ * JTAG | 7
+ * IO Bank 1 | 6
+ * IO Bank 0 | 5
+ * I2C 1 | 4
+ * I2C 0 | 3
+ * DMA | 2
+ * Bus Control | 1
+ * ADC 0 | 0
+ *
+ * \subsection reset_example Example
+ * \addtogroup hardware_resets
+ * \include hello_reset.c
+ */
+
+/// \tag::reset_funcs[]
+
+/*! \brief Reset the specified HW blocks
+ * \ingroup hardware_resets
+ *
+ * \param bits Bit pattern indicating blocks to reset. See \ref reset_bitmask
+ */
+static inline void reset_block(uint32_t bits) {
+ hw_set_bits(&resets_hw->reset, bits);
+}
+
+/*! \brief bring specified HW blocks out of reset
+ * \ingroup hardware_resets
+ *
+ * \param bits Bit pattern indicating blocks to unreset. See \ref reset_bitmask
+ */
+static inline void unreset_block(uint32_t bits) {
+ hw_clear_bits(&resets_hw->reset, bits);
+}
+
+/*! \brief Bring specified HW blocks out of reset and wait for completion
+ * \ingroup hardware_resets
+ *
+ * \param bits Bit pattern indicating blocks to unreset. See \ref reset_bitmask
+ */
+static inline void unreset_block_wait(uint32_t bits) {
+ hw_clear_bits(&resets_hw->reset, bits);
+ while (~resets_hw->reset_done & bits)
+ tight_loop_contents();
+}
+/// \end::reset_funcs[]
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_rtc/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_rtc/CMakeLists.txt
new file mode 100644
index 00000000000..dce6effb6d2
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_rtc/CMakeLists.txt
@@ -0,0 +1 @@
+pico_simple_hardware_target(rtc)
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_rtc/include/hardware/rtc.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_rtc/include/hardware/rtc.h
new file mode 100644
index 00000000000..83d5bdf288c
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_rtc/include/hardware/rtc.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_RTC_H
+#define _HARDWARE_RTC_H
+
+#include "pico.h"
+#include "hardware/structs/rtc.h"
+
+/** \file hardware/rtc.h
+ * \defgroup hardware_rtc hardware_rtc
+ *
+ * Hardware Real Time Clock API
+ *
+ * The RTC keeps track of time in human readable format and generates events when the time is equal
+ * to a preset value. Think of a digital clock, not epoch time used by most computers. There are seven
+ * fields, one each for year (12 bit), month (4 bit), day (5 bit), day of the week (3 bit), hour (5 bit)
+ * minute (6 bit) and second (6 bit), storing the data in binary format.
+ *
+ * \sa datetime_t
+ *
+ * \subsection rtc_example Example
+ * \addtogroup hardware_rtc
+ *
+ * \include hello_rtc.c
+ */
+
+
+typedef void (*rtc_callback_t)(void);
+
+/*! \brief Initialise the RTC system
+ * \ingroup hardware_rtc
+ */
+void rtc_init(void);
+
+/*! \brief Set the RTC to the specified time
+ * \ingroup hardware_rtc
+ *
+ * \param t Pointer to a \ref datetime_t structure contains time to set
+ * \return true if set, false if the passed in datetime was invalid.
+ */
+bool rtc_set_datetime(datetime_t *t);
+
+/*! \brief Get the current time from the RTC
+ * \ingroup hardware_rtc
+ *
+ * \param t Pointer to a \ref datetime_t structure to receive the current RTC time
+ * \return true if datetime is valid, false if the RTC is not running.
+ */
+bool rtc_get_datetime(datetime_t *t);
+
+/*! \brief Is the RTC running?
+ * \ingroup hardware_rtc
+ *
+ */
+bool rtc_running(void);
+
+/*! \brief Set a time in the future for the RTC to call a user provided callback
+ * \ingroup hardware_rtc
+ *
+ * \param t Pointer to a \ref datetime_t structure containing a time in the future to fire the alarm. Any values set to -1 will not be matched on.
+ * \param user_callback pointer to a \ref rtc_callback_t to call when the alarm fires
+ */
+void rtc_set_alarm(datetime_t *t, rtc_callback_t user_callback);
+
+/*! \brief Disable the RTC alarm (if active)
+ * \ingroup hardware_rtc
+ */
+void rtc_disable_alarm(void);
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_rtc/rtc.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_rtc/rtc.c
new file mode 100644
index 00000000000..91bd1994c1d
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_rtc/rtc.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico.h"
+
+#include "hardware/irq.h"
+#include "hardware/rtc.h"
+#include "hardware/resets.h"
+#include "hardware/clocks.h"
+
+// Set this when setting an alarm
+static rtc_callback_t _callback = NULL;
+static bool _alarm_repeats = false;
+
+bool rtc_running(void) {
+ return (rtc_hw->ctrl & RTC_CTRL_RTC_ACTIVE_BITS);
+}
+
+void rtc_init(void) {
+ // Get clk_rtc freq and make sure it is running
+ uint rtc_freq = clock_get_hz(clk_rtc);
+ assert(rtc_freq != 0);
+
+ // Take rtc out of reset now that we know clk_rtc is running
+ reset_block(RESETS_RESET_RTC_BITS);
+ unreset_block_wait(RESETS_RESET_RTC_BITS);
+
+ // Set up the 1 second divider.
+ // If rtc_freq is 400 then clkdiv_m1 should be 399
+ rtc_freq -= 1;
+
+ // Check the freq is not too big to divide
+ assert(rtc_freq <= RTC_CLKDIV_M1_BITS);
+
+ // Write divide value
+ rtc_hw->clkdiv_m1 = rtc_freq;
+}
+
+static bool valid_datetime(datetime_t *t) {
+ // Valid ranges taken from RTC doc. Note when setting an RTC alarm
+ // these values are allowed to be -1 to say "don't match this value"
+ if (!(t->year >= 0 && t->year <= 4095)) return false;
+ if (!(t->month >= 1 && t->month <= 12)) return false;
+ if (!(t->day >= 1 && t->day <= 31)) return false;
+ if (!(t->dotw >= 0 && t->dotw <= 6)) return false;
+ if (!(t->hour >= 0 && t->hour <= 23)) return false;
+ if (!(t->min >= 0 && t->min <= 59)) return false;
+ if (!(t->sec >= 0 && t->sec <= 59)) return false;
+ return true;
+}
+
+bool rtc_set_datetime(datetime_t *t) {
+ if (!valid_datetime(t)) {
+ return false;
+ }
+
+ // Disable RTC
+ rtc_hw->ctrl = 0;
+ // Wait while it is still active
+ while (rtc_running()) {
+ tight_loop_contents();
+ }
+
+ // Write to setup registers
+ rtc_hw->setup_0 = (t->year << RTC_SETUP_0_YEAR_LSB ) |
+ (t->month << RTC_SETUP_0_MONTH_LSB) |
+ (t->day << RTC_SETUP_0_DAY_LSB);
+ rtc_hw->setup_1 = (t->dotw << RTC_SETUP_1_DOTW_LSB) |
+ (t->hour << RTC_SETUP_1_HOUR_LSB) |
+ (t->min << RTC_SETUP_1_MIN_LSB) |
+ (t->sec << RTC_SETUP_1_SEC_LSB);
+
+ // Load setup values into rtc clock domain
+ rtc_hw->ctrl = RTC_CTRL_LOAD_BITS;
+
+ // Enable RTC and wait for it to be running
+ rtc_hw->ctrl = RTC_CTRL_RTC_ENABLE_BITS;
+ while (!rtc_running()) {
+ tight_loop_contents();
+ }
+
+ return true;
+}
+
+bool rtc_get_datetime(datetime_t *t) {
+ // Make sure RTC is running
+ if (!rtc_running()) {
+ return false;
+ }
+
+ // Note: RTC_0 should be read before RTC_1
+ t->dotw = (rtc_hw->rtc_0 & RTC_RTC_0_DOTW_BITS ) >> RTC_RTC_0_DOTW_LSB;
+ t->hour = (rtc_hw->rtc_0 & RTC_RTC_0_HOUR_BITS ) >> RTC_RTC_0_HOUR_LSB;
+ t->min = (rtc_hw->rtc_0 & RTC_RTC_0_MIN_BITS ) >> RTC_RTC_0_MIN_LSB;
+ t->sec = (rtc_hw->rtc_0 & RTC_RTC_0_SEC_BITS ) >> RTC_RTC_0_SEC_LSB;
+ t->year = (rtc_hw->rtc_1 & RTC_RTC_1_YEAR_BITS ) >> RTC_RTC_1_YEAR_LSB;
+ t->month = (rtc_hw->rtc_1 & RTC_RTC_1_MONTH_BITS) >> RTC_RTC_1_MONTH_LSB;
+ t->day = (rtc_hw->rtc_1 & RTC_RTC_1_DAY_BITS ) >> RTC_RTC_1_DAY_LSB;
+
+ return true;
+}
+
+static void rtc_enable_alarm(void) {
+ // Set matching and wait for it to be enabled
+ hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_MATCH_ENA_BITS);
+ while(!(rtc_hw->irq_setup_0 & RTC_IRQ_SETUP_0_MATCH_ACTIVE_BITS)) {
+ tight_loop_contents();
+ }
+}
+
+static void rtc_irq_handler(void) {
+ // Always disable the alarm to clear the current IRQ.
+ // Even if it is a repeatable alarm, we don't want it to keep firing.
+ // If it matches on a second it can keep firing for that second.
+ rtc_disable_alarm();
+
+ if (_alarm_repeats) {
+ // If it is a repeatable alarm, re enable the alarm.
+ rtc_enable_alarm();
+ }
+
+ // Call user callback function
+ if (_callback) {
+ _callback();
+ }
+}
+
+static bool rtc_alarm_repeats(datetime_t *t) {
+ // If any value is set to -1 then we don't match on that value
+ // hence the alarm will eventually repeat
+ if (t->year == -1) return true;
+ if (t->month == -1) return true;
+ if (t->day == -1) return true;
+ if (t->dotw == -1) return true;
+ if (t->hour == -1) return true;
+ if (t->min == -1) return true;
+ if (t->sec == -1) return true;
+ return false;
+}
+
+void rtc_set_alarm(datetime_t *t, rtc_callback_t user_callback) {
+ rtc_disable_alarm();
+
+ // Only add to setup if it isn't -1
+ rtc_hw->irq_setup_0 = ((t->year == -1) ? 0 : (t->year << RTC_IRQ_SETUP_0_YEAR_LSB )) |
+ ((t->month == -1) ? 0 : (t->month << RTC_IRQ_SETUP_0_MONTH_LSB)) |
+ ((t->day == -1) ? 0 : (t->day << RTC_IRQ_SETUP_0_DAY_LSB ));
+ rtc_hw->irq_setup_1 = ((t->dotw == -1) ? 0 : (t->dotw << RTC_IRQ_SETUP_1_DOTW_LSB)) |
+ ((t->hour == -1) ? 0 : (t->hour << RTC_IRQ_SETUP_1_HOUR_LSB)) |
+ ((t->min == -1) ? 0 : (t->min << RTC_IRQ_SETUP_1_MIN_LSB )) |
+ ((t->sec == -1) ? 0 : (t->sec << RTC_IRQ_SETUP_1_SEC_LSB ));
+
+ // Set the match enable bits for things we care about
+ if (t->year != -1) hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_YEAR_ENA_BITS);
+ if (t->month != -1) hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_MONTH_ENA_BITS);
+ if (t->day != -1) hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_DAY_ENA_BITS);
+ if (t->dotw != -1) hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_DOTW_ENA_BITS);
+ if (t->hour != -1) hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_HOUR_ENA_BITS);
+ if (t->min != -1) hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_MIN_ENA_BITS);
+ if (t->sec != -1) hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_SEC_ENA_BITS);
+
+ // Does it repeat? I.e. do we not match on any of the bits
+ _alarm_repeats = rtc_alarm_repeats(t);
+
+ // Store function pointer we can call later
+ _callback = user_callback;
+
+ irq_set_exclusive_handler(RTC_IRQ, rtc_irq_handler);
+
+ // Enable the IRQ at the peri
+ rtc_hw->inte = RTC_INTE_RTC_BITS;
+
+ // Enable the IRQ at the proc
+ irq_set_enabled(RTC_IRQ, true);
+
+ rtc_enable_alarm();
+}
+
+void rtc_disable_alarm(void) {
+ // Disable matching and wait for it to stop being active
+ hw_clear_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_MATCH_ENA_BITS);
+ while(rtc_hw->irq_setup_0 & RTC_IRQ_SETUP_0_MATCH_ACTIVE_BITS) {
+ tight_loop_contents();
+ }
+}
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_spi/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_spi/CMakeLists.txt
new file mode 100644
index 00000000000..03e7f1f290c
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_spi/CMakeLists.txt
@@ -0,0 +1 @@
+pico_simple_hardware_target(spi)
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_spi/include/hardware/spi.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_spi/include/hardware/spi.h
new file mode 100644
index 00000000000..789efc6f0d4
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_spi/include/hardware/spi.h
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_SPI_H
+#define _HARDWARE_SPI_H
+
+#include "pico.h"
+#include "pico/time.h"
+#include "hardware/structs/spi.h"
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_SPI, Enable/disable assertions in the SPI module, type=bool, default=0, group=hardware_spi
+#ifndef PARAM_ASSERTIONS_ENABLED_SPI
+#define PARAM_ASSERTIONS_ENABLED_SPI 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file hardware/spi.h
+ * \defgroup hardware_spi hardware_spi
+ *
+ * Hardware SPI API
+ *
+ * RP2040 has 2 identical instances of the Serial Peripheral Interface (SPI) controller.
+ *
+ * The PrimeCell SSP is a master or slave interface for synchronous serial communication with peripheral devices that have
+ * Motorola SPI, National Semiconductor Microwire, or Texas Instruments synchronous serial interfaces.
+ *
+ * Controller can be defined as master or slave using the \ref spi_set_slave function.
+ *
+ * Each controller can be connected to a number of GPIO pins, see the datasheet GPIO function selection table for more information.
+ */
+
+/**
+ * Opaque type representing an SPI instance.
+ */
+typedef struct spi_inst spi_inst_t;
+
+/** Identifier for the first (SPI 0) hardware SPI instance (for use in SPI functions).
+ *
+ * e.g. spi_init(spi0, 48000)
+ *
+ * \ingroup hardware_spi
+ */
+#define spi0 ((spi_inst_t * const)spi0_hw)
+
+/** Identifier for the second (SPI 1) hardware SPI instance (for use in SPI functions).
+ *
+ * e.g. spi_init(spi1, 48000)
+ *
+ * \ingroup hardware_spi
+ */
+#define spi1 ((spi_inst_t * const)spi1_hw)
+
+typedef enum {
+ SPI_CPHA_0 = 0,
+ SPI_CPHA_1 = 1
+} spi_cpha_t;
+
+typedef enum {
+ SPI_CPOL_0 = 0,
+ SPI_CPOL_1 = 1
+} spi_cpol_t;
+
+typedef enum {
+ SPI_LSB_FIRST = 0,
+ SPI_MSB_FIRST = 1
+} spi_order_t;
+
+// ----------------------------------------------------------------------------
+// Setup
+
+/*! \brief Initialise SPI instances
+ * \ingroup hardware_spi
+ * Puts the SPI into a known state, and enable it. Must be called before other
+ * functions.
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \param baudrate Baudrate required in Hz
+ *
+ * \note There is no guarantee that the baudrate requested will be possible, the nearest will be chosen,
+ * and this function does not return any indication of this. You can use the \ref spi_set_baudrate function
+ * which will return the actual baudrate selected if this is important.
+ */
+void _spi_init(spi_inst_t *spi, uint baudrate);
+
+/*! \brief Deinitialise SPI instances
+ * \ingroup hardware_spi
+ * Puts the SPI into a disabled state. Init will need to be called to reenable the device
+ * functions.
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ */
+void spi_deinit(spi_inst_t *spi);
+
+/*! \brief Set SPI baudrate
+ * \ingroup hardware_spi
+ *
+ * Set SPI frequency as close as possible to baudrate, and return the actual
+ * achieved rate.
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \param baudrate Baudrate required in Hz, should be capable of a bitrate of at least 2Mbps, or higher, depending on system clock settings.
+ * \return The actual baudrate set
+ */
+uint spi_set_baudrate(spi_inst_t *spi, uint baudrate);
+
+/*! \brief Convert I2c instance to hardware instance number
+ * \ingroup hardware_spi
+ *
+ * \param spi SPI instance
+ * \return Number of SPI, 0 or 1.
+ */
+static inline uint spi_get_index(spi_inst_t *spi) {
+ invalid_params_if(SPI, spi != spi0 && spi != spi1);
+ return spi == spi1 ? 1 : 0;
+}
+
+static inline spi_hw_t *spi_get_hw(spi_inst_t *spi) {
+ spi_get_index(spi); // check it is a hw spi
+ return (spi_hw_t *)spi;
+}
+
+/*! \brief Configure SPI
+ * \ingroup hardware_spi
+ *
+ * Configure how the SPI serialises and deserialises data on the wire
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \param data_bits Number of data bits per transfer. Valid values 4..16.
+ * \param cpol SSPCLKOUT polarity, applicable to Motorola SPI frame format only.
+ * \param cpha SSPCLKOUT phase, applicable to Motorola SPI frame format only
+ * \param order Must be SPI_MSB_FIRST, no other values supported on the PL022
+ */
+static inline void spi_set_format(spi_inst_t *spi, uint data_bits, spi_cpol_t cpol, spi_cpha_t cpha, spi_order_t order) {
+ invalid_params_if(SPI, data_bits < 4 || data_bits > 16);
+ // LSB-first not supported on PL022:
+ invalid_params_if(SPI, order != SPI_MSB_FIRST);
+ invalid_params_if(SPI, cpol != SPI_CPOL_0 && cpol != SPI_CPOL_1);
+ invalid_params_if(SPI, cpha != SPI_CPHA_0 && cpha != SPI_CPHA_1);
+ hw_write_masked(&spi_get_hw(spi)->cr0,
+ (data_bits - 1) << SPI_SSPCR0_DSS_LSB |
+ cpol << SPI_SSPCR0_SPO_LSB |
+ cpha << SPI_SSPCR0_SPH_LSB,
+ SPI_SSPCR0_DSS_BITS |
+ SPI_SSPCR0_SPO_BITS |
+ SPI_SSPCR0_SPH_BITS);
+}
+
+/*! \brief Set SPI master/slave
+ * \ingroup hardware_spi
+ *
+ * Configure the SPI for master- or slave-mode operation. By default,
+ * spi_init() sets master-mode.
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \param slave true to set SPI device as a slave device, false for master.
+ */
+static inline void spi_set_slave(spi_inst_t *spi, bool slave) {
+ if (slave)
+ hw_set_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_MS_BITS);
+ else
+ hw_clear_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_MS_BITS);
+}
+
+// ----------------------------------------------------------------------------
+// Generic input/output
+
+/*! \brief Check whether a write can be done on SPI device
+ * \ingroup hardware_spi
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \return 0 if no space is available to write. Non-zero if a write is possible
+ *
+ * \note Although the controllers each have a 8 deep TX FIFO, the current HW implementation can only return 0 or 1
+ * rather than the space available.
+ */
+static inline size_t spi_is_writable(spi_inst_t *spi) {
+ // PL022 doesn't expose levels directly, so return values are only 0 or 1
+ return (spi_get_hw(spi)->sr & SPI_SSPSR_TNF_BITS) >> SPI_SSPSR_TNF_LSB;
+}
+
+/*! \brief Check whether a read can be done on SPI device
+ * \ingroup hardware_spi
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \return Non-zero if a read is possible i.e. data is present
+ *
+ * \note Although the controllers each have a 8 deep RX FIFO, the current HW implementation can only return 0 or 1
+ * rather than the data available.
+ */
+static inline size_t spi_is_readable(spi_inst_t *spi) {
+ return (spi_get_hw(spi)->sr & SPI_SSPSR_RNE_BITS) >> SPI_SSPSR_RNE_LSB;
+}
+
+/*! \brief Write/Read to/from an SPI device
+ * \ingroup hardware_spi
+ *
+ * Write \p len bytes from \p src to SPI. Simultaneously read \p len bytes from SPI to \p dst.
+ * Blocks until all data is transferred. No timeout, as SPI hardware always transfers at a known data rate.
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \param src Buffer of data to write
+ * \param dst Buffer for read data
+ * \param len Length of BOTH buffers
+ * \return Number of bytes written/read
+*/
+int spi_write_read_blocking(spi_inst_t *spi, const uint8_t *src, uint8_t *dst, size_t len);
+
+/*! \brief Write to an SPI device, blocking
+ * \ingroup hardware_spi
+ *
+ * Write \p len bytes from \p src to SPI, and discard any data received back
+ * Blocks until all data is transferred. No timeout, as SPI hardware always transfers at a known data rate.
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \param src Buffer of data to write
+ * \param len Length of \p src
+ * \return Number of bytes written/read
+ */
+int spi_write_blocking(spi_inst_t *spi, const uint8_t *src, size_t len);
+
+/*! \brief Read from an SPI device
+ * \ingroup hardware_spi
+ *
+ * Read \p len bytes from SPI to \p dst.
+ * Blocks until all data is transferred. No timeout, as SPI hardware always transfers at a known data rate.
+ * \p repeated_tx_data is output repeatedly on TX as data is read in from RX.
+ * Generally this can be 0, but some devices require a specific value here,
+ * e.g. SD cards expect 0xff
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \param repeated_tx_data Buffer of data to write
+ * \param dst Buffer for read data
+ * \param len Length of buffer \p dst
+ * \return Number of bytes written/read
+ */
+int spi_read_blocking(spi_inst_t *spi, uint8_t repeated_tx_data, uint8_t *dst, size_t len);
+
+// ----------------------------------------------------------------------------
+// SPI-specific operations and aliases
+
+// FIXME need some instance-private data for select() and deselect() if we are going that route
+
+/*! \brief Write/Read half words to/from an SPI device
+ * \ingroup hardware_spi
+ *
+ * Write \p len halfwords from \p src to SPI. Simultaneously read \p len halfwords from SPI to \p dst.
+ * Blocks until all data is transferred. No timeout, as SPI hardware always transfers at a known data rate.
+ *
+ * \note SPI should be initialised with 16 data_bits using \ref spi_set_format first, otherwise this function will only read/write 8 data_bits.
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \param src Buffer of data to write
+ * \param dst Buffer for read data
+ * \param len Length of BOTH buffers in halfwords
+ * \return Number of bytes written/read
+*/
+int spi_write16_read16_blocking(spi_inst_t *spi, const uint16_t *src, uint16_t *dst, size_t len);
+
+/*! \brief Write to an SPI device
+ * \ingroup hardware_spi
+ *
+ * Write \p len halfwords from \p src to SPI. Discard any data received back.
+ * Blocks until all data is transferred. No timeout, as SPI hardware always transfers at a known data rate.
+ *
+ * \note SPI should be initialised with 16 data_bits using \ref spi_set_format first, otherwise this function will only write 8 data_bits.
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \param src Buffer of data to write
+ * \param len Length of buffers
+ * \return Number of bytes written/read
+*/
+int spi_write16_blocking(spi_inst_t *spi, const uint16_t *src, size_t len);
+
+/*! \brief Read from an SPI device
+ * \ingroup hardware_spi
+ *
+ * Read \p len halfwords from SPI to \p dst.
+ * Blocks until all data is transferred. No timeout, as SPI hardware always transfers at a known data rate.
+ * \p repeated_tx_data is output repeatedly on TX as data is read in from RX.
+ * Generally this can be 0, but some devices require a specific value here,
+ * e.g. SD cards expect 0xff
+ *
+ * \note SPI should be initialised with 16 data_bits using \ref spi_set_format first, otherwise this function will only read 8 data_bits.
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \param repeated_tx_data Buffer of data to write
+ * \param dst Buffer for read data
+ * \param len Length of buffer \p dst in halfwords
+ * \return Number of bytes written/read
+ */
+int spi_read16_blocking(spi_inst_t *spi, uint16_t repeated_tx_data, uint16_t *dst, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_spi/include/placeholder.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_spi/include/placeholder.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_spi/spi.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_spi/spi.c
new file mode 100644
index 00000000000..1de19764e3c
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_spi/spi.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/resets.h"
+#include "hardware/clocks.h"
+#include "hardware/spi.h"
+
+static inline void spi_reset(spi_inst_t *spi) {
+ invalid_params_if(SPI, spi != spi0 && spi != spi1);
+ reset_block(spi == spi0 ? RESETS_RESET_SPI0_BITS : RESETS_RESET_SPI1_BITS);
+}
+
+static inline void spi_unreset(spi_inst_t *spi) {
+ invalid_params_if(SPI, spi != spi0 && spi != spi1);
+ unreset_block_wait(spi == spi0 ? RESETS_RESET_SPI0_BITS : RESETS_RESET_SPI1_BITS);
+}
+
+void _spi_init(spi_inst_t *spi, uint baudrate) {
+ spi_reset(spi);
+ spi_unreset(spi);
+
+ (void) spi_set_baudrate(spi, baudrate);
+ spi_set_format(spi, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
+ // Always enable DREQ signals -- harmless if DMA is not listening
+ hw_set_bits(&spi_get_hw(spi)->dmacr, SPI_SSPDMACR_TXDMAE_BITS | SPI_SSPDMACR_RXDMAE_BITS);
+ spi_set_format(spi, 8, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);
+
+ // Finally enable the SPI
+ hw_set_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_SSE_BITS);
+}
+
+void spi_deinit(spi_inst_t *spi) {
+ hw_clear_bits(&spi_get_hw(spi)->cr1, SPI_SSPCR1_SSE_BITS);
+ hw_clear_bits(&spi_get_hw(spi)->dmacr, SPI_SSPDMACR_TXDMAE_BITS | SPI_SSPDMACR_RXDMAE_BITS);
+ spi_reset(spi);
+}
+
+uint spi_set_baudrate(spi_inst_t *spi, uint baudrate) {
+ uint freq_in = clock_get_hz(clk_peri);
+ uint prescale, postdiv;
+ invalid_params_if(SPI, baudrate > freq_in);
+
+ // Find smallest prescale value which puts output frequency in range of
+ // post-divide. Prescale is an even number from 2 to 254 inclusive.
+ for (prescale = 2; prescale <= 254; prescale += 2) {
+ if (freq_in < (prescale + 2) * 256 * (uint64_t) baudrate)
+ break;
+ }
+ invalid_params_if(SPI, prescale > 254); // Frequency too low
+
+ // Find largest post-divide which makes output <= baudrate. Post-divide is
+ // an integer in the range 1 to 256 inclusive.
+ for (postdiv = 256; postdiv > 1; --postdiv) {
+ if (freq_in / (prescale * (postdiv - 1)) > baudrate)
+ break;
+ }
+
+ spi_get_hw(spi)->cpsr = prescale;
+ hw_write_masked(&spi_get_hw(spi)->cr0, (postdiv - 1) << SPI_SSPCR0_SCR_LSB, SPI_SSPCR0_SCR_BITS);
+
+ // Return the frequency we were able to achieve
+ return freq_in / (prescale * postdiv);
+}
+
+// Write len bytes from src to SPI. Simultaneously read len bytes from SPI to dst.
+// Note this function is guaranteed to exit in a known amount of time (bits sent * time per bit)
+int __not_in_flash_func(spi_write_read_blocking)(spi_inst_t *spi, const uint8_t *src, uint8_t *dst, size_t len) {
+ // Never have more transfers in flight than will fit into the RX FIFO,
+ // else FIFO will overflow if this code is heavily interrupted.
+ const size_t fifo_depth = 8;
+ size_t rx_remaining = len, tx_remaining = len;
+
+ while (rx_remaining || tx_remaining) {
+ if (tx_remaining && spi_is_writable(spi) && rx_remaining - tx_remaining < fifo_depth) {
+ spi_get_hw(spi)->dr = (uint32_t) *src++;
+ --tx_remaining;
+ }
+ if (rx_remaining && spi_is_readable(spi)) {
+ *dst++ = (uint8_t) spi_get_hw(spi)->dr;
+ --rx_remaining;
+ }
+ }
+
+ return len;
+}
+
+// Write len bytes directly from src to the SPI, and discard any data received back
+int __not_in_flash_func(spi_write_blocking)(spi_inst_t *spi, const uint8_t *src, size_t len) {
+ // Write to TX FIFO whilst ignoring RX, then clean up afterward. When RX
+ // is full, PL022 inhibits RX pushes, and sets a sticky flag on
+ // push-on-full, but continues shifting. Safe if SSPIMSC_RORIM is not set.
+ for (size_t i = 0; i < len; ++i) {
+ while (!spi_is_writable(spi))
+ tight_loop_contents();
+ spi_get_hw(spi)->dr = (uint32_t)src[i];
+ }
+ // Drain RX FIFO, then wait for shifting to finish (which may be *after*
+ // TX FIFO drains), then drain RX FIFO again
+ while (spi_is_readable(spi))
+ (void)spi_get_hw(spi)->dr;
+ while (spi_get_hw(spi)->sr & SPI_SSPSR_BSY_BITS)
+ tight_loop_contents();
+ while (spi_is_readable(spi))
+ (void)spi_get_hw(spi)->dr;
+
+ // Don't leave overrun flag set
+ spi_get_hw(spi)->icr = SPI_SSPICR_RORIC_BITS;
+
+ return len;
+}
+
+// Read len bytes directly from the SPI to dst.
+// repeated_tx_data is output repeatedly on SO as data is read in from SI.
+// Generally this can be 0, but some devices require a specific value here,
+// e.g. SD cards expect 0xff
+int __not_in_flash_func(spi_read_blocking)(spi_inst_t *spi, uint8_t repeated_tx_data, uint8_t *dst, size_t len) {
+ const size_t fifo_depth = 8;
+ size_t rx_remaining = len, tx_remaining = len;
+
+ while (rx_remaining || tx_remaining) {
+ if (tx_remaining && spi_is_writable(spi) && rx_remaining - tx_remaining < fifo_depth) {
+ spi_get_hw(spi)->dr = (uint32_t) repeated_tx_data;
+ --tx_remaining;
+ }
+ if (rx_remaining && spi_is_readable(spi)) {
+ *dst++ = (uint8_t) spi_get_hw(spi)->dr;
+ --rx_remaining;
+ }
+ }
+
+ return len;
+}
+
+// Write len halfwords from src to SPI. Simultaneously read len halfwords from SPI to dst.
+int __not_in_flash_func(spi_write16_read16_blocking)(spi_inst_t *spi, const uint16_t *src, uint16_t *dst, size_t len) {
+ // Never have more transfers in flight than will fit into the RX FIFO,
+ // else FIFO will overflow if this code is heavily interrupted.
+ const size_t fifo_depth = 8;
+ size_t rx_remaining = len, tx_remaining = len;
+
+ while (rx_remaining || tx_remaining) {
+ if (tx_remaining && spi_is_writable(spi) && rx_remaining - tx_remaining < fifo_depth) {
+ spi_get_hw(spi)->dr = (uint32_t) *src++;
+ --tx_remaining;
+ }
+ if (rx_remaining && spi_is_readable(spi)) {
+ *dst++ = (uint16_t) spi_get_hw(spi)->dr;
+ --rx_remaining;
+ }
+ }
+
+ return len;
+}
+
+// Write len bytes directly from src to the SPI, and discard any data received back
+int __not_in_flash_func(spi_write16_blocking)(spi_inst_t *spi, const uint16_t *src, size_t len) {
+ // Deliberately overflow FIFO, then clean up afterward, to minimise amount
+ // of APB polling required per halfword
+ for (size_t i = 0; i < len; ++i) {
+ while (!spi_is_writable(spi))
+ tight_loop_contents();
+ spi_get_hw(spi)->dr = (uint32_t)src[i];
+ }
+
+ while (spi_is_readable(spi))
+ (void)spi_get_hw(spi)->dr;
+ while (spi_get_hw(spi)->sr & SPI_SSPSR_BSY_BITS)
+ tight_loop_contents();
+ while (spi_is_readable(spi))
+ (void)spi_get_hw(spi)->dr;
+
+ // Don't leave overrun flag set
+ spi_get_hw(spi)->icr = SPI_SSPICR_RORIC_BITS;
+
+ return len;
+}
+
+// Read len halfwords directly from the SPI to dst.
+// repeated_tx_data is output repeatedly on SO as data is read in from SI.
+int __not_in_flash_func(spi_read16_blocking)(spi_inst_t *spi, uint16_t repeated_tx_data, uint16_t *dst, size_t len) {
+ const size_t fifo_depth = 8;
+ size_t rx_remaining = len, tx_remaining = len;
+
+ while (rx_remaining || tx_remaining) {
+ if (tx_remaining && spi_is_writable(spi) && rx_remaining - tx_remaining < fifo_depth) {
+ spi_get_hw(spi)->dr = (uint32_t) repeated_tx_data;
+ --tx_remaining;
+ }
+ if (rx_remaining && spi_is_readable(spi)) {
+ *dst++ = (uint16_t) spi_get_hw(spi)->dr;
+ --rx_remaining;
+ }
+ }
+
+ return len;
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/CMakeLists.txt
new file mode 100644
index 00000000000..1c64ed61a49
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/CMakeLists.txt
@@ -0,0 +1 @@
+pico_simple_hardware_target(sync)
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/include/hardware/sync.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/include/hardware/sync.h
new file mode 100644
index 00000000000..f375ff8bdad
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/include/hardware/sync.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_SYNC_H
+#define _HARDWARE_SYNC_H
+
+#include "pico.h"
+#include "hardware/address_mapped.h"
+#include "hardware/regs/sio.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file hardware/sync.h
+ * \defgroup hardware_sync hardware_sync
+ *
+ * Low level hardware spin-lock, barrier and processor event API
+ *
+ * Functions for synchronisation between core's, HW, etc
+ *
+ * The RP2040 provides 32 hardware spin locks, which can be used to manage mutually-exclusive access to shared software
+ * resources.
+ *
+ * \note spin locks 0-15 are currently reserved for fixed uses by the SDK - i.e. if you use them other
+ * functionality may break or not function optimally
+ */
+
+/** \brief A spin lock identifier
+ * \ingroup hardware_sync
+ */
+typedef volatile uint32_t spin_lock_t;
+
+// PICO_CONFIG: PICO_SPINLOCK_ID_IRQ, Spinlock ID for IRQ protection, min=0, max=31, default=9, group=hardware_sync
+#ifndef PICO_SPINLOCK_ID_IRQ
+#define PICO_SPINLOCK_ID_IRQ 9
+#endif
+
+// PICO_CONFIG: PICO_SPINLOCK_ID_TIMER, Spinlock ID for Timer protection, min=0, max=31, default=10, group=hardware_sync
+#ifndef PICO_SPINLOCK_ID_TIMER
+#define PICO_SPINLOCK_ID_TIMER 10
+#endif
+
+// PICO_CONFIG: PICO_SPINLOCK_ID_HARDWARE_CLAIM, Spinlock ID for Hardware claim protection, min=0, max=31, default=11, group=hardware_sync
+#ifndef PICO_SPINLOCK_ID_HARDWARE_CLAIM
+#define PICO_SPINLOCK_ID_HARDWARE_CLAIM 11
+#endif
+
+// PICO_CONFIG: PICO_SPINLOCK_ID_STRIPED_FIRST, Spinlock ID for striped first, min=16, max=31, default=16, group=hardware_sync
+#ifndef PICO_SPINLOCK_ID_STRIPED_FIRST
+#define PICO_SPINLOCK_ID_STRIPED_FIRST 16
+#endif
+
+// PICO_CONFIG: PICO_SPINLOCK_ID_STRIPED_LAST, Spinlock ID for striped last, min=16, max=31, default=23, group=hardware_sync
+#ifndef PICO_SPINLOCK_ID_STRIPED_LAST
+#define PICO_SPINLOCK_ID_STRIPED_LAST 23
+#endif
+
+// PICO_CONFIG: PICO_SPINLOCK_ID_CLAIM_FREE_FIRST, Spinlock ID for claim free first, min=16, max=31, default=24, group=hardware_sync
+#ifndef PICO_SPINLOCK_ID_CLAIM_FREE_FIRST
+#define PICO_SPINLOCK_ID_CLAIM_FREE_FIRST 24
+#endif
+
+// PICO_CONFIG: PICO_SPINLOCK_ID_CLAIM_FREE_END, Spinlock ID for claim free end, min=16, max=31, default=31, group=hardware_sync
+#ifndef PICO_SPINLOCK_ID_CLAIM_FREE_END
+#define PICO_SPINLOCK_ID_CLAIM_FREE_END 31
+#endif
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_SYNC, Enable/disable assertions in the HW sync module, type=bool, default=0, group=hardware_sync
+#ifndef PARAM_ASSERTIONS_ENABLED_SYNC
+#define PARAM_ASSERTIONS_ENABLED_SYNC 0
+#endif
+
+
+/*! \brief Insert a SEV instruction in to the code path.
+ * \ingroup hardware_sync
+
+ * The SEV (send event) instruction sends an event to both cores.
+ */
+inline static void __sev() {
+ __asm volatile ("sev");
+}
+
+/*! \brief Insert a WFE instruction in to the code path.
+ * \ingroup hardware_sync
+ *
+ * The WFE (wait for event) instruction waits until one of a number of
+ * events occurs, including events signalled by the SEV instruction on either core.
+ */
+inline static void __wfe() {
+ __asm volatile ("wfe");
+}
+
+/*! \brief Insert a WFI instruction in to the code path.
+ * \ingroup hardware_sync
+*
+ * The WFI (wait for interrupt) instruction waits for a interrupt to wake up the core.
+ */
+inline static void __wfi() {
+ __asm volatile ("wfi");
+}
+
+/*! \brief Insert a DMB instruction in to the code path.
+ * \ingroup hardware_sync
+ *
+ * The DMB (data memory barrier) acts as a memory barrier, all memory accesses prior to this
+ * instruction will be observed before any explicit access after the instruction.
+ */
+inline static void __dmb() {
+ __asm volatile ("dmb");
+}
+
+/*! \brief Insert a ISB instruction in to the code path.
+ * \ingroup hardware_sync
+ *
+ * ISB acts as an instruction synchronization barrier. It flushes the pipeline of the processor,
+ * so that all instructions following the ISB are fetched from cache or memory again, after
+ * the ISB instruction has been completed.
+ */
+inline static void __isb() {
+ __asm volatile ("isb");
+}
+
+/*! \brief Acquire a memory fence
+ * \ingroup hardware_sync
+ */
+inline static void __mem_fence_acquire() {
+ // the original code below makes it hard for us to be included from C++ via a header
+ // which itself is in an extern "C", so just use __dmb instead, which is what
+ // is required on Cortex M0+
+ __dmb();
+//#ifndef __cplusplus
+// atomic_thread_fence(memory_order_acquire);
+//#else
+// std::atomic_thread_fence(std::memory_order_acquire);
+//#endif
+}
+
+/*! \brief Release a memory fence
+ * \ingroup hardware_sync
+ *
+ */
+inline static void __mem_fence_release() {
+ // the original code below makes it hard for us to be included from C++ via a header
+ // which itself is in an extern "C", so just use __dmb instead, which is what
+ // is required on Cortex M0+
+ __dmb();
+//#ifndef __cplusplus
+// atomic_thread_fence(memory_order_release);
+//#else
+// std::atomic_thread_fence(std::memory_order_release);
+//#endif
+}
+
+/*! \brief Save and disable interrupts
+ * \ingroup hardware_sync
+ *
+ * \return The prior interrupt enable status for restoration later via restore_interrupts()
+ */
+inline static uint32_t save_and_disable_interrupts() {
+ uint32_t status;
+ __asm volatile ("mrs %0, PRIMASK" : "=r" (status)::);
+ __asm volatile ("cpsid i");
+ return status;
+}
+
+/*! \brief Restore interrupts to a specified state
+ * \ingroup hardware_sync
+ *
+ * \param status Previous interrupt status from save_and_disable_interrupts()
+ */
+inline static void restore_interrupts(uint32_t status) {
+ __asm volatile ("msr PRIMASK,%0"::"r" (status) : );
+}
+
+/*! \brief Get HW Spinlock instance from number
+ * \ingroup hardware_sync
+ *
+ * \param lock_num Spinlock ID
+ * \return The spinlock instance
+ */
+inline static spin_lock_t *spin_lock_instance(uint lock_num) {
+ return (spin_lock_t *) (SIO_BASE + SIO_SPINLOCK0_OFFSET + lock_num * 4);
+}
+
+/*! \brief Get HW Spinlock number from instance
+ * \ingroup hardware_sync
+ *
+ * \param lock The Spinlock instance
+ * \return The Spinlock ID
+ */
+inline static uint spin_lock_get_num(spin_lock_t *lock) {
+ return lock - (spin_lock_t *) (SIO_BASE + SIO_SPINLOCK0_OFFSET);
+}
+
+/*! \brief Acquire a spin lock without disabling interrupts (hence unsafe)
+ * \ingroup hardware_sync
+ *
+ * \param lock Spinlock instance
+ */
+inline static void spin_lock_unsafe_blocking(spin_lock_t *lock) {
+ // Note we don't do a wfe or anything, because by convention these spin_locks are VERY SHORT LIVED and NEVER BLOCK and run
+ // with INTERRUPTS disabled (to ensure that)... therefore nothing on our core could be blocking us, so we just need to wait on another core
+ // anyway which should be finished soon
+ while (__builtin_expect(!*lock, 0));
+ __mem_fence_acquire();
+}
+
+/*! \brief Release a spin lock without re-enabling interrupts
+ * \ingroup hardware_sync
+ *
+ * \param lock Spinlock instance
+ */
+inline static void spin_unlock_unsafe(spin_lock_t *lock) {
+ __mem_fence_release();
+ *lock = 0;
+}
+
+/*! \brief Acquire a spin lock safely
+ * \ingroup hardware_sync
+ *
+ * This function will disable interrupts prior to acquiring the spinlock
+ *
+ * \param lock Spinlock instance
+ * \return interrupt status to be used when unlocking, to restore to original state
+ */
+inline static uint32_t spin_lock_blocking(spin_lock_t *lock) {
+ uint32_t save = save_and_disable_interrupts();
+ spin_lock_unsafe_blocking(lock);
+ return save;
+}
+
+/*! \brief Check to see if a spinlock is currently acquired elsewhere.
+ * \ingroup hardware_sync
+ *
+ * \param lock Spinlock instance
+ */
+inline static bool is_spin_locked(const spin_lock_t *lock) {
+ check_hw_size(spin_lock_t, 4);
+ uint32_t lock_num = lock - spin_lock_instance(0);
+ return 0 != (*(io_ro_32 *) (SIO_BASE + SIO_SPINLOCK_ST_OFFSET) & (1u << lock_num));
+}
+
+/*! \brief Release a spin lock safely
+ * \ingroup hardware_sync
+ *
+ * This function will re-enable interrupts according to the parameters.
+ *
+ * \param lock Spinlock instance
+ * \param saved_irq Return value from the \ref spin_lock_blocking() function.
+ * \return interrupt status to be used when unlocking, to restore to original state
+ *
+ * \sa spin_lock_blocking()
+ */
+inline static void spin_unlock(spin_lock_t *lock, uint32_t saved_irq) {
+ spin_unlock_unsafe(lock);
+ restore_interrupts(saved_irq);
+}
+
+/*! \brief Get the current core number
+ * \ingroup hardware_sync
+ *
+ * \return The core number the call was made from
+ */
+static inline uint get_core_num() {
+ return (*(uint32_t *) (SIO_BASE + SIO_CPUID_OFFSET));
+}
+
+/*! \brief Initialise a spin lock
+ * \ingroup hardware_sync
+ *
+ * The spin lock is initially unlocked
+ *
+ * \param lock_num The spin lock number
+ * \return The spin lock instance
+ */
+spin_lock_t *spin_lock_init(uint lock_num);
+
+/*! \brief Release all spin locks
+ * \ingroup hardware_sync
+ */
+void spin_locks_reset(void);
+
+// this number is not claimed
+uint next_striped_spin_lock_num();
+
+/*! \brief Mark a spin lock as used
+ * \ingroup hardware_sync
+ *
+ * Method for cooperative claiming of hardware. Will cause a panic if the spin lock
+ * is already claimed. Use of this method by libraries detects accidental
+ * configurations that would fail in unpredictable ways.
+ *
+ * \param lock_num the spin lock number
+ */
+void spin_lock_claim(uint lock_num);
+
+/*! \brief Mark multiple spin locks as used
+ * \ingroup hardware_sync
+ *
+ * Method for cooperative claiming of hardware. Will cause a panic if any of the spin locks
+ * are already claimed. Use of this method by libraries detects accidental
+ * configurations that would fail in unpredictable ways.
+ *
+ * \param lock_num_mask Bitfield of all required spin locks to claim (bit 0 == spin lock 0, bit 1 == spin lock 1 etc)
+ */
+void spin_lock_claim_mask(uint32_t lock_num_mask);
+
+/*! \brief Mark a spin lock as no longer used
+ * \ingroup hardware_sync
+ *
+ * Method for cooperative claiming of hardware.
+ *
+ * \param lock_num the spin lock number to release
+ */
+void spin_lock_unclaim(uint lock_num);
+
+/*! \brief Claim a free spin lock
+ * \ingroup hardware_sync
+ *
+ * \param required if true the function will panic if none are available
+ * \return the spin lock number or -1 if required was false, and none were free
+ */
+int spin_lock_claim_unused(bool required);
+
+#define remove_volatile_cast(t, x) ({__mem_fence_acquire(); (t)(x); })
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/sync.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/sync.c
new file mode 100644
index 00000000000..dba040a1772
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_sync/sync.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/sync.h"
+#include "hardware/claim.h"
+
+static_assert(PICO_SPINLOCK_ID_STRIPED_LAST >= PICO_SPINLOCK_ID_STRIPED_FIRST, "");
+static uint8_t striped_spin_lock_num = PICO_SPINLOCK_ID_STRIPED_FIRST;
+static uint32_t claimed;
+
+static void check_lock_num(uint __unused lock_num) {
+ invalid_params_if(SYNC, lock_num >= 32);
+}
+
+void spin_locks_reset(void) {
+ for (uint i = 0; i < NUM_SPIN_LOCKS; i++) {
+ spin_unlock_unsafe(spin_lock_instance(i));
+ }
+}
+
+spin_lock_t *spin_lock_init(uint lock_num) {
+ assert(lock_num >= 0 && lock_num < NUM_SPIN_LOCKS);
+ spin_lock_t *lock = spin_lock_instance(lock_num);
+ spin_unlock_unsafe(lock);
+ return lock;
+}
+
+uint next_striped_spin_lock_num() {
+ uint rc = striped_spin_lock_num++;
+ if (striped_spin_lock_num > PICO_SPINLOCK_ID_STRIPED_LAST) {
+ striped_spin_lock_num = PICO_SPINLOCK_ID_STRIPED_FIRST;
+ }
+ return rc;
+}
+
+void spin_lock_claim(uint lock_num) {
+ check_lock_num(lock_num);
+ hw_claim_or_assert((uint8_t *) &claimed, lock_num, "Spinlock %d is already claimed");
+}
+
+void spin_lock_claim_mask(uint32_t mask) {
+ for(uint i = 0; mask; i++, mask >>= 1u) {
+ if (mask & 1u) spin_lock_claim(i);
+ }
+}
+
+void spin_lock_unclaim(uint lock_num) {
+ check_lock_num(lock_num);
+ hw_claim_clear((uint8_t *) &claimed, lock_num);
+}
+
+int spin_lock_claim_unused(bool required) {
+ return hw_claim_unused_from_range((uint8_t*)&claimed, required, PICO_SPINLOCK_ID_CLAIM_FREE_FIRST, PICO_SPINLOCK_ID_CLAIM_FREE_END, "No spinlocks are available");
+}
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_timer/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_timer/CMakeLists.txt
new file mode 100644
index 00000000000..358f74c50f3
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_timer/CMakeLists.txt
@@ -0,0 +1,2 @@
+pico_simple_hardware_target(timer)
+target_link_libraries(hardware_timer INTERFACE hardware_claim)
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_timer/include/hardware/timer.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_timer/include/hardware/timer.h
new file mode 100644
index 00000000000..1815a2780eb
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_timer/include/hardware/timer.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_TIMER_H
+#define _HARDWARE_TIMER_H
+
+#include "pico.h"
+#include "hardware/structs/timer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file hardware/timer.h
+ * \defgroup hardware_timer hardware_timer
+ *
+ * Low-level hardware timer API
+ *
+ * This API provides medium level access to the timer HW.
+ * See also \ref pico_time which provides higher levels functionality using the hardware timer.
+ *
+ * The timer peripheral on RP2040 supports the following features:
+ * - single 64-bit counter, incrementing once per microsecond
+ * - Latching two-stage read of counter, for race-free read over 32 bit bus
+ * - Four alarms: match on the lower 32 bits of counter, IRQ on match.
+ *
+ * By default the timer uses a one microsecond reference that is generated in the Watchdog (see Section 4.8.2) which is derived
+ * from the clk_ref.
+ *
+ * The timer has 4 alarms, and can output a separate interrupt for each alarm. The alarms match on the lower 32 bits of the 64
+ * bit counter which means they can be fired a maximum of 2^32 microseconds into the future. This is equivalent to:
+ * - 2^32 ÷ 10^6: ~4295 seconds
+ * - 4295 ÷ 60: ~72 minutes
+ *
+ * The timer is expected to be used for short sleeps, if you want a longer alarm see the \ref hardware_rtc functions.
+ *
+ * \subsection timer_example Example
+ * \addtogroup hardware_timer
+ *
+ * \include hello_timer.c
+ *
+ * \see pico_time
+ */
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_TIMER, Enable/disable assertions in the timer module, type=bool, default=0, group=hardware_timer
+#ifndef PARAM_ASSERTIONS_ENABLED_TIMER
+#define PARAM_ASSERTIONS_ENABLED_TIMER 0
+#endif
+
+static inline void check_hardware_alarm_num_param(uint alarm_num) {
+ invalid_params_if(TIMER, alarm_num >= NUM_TIMERS);
+}
+
+/*! \brief Return a 32 bit timestamp value in microseconds
+* \ingroup hardware_timer
+*
+* Returns the low 32 bits of the hardware timer.
+* \note This value wraps roughly every 1 hour 11 minutes and 35 seconds.
+*
+* \return the 32 bit timestamp
+*/
+static inline uint32_t time_us_32() {
+ return timer_hw->timerawl;
+}
+
+/*! \brief Return the current 64 bit timestamp value in microseconds
+* \ingroup hardware_timer
+*
+* Returns the full 64 bits of the hardware timer. The \ref pico_time and other functions rely on the fact that this
+* value monotonically increases from power up. As such it is expected that this value counts upwards and never wraps
+* (we apologize for introducing a potential year 5851444 bug).
+*
+* \return the 64 bit timestamp
+*/
+uint64_t time_us_64();
+
+/*! \brief Busy wait wasting cycles for the given (32 bit) number of microseconds
+ * \ingroup hardware_timer
+ *
+ * \param delay_us delay amount
+ */
+void busy_wait_us_32(uint32_t delay_us);
+
+/*! \brief Busy wait wasting cycles for the given (64 bit) number of microseconds
+ * \ingroup hardware_timer
+ *
+ * \param delay_us delay amount
+ */
+void busy_wait_us(uint64_t delay_us);
+
+/*! \brief Busy wait wasting cycles until after the specified timestamp
+ * \ingroup hardware_timer
+ *
+ * \param t Absolute time to wait until
+ */
+void busy_wait_until(absolute_time_t t);
+
+/*! \brief Check if the specified timestamp has been reached
+ * \ingroup hardware_timer
+ *
+ * \param t Absolute time to compare against current time
+ * \return true if it is now after the specified timestamp
+ */
+static inline bool time_reached(absolute_time_t t) {
+ uint64_t target = to_us_since_boot(t);
+ uint32_t hi_target = target >> 32u;
+ uint32_t hi = timer_hw->timerawh;
+ return (hi >= hi_target && (timer_hw->timerawl >= (uint32_t) target || hi != hi_target));
+}
+
+/*! Callback function type for hardware alarms
+ * \ingroup hardware_timer
+ *
+ * \param alarm_num the hardware alarm number
+ * \sa hardware_alarm_set_callback
+ */
+typedef void (*hardware_alarm_callback_t)(uint alarm_num);
+
+/*! \brief cooperatively claim the use of this hardware alarm_num
+ * \ingroup hardware_timer
+ *
+ * This method hard asserts if the hardware alarm is currently claimed.
+ *
+ * \param alarm_num the hardware alarm to claim
+ * \sa hardware_claiming
+ */
+void hardware_alarm_claim(uint alarm_num);
+
+/*! \brief cooperatively release the claim on use of this hardware alarm_num
+ * \ingroup hardware_timer
+ *
+ * \param alarm_num the hardware alarm to unclaim
+ * \sa hardware_claiming
+ */
+void hardware_alarm_unclaim(uint alarm_num);
+
+/*! \brief Enable/Disable a callback for a hardware timer on this core
+ * \ingroup hardware_timer
+ *
+ * This method enables/disables the alarm IRQ for the specified hardware alarm on the
+ * calling core, and set the specified callback to be associated with that alarm.
+ *
+ * This callback will be used for the timeout set via hardware_alarm_set_target
+ *
+ * \note This will install the handler on the current core if the IRQ handler isn't already set.
+ * Therefore the user has the opportunity to call this up from the core of their choice
+ *
+ * \param alarm_num the hardware alarm number
+ * \param callback the callback to install, or NULL to unset
+ *
+ * \sa hardware_alarm_set_target
+ */
+void hardware_alarm_set_callback(uint alarm_num, hardware_alarm_callback_t callback);
+
+/**
+ * \brief Set the current target for the specified hardware alarm
+ *
+ * This will replace any existing target
+ *
+ * @param alarm_num the hardware alarm number
+ * @param t the target timestamp
+ * @return true if the target was "missed"; i.e. it was in the past, or occurred before a future hardware timeout could be set
+ */
+bool hardware_alarm_set_target(uint alarm_num, absolute_time_t t);
+
+/**
+ * \brief Cancel an existing target (if any) for a given hardware_alarm
+ *
+ * @param alarm_num
+ */
+
+void hardware_alarm_cancel(uint alarm_num);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_timer/timer.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_timer/timer.c
new file mode 100644
index 00000000000..76d5f9038ac
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_timer/timer.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/timer.h"
+#include "hardware/irq.h"
+#include "hardware/sync.h"
+#include "hardware/claim.h"
+
+check_hw_layout(timer_hw_t, ints, TIMER_INTS_OFFSET);
+
+static hardware_alarm_callback_t alarm_callbacks[NUM_TIMERS];
+static uint32_t target_hi[NUM_TIMERS];
+static uint8_t timer_callbacks_pending;
+
+static_assert(NUM_TIMERS <= 4, "");
+static uint8_t claimed;
+
+void hardware_alarm_claim(uint alarm_num) {
+ check_hardware_alarm_num_param(alarm_num);
+ hw_claim_or_assert(&claimed, alarm_num, "Hardware alarm %d already claimed");
+}
+
+void hardware_alarm_unclaim(uint alarm_num) {
+ check_hardware_alarm_num_param(alarm_num);
+ hw_claim_clear(&claimed, alarm_num);
+}
+
+/// tag::time_us_64[]
+uint64_t time_us_64() {
+ // Need to make sure that the upper 32 bits of the timer
+ // don't change, so read that first
+ uint32_t hi = timer_hw->timerawh;
+ uint32_t lo;
+ do {
+ // Read the lower 32 bits
+ lo = timer_hw->timerawl;
+ // Now read the upper 32 bits again and
+ // check that it hasn't incremented. If it has loop around
+ // and read the lower 32 bits again to get an accurate value
+ uint32_t next_hi = timer_hw->timerawh;
+ if (hi == next_hi) break;
+ hi = next_hi;
+ } while (true);
+ return ((uint64_t) hi << 32u) | lo;
+}
+/// end::time_us_64[]
+
+/// \tag::busy_wait[]
+void busy_wait_us_32(uint32_t delay_us) {
+ if (0 <= (int32_t)delay_us) {
+ // we only allow 31 bits, otherwise we could have a race in the loop below with
+ // values very close to 2^32
+ uint32_t start = timer_hw->timerawl;
+ while (timer_hw->timerawl - start < delay_us) {
+ tight_loop_contents();
+ }
+ } else {
+ busy_wait_us(delay_us);
+ }
+}
+
+void busy_wait_us(uint64_t delay_us) {
+ uint64_t base = time_us_64();
+ uint64_t target = base + delay_us;
+ if (target < base) {
+ target = (uint64_t)-1;
+ }
+ absolute_time_t t;
+ update_us_since_boot(&t, target);
+ busy_wait_until(t);
+}
+
+void busy_wait_until(absolute_time_t t) {
+ uint64_t target = to_us_since_boot(t);
+ uint32_t hi_target = target >> 32u;
+ uint32_t hi = timer_hw->timerawh;
+ while (hi < hi_target) {
+ hi = timer_hw->timerawh;
+ tight_loop_contents();
+ }
+ while (hi == hi_target && timer_hw->timerawl < (uint32_t) target) {
+ hi = timer_hw->timerawh;
+ tight_loop_contents();
+ }
+}
+/// \end::busy_wait[]
+
+static inline uint harware_alarm_irq_number(uint alarm_num) {
+ return TIMER_IRQ_0 + alarm_num;
+}
+
+static void hardware_alarm_irq_handler() {
+ // Determine which timer this IRQ is for
+ uint32_t ipsr;
+ __asm volatile ("mrs %0, ipsr" : "=r" (ipsr)::);
+ uint alarm_num = (ipsr & 0x3fu) - 16 - TIMER_IRQ_0;
+ check_hardware_alarm_num_param(alarm_num);
+
+ hardware_alarm_callback_t callback = NULL;
+
+ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
+ uint32_t save = spin_lock_blocking(lock);
+ // Clear the timer IRQ (inside lock, because we check whether we have handled the IRQ yet in alarm_set by looking at the interrupt status
+ timer_hw->intr = 1u << alarm_num;
+
+ // make sure the IRQ is still valid
+ if (timer_callbacks_pending & (1u << alarm_num)) {
+ // Now check whether we have a timer event to handle that isn't already obsolete (this could happen if we
+ // were already in the IRQ handler before someone else changed the timer setup
+ if (timer_hw->timerawh >= target_hi[alarm_num]) {
+ // we have reached the right high word as well as low word value
+ callback = alarm_callbacks[alarm_num];
+ timer_callbacks_pending &= ~(1u << alarm_num);
+ } else {
+ // try again in 2^32 us
+ timer_hw->alarm[alarm_num] = timer_hw->alarm[alarm_num]; // re-arm the timer
+ }
+ }
+
+ spin_unlock(lock, save);
+
+ if (callback) {
+ callback(alarm_num);
+ }
+}
+
+void hardware_alarm_set_callback(uint alarm_num, hardware_alarm_callback_t callback) {
+ // todo check current core owner
+ // note this should probably be subsumed by irq_set_exclusive_handler anyway, since that
+ // should disallow IRQ handlers on both cores
+ check_hardware_alarm_num_param(alarm_num);
+ uint irq_num = harware_alarm_irq_number(alarm_num);
+ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
+ uint32_t save = spin_lock_blocking(lock);
+ if (callback) {
+ if (hardware_alarm_irq_handler != irq_get_vtable_handler(irq_num)) {
+ // note that set_exclusive will silently allow you to set the handler to the same thing
+ // since it is idempotent, which means we don't need to worry about locking ourselves
+ irq_set_exclusive_handler(irq_num, hardware_alarm_irq_handler);
+ irq_set_enabled(irq_num, true);
+ // Enable interrupt in block and at processor
+ hw_set_bits(&timer_hw->inte, 1u << alarm_num);
+ }
+ alarm_callbacks[alarm_num] = callback;
+ } else {
+ alarm_callbacks[alarm_num] = NULL;
+ timer_callbacks_pending &= ~(1u << alarm_num);
+ irq_remove_handler(irq_num, hardware_alarm_irq_handler);
+ irq_set_enabled(irq_num, false);
+ }
+ spin_unlock(lock, save);
+}
+
+bool hardware_alarm_set_target(uint alarm_num, absolute_time_t target) {
+ bool missed;
+ uint64_t now = time_us_64();
+ uint64_t t = to_us_since_boot(target);
+ if (now >= t) {
+ missed = true;
+ } else {
+ missed = false;
+
+ // 1) actually set the hardware timer
+ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
+ uint32_t save = spin_lock_blocking(lock);
+ timer_hw->intr = 1u << alarm_num;
+ timer_callbacks_pending |= 1u << alarm_num;
+ timer_hw->alarm[alarm_num] = (uint32_t) t;
+ // Set the alarm. Writing time should arm it
+ target_hi[alarm_num] = t >> 32u;
+
+ // 2) check for races
+ if (!(timer_hw->armed & 1u << alarm_num)) {
+ // not armed, so has already fired .. IRQ must be pending (we are still under lock)
+ assert(timer_hw->ints & 1u << alarm_num);
+ } else {
+ if (time_us_64() >= t) {
+ // ok well it is time now; the irq isn't being handled yet because of the spin lock
+ // however the other core might be in the IRQ handler itself about to do a callback
+ // we do the firing ourselves (and indicate to the IRQ handler if any that it shouldn't
+ missed = true;
+ // disarm the timer
+ timer_hw->armed = 1u << alarm_num;
+ timer_hw->intr = 1u << alarm_num; // clear the IRQ too
+ // and set flag in case we're already in the IRQ handler waiting on the spinlock (on the other core)
+ timer_callbacks_pending &= ~(1u << alarm_num);
+ }
+ }
+ spin_unlock(lock, save);
+ }
+ return missed;
+}
+
+void hardware_alarm_cancel(uint alarm_num) {
+ check_hardware_alarm_num_param(alarm_num);
+
+ spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
+ uint32_t save = spin_lock_blocking(lock);
+ timer_hw->armed = 1u << alarm_num;
+ timer_callbacks_pending &= ~(1u << alarm_num);
+ spin_unlock(lock, save);
+}
+
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_uart/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_uart/CMakeLists.txt
new file mode 100644
index 00000000000..9fe65d54226
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_uart/CMakeLists.txt
@@ -0,0 +1 @@
+pico_simple_hardware_target(uart)
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_uart/include/hardware/uart.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_uart/include/hardware/uart.h
new file mode 100644
index 00000000000..c957a335284
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_uart/include/hardware/uart.h
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_UART_H
+#define _HARDWARE_UART_H
+
+#include "pico.h"
+#include "hardware/structs/uart.h"
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_UART, Enable/disable assertions in the UART module, type=bool, default=0, group=hardware_uart
+#ifndef PARAM_ASSERTIONS_ENABLED_UART
+#define PARAM_ASSERTIONS_ENABLED_UART 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// PICO_CONFIG: PICO_UART_ENABLE_CRLF_SUPPORT, Enable/disable CR/LF translation support, type=bool, default=1, group=hardware_uart
+#ifndef PICO_UART_ENABLE_CRLF_SUPPORT
+#define PICO_UART_ENABLE_CRLF_SUPPORT 1
+#endif
+
+// PICO_CONFIG: PICO_UART_DEFAULT_CRLF, Enable/disable CR/LF translation on UART, type=bool, default=0, depends=PICO_UART_ENABLE_CRLF_SUPPORT, group=hardware_uart
+#ifndef PICO_UART_DEFAULT_CRLF
+#define PICO_UART_DEFAULT_CRLF 0
+#endif
+
+// PICO_CONFIG: PICO_DEFAULT_UART, Define the default UART used for printf etc, default=0, group=hardware_uart
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0 ///< Default UART instance
+#endif
+
+// PICO_CONFIG: PICO_DEFAULT_UART_BAUD_RATE, Define the default UART baudrate, max=921600, default=115200, group=hardware_uart
+#ifndef PICO_DEFAULT_UART_BAUD_RATE
+#define PICO_DEFAULT_UART_BAUD_RATE 115200 ///< Default baud rate
+#endif
+
+// PICO_CONFIG: PICO_DEFAULT_UART_TX_PIN, Define the default UART TX pin, min=0, max=29, default=0, group=hardware_uart
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 0 ///< Default TX pin
+#endif
+
+// PICO_CONFIG: PICO_DEFAULT_UART_RX_PIN, Define the default UART RX pin, min=0, max=29, default=1, group=hardware_uart
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 1 ///< Default RX pin
+#endif
+
+/** \file hardware/uart.h
+ * \defgroup hardware_uart hardware_uart
+ *
+ * Hardware UART API
+ *
+ * RP2040 has 2 identical instances of a UART peripheral, based on the ARM PL011. Each UART can be connected to a number
+ * of GPIO pins as defined in the GPIO muxing.
+ *
+ * Only the TX, RX, RTS, and CTS signals are
+ * connected, meaning that the modem mode and IrDA mode of the PL011 are not supported.
+ *
+ * \subsection uart_example Example
+ * \addtogroup hardware_uart
+ *
+ * \code
+ * int main() {
+ *
+ * // Initialise UART 0
+ * uart_init(uart0, 115200);
+ *
+ * // Set the GPIO pin mux to the UART - 0 is TX, 1 is RX
+ * gpio_set_function(0, GPIO_FUNC_UART);
+ * gpio_set_function(1, GPIO_FUNC_UART);
+ *
+ * uart_puts(uart0, "Hello world!");
+ * }
+ * \endcode
+ */
+
+// Currently always a pointer to hw but it might not be in the future
+typedef struct uart_inst uart_inst_t;
+
+/** The UART identifiers for use in UART functions.
+ *
+ * e.g. uart_init(uart1, 48000)
+ *
+ * \ingroup hardware_uart
+ * @{
+ */
+#define uart0 ((uart_inst_t * const)uart0_hw) ///< Identifier for UART instance 0
+#define uart1 ((uart_inst_t * const)uart1_hw) ///< Identifier for UART instance 1
+
+/** @} */
+
+#ifndef PICO_DEFAULT_UART_INSTANCE
+#define PICO_DEFAULT_UART_INSTANCE (__CONCAT(uart,PICO_DEFAULT_UART))
+#endif
+
+#define uart_default PICO_DEFAULT_UART_INSTANCE
+
+/*! \brief Convert UART instance to hardware instance number
+ * \ingroup hardware_uart
+ *
+ * \param uart UART instance
+ * \return Number of UART, 0 or 1.
+ */
+static inline uint uart_get_index(uart_inst_t *uart) {
+ invalid_params_if(UART, uart != uart0 && uart != uart1);
+ return uart == uart1 ? 1 : 0;
+}
+
+static inline uart_hw_t *uart_get_hw(uart_inst_t *uart) {
+ uart_get_index(uart); // check it is a hw uart
+ return (uart_hw_t *)uart;
+}
+
+/** \brief UART Parity enumeration
+ * \ingroup hardware_uart
+ */
+typedef enum {
+ UART_PARITY_NONE,
+ UART_PARITY_EVEN,
+ UART_PARITY_ODD
+} uart_parity_t;
+
+// ----------------------------------------------------------------------------
+// Setup
+
+/*! \brief Initialise a UART
+ * \ingroup hardware_uart
+ *
+ * Put the UART into a known state, and enable it. Must be called before other
+ * functions.
+ *
+ * \note There is no guarantee that the baudrate requested will be possible, the nearest will be chosen,
+ * and this function will return the configured baud rate.
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param baudrate Baudrate of UART in Hz
+ * \return Actual set baudrate
+ */
+uint uart_init(uart_inst_t *uart, uint baudrate);
+
+/*! \brief DeInitialise a UART
+ * \ingroup hardware_uart
+ *
+ * Disable the UART if it is no longer used. Must be reinitialised before
+ * being used again.
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ */
+void uart_deinit(uart_inst_t *uart);
+
+/*! \brief Set UART baud rate
+ * \ingroup hardware_uart
+ *
+ * Set baud rate as close as possible to requested, and return actual rate selected.
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param baudrate Baudrate in Hz
+ * \return Actual set baudrate
+ */
+uint uart_set_baudrate(uart_inst_t *uart, uint baudrate);
+
+/*! \brief Set UART flow control CTS/RTS
+ * \ingroup hardware_uart
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param cts If true enable flow control of TX by clear-to-send input
+ * \param rts If true enable assertion of request-to-send output by RX flow control
+ */
+static inline void uart_set_hw_flow(uart_inst_t *uart, bool cts, bool rts) {
+ hw_write_masked(&uart_get_hw(uart)->cr,
+ (!!cts << UART_UARTCR_CTSEN_LSB) | (!!rts << UART_UARTCR_RTSEN_LSB),
+ UART_UARTCR_RTSEN_BITS | UART_UARTCR_CTSEN_BITS);
+}
+
+/*! \brief Set UART data format
+ * \ingroup hardware_uart
+ *
+ * Configure the data format (bits etc() for the UART
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param data_bits Number of bits of data. 5..8
+ * \param stop_bits Number of stop bits 1..2
+ * \param parity Parity option.
+ */
+static inline void uart_set_format(uart_inst_t *uart, uint data_bits, uint stop_bits, uart_parity_t parity) {
+ invalid_params_if(UART, data_bits < 5 || data_bits > 8);
+ invalid_params_if(UART, stop_bits != 1 && stop_bits != 2);
+ invalid_params_if(UART, parity != UART_PARITY_NONE && parity != UART_PARITY_EVEN && parity != UART_PARITY_ODD);
+ hw_write_masked(&uart_get_hw(uart)->lcr_h,
+ ((data_bits - 5) << UART_UARTLCR_H_WLEN_LSB) |
+ ((stop_bits - 1) << UART_UARTLCR_H_STP2_LSB) |
+ ((parity != UART_PARITY_NONE) << UART_UARTLCR_H_PEN_LSB) |
+ ((parity == UART_PARITY_EVEN) << UART_UARTLCR_H_EPS_LSB),
+ UART_UARTLCR_H_WLEN_BITS |
+ UART_UARTLCR_H_STP2_BITS |
+ UART_UARTLCR_H_PEN_BITS |
+ UART_UARTLCR_H_EPS_BITS);
+}
+
+/*! \brief Setup UART interrupts
+ * \ingroup hardware_uart
+ *
+ * Enable the UART's interrupt output. An interrupt handler will need to be installed prior to calling
+ * this function.
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param rx_has_data If true an interrupt will be fired when the RX FIFO contain data.
+ * \param tx_needs_data If true an interrupt will be fired when the TX FIFO needs data.
+ */
+static inline void uart_set_irq_enables(uart_inst_t *uart, bool rx_has_data, bool tx_needs_data) {
+ uart_get_hw(uart)->imsc = (!!tx_needs_data << UART_UARTIMSC_TXIM_LSB) |
+ (!!rx_has_data << UART_UARTIMSC_RXIM_LSB);
+ if (rx_has_data) {
+ // Set minimum threshold
+ hw_write_masked(&uart_get_hw(uart)->ifls, 0 << UART_UARTIFLS_RXIFLSEL_LSB,
+ UART_UARTIFLS_RXIFLSEL_BITS);
+ }
+ if (tx_needs_data) {
+ // Set maximum threshold
+ hw_write_masked(&uart_get_hw(uart)->ifls, 0 << UART_UARTIFLS_TXIFLSEL_LSB,
+ UART_UARTIFLS_TXIFLSEL_BITS);
+ }
+}
+
+/*! \brief Test if specific UART is enabled
+ * \ingroup hardware_uart
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \return true if the UART is enabled
+ */
+static inline bool uart_is_enabled(uart_inst_t *uart) {
+ return !!(uart_get_hw(uart)->cr & UART_UARTCR_UARTEN_BITS);
+}
+
+/*! \brief Enable/Disable the FIFOs on specified UART
+ * \ingroup hardware_uart
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param enabled true to enable FIFO (default), false to disable
+ */
+static inline void uart_set_fifo_enabled(uart_inst_t *uart, bool enabled) {
+ hw_write_masked(&uart_get_hw(uart)->lcr_h,
+ (!!enabled << UART_UARTLCR_H_FEN_LSB),
+ UART_UARTLCR_H_FEN_BITS);
+}
+
+
+// ----------------------------------------------------------------------------
+// Generic input/output
+
+/*! \brief Determine if space is available in the TX FIFO
+ * \ingroup hardware_uart
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \return false if no space available, true otherwise
+ */
+static inline bool uart_is_writable(uart_inst_t *uart) {
+ return !(uart_get_hw(uart)->fr & UART_UARTFR_TXFF_BITS);
+}
+
+/*! \brief Wait for the UART TX fifo to be drained
+ * \ingroup hardware_uart
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ */
+static inline void uart_tx_wait_blocking(uart_inst_t *uart) {
+ while (uart_get_hw(uart)->fr & UART_UARTFR_BUSY_BITS) tight_loop_contents();
+}
+
+/*! \brief Determine whether data is waiting in the RX FIFO
+ * \ingroup hardware_uart
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \return 0 if no data available, otherwise the number of bytes, at least, that can be read
+ *
+ * \note HW limitations mean this function will return either 0 or 1.
+ */
+static inline bool uart_is_readable(uart_inst_t *uart) {
+ // PL011 doesn't expose levels directly, so return values are only 0 or 1
+ return !(uart_get_hw(uart)->fr & UART_UARTFR_RXFE_BITS);
+}
+
+/*! \brief Write to the UART for transmission.
+ * \ingroup hardware_uart
+ *
+ * This function will block until all the data has been sent to the UART
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param src The bytes to send
+ * \param len The number of bytes to send
+ */
+static inline void uart_write_blocking(uart_inst_t *uart, const uint8_t *src, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ while (!uart_is_writable(uart))
+ tight_loop_contents();
+ uart_get_hw(uart)->dr = *src++;
+ }
+}
+
+/*! \brief Read from the UART
+ * \ingroup hardware_uart
+ *
+ * This function will block until all the data has been received from the UART
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param dst Buffer to accept received bytes
+ * \param len The number of bytes to receive.
+ */
+static inline void uart_read_blocking(uart_inst_t *uart, uint8_t *dst, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ while (!uart_is_readable(uart))
+ tight_loop_contents();
+ *dst++ = uart_get_hw(uart)->dr;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// UART-specific operations and aliases
+
+/*! \brief Write single character to UART for transmission.
+ * \ingroup hardware_uart
+ *
+ * This function will block until all the character has been sent
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param c The character to send
+ */
+static inline void uart_putc_raw(uart_inst_t *uart, char c) {
+ uart_write_blocking(uart, (const uint8_t *) &c, 1);
+}
+
+/*! \brief Write single character to UART for transmission, with optional CR/LF conversions
+ * \ingroup hardware_uart
+ *
+ * This function will block until the character has been sent
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param c The character to send
+ */
+static inline void uart_putc(uart_inst_t *uart, char c) {
+#if PICO_UART_ENABLE_CRLF_SUPPORT
+ extern short uart_char_to_line_feed[NUM_UARTS];
+ if (uart_char_to_line_feed[uart_get_index(uart)] == c)
+ uart_putc_raw(uart, '\r');
+#endif
+ uart_putc_raw(uart, c);
+}
+
+/*! \brief Write string to UART for transmission, doing any CR/LF conversions
+ * \ingroup hardware_uart
+ *
+ * This function will block until the entire string has been sent
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param s The null terminated string to send
+ */
+static inline void uart_puts(uart_inst_t *uart, const char *s) {
+#if PICO_UART_ENABLE_CRLF_SUPPORT
+ bool last_was_cr = false;
+ while (*s) {
+ // Don't add extra carriage returns if one is present
+ if (last_was_cr)
+ uart_putc_raw(uart, *s);
+ else
+ uart_putc(uart, *s);
+ last_was_cr = *s++ == '\r';
+ }
+#else
+ while (*s)
+ uart_putc(uart, *s++);
+#endif
+}
+
+/*! \brief Read a single character to UART
+ * \ingroup hardware_uart
+ *
+ * This function will block until the character has been read
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \return The character read.
+ */
+static inline char uart_getc(uart_inst_t *uart) {
+ char c;
+ uart_read_blocking(uart, (uint8_t *) &c, 1);
+ return c;
+}
+
+/*! \brief Assert a break condition on the UART transmission.
+ * \ingroup hardware_uart
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param en Assert break condition (TX held low) if true. Clear break condition if false.
+ */
+static inline void uart_set_break(uart_inst_t *uart, bool en) {
+ if (en)
+ hw_set_bits(&uart_get_hw(uart)->lcr_h, UART_UARTLCR_H_BRK_BITS);
+ else
+ hw_clear_bits(&uart_get_hw(uart)->lcr_h, UART_UARTLCR_H_BRK_BITS);
+}
+
+/*! \brief Set CR/LF conversion on UART
+ * \ingroup hardware_uart
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param translate If true, convert line feeds to carriage return on transmissions
+ */
+void uart_set_translate_crlf(uart_inst_t *uart, bool translate);
+
+/*! \brief Wait for the default UART'S TX fifo to be drained
+ * \ingroup hardware_uart
+ */
+static inline void uart_default_tx_wait_blocking() {
+ uart_tx_wait_blocking(uart_default);
+}
+
+/*! \brief Wait for up to a certain number of microseconds for the RX FIFO to be non empty
+ * \ingroup hardware_uart
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param us the number of microseconds to wait at most (may be 0 for an instantaneous check)
+ * \return true if the RX FIFO became non empty before the timeout, false otherwise
+ */
+bool uart_is_readable_within_us(uart_inst_t *uart, uint32_t us);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_uart/uart.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_uart/uart.c
new file mode 100644
index 00000000000..51d8d74b223
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_uart/uart.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/address_mapped.h"
+#include "hardware/platform_defs.h"
+#include "hardware/uart.h"
+
+#include "hardware/structs/uart.h"
+#include "hardware/resets.h"
+#include "hardware/clocks.h"
+#include "hardware/timer.h"
+
+#include "pico/assert.h"
+#include "pico.h"
+
+check_hw_layout(uart_hw_t, fr, UART_UARTFR_OFFSET);
+check_hw_layout(uart_hw_t, dmacr, UART_UARTDMACR_OFFSET);
+
+#if PICO_UART_ENABLE_CRLF_SUPPORT
+short uart_char_to_line_feed[NUM_UARTS];
+#endif
+
+/// \tag::uart_reset[]
+static inline void uart_reset(uart_inst_t *uart) {
+ invalid_params_if(UART, uart != uart0 && uart != uart1);
+ reset_block(uart_get_index(uart) ? RESETS_RESET_UART1_BITS : RESETS_RESET_UART0_BITS);
+}
+
+static inline void uart_unreset(uart_inst_t *uart) {
+ invalid_params_if(UART, uart != uart0 && uart != uart1);
+ unreset_block_wait(uart_get_index(uart) ? RESETS_RESET_UART1_BITS : RESETS_RESET_UART0_BITS);
+}
+/// \end::uart_reset[]
+
+/// \tag::uart_init[]
+uint uart_init(uart_inst_t *uart, uint baudrate) {
+ invalid_params_if(UART, uart != uart0 && uart != uart1);
+
+ if (clock_get_hz(clk_peri) == 0)
+ return 0;
+
+ uart_reset(uart);
+ uart_unreset(uart);
+
+#if PICO_UART_ENABLE_CRLF_SUPPORT
+ uart_set_translate_crlf(uart, PICO_UART_DEFAULT_CRLF);
+#endif
+
+ // Any LCR writes need to take place before enabling the UART
+ uint baud = uart_set_baudrate(uart, baudrate);
+ uart_set_format(uart, 8, 1, UART_PARITY_NONE);
+
+ // Enable the UART, both TX and RX
+ uart_get_hw(uart)->cr = UART_UARTCR_UARTEN_BITS | UART_UARTCR_TXE_BITS | UART_UARTCR_RXE_BITS;
+ // Enable FIFOs
+ hw_set_bits(&uart_get_hw(uart)->lcr_h, UART_UARTLCR_H_FEN_BITS);
+ // Always enable DREQ signals -- no harm in this if DMA is not listening
+ uart_get_hw(uart)->dmacr = UART_UARTDMACR_TXDMAE_BITS | UART_UARTDMACR_RXDMAE_BITS;
+
+ return baud;
+}
+/// \end::uart_init[]
+
+void uart_deinit(uart_inst_t *uart) {
+ invalid_params_if(UART, uart != uart0 && uart != uart1);
+ uart_reset(uart);
+}
+
+/// \tag::uart_set_baudrate[]
+uint uart_set_baudrate(uart_inst_t *uart, uint baudrate) {
+ invalid_params_if(UART, baudrate == 0);
+ uint32_t baud_rate_div = (8 * clock_get_hz(clk_peri) / baudrate);
+ uint32_t baud_ibrd = baud_rate_div >> 7;
+ uint32_t baud_fbrd = ((baud_rate_div & 0x7f) + 1) / 2;
+
+ if (baud_ibrd == 0) {
+ baud_ibrd = 1;
+ baud_fbrd = 0;
+ } else if (baud_ibrd >= 65535) {
+ baud_ibrd = 65535;
+ baud_fbrd = 0;
+ }
+
+ // Load PL011's baud divisor registers
+ uart_get_hw(uart)->ibrd = baud_ibrd;
+ uart_get_hw(uart)->fbrd = baud_fbrd;
+
+ // PL011 needs a (dummy) line control register write to latch in the
+ // divisors. We don't want to actually change LCR contents here.
+ hw_set_bits(&uart_get_hw(uart)->lcr_h, 0);
+
+ // See datasheet
+ return (4 * clock_get_hz(clk_peri)) / (64 * baud_ibrd + baud_fbrd);
+}
+/// \end::uart_set_baudrate[]
+
+void uart_set_translate_crlf(uart_inst_t *uart, bool crlf) {
+#if PICO_UART_ENABLE_CRLF_SUPPORT
+ uart_char_to_line_feed[uart_get_index(uart)] = crlf ? '\n' : 0x100;
+#else
+ panic_unsupported();
+#endif
+}
+
+bool uart_is_readable_within_us(uart_inst_t *uart, uint32_t us) {
+ uint32_t t = time_us_32();
+ do {
+ if (uart_is_readable(uart)) return true;
+ } while ((time_us_32() - t) <= us);
+ return false;
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_vreg/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_vreg/CMakeLists.txt
new file mode 100644
index 00000000000..9a5b1507e6f
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_vreg/CMakeLists.txt
@@ -0,0 +1 @@
+pico_simple_hardware_target(vreg)
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_vreg/include/hardware/vreg.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_vreg/include/hardware/vreg.h
new file mode 100644
index 00000000000..7b4e2598655
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_vreg/include/hardware/vreg.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_VREG_H_
+#define _HARDWARE_VREG_H_
+
+#include "pico.h"
+#include "hardware/structs/vreg_and_chip_reset.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file vreg.h
+ * \defgroup hardware_vreg hardware_vreg
+ *
+ * Voltage Regulation API
+ *
+ */
+
+/** Possible voltage values that can be applied to the regulator
+ */
+enum vreg_voltage {
+ VREG_VOLTAGE_0_85 = 0b0110, ///< 0.85v
+ VREG_VOLTAGE_0_90 = 0b0111, ///< 0.90v
+ VREG_VOLTAGE_0_95 = 0b1000, ///< 0.95v
+ VREG_VOLTAGE_1_00 = 0b1001, ///< 1.00v
+ VREG_VOLTAGE_1_05 = 0b1010, ///< 1.05v
+ VREG_VOLTAGE_1_10 = 0b1011, ///< 1.10v
+ VREG_VOLTAGE_1_15 = 0b1100, ///< 1.15v
+ VREG_VOLTAGE_1_20 = 0b1101, ///< 1.20v
+ VREG_VOLTAGE_1_25 = 0b1110, ///< 1.25v
+ VREG_VOLTAGE_1_30 = 0b1111, ///< 1.30v
+
+ VREG_VOLTAGE_MIN = VREG_VOLTAGE_0_85, ///< Always the minimum possible voltage
+ VREG_VOLTAGE_DEFAULT = VREG_VOLTAGE_1_10, ///< Default voltage on power up.
+ VREG_VOLTAGE_MAX = VREG_VOLTAGE_1_30, ///< Always the maximum possible voltage
+};
+
+
+/*! \brief Set voltage
+ * \ingroup hardware_vreg
+ *
+ * \param voltage The voltage (from enumeration \ref vreg_voltage) to apply to the voltage regulator
+ **/
+void vreg_set_voltage(enum vreg_voltage voltage);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_vreg/vreg.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_vreg/vreg.c
new file mode 100644
index 00000000000..654ab5af3d3
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_vreg/vreg.c
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico.h"
+#include "hardware/vreg.h"
+
+void vreg_set_voltage(enum vreg_voltage voltage) {
+ hw_write_masked(&vreg_and_chip_reset_hw->vreg, voltage << VREG_AND_CHIP_RESET_VREG_VSEL_LSB, VREG_AND_CHIP_RESET_VREG_VSEL_BITS);
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_watchdog/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_watchdog/CMakeLists.txt
new file mode 100644
index 00000000000..43a401b11f0
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_watchdog/CMakeLists.txt
@@ -0,0 +1 @@
+pico_simple_hardware_target(watchdog)
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_watchdog/include/hardware/watchdog.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_watchdog/include/hardware/watchdog.h
new file mode 100644
index 00000000000..ae5ccdc8639
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_watchdog/include/hardware/watchdog.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_WATCHDOG_H
+#define _HARDWARE_WATCHDOG_H
+
+#include "pico.h"
+
+/** \file hardware/watchdog.h
+ * \defgroup hardware_watchdog hardware_watchdog
+ *
+ * Hardware Watchdog Timer API
+ *
+ * Supporting functions for the Pico hardware watchdog timer.
+ *
+ * The RP2040 has a built in HW watchdog Timer. This is a countdown timer that can restart parts of the chip if it reaches zero.
+ * For example, this can be used to restart the processor if the software running on it gets stuck in an infinite loop
+ * or similar. The programmer has to periodically write a value to the watchdog to stop it reaching zero.
+ *
+ * \subsection watchdog_example Example
+ * \addtogroup hardware_watchdog
+ * \include hello_watchdog.c
+ */
+
+/*! \brief Define actions to perform at watchdog timeout
+ * \ingroup hardware_watchdog
+ *
+ * \note If \ref watchdog_start_tick value does not give a 1MHz clock to the watchdog system, then the \ref delay_ms
+ * parameter will not be in microseconds. See the datasheet for more details.
+ *
+ * By default the SDK assumes a 12MHz XOSC and sets the \ref watchdog_start_tick appropriately.
+ *
+ * \param pc If Zero, a standard boot will be performed, if non-zero this is the program counter to jump to on reset.
+ * \param sp If \p pc is non-zero, this will be the stack pointer used.
+ * \param delay_ms Initial load value. Maximum value 0x7fffff, approximately 8.3s.
+ */
+void watchdog_reboot(uint32_t pc, uint32_t sp, uint32_t delay_ms);
+
+/*! \brief Start the watchdog tick
+ * \ingroup hardware_watchdog
+ *
+ * \param cycles This needs to be a divider that when applied to the XOSC input, produces a 1MHz clock. So if the XOSC is
+ * 12MHz, this will need to be 12.
+ */
+void watchdog_start_tick(uint cycles);
+
+/*! \brief Reload the watchdog counter with the amount of time set in watchdog_enable
+ * \ingroup hardware_watchdog
+ *
+ */
+void watchdog_update(void);
+
+/**
+ * \brief Enable the watchdog
+ * \ingroup hardware_watchdog
+ *
+ * \note If \ref watchdog_start_tick value does not give a 1MHz clock to the watchdog system, then the \ref delay_ms
+ * parameter will not be in microseconds. See the datasheet for more details.
+ *
+ * By default the SDK assumes a 12MHz XOSC and sets the \ref watchdog_start_tick appropriately.
+ *
+ * \param delay_ms Number of milliseconds before watchdog will reboot without watchdog_update being called. Maximum of 0x7fffff, which is approximately 8.3 seconds
+ * \param pause_on_debug If the watchdog should be paused when the debugger is stepping through code
+ */
+void watchdog_enable(uint32_t delay_ms, bool pause_on_debug);
+
+/**
+ * \brief Did the watchdog cause the last reboot?
+ * \ingroup hardware_watchdog
+ *
+ * @return true if the watchdog timer or a watchdog force caused the last reboot
+ * @return false there has been no watchdog reboot since run has been
+ */
+bool watchdog_caused_reboot(void);
+
+/**
+ * @brief Returns the number of microseconds before the watchdog will reboot the chip.
+ * \ingroup hardware_watchdog
+ *
+ * @return The number of microseconds before the watchdog will reboot the chip.
+ */
+uint32_t watchdog_get_count(void);
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_watchdog/watchdog.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_watchdog/watchdog.c
new file mode 100644
index 00000000000..36031aaffca
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_watchdog/watchdog.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include
+
+#include "hardware/watchdog.h"
+#include "hardware/structs/watchdog.h"
+#include "hardware/structs/psm.h"
+
+/// \tag::watchdog_start_tick[]
+void watchdog_start_tick(uint cycles) {
+ // Important: This function also provides a tick reference to the timer
+ watchdog_hw->tick = cycles | WATCHDOG_TICK_ENABLE_BITS;
+}
+/// \end::watchdog_start_tick[]
+
+// Value to load when updating the watchdog
+
+// tag::watchdog_update[]
+static uint32_t load_value;
+
+void watchdog_update(void) {
+ watchdog_hw->load = load_value;
+}
+// end::watchdog_update[]
+
+uint32_t watchdog_get_count(void) {
+ return (watchdog_hw->ctrl & WATCHDOG_CTRL_TIME_BITS) / 2 ;
+}
+
+// tag::watchdog_enable[]
+// Helper function used by both watchdog_enable and watchdog_reboot
+void _watchdog_enable(uint32_t delay_ms, bool pause_on_debug) {
+ hw_clear_bits(&watchdog_hw->ctrl, WATCHDOG_CTRL_ENABLE_BITS);
+
+ // Reset everything apart from ROSC and XOSC
+ hw_set_bits(&psm_hw->wdsel, PSM_WDSEL_BITS & ~(PSM_WDSEL_ROSC_BITS | PSM_WDSEL_XOSC_BITS));
+
+ uint32_t dbg_bits = WATCHDOG_CTRL_PAUSE_DBG0_BITS |
+ WATCHDOG_CTRL_PAUSE_DBG1_BITS |
+ WATCHDOG_CTRL_PAUSE_JTAG_BITS;
+
+ if (pause_on_debug) {
+ hw_set_bits(&watchdog_hw->ctrl, dbg_bits);
+ } else {
+ hw_clear_bits(&watchdog_hw->ctrl, dbg_bits);
+ }
+
+ if (!delay_ms) delay_ms = 50;
+
+ // Note, we have x2 here as the watchdog HW currently decrements twice per tick
+ load_value = delay_ms * 1000 * 2;
+
+ if (load_value > 0xffffffu)
+ load_value = 0xffffffu;
+
+
+ watchdog_update();
+
+ hw_set_bits(&watchdog_hw->ctrl, WATCHDOG_CTRL_ENABLE_BITS);
+}
+// end::watchdog_enable[]
+
+void watchdog_enable(uint32_t delay_ms, bool pause_on_debug) {
+ // This watchdog enable doesn't reboot so clear scratch register
+ // with magic word to jump into code
+ watchdog_hw->scratch[4] = 0;
+ _watchdog_enable(delay_ms, pause_on_debug);
+}
+
+void watchdog_reboot(uint32_t pc, uint32_t sp, uint32_t delay_ms) {
+ check_hw_layout(watchdog_hw_t, scratch[7], WATCHDOG_SCRATCH7_OFFSET);
+
+ // Clear enable before setting up scratch registers
+ hw_clear_bits(&watchdog_hw->ctrl, WATCHDOG_CTRL_ENABLE_BITS);
+
+ if (pc) {
+ pc |= 1u; // thumb mode
+ watchdog_hw->scratch[4] = 0xb007c0d3;
+ watchdog_hw->scratch[5] = pc ^ -0xb007c0d3;
+ watchdog_hw->scratch[6] = sp;
+ watchdog_hw->scratch[7] = pc;
+// printf("rebooting %08x/%08x in %dms...\n", (uint) pc, (uint) sp, (uint) delay_ms);
+ } else {
+ watchdog_hw->scratch[4] = 0;
+// printf("rebooting (regular)) in %dms...\n", (uint) delay_ms);
+ }
+
+ // Don't pause watchdog for debug
+ _watchdog_enable(delay_ms, 0);
+}
+
+bool watchdog_caused_reboot(void) {
+ // If any reason bits are set this is true
+ return watchdog_hw->reason;
+}
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_xosc/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_xosc/CMakeLists.txt
new file mode 100644
index 00000000000..50e86c23398
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_xosc/CMakeLists.txt
@@ -0,0 +1 @@
+pico_simple_hardware_target(xosc)
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_xosc/include/hardware/xosc.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_xosc/include/hardware/xosc.h
new file mode 100644
index 00000000000..0aa0842dbcb
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_xosc/include/hardware/xosc.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_XOSC_H_
+#define _HARDWARE_XOSC_H_
+
+#include "pico.h"
+#include "hardware/structs/xosc.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file hardware/xosc.h
+ * \defgroup hardware_xosc hardware_xosc
+ *
+ * Crystal Oscillator (XOSC) API
+ */
+
+/*! \brief Initialise the crystal oscillator system
+ * \ingroup hardware_xosc
+ *
+ * This function will block until the crystal oscillator has stabilised.
+ **/
+void xosc_init(void);
+
+/*! \brief Disable the Crystal oscillator
+ * \ingroup hardware_xosc
+ *
+ * Turns off the crystal oscillator source, and waits for it to become unstable
+ **/
+void xosc_disable(void);
+
+/*! \brief Set the crystal oscillator system to dormant
+ * \ingroup hardware_xosc
+ *
+ * Turns off the crystal oscillator until it is woken by an interrupt. This will block and hence
+ * the entire system will stop, until an interrupt wakes it up. This function will
+ * continue to block until the oscillator becomes stable after its wakeup.
+ **/
+void xosc_dormant(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_xosc/xosc.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_xosc/xosc.c
new file mode 100644
index 00000000000..977f0bdc007
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/hardware_xosc/xosc.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico.h"
+
+// For MHZ definitions etc
+#include "hardware/clocks.h"
+
+#include "hardware/platform_defs.h"
+#include "hardware/regs/xosc.h"
+#include "hardware/structs/xosc.h"
+
+void xosc_init(void) {
+ // Assumes 1-15 MHz input
+ assert(XOSC_MHZ <= 15);
+ xosc_hw->ctrl = XOSC_CTRL_FREQ_RANGE_VALUE_1_15MHZ;
+
+ // Set xosc startup delay
+ uint32_t startup_delay = (((12 * MHZ) / 1000) + 128) / 256;
+ xosc_hw->startup = startup_delay;
+
+ // Set the enable bit now that we have set freq range and startup delay
+ hw_set_bits(&xosc_hw->ctrl, XOSC_CTRL_ENABLE_VALUE_ENABLE << XOSC_CTRL_ENABLE_LSB);
+
+ // Wait for XOSC to be stable
+ while(!(xosc_hw->status & XOSC_STATUS_STABLE_BITS));
+}
+
+void xosc_disable(void) {
+ uint32_t tmp = xosc_hw->ctrl;
+ tmp &= (~XOSC_CTRL_ENABLE_BITS);
+ tmp |= (XOSC_CTRL_ENABLE_VALUE_DISABLE << XOSC_CTRL_ENABLE_LSB);
+ xosc_hw->ctrl = tmp;
+ // Wait for stable to go away
+ while(xosc_hw->status & XOSC_STATUS_STABLE_BITS);
+}
+
+void xosc_dormant(void) {
+ // WARNING: This stops the xosc until woken up by an irq
+ xosc_hw->dormant = XOSC_DORMANT_VALUE_DORMANT;
+ // Wait for it to become stable once woken up
+ while(!(xosc_hw->status & XOSC_STATUS_STABLE_BITS));
+}
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bit_ops/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bit_ops/CMakeLists.txt
new file mode 100644
index 00000000000..7e5f2b97c73
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bit_ops/CMakeLists.txt
@@ -0,0 +1,57 @@
+if (NOT TARGET pico_bit_ops)
+ #shims for ROM functions for -lgcc functions (listed below)
+ add_library(pico_bit_ops INTERFACE)
+
+ # no custom implementation; falls thru to compiler
+ add_library(pico_bit_ops_compiler INTERFACE)
+ # PICO_BUILD_DEFINE: PICO_BIT_OPS_COMPILER, whether compiler provided bit_ops bit functions support is being used, type=bool, default=0, but dependent on CMake options, group=pico_bit_ops
+ target_compile_definitions(pico_bit_ops_compiler INTERFACE
+ PICO_BIT_OPS_COMPILER=1
+ )
+
+ # add alias "default" which is just pico.
+ add_library(pico_bit_ops_default INTERFACE)
+ target_link_libraries(pico_bit_ops_default INTERFACE pico_bit_ops_pico)
+
+ set(PICO_DEFAULT_BIT_OPS_IMPL pico_bit_ops_default)
+
+ add_library(pico_bit_ops_pico INTERFACE)
+ target_link_libraries(pico_bit_ops INTERFACE
+ $>,$,${PICO_DEFAULT_BIT_OPS_IMPL}>)
+
+ # PICO_BUILD_DEFINE: PICO_BIT_OPS_PICO, whether optimized pico/bootrom provided bit_ops bit functions support is being used, type=bool, default=1, but dependent on CMake options, group=pico_bit_ops
+ target_compile_definitions(pico_bit_ops_pico INTERFACE
+ PICO_BIT_OPS_PICO=1
+ )
+
+ target_sources(pico_bit_ops_pico INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/bit_ops_aeabi.S
+ )
+
+ target_link_libraries(pico_bit_ops_pico INTERFACE pico_bootrom pico_bit_ops_headers)
+
+ # gcc
+ pico_wrap_function(pico_bit_ops_pico __clzsi2)
+ pico_wrap_function(pico_bit_ops_pico __clzsi2)
+ pico_wrap_function(pico_bit_ops_pico __clzdi2)
+ pico_wrap_function(pico_bit_ops_pico __ctzsi2)
+ pico_wrap_function(pico_bit_ops_pico __ctzdi2)
+ pico_wrap_function(pico_bit_ops_pico __popcountsi2)
+ pico_wrap_function(pico_bit_ops_pico __popcountdi2)
+
+ # armclang
+ pico_wrap_function(pico_bit_ops_pico __clz)
+ pico_wrap_function(pico_bit_ops_pico __clzl)
+ pico_wrap_function(pico_bit_ops_pico __clzsi2)
+ pico_wrap_function(pico_bit_ops_pico __clzll)
+
+ macro(pico_set_bit_ops_implementation TARGET IMPL)
+ get_target_property(target_type ${TARGET} TYPE)
+ if ("EXECUTABLE" STREQUAL "${target_type}")
+ set_target_properties(${TARGET} PROPERTIES PICO_TARGET_BIT_OPS_IMPL "pico_bit_ops_${IMPL}")
+ else()
+ message(FATAL_ERROR "bit_ops implementation must be set on executable not library")
+ endif()
+ endmacro()
+
+endif()
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bit_ops/bit_ops_aeabi.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bit_ops/bit_ops_aeabi.S
new file mode 100644
index 00000000000..7c0b42cc672
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bit_ops/bit_ops_aeabi.S
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+#include "pico/asm_helper.S"
+__pre_init __aeabi_bits_init, 00010
+
+.macro bits_section name
+#if PICO_BITS_IN_RAM
+.section RAM_SECTION_NAME(\name), "ax"
+#else
+.section SECTION_NAME(\name), "ax"
+#endif
+.endm
+
+.section .data.aeabi_bits_funcs
+.global aeabi_bits_funcs, aeabi_bits_funcs_end
+.equ BITS_FUNC_COUNT, 4
+.align 4
+aeabi_bits_funcs:
+ .word rom_table_code('P','3') // popcount32
+ .word rom_table_code('L','3') // clz32
+ .word rom_table_code('T','3') // ctz32
+ .word rom_table_code('R','3') // reverse32
+aeabi_bits_funcs_end:
+
+.section .text
+.thumb_func
+__aeabi_bits_init:
+ ldr r0, =aeabi_bits_funcs
+ movs r1, #BITS_FUNC_COUNT
+ ldr r3, =rom_funcs_lookup
+ bx r3
+
+.equ POPCOUNT32, 0
+.equ CLZ32, 4
+.equ CTZ32, 8
+.equ REVERSE32, 12
+
+bits_section clzsi
+wrapper_func __clz
+wrapper_func __clzl
+wrapper_func __clzsi2
+ ldr r3, =aeabi_bits_funcs
+ ldr r3, [r3, #CLZ32]
+ bx r3
+
+bits_section ctzsi
+wrapper_func __ctzsi2
+ ldr r3, =aeabi_bits_funcs
+ ldr r3, [r3, #CTZ32]
+ bx r3
+
+bits_section popcountsi
+wrapper_func __popcountsi2
+ ldr r3, =aeabi_bits_funcs
+ ldr r3, [r3, #POPCOUNT32]
+ bx r3
+
+bits_section clzdi
+wrapper_func __clzll
+wrapper_func __clzdi2
+ ldr r3, =aeabi_bits_funcs
+ ldr r3, [r3, #CLZ32]
+ cmp r1, #0
+ bne 1f
+ push {lr}
+ blx r3
+ adds r0, #32
+ pop {pc}
+1:
+ mov r0, r1
+ bx r3
+
+bits_section ctzdi
+wrapper_func __ctzdi2
+ ldr r3, =aeabi_bits_funcs
+ ldr r3, [r3, #CTZ32]
+ cmp r0, #0
+ bne 1f
+ bx r3
+1:
+ push {lr}
+ mov r0, r1
+ blx r3
+ adds r0, #32
+ pop {pc}
+
+bits_section popcountdi
+wrapper_func __popcountdi2
+ ldr r3, =aeabi_bits_funcs
+ ldr r3, [r3, #POPCOUNT32]
+ push {r1, r3, lr}
+ blx r3
+ mov ip, r0
+ pop {r0, r3}
+ blx r3
+ mov r1, ip
+ add r0, r1
+ pop {pc}
+
+bits_section reverse32
+regular_func reverse32
+ ldr r3, =aeabi_bits_funcs
+ ldr r3, [r3, #REVERSE32]
+ bx r3
+
+bits_section __rev
+regular_func __rev
+regular_func __revl
+ ldr r3, =aeabi_bits_funcs
+ ldr r3, [r3, #REVERSE32]
+ bx r3
+
+bits_section __revll
+regular_func __revll
+ push {lr}
+ ldr r3, =aeabi_bits_funcs
+ ldr r3, [r3, #REVERSE32]
+ push {r1, r3}
+ blx r3
+ mov ip, r0 // reverse32 preserves ip
+ pop {r0, r3}
+ blx r3
+ mov r1, ip
+ pop {pc}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bootrom/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bootrom/CMakeLists.txt
new file mode 100644
index 00000000000..58ea575cd0b
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bootrom/CMakeLists.txt
@@ -0,0 +1,8 @@
+add_library(pico_bootrom INTERFACE)
+
+target_sources(pico_bootrom INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/bootrom.c
+ )
+
+target_include_directories(pico_bootrom INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+target_link_libraries(pico_bootrom INTERFACE pico_base_headers)
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bootrom/bootrom.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bootrom/bootrom.c
new file mode 100644
index 00000000000..08cdb33738e
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bootrom/bootrom.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico/bootrom.h"
+
+/// \tag::table_lookup[]
+
+// Bootrom function: rom_table_lookup
+// Returns the 32 bit pointer into the ROM if found or NULL otherwise.
+typedef void *(*rom_table_lookup_fn)(uint16_t *table, uint32_t code);
+
+// Convert a 16 bit pointer stored at the given rom address into a 32 bit pointer
+#define rom_hword_as_ptr(rom_address) (void *)(uintptr_t)(*(uint16_t *)rom_address)
+
+void *rom_func_lookup(uint32_t code) {
+ rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
+ uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
+ return rom_table_lookup(func_table, code);
+}
+
+void *rom_data_lookup(uint32_t code) {
+ rom_table_lookup_fn rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
+ uint16_t *data_table = (uint16_t *) rom_hword_as_ptr(0x16);
+ return rom_table_lookup(data_table, code);
+}
+/// \end::table_lookup[]
+
+bool rom_funcs_lookup(uint32_t *table, unsigned int count) {
+ bool ok = true;
+ for (unsigned int i = 0; i < count; i++) {
+ table[i] = (uintptr_t) rom_func_lookup(table[i]);
+ if (!table[i]) ok = false;
+ }
+ return ok;
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bootrom/include/pico/bootrom.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bootrom/include/pico/bootrom.h
new file mode 100644
index 00000000000..1aa12973ef9
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bootrom/include/pico/bootrom.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PLATFORM_BOOTROM_H
+#define _PLATFORM_BOOTROM_H
+
+#include "pico.h"
+
+/** \file bootrom.h
+ * \defgroup pico_bootrom pico_bootrom
+ * Access to functions and data in the RP2040 bootrom
+ */
+
+
+/*! \brief Return a bootrom lookup code based on two ASCII characters
+ * \ingroup pico_bootrom
+ *
+ * These codes are uses to lookup data or function addresses in the bootrom
+ *
+ * \param c1 the first character
+ * \param c2 the second character
+ * \return the 'code' to use in rom_func_lookup() or rom_data_lookup()
+ */
+static inline uint32_t rom_table_code(char c1, char c2) {
+ return (c2 << 8u) | c1;
+}
+
+/*!
+ * \brief Lookup a bootrom function by code
+ * \ingroup pico_bootrom
+ * \param code the code
+ * \return a pointer to the function, or NULL if the code does not match any bootrom function
+ */
+void *rom_func_lookup(uint32_t code);
+
+/*!
+ * \brief Lookup a bootrom address by code
+ * \ingroup pico_bootrom
+ * \param code the code
+ * \return a pointer to the data, or NULL if the code does not match any bootrom function
+ */
+void *rom_data_lookup(uint32_t code);
+
+/*!
+ * \brief Helper function to lookup the addresses of multiple bootrom functions
+ * \ingroup pico_bootrom
+ *
+ * This method looks up the 'codes' in the table, and convert each table entry to the looked up
+ * function pointer, if there is a function for that code in the bootrom.
+ *
+ * \param table an IN/OUT array, elements are codes on input, function pointers on success.
+ * \param count the number of elements in the table
+ * \return true if all the codes were found, and converted to function pointers, false otherwise
+ */
+bool rom_funcs_lookup(uint32_t *table, unsigned int count);
+
+typedef void __attribute__((noreturn)) (*reset_usb_boot_fn)(uint32_t, uint32_t);
+
+/*!
+ * \brief Reboot the device into BOOTSEL mode
+ * \ingroup pico_bootrom
+ *
+ * This function reboots the device into the BOOTSEL mode ('usb boot").
+ *
+ * Facilities are provided to enable an "activity light" via GPIO attached LED for the USB Mass Storage Device,
+ * and to limit the USB interfaces exposed.
+ *
+ * \param usb_activity_gpio_pin_mask 0 No pins are used as per a cold boot. Otherwise a single bit set indicating which
+ * GPIO pin should be set to output and raised whenever there is mass storage activity
+ * from the host.
+ * \param disable_interface_mask value to control exposed interfaces
+ * - 0 To enable both interfaces (as per a cold boot)
+ * - 1 To disable the USB Mass Storage Interface
+ * - 2 To disable the USB PICOBOOT Interface
+ */
+static inline void __attribute__((noreturn)) reset_usb_boot(uint32_t usb_activity_gpio_pin_mask,
+ uint32_t disable_interface_mask) {
+ reset_usb_boot_fn func = (reset_usb_boot_fn) rom_func_lookup(rom_table_code('U', 'B'));
+ func(usb_activity_gpio_pin_mask, disable_interface_mask);
+}
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bootrom/include/pico/bootrom/sf_table.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bootrom/include/pico/bootrom/sf_table.h
new file mode 100644
index 00000000000..4eb4b1c8903
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_bootrom/include/pico/bootrom/sf_table.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_SF_TABLE_H
+#define _PICO_SF_TABLE_H
+
+// NOTE THESE FUNCTION IMPLEMENTATIONS MATCH THE BEHAVIOR DESCRIBED IN THE BOOTROM SECTION OF THE RP2040 DATASHEET
+
+#define SF_TABLE_FADD 0x00
+#define SF_TABLE_FSUB 0x04
+#define SF_TABLE_FMUL 0x08
+#define SF_TABLE_FDIV 0x0c
+#define SF_TABLE_FCMP_FAST 0x10
+#define SF_TABLE_FCMP_FAST_FLAGS 0x14
+#define SF_TABLE_FSQRT 0x18
+#define SF_TABLE_FLOAT2INT 0x1c
+#define SF_TABLE_FLOAT2FIX 0x20
+#define SF_TABLE_FLOAT2UINT 0x24
+#define SF_TABLE_FLOAT2UFIX 0x28
+#define SF_TABLE_INT2FLOAT 0x2c
+#define SF_TABLE_FIX2FLOAT 0x30
+#define SF_TABLE_UINT2FLOAT 0x34
+#define SF_TABLE_UFIX2FLOAT 0x38
+#define SF_TABLE_FCOS 0x3c
+#define SF_TABLE_FSIN 0x40
+#define SF_TABLE_FTAN 0x44
+#define SF_TABLE_V3_FSINCOS 0x48
+#define SF_TABLE_FEXP 0x4c
+#define SF_TABLE_FLN 0x50
+
+#define SF_TABLE_V1_SIZE 0x54
+
+#define SF_TABLE_FCMP_BASIC 0x54
+#define SF_TABLE_FATAN2 0x58
+#define SF_TABLE_INT642FLOAT 0x5c
+#define SF_TABLE_FIX642FLOAT 0x60
+#define SF_TABLE_UINT642FLOAT 0x64
+#define SF_TABLE_UFIX642FLOAT 0x68
+#define SF_TABLE_FLOAT2INT64 0x6c
+#define SF_TABLE_FLOAT2FIX64 0x70
+#define SF_TABLE_FLOAT2UINT64 0x74
+#define SF_TABLE_FLOAT2UFIX64 0x78
+#define SF_TABLE_FLOAT2DOUBLE 0x7c
+
+#define SF_TABLE_V2_SIZE 0x80
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_cxx_options/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_cxx_options/CMakeLists.txt
new file mode 100644
index 00000000000..4b20e3ab2c3
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_cxx_options/CMakeLists.txt
@@ -0,0 +1,23 @@
+if (NOT TARGET pico_cxx_options)
+ add_library(pico_cxx_options INTERFACE)
+
+ # PICO_CMAKE_CONFIG: PICO_CXX_ENABLE_EXCEPTIONS, Enabled CXX exception handling, type=bool, default=0, group=pico_cxx_options
+ # PICO_BUILD_DEFINE: PICO_CXX_ENABLE_EXCEPTIONS, value of CMake var PICO_CXX_ENABLE_EXCEPTIONS, type=string, default=0, group=pico_cxx_options
+ if (NOT PICO_CXX_ENABLE_EXCEPTIONS)
+ target_compile_definitions( pico_cxx_options INTERFACE PICO_CXX_ENABLE_EXCEPTIONS=0)
+ target_compile_options( pico_cxx_options INTERFACE $<$:-fno-exceptions>)
+ target_compile_options( pico_cxx_options INTERFACE $<$:-fno-unwind-tables>)
+ else()
+ target_compile_definitions( pico_cxx_options INTERFACE PICO_CXX_ENABLE_EXCEPTIONS=1)
+ endif()
+
+ # PICO_CMAKE_CONFIG: PICO_CXX_ENABLE_RTTI, Enabled CXX rtti, type=bool, default=0, group=pico_cxx_options
+ if (NOT PICO_CXX_ENABLE_RTTI)
+ target_compile_options( pico_cxx_options INTERFACE $<$:-fno-rtti>)
+ endif()
+
+ # PICO_CMAKE_CONFIG: PICO_CXX_ENABLE_CXA_ATEXIT, Enabled cxa-atexit, type=bool, default=0, group=pico_cxx_options
+ if (NOT PICO_CXX_ENABLE_CXA_ATEXIT)
+ target_compile_options( pico_cxx_options INTERFACE $<$:-fno-use-cxa-atexit>)
+ endif()
+endif()
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_cxx_options/doc.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_cxx_options/doc.h
new file mode 100644
index 00000000000..5d84e22549f
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_cxx_options/doc.h
@@ -0,0 +1,4 @@
+/**
+ * \defgroup pico_cxx_options pico_cxx_options
+ * \brief non-code library controlling C++ related compile options
+ */
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_divider/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_divider/CMakeLists.txt
new file mode 100644
index 00000000000..9eda2355633
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_divider/CMakeLists.txt
@@ -0,0 +1,52 @@
+if (NOT TARGET pico_divider)
+ # library to be depended on - we make this depend on particular implementations using per target generator expressions
+ add_library(pico_divider INTERFACE)
+
+ # no custom implementation; falls thru to compiler
+ add_library(pico_divider_compiler INTERFACE)
+ target_compile_definitions(pico_divider_compiler INTERFACE
+ PICO_DIVIDER_COMPILER=1
+ )
+
+ # add alias "default" which is just hardware.
+ add_library(pico_divider_default INTERFACE)
+ target_link_libraries(pico_divider_default INTERFACE pico_divider_hardware)
+
+ set(PICO_DEFAULT_DIVIDER_IMPL pico_divider_default)
+
+ target_link_libraries(pico_divider INTERFACE
+ $>,$,${PICO_DEFAULT_DIVIDER_IMPL}>)
+
+ add_library(pico_divider_hardware_explicit INTERFACE)
+ target_sources(pico_divider_hardware_explicit INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/divider.S
+ )
+
+ target_link_libraries(pico_divider_hardware_explicit INTERFACE
+ pico_divider_headers
+ hardware_regs
+ )
+
+ add_library(pico_divider_hardware INTERFACE)
+ target_compile_definitions(pico_divider_hardware INTERFACE
+ PICO_DIVIDER_HARDWARE=1
+ )
+
+ target_link_libraries(pico_divider_hardware INTERFACE pico_divider_hardware_explicit)
+
+ pico_wrap_function(pico_divider_hardware __aeabi_idiv)
+ pico_wrap_function(pico_divider_hardware __aeabi_idivmod)
+ pico_wrap_function(pico_divider_hardware __aeabi_ldivmod)
+ pico_wrap_function(pico_divider_hardware __aeabi_uidiv)
+ pico_wrap_function(pico_divider_hardware __aeabi_uidivmod)
+ pico_wrap_function(pico_divider_hardware __aeabi_uldivmod)
+
+ macro(pico_set_divider_implementation TARGET IMPL)
+ get_target_property(target_type ${TARGET} TYPE)
+ if ("EXECUTABLE" STREQUAL "${target_type}")
+ set_target_properties(${TARGET} PROPERTIES PICO_TARGET_DIVIDER_IMPL "pico_divider_${IMPL}")
+ else()
+ message(FATAL_ERROR "divider implementation must be set on executable not library")
+ endif()
+ endmacro()
+endif()
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_divider/divider.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_divider/divider.S
new file mode 100644
index 00000000000..12eae389959
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_divider/divider.S
@@ -0,0 +1,863 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/regs/sio.h"
+#include "hardware/regs/addressmap.h"
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+#include "pico/asm_helper.S"
+
+#ifndef PICO_DIVIDER_CALL_IDIV0
+#define PICO_DIVIDER_CALL_IDIV0 1
+#endif
+
+#ifndef PICO_DIVIDER_CALL_LDIV0
+#define PICO_DIVIDER_CALL_LDIV0 1
+#endif
+
+.macro div_section name
+#if PICO_DIVIDER_IN_RAM
+.section RAM_SECTION_NAME(\name), "ax"
+#else
+.section SECTION_NAME(\name), "ax"
+#endif
+.endm
+
+#if SIO_DIV_CSR_READY_LSB == 0
+.equ SIO_DIV_CSR_READY_SHIFT_FOR_CARRY, 1
+#else
+need to change SHIFT above
+#endif
+#if SIO_DIV_CSR_DIRTY_LSB == 1
+.equ SIO_DIV_CSR_DIRTY_SHIFT_FOR_CARRY, 2
+#else
+need to change SHIFT above
+#endif
+
+@ wait 8-n cycles for the hardware divider
+.macro wait_div n
+.rept (8-\n) / 2
+ b 9f
+9:
+.endr
+.if (8-\n) % 2
+ nop
+.endif
+.endm
+
+
+#if (SIO_DIV_SDIVISOR_OFFSET != SIO_DIV_SDIVIDEND_OFFSET + 4) || (SIO_DIV_QUOTIENT_OFFSET != SIO_DIV_SDIVISOR_OFFSET + 4) || (SIO_DIV_REMAINDER_OFFSET != SIO_DIV_QUOTIENT_OFFSET + 4)
+#error register layout has changed - we rely on this order to make sure we save/restore in the right order
+#endif
+
+# SIO_BASE ptr in r2
+.macro save_div_state_and_lr
+ ldr r3, [r2, #SIO_DIV_CSR_OFFSET]
+ # wait for results as we can't save signed-ness of operation
+1:
+ lsrs r3, #SIO_DIV_CSR_READY_SHIFT_FOR_CARRY
+ bcc 1b
+ push {r4, r5, r6, r7, lr}
+ // note we must read quotient last, and since it isn't the last reg, we'll not use ldmia!
+ ldr r4, [r2, #SIO_DIV_SDIVIDEND_OFFSET]
+ ldr r5, [r2, #SIO_DIV_SDIVISOR_OFFSET]
+ ldr r7, [r2, #SIO_DIV_REMAINDER_OFFSET]
+ ldr r6, [r2, #SIO_DIV_QUOTIENT_OFFSET]
+.endm
+
+.macro restore_div_state_and_return
+ // writing sdividend (r4), sdivisor (r5), quotient (r6), remainder (r7) in that order
+ //
+ // it is worth considering what happens if we are interrupted
+ //
+ // after writing r4: we are DIRTY and !READY
+ // ... interruptor using div will complete based on incorrect inputs, but dividend at least will be
+ // saved/restored correctly and we'll restore the rest ourselves
+ // after writing r4, r5: we are DIRTY and !READY
+ // ... interruptor using div will complete based on possibly wrongly signed inputs, but dividend, divisor
+ // at least will be saved/restored correctly and and we'll restore the rest ourselves
+ // after writing r4, r5, r6: we are DIRTY and READY
+ // ... interruptor using div will dividend, divisor, quotient registers as is (what we just restored ourselves),
+ // and we'll restore the remainder after the fact
+
+ // note we are not use STM not because it can be restarted due to interrupt which is harmless, more because this is 1 cycle IO space
+ // and so 4 reads is cheaper (and we don't have to adjust r2)
+ str r4, [r2, #SIO_DIV_SDIVIDEND_OFFSET]
+ str r5, [r2, #SIO_DIV_SDIVISOR_OFFSET]
+ str r7, [r2, #SIO_DIV_REMAINDER_OFFSET]
+ str r6, [r2, #SIO_DIV_QUOTIENT_OFFSET]
+ pop {r4, r5, r6, r7, pc}
+.endm
+
+.macro save_div_state_and_lr_64
+ push {r4, r5, r6, r7, lr}
+ ldr r6, =SIO_BASE
+1:
+ ldr r5, [r6, #SIO_DIV_CSR_OFFSET]
+ # wait for results as we can't save signed-ness of operation
+ lsrs r5, #SIO_DIV_CSR_READY_SHIFT_FOR_CARRY
+ bcc 1b
+ // note we must read quotient last, and since it isn't the last reg, we'll not use ldmia!
+ ldr r4, [r6, #SIO_DIV_UDIVIDEND_OFFSET]
+ ldr r5, [r6, #SIO_DIV_UDIVISOR_OFFSET]
+ ldr r7, [r6, #SIO_DIV_REMAINDER_OFFSET]
+ ldr r6, [r6, #SIO_DIV_QUOTIENT_OFFSET]
+.endm
+
+.macro restore_div_state_and_return_64
+ // writing sdividend (r4), sdivisor (r5), quotient (r6), remainder (r7) in that order
+ //
+ // it is worth considering what happens if we are interrupted
+ //
+ // after writing r4: we are DIRTY and !READY
+ // ... interruptor using div will complete based on incorrect inputs, but dividend at least will be
+ // saved/restored correctly and we'll restore the rest ourselves
+ // after writing r4, r5: we are DIRTY and !READY
+ // ... interruptor using div will complete based on possibly wrongly signed inputs, but dividend, divisor
+ // at least will be saved/restored correctly and and we'll restore the rest ourselves
+ // after writing r4, r5, r6: we are DIRTY and READY
+ // ... interruptor using div will dividend, divisor, quotient registers as is (what we just restored ourselves),
+ // and we'll restore the remainder after the fact
+
+ mov ip, r2
+ ldr r2, =SIO_BASE
+ // note we are not use STM not because it can be restarted due to interrupt which is harmless, more because this is 1 cycle IO space
+ // and so 4 reads is cheaper (and we don't have to adjust r2)
+ str r4, [r2, #SIO_DIV_UDIVIDEND_OFFSET]
+ str r5, [r2, #SIO_DIV_UDIVISOR_OFFSET]
+ str r7, [r2, #SIO_DIV_REMAINDER_OFFSET]
+ str r6, [r2, #SIO_DIV_QUOTIENT_OFFSET]
+ mov r2, ip
+ pop {r4, r5, r6, r7, pc}
+.endm
+
+
+// since idiv and idivmod only differ by a cycle, we'll make them the same!
+div_section WRAPPER_FUNC_NAME(__aeabi_idiv)
+.align 2
+wrapper_func __aeabi_idiv
+wrapper_func __aeabi_idivmod
+regular_func div_s32s32
+regular_func divmod_s32s32
+ ldr r2, =(SIO_BASE)
+ # to support IRQ usage we must save/restore
+ ldr r3, [r2, #SIO_DIV_CSR_OFFSET]
+ lsrs r3, #SIO_DIV_CSR_DIRTY_SHIFT_FOR_CARRY
+ bcs divmod_s32s32_savestate
+regular_func divmod_s32s32_unsafe
+ str r0, [r2, #SIO_DIV_SDIVIDEND_OFFSET]
+ str r1, [r2, #SIO_DIV_SDIVISOR_OFFSET]
+ cmp r1, #0
+ beq 1f
+ wait_div 2
+ // return 64 bit value so we can efficiently return both (note read order is important since QUOTIENT must be read last)
+ ldr r1, [r2, #SIO_DIV_REMAINDER_OFFSET]
+ ldr r0, [r2, #SIO_DIV_QUOTIENT_OFFSET]
+ bx lr
+1:
+ push {r2, lr}
+ movs r1, #0x80
+ lsls r1, #24
+ asrs r2, r0, #31
+ eors r1, r2
+ cmp r0, #0
+ beq 1f
+ mvns r0, r1
+1:
+#if PICO_DIVIDER_CALL_IDIV0
+ bl __aeabi_idiv0
+#endif
+ movs r1, #0 // remainder 0
+ // need to restore saved r2 as it hold SIO ptr
+ pop {r2, pc}
+.align 2
+regular_func divmod_s32s32_savestate
+ save_div_state_and_lr
+ bl divmod_s32s32_unsafe
+ restore_div_state_and_return
+
+// since uidiv and uidivmod only differ by a cycle, we'll make them the same!
+div_section WRAPPER_FUNC_NAME(__aeabi_uidiv)
+regular_func div_u32u32
+regular_func divmod_u32u32
+wrapper_func __aeabi_uidiv
+wrapper_func __aeabi_uidivmod
+ ldr r2, =(SIO_BASE)
+ # to support IRQ usage we must save/restore
+ ldr r3, [r2, #SIO_DIV_CSR_OFFSET]
+ lsrs r3, #SIO_DIV_CSR_DIRTY_SHIFT_FOR_CARRY
+ bcs divmod_u32u32_savestate
+regular_func divmod_u32u32_unsafe
+ str r0, [r2, #SIO_DIV_UDIVIDEND_OFFSET]
+ str r1, [r2, #SIO_DIV_UDIVISOR_OFFSET]
+ cmp r1, #0
+ beq 1f
+ wait_div 2
+ // return 64 bit value so we can efficiently return both (note read order is important since QUOTIENT must be read last)
+ ldr r1, [r2, #SIO_DIV_REMAINDER_OFFSET]
+ ldr r0, [r2, #SIO_DIV_QUOTIENT_OFFSET]
+ bx lr
+1:
+ push {r2, lr}
+ cmp r0, #0
+ beq 1f
+ movs r0, #0
+ mvns r0, r0
+1:
+#if PICO_DIVIDER_CALL_IDIV0
+ bl __aeabi_idiv0
+#endif
+ movs r1, #0 // remainder 0
+ // need to restore saved r2 as it hold SIO ptr
+ pop {r2, pc}
+.align 2
+regular_func divmod_u32u32_savestate
+ save_div_state_and_lr
+ bl divmod_u32u32_unsafe
+ restore_div_state_and_return
+
+div_section WRAPPER_FUNC_NAME(__aeabi_ldiv)
+
+.align 2
+wrapper_func __aeabi_ldivmod
+regular_func div_s64s64
+regular_func divmod_s64s64
+ mov ip, r2
+ ldr r2, =(SIO_BASE)
+ # to support IRQ usage we must save/restore
+ ldr r2, [r2, #SIO_DIV_CSR_OFFSET]
+ lsrs r2, #SIO_DIV_CSR_DIRTY_SHIFT_FOR_CARRY
+ mov r2, ip
+ bcs divmod_s64s64_savestate
+ b divmod_s64s64_unsafe
+.align 2
+divmod_s64s64_savestate:
+ save_div_state_and_lr_64
+ bl divmod_s64s64_unsafe
+ restore_div_state_and_return_64
+
+.align 2
+wrapper_func __aeabi_uldivmod
+regular_func div_u64u64
+regular_func divmod_u64u64
+ mov ip, r2
+ ldr r2, =(SIO_BASE)
+ # to support IRQ usage we must save/restore
+ ldr r2, [r2, #SIO_DIV_CSR_OFFSET]
+ lsrs r2, #SIO_DIV_CSR_DIRTY_SHIFT_FOR_CARRY
+ mov r2, ip
+ bcs divmod_u64u64_savestate
+ b divmod_u64u64_unsafe
+.align 2
+regular_func divmod_u64u64_savestate
+ save_div_state_and_lr_64
+ bl divmod_u64u64_unsafe
+ restore_div_state_and_return_64
+.macro dneg lo,hi
+ mvns \hi,\hi
+ rsbs \lo,#0
+ bne l\@_1
+ adds \hi,#1
+l\@_1:
+.endm
+
+.align 2
+regular_func divmod_s64s64_unsafe
+ cmp r3,#0
+ blt 1f
+@ here x +ve
+ beq 2f @ could x be zero?
+3:
+ cmp r1,#0
+ bge divmod_u64u64_unsafe @ both positive
+@ y -ve, x +ve
+ push {r14}
+ dneg r0,r1
+ bl divmod_u64u64_unsafe
+ dneg r0,r1
+ dneg r2,r3
+ pop {r15}
+
+2:
+ cmp r2,#0
+ bne 3b @ back if x not zero
+
+ cmp r0,#0 @ y==0?
+ bne 4f
+ cmp r1,#0
+ beq 5f @ then pass 0 to __aeabi_ldiv0
+4:
+ movs r0,#0
+ lsrs r1,#31
+ lsls r1,#31 @ get sign bit
+ bne 5f @ y -ve? pass -2^63 to __aeabi_ldiv0
+ mvns r0,r0
+ lsrs r1,r0,#1 @ y +ve: pass 2^63-1 to __aeabi_ldiv0
+5:
+ push {r14}
+#if PICO_DIVIDER_CALL_LDIV0
+ bl __aeabi_ldiv0
+#endif
+ movs r2,#0 @ and return 0 for the remainder
+ movs r3,#0
+ pop {r15}
+
+1:
+@ here x -ve
+ push {r14}
+ cmp r1,#0
+ blt 1f
+@ y +ve, x -ve
+ dneg r2,r3
+ bl divmod_u64u64_unsafe
+ dneg r0,r1
+ pop {r15}
+
+1:
+@ y -ve, x -ve
+ dneg r0,r1
+ dneg r2,r3
+ bl divmod_u64u64_unsafe
+ dneg r2,r3
+ pop {r15}
+
+regular_func divmod_u64u64_unsafe
+ cmp r1,#0
+ bne y64 @ y fits in 32 bits?
+ cmp r3,#0 @ yes; and x?
+ bne 1f
+ cmp r2,#0
+ beq 2f @ x==0?
+ mov r12,r7
+ ldr r7,=#SIO_BASE
+ str r0,[r7,#SIO_DIV_UDIVIDEND_OFFSET]
+ str r2,[r7,#SIO_DIV_UDIVISOR_OFFSET]
+ movs r1,#0
+ movs r3,#0
+ wait_div 2
+ ldr r2,[r7,#SIO_DIV_REMAINDER_OFFSET]
+ ldr r0,[r7,#SIO_DIV_QUOTIENT_OFFSET]
+ mov r7,r12
+ bx r14
+
+2: @ divide by 0 with y<2^32
+ cmp r0,#0 @ y==0?
+ beq 3f @ then pass 0 to __aeabi_ldiv0
+udiv0:
+ ldr r0,=#0xffffffff
+ movs r1,r0 @ pass 2^64-1 to __aeabi_ldiv0
+3:
+ push {r14}
+#if PICO_DIVIDER_CALL_LDIV0
+ bl __aeabi_ldiv0
+#endif
+ movs r2,#0 @ and return 0 for the remainder
+ movs r3,#0
+ pop {r15}
+
+1:
+ movs r2,r0 @ x>y, so result is 0 remainder y
+ movs r3,r1
+ movs r0,#0
+ movs r1,#0
+ bx r14
+
+.ltorg
+
+@ here y occupies more than 32 bits
+@ split into cases acccording to the size of x
+y64:
+ cmp r3,#0
+ beq 1f
+ b y64_x48 @ if x does not fit in 32 bits, go to 48- and 64-bit cases
+1:
+ lsrs r3,r2,#16
+ bne y64_x32 @ jump if x is 17..32 bits
+
+@ here x is at most 16 bits
+
+ cmp r2,#0
+ beq udiv0 @ x==0? exit as with y!=0 case above
+ push {r7}
+ ldr r7,=#SIO_BASE
+ str r1,[r7,#SIO_DIV_UDIVIDEND_OFFSET]
+ str r2,[r7,#SIO_DIV_UDIVISOR_OFFSET]
+ wait_div 4
+ push {r4, r5}
+ lsrs r4,r0,#16
+ ldr r3,[r7,#SIO_DIV_REMAINDER_OFFSET] @ r0=y0-q0*x; 0<=r0>16);
+ wait_div 1
+ uxth r4,r0
+ ldr r3,[r7,#SIO_DIV_REMAINDER_OFFSET] @ r1=y1-q1*x; 0<=r1>16);
+ wait_div 3
+ movs r3,#0
+ lsls r4,r5,#16 @ quotient=(q0<<32)+(q1<<16)+q2
+ lsrs r5,#16
+ ldr r2,[r7,#SIO_DIV_REMAINDER_OFFSET] @ r2=y2-q2*x; 0<=r2>15)+1; 2^16>48)*r)>>16;
+ lsls r7,r6,#13
+ mov r14,r7 @ quh=q0<<13
+
+ muls r3,r6 @ x0l*q
+ lsrs r7,r3,#15
+ lsls r3,#17 @ r3:r7 is (x0l*q)<<17
+ subs r0,r3
+ sbcs r1,r7 @ y-=(x0l*q)<<17
+
+ lsrs r3,r2,#16 @ x0h
+ muls r3,r6 @ q*x0h
+ adds r3,r3
+ subs r1,r3 @ y-=(x0h*q)<<17
+
+ lsrs r6,r1,#3
+ muls r6,r4
+ lsrs r6,#16 @ q=((ui32)(y>>35)*r)>>16;
+ add r14,r6 @ quh+=q1
+
+ uxth r3,r2 @ x0l
+ muls r3,r6 @ x0l*q
+ lsrs r7,r3,#28
+ lsls r3,#4 @ r3:r7 is (x0l*q)<<4
+ subs r0,r3
+ sbcs r1,r7 @ y-=(x0l*q)<<4
+
+ lsrs r3,r2,#16 @ x0h
+ muls r3,r6 @ x0h*q
+ lsrs r7,r3,#12
+ lsls r3,#20 @ r3:r7 is (x0h*q)<<4
+ subs r0,r3
+ sbcs r1,r7 @ y-=(x0h*q)<<4
+
+ lsrs r6,r0,#22
+ lsls r7,r1,#10
+ orrs r6,r7 @ y>>22
+ muls r6,r4
+ lsrs r6,#16 @ q=((ui32)(y>>22)*r)>>16;
+
+ cmp r5,#9
+ blt last0 @ if(xsh<9) goto last0;
+
+@ on this path xsh>=9, which means x<2^23
+ lsrs r2,#9 @ x0>>9: this shift loses no bits
+@ the remainder y-x0*q is guaranteed less than a very small multiple of the remaining quotient
+@ bits (at most 6 bits) times x, and so fits in one word
+ muls r2,r6 @ x0*q
+ subs r0,r2 @ y-x0*q
+ lsls r7,r6,#13 @ qul=q<<13
+1:
+ lsrs r6,r0,#9
+ muls r6,r4
+ lsrs r6,#16 @ q=((ui32)(y>>9)*r)>>16;
+
+@ here
+@ r0 y
+@ r2 x0>>9
+@ r5 xsh
+@ r6 q
+@ r7 qul
+@ r12 x
+@ r14 quh
+
+ movs r3,#22
+ subs r3,r5 @ 22-xsh
+ lsrs r6,r3 @ q>>=22-xsh
+ lsrs r7,r3 @ qul>>=22-xsh
+ adds r7,r6 @ qul+=q
+ mov r4,r12
+ muls r6,r4 @ x*q
+ subs r2,r0,r6 @ y-=x*q
+ mov r0,r14 @ quh
+ adds r5,#4 @ xsh+4
+ adds r3,#6 @ 28-xsh
+ movs r1,r0
+ lsrs r1,r3
+ lsls r0,r5 @ r0:r1 is quh<<(4+xsh)
+ adds r0,r7
+ bcc 1f
+2:
+ adds r1,#1
+1: @ qu=((ui64)quh<<(4+xsh))+qul
+ cmp r2,r4
+ bhs 3f
+ movs r3,#0
+ pop {r4-r7,r15}
+
+.ltorg
+
+3:
+ subs r2,r4
+ adds r0,#1
+ bcc 1b
+ b 2b @ while(y>=x) y-=x,qu++;
+
+@ here:
+@ r0:r1 y
+@ r2 x0
+@ r4 r
+@ r5 xsh; xsh<9
+@ r6 q
+
+last0:
+ movs r7,#9
+ subs r7,r5 @ 9-xsh
+ lsrs r6,r7
+ mov r4,r12 @ x
+ uxth r2,r4
+ muls r2,r6 @ q*xlo
+ subs r0,r2
+ bcs 1f
+ subs r1,#1 @ y-=q*xlo
+1:
+ lsrs r2,r4,#16 @ xhi
+ muls r2,r6 @ q*xhi
+ lsrs r3,r2,#16
+ lsls r2,#16
+ subs r2,r0,r2
+ sbcs r1,r3 @ y-q*xhi
+ movs r3,r1 @ y now in r2:r3
+ mov r0,r14 @ quh
+ adds r5,#4 @ xsh+4
+ adds r7,#19 @ 28-xsh
+ movs r1,r0
+ lsrs r1,r7
+ lsls r0,r5 @ r0:r1 is quh<<(4+xsh)
+ adds r0,r6
+ bcc 1f
+ adds r1,#1 @ quh<<(xsh+4))+q
+1:
+ cmp r3,#0 @ y>=2^32?
+ bne 3f
+ cmp r2,r4 @ y>=x?
+ bhs 4f
+ pop {r4-r7,r15}
+
+3:
+ adds r0,#1 @ qu++
+ bcc 2f
+ adds r1,#1
+2:
+ subs r2,r4 @ y-=x
+ bcs 3b
+ subs r3,#1
+ bne 3b
+
+1:
+ cmp r2,r4
+ bhs 4f
+ pop {r4-r7,r15}
+
+4:
+ adds r0,#1 @ qu++
+ bcc 2f
+ adds r1,#1
+2:
+ subs r2,r4 @ y-=x
+ b 1b
+
+y64_x48:
+@ here x is 33..64 bits
+ push {r4-r7,r14} @ save a copy of x
+ lsrs r4,r3,#16
+ beq 1f
+ b y64_x64 @ jump if x is 49..64 bits
+1:
+ push {r2-r3} @ save a copy of x
+@ here x is 33..48 bits
+ movs r5,#0 @ xsh=0
+ lsrs r4,r3,#8
+ bne 1f
+ lsls r3,#8
+ lsrs r6,r2,#24
+ orrs r3,r6
+ lsls r2,#8 @ if(x0<1U<<40) x0<<=8,xsh =8;
+ adds r5,#8
+1:
+ lsrs r4,r3,#12
+ bne 1f
+ lsls r3,#4
+ lsrs r6,r2,#28
+ orrs r3,r6
+ lsls r2,#4 @ if(x0<1U<<44) x0<<=4,xsh+=4;
+ adds r5,#4
+1:
+ lsrs r4,r3,#14
+ bne 1f
+ lsls r3,#2
+ lsrs r6,r2,#30
+ orrs r3,r6
+ lsls r2,#2 @ if(x0<1U<<46) x0<<=2,xsh+=2;
+ adds r5,#2
+1:
+ lsrs r4,r3,#15
+ bne 1f
+ adds r2,r2
+ adcs r3,r3 @ if(x0<1U<<47) x0<<=1,xsh+=1;
+ adds r5,#1
+1:
+@ now 2^47<=x0<2^48, 0<=xsh<16 (amount x is shifted in x0); number of quotient bits to be calculated qb=xsh+17 17<=qb<33
+ movs r4,r3
+ adds r7,r2,r2
+ adcs r4,r4
+ adds r4,#1 @ x1=(ui32)(x0>>31)+1; // 2^16>48)*r)>>16;
+ lsls r7,r6,#13
+ mov r14,r7 @ save q<<13
+ uxth r7,r2 @ x0l
+ muls r7,r6
+ subs r0,r7
+ bcs 1f
+ subs r1,#1
+1:
+ subs r0,r7
+ bcs 1f
+ subs r1,#1
+1:
+ uxth r7,r3 @ x0h
+ muls r7,r6
+ subs r1,r7
+ subs r1,r7
+ lsrs r7,r2,#16 @ x0m
+ muls r7,r6
+ lsls r6,r7,#17
+ lsrs r7,#15
+ subs r0,r6
+ sbcs r1,r7 @ y-=((ui64)q*x0)<<1;
+
+ lsrs r6,r1,#3 @ y>>35
+ muls r6,r4
+ lsrs r6,#16 @ q=((ui32)(y>>35)*r)>>16;
+
+ cmp r5,#12
+ blt last1 @ if(xsh<12) goto last1;
+
+ add r14,r6 @ qu<<13+q
+ lsrs r2,#12
+ lsls r7,r3,#20
+ orrs r2,r7
+ lsrs r3,#12 @ x0>>12
+
+ uxth r7,r2 @ x0l
+ muls r7,r6
+ subs r0,r7
+ bcs 1f
+ subs r1,#1
+1:
+ uxth r7,r3 @ x0h
+ muls r7,r6
+ subs r1,r7
+ lsrs r7,r2,#16 @ x0m
+ muls r7,r6
+ lsls r6,r7,#16
+ lsrs r7,#16
+ subs r0,r6
+ sbcs r1,r7 @ y-=((ui64)q*x0)>>12
+
+ lsrs r6,r0,#22
+ lsls r7,r1,#10
+ orrs r6,r7 @ y>>22
+ muls r6,r4
+ movs r7,#41
+ subs r7,r5
+ lsrs r6,r7 @ q=((ui32)(y>>22)*r)>>(16+25-xsh)
+
+ subs r5,#12
+ mov r7,r14
+ lsls r7,r5
+2:
+ adds r7,r6 @ qu=(qu<<(xsh-12))+q
+ pop {r4,r5} @ recall x
+
+@ here
+@ r0:r1 y
+@ r4:r5 x
+@ r6 q
+@ r7 qu
+
+ uxth r2,r4
+ uxth r3,r5
+ muls r2,r6 @ xlo*q
+ muls r3,r6 @ xhi*q
+ subs r0,r2
+ sbcs r1,r3
+ lsrs r2,r4,#16
+ muls r2,r6
+ lsrs r3,r2,#16
+ lsls r2,#16 @ xm*q
+ subs r0,r2
+ sbcs r1,r3 @ y-=(ui64)q*x
+
+1:
+ movs r2,r0
+ movs r3,r1
+ adds r7,#1
+ subs r0,r4
+ sbcs r1,r5 @ while(y>=x) y-=x,qu++;
+ bhs 1b
+ subs r0,r7,#1 @ correction to qu
+ movs r1,#0
+ pop {r4-r7,r15}
+
+last1:
+@ r0:r1 y
+@ r2:r3 x0
+@ r5 xsh
+@ r6 q
+
+ movs r7,#12
+ subs r7,r5
+ lsrs r6,r7 @ q>>=12-xsh
+ mov r7,r14
+ lsrs r7,#13
+ lsls r7,r5
+ adds r7,r7 @ qu<<(xsh+1)
+ b 2b
+
+y64_x64:
+@ here x is 49..64 bits
+ movs r4,#0 @ q=0 if x>>32==0xffffffff
+ adds r5,r3,#1
+ beq 1f
+
+ ldr r7,=#SIO_BASE
+ str r5,[r7,#SIO_DIV_UDIVISOR_OFFSET]
+ str r1,[r7,#SIO_DIV_UDIVIDEND_OFFSET]
+ wait_div 0
+ ldr r4,[r7,#SIO_DIV_QUOTIENT_OFFSET] @ q=(ui32)(y>>32)/((x>>32)+1)
+1:
+ uxth r5,r2
+ uxth r6,r3
+ muls r5,r4
+ muls r6,r4
+ subs r0,r5
+ sbcs r1,r6
+ lsrs r5,r2,#16
+ lsrs r6,r3,#16
+ muls r5,r4
+ muls r6,r4
+ lsls r6,#16
+ lsrs r7,r5,#16
+ orrs r6,r7
+ lsls r5,#16
+ subs r0,r5
+ sbcs r1,r6 @ y-=(ui64)q*x
+
+ cmp r1,r3 @ while(y>=x) y-=x,q++
+ bhs 1f
+3:
+ movs r2,r0
+ movs r3,r1
+ movs r0,r4
+ movs r1,#0
+ pop {r4-r7,r15}
+
+1:
+ bne 2f
+ cmp r0,r2
+ blo 3b
+2:
+ subs r0,r2
+ sbcs r1,r3
+ adds r4,#1
+ cmp r1,r3
+ blo 3b
+ b 1b
+
+div_section divmod_s64s64_rem
+regular_func divmod_s64s64_rem
+ push {r4, lr}
+ bl divmod_s64s64
+ ldr r4, [sp, #8]
+ stmia r4!, {r2,r3}
+ pop {r4, pc}
+
+div_section divmod_u64u64_rem
+regular_func divmod_u64u64_rem
+ push {r4, lr}
+ bl divmod_u64u64
+ ldr r4, [sp, #8]
+ stmia r4!, {r2,r3}
+ pop {r4, pc}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/CMakeLists.txt
new file mode 100644
index 00000000000..a707385aa48
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/CMakeLists.txt
@@ -0,0 +1,127 @@
+if (NOT TARGET pico_double)
+ # library to be depended on - we make this depend on particular implementations using per target generator expressions
+ add_library(pico_double INTERFACE)
+
+ # no custom implementation; falls thru to compiler
+ add_library(pico_double_compiler INTERFACE)
+ # PICO_BUILD_DEFINE: PICO_DOUBLE_COMPILER, whether compiler provided double support is being used, type=bool, default=0, but dependent on CMake options, group=pico_double
+ target_compile_definitions(pico_double_compiler INTERFACE
+ PICO_DOUBLE_COMPILER=1
+ )
+
+ add_library(pico_double_headers INTERFACE)
+ target_include_directories(pico_double_headers INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
+ # add alias "default" which is just pico.
+ add_library(pico_double_default INTERFACE)
+ target_link_libraries(pico_double_default INTERFACE pico_double_pico)
+
+ set(PICO_DEFAULT_DOUBLE_IMPL pico_double_default)
+
+ target_link_libraries(pico_double INTERFACE
+ $>,$,${PICO_DEFAULT_DOUBLE_IMPL}>)
+
+ add_library(pico_double_pico INTERFACE)
+ target_sources(pico_double_pico INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/double_aeabi.S
+ ${CMAKE_CURRENT_LIST_DIR}/double_init_rom.c
+ ${CMAKE_CURRENT_LIST_DIR}/double_math.c
+ ${CMAKE_CURRENT_LIST_DIR}/double_v1_rom_shim.S
+ )
+ # PICO_BUILD_DEFINE: PICO_DOUBLE_PICO, whether optimized pico/bootrom provided double support is being used, type=bool, default=1, but dependent on CMake options, group=pico_double
+ target_compile_definitions(pico_double_pico INTERFACE
+ PICO_DOUBLE_PICO=1
+ )
+
+ target_link_libraries(pico_double_pico INTERFACE pico_bootrom pico_double_headers)
+
+ add_library(pico_double_none INTERFACE)
+ target_sources(pico_double_none INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/double_none.S
+ )
+
+ target_link_libraries(pico_double_none INTERFACE pico_double_headers)
+
+ # PICO_BUILD_DEFINE: PICO_DOUBLE_NONE, whether double support is disabled and functions will panic, type=bool, default=0, but dependent on CMake options, group=pico_double
+ target_compile_definitions(pico_double_none INTERFACE
+ PICO_DOUBLE_NONE=1
+ PICO_PRINTF_SUPPORT_FLOAT=0 # printing floats/doubles won't work, so we can save space by removing it
+ )
+
+ function(wrap_double_functions TARGET)
+ pico_wrap_function(${TARGET} __aeabi_dadd)
+ pico_wrap_function(${TARGET} __aeabi_ddiv)
+ pico_wrap_function(${TARGET} __aeabi_dmul)
+ pico_wrap_function(${TARGET} __aeabi_drsub)
+ pico_wrap_function(${TARGET} __aeabi_dsub)
+ pico_wrap_function(${TARGET} __aeabi_cdcmpeq)
+ pico_wrap_function(${TARGET} __aeabi_cdrcmple)
+ pico_wrap_function(${TARGET} __aeabi_cdcmple)
+ pico_wrap_function(${TARGET} __aeabi_dcmpeq)
+ pico_wrap_function(${TARGET} __aeabi_dcmplt)
+ pico_wrap_function(${TARGET} __aeabi_dcmple)
+ pico_wrap_function(${TARGET} __aeabi_dcmpge)
+ pico_wrap_function(${TARGET} __aeabi_dcmpgt)
+ pico_wrap_function(${TARGET} __aeabi_dcmpun)
+ pico_wrap_function(${TARGET} __aeabi_i2d)
+ pico_wrap_function(${TARGET} __aeabi_l2d)
+ pico_wrap_function(${TARGET} __aeabi_ui2d)
+ pico_wrap_function(${TARGET} __aeabi_ul2d)
+ pico_wrap_function(${TARGET} __aeabi_d2iz)
+ pico_wrap_function(${TARGET} __aeabi_d2lz)
+ pico_wrap_function(${TARGET} __aeabi_d2uiz)
+ pico_wrap_function(${TARGET} __aeabi_d2ulz)
+ pico_wrap_function(${TARGET} __aeabi_d2f)
+ pico_wrap_function(${TARGET} sqrt)
+ pico_wrap_function(${TARGET} cos)
+ pico_wrap_function(${TARGET} sin)
+ pico_wrap_function(${TARGET} tan)
+ pico_wrap_function(${TARGET} atan2)
+ pico_wrap_function(${TARGET} exp)
+ pico_wrap_function(${TARGET} log)
+
+ pico_wrap_function(${TARGET} ldexp)
+ pico_wrap_function(${TARGET} copysign)
+ pico_wrap_function(${TARGET} trunc)
+ pico_wrap_function(${TARGET} floor)
+ pico_wrap_function(${TARGET} ceil)
+ pico_wrap_function(${TARGET} round)
+ pico_wrap_function(${TARGET} sincos) # gnu
+ pico_wrap_function(${TARGET} asin)
+ pico_wrap_function(${TARGET} acos)
+ pico_wrap_function(${TARGET} atan)
+ pico_wrap_function(${TARGET} sinh)
+ pico_wrap_function(${TARGET} cosh)
+ pico_wrap_function(${TARGET} tanh)
+ pico_wrap_function(${TARGET} asinh)
+ pico_wrap_function(${TARGET} acosh)
+ pico_wrap_function(${TARGET} atanh)
+ pico_wrap_function(${TARGET} exp2)
+ pico_wrap_function(${TARGET} log2)
+ pico_wrap_function(${TARGET} exp10)
+ pico_wrap_function(${TARGET} log10)
+ pico_wrap_function(${TARGET} pow)
+ pico_wrap_function(${TARGET} powint) #gnu
+ pico_wrap_function(${TARGET} hypot)
+ pico_wrap_function(${TARGET} cbrt)
+ pico_wrap_function(${TARGET} fmod)
+ pico_wrap_function(${TARGET} drem)
+ pico_wrap_function(${TARGET} remainder)
+ pico_wrap_function(${TARGET} remquo)
+ pico_wrap_function(${TARGET} expm1)
+ pico_wrap_function(${TARGET} log1p)
+ pico_wrap_function(${TARGET} fma)
+ endfunction()
+
+ wrap_double_functions(pico_double_pico)
+ wrap_double_functions(pico_double_none)
+
+ macro(pico_set_double_implementation TARGET IMPL)
+ get_target_property(target_type ${TARGET} TYPE)
+ if ("EXECUTABLE" STREQUAL "${target_type}")
+ set_target_properties(${TARGET} PROPERTIES PICO_TARGET_DOUBLE_IMPL "pico_double_${IMPL}")
+ else()
+ message(FATAL_ERROR "double implementation must be set on executable not library")
+ endif()
+ endmacro()
+endif()
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_aeabi.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_aeabi.S
new file mode 100644
index 00000000000..4ef7748e9a8
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_aeabi.S
@@ -0,0 +1,801 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico/asm_helper.S"
+#include "pico/bootrom/sf_table.h"
+
+__pre_init __aeabi_double_init, 00020
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+.macro double_section name
+#if PICO_DOUBLE_IN_RAM
+.section RAM_SECTION_NAME(\name), "ax"
+#else
+.section SECTION_NAME(\name), "ax"
+#endif
+.endm
+
+.macro _double_wrapper_func x
+ wrapper_func \x
+.endm
+
+.macro wrapper_func_d1 x
+ _double_wrapper_func \x
+#if PICO_DOUBLE_PROPAGATE_NANS
+ mov ip, lr
+ bl __check_nan_d1
+ mov lr, ip
+#endif
+.endm
+
+.macro wrapper_func_d2 x
+ _double_wrapper_func \x
+#if PICO_DOUBLE_PROPAGATE_NANS
+ mov ip, lr
+ bl __check_nan_d2
+ mov lr, ip
+#endif
+.endm
+
+.section .text
+
+#if PICO_DOUBLE_PROPAGATE_NANS
+.thumb_func
+__check_nan_d1:
+ movs r3, #1
+ lsls r3, #21
+ lsls r2, r1, #1
+ adds r2, r3
+ bhi 1f
+ bx lr
+1:
+ bx ip
+
+.thumb_func
+__check_nan_d2:
+ push {r0, r2}
+ movs r2, #1
+ lsls r2, #21
+ lsls r0, r1, #1
+ adds r0, r2
+ bhi 1f
+ lsls r0, r3, #1
+ adds r0, r2
+ bhi 2f
+ pop {r0, r2}
+ bx lr
+2:
+ pop {r0, r2}
+ mov r0, r2
+ mov r1, r3
+ bx ip
+1:
+ pop {r0, r2}
+ bx ip
+#endif
+
+.macro table_tail_call SF_TABLE_OFFSET
+ push {r3, r4}
+#if PICO_DOUBLE_SUPPORT_ROM_V1
+#ifndef NDEBUG
+ movs r3, #0
+ mov ip, r3
+#endif
+#endif
+ ldr r3, =sd_table
+ ldr r3, [r3, #\SF_TABLE_OFFSET]
+ str r3, [sp, #4]
+ pop {r3, pc}
+.endm
+
+.macro shimmable_table_tail_call SF_TABLE_OFFSET shim
+ push {r3, r4}
+ ldr r3, =sd_table
+ ldr r3, [r3, #\SF_TABLE_OFFSET]
+#if PICO_DOUBLE_SUPPORT_ROM_V1
+ mov ip, pc
+#endif
+ str r3, [sp, #4]
+ pop {r3, pc}
+#if PICO_DOUBLE_SUPPORT_ROM_V1
+.byte \SF_TABLE_OFFSET, 0xdf
+.word \shim
+#endif
+.endm
+
+.macro double_wrapper_section func
+double_section WRAPPER_FUNC_NAME(\func)
+.endm
+
+double_section push_r8_r11
+regular_func push_r8_r11
+ mov r4,r8
+ mov r5,r9
+ mov r6,r10
+ mov r7,r11
+ push {r4-r7}
+ bx r14
+
+double_section pop_r8_r11
+regular_func pop_r8_r11
+ pop {r4-r7}
+ mov r8,r4
+ mov r9,r5
+ mov r10,r6
+ mov r11,r7
+ bx r14
+
+# note generally each function is in a separate section unless there is fall thru or branching between them
+# note fadd, fsub, fmul, fdiv are so tiny and just defer to rom so are lumped together so they can share constant pool
+
+# note functions are word aligned except where they are an odd number of linear instructions
+
+// double FUNC_NAME(__aeabi_dadd)(double, double) double-precision addition
+double_wrapper_section __aeabi_darithmetic
+// double FUNC_NAME(__aeabi_drsub)(double x, double y) double-precision reverse subtraction, y - x
+
+# frsub first because it is the only one that needs alignment
+.align 2
+wrapper_func __aeabi_drsub
+ eors r0, r1
+ eors r1, r0
+ eors r0, r1
+ // fall thru
+
+// double FUNC_NAME(__aeabi_dsub)(double x, double y) double-precision subtraction, x - y
+wrapper_func_d2 __aeabi_dsub
+#if PICO_DOUBLE_PROPAGATE_NANS
+ // we want to return nan for inf-inf or -inf - -inf, but without too much upfront cost
+ mov ip, r0
+ mov r0, r1
+ eors r0, r3
+ bmi 1f // different signs
+ mov r0, ip
+ push {r0-r3, lr}
+ bl 2f
+ b ddiv_dsub_nan_helper
+1:
+ mov r0, ip
+2:
+#endif
+ shimmable_table_tail_call SF_TABLE_FSUB dsub_shim
+
+wrapper_func_d2 __aeabi_dadd
+ shimmable_table_tail_call SF_TABLE_FADD dadd_shim
+
+// double FUNC_NAME(__aeabi_ddiv)(double n, double d) double-precision division, n / d
+wrapper_func_d2 __aeabi_ddiv
+#if PICO_DOUBLE_PROPAGATE_NANS
+ push {r0-r3, lr}
+ bl 1f
+ b ddiv_dsub_nan_helper
+1:
+#endif
+ shimmable_table_tail_call SF_TABLE_FDIV ddiv_shim
+
+ddiv_dsub_nan_helper:
+#if PICO_DOUBLE_PROPAGATE_NANS
+ // check for infinite op infinite (or rather check for infinite result with both
+ // operands being infinite)
+ lsls r2, r1, #1
+ asrs r2, r2, #21
+ adds r2, #1
+ beq 2f
+ add sp, #16
+ pop {pc}
+2:
+ ldr r2, [sp, #4]
+ ldr r3, [sp, #12]
+ lsls r2, #1
+ asrs r2, r2, #21
+ lsls r3, #1
+ asrs r3, r3, #24
+ ands r2, r3
+ adds r2, #1
+ bne 3f
+ // infinite to nan
+ movs r2, #1
+ lsls r2, #19
+ orrs r1, r2
+3:
+ add sp, #16
+ pop {pc}
+#endif
+
+// double FUNC_NAME(__aeabi_dmul)(double, double) double-precision multiplication
+wrapper_func_d2 __aeabi_dmul
+#if PICO_DOUBLE_PROPAGATE_NANS
+ push {r0-r3, lr}
+ bl 1f
+
+ // check for multiplication of infinite by zero (or rather check for infinite result with either
+ // operand 0)
+ lsls r3, r1, #1
+ asrs r3, r3, #21
+ adds r3, #1
+ beq 2f
+ add sp, #16
+ pop {pc}
+2:
+ ldr r2, [sp, #4]
+ ldr r3, [sp, #12]
+ ands r2, r3
+ bne 3f
+ // infinite to nan
+ movs r2, #1
+ lsls r2, #19
+ orrs r1, r2
+3:
+ add sp, #16
+ pop {pc}
+1:
+#endif
+ shimmable_table_tail_call SF_TABLE_FMUL dmul_shim
+
+// void FUNC_NAME(__aeabi_cdrcmple)(double, double) reversed 3-way (<, =, ?>) compare [1], result in PSR ZC flags
+double_wrapper_section __aeabi_cdcmple
+
+wrapper_func __aeabi_cdrcmple
+ push {r0-r7,r14}
+ eors r0, r2
+ eors r2, r0
+ eors r0, r2
+ eors r1, r3
+ eors r3, r1
+ eors r1, r3
+ b __aeabi_dfcmple_guts
+
+// NOTE these share an implementation as we have no excepting NaNs.
+// void FUNC_NAME(__aeabi_cdcmple)(double, double) 3-way (<, =, ?>) compare [1], result in PSR ZC flags
+// void FUNC_NAME(__aeabi_cdcmpeq)(double, double) non-excepting equality comparison [1], result in PSR ZC flags
+@ compare r0:r1 against r2:r3, returning -1/0/1 for <, =, >
+@ also set flags accordingly
+.align 2
+wrapper_func __aeabi_cdcmple
+wrapper_func __aeabi_cdcmpeq
+ push {r0-r7,r14}
+__aeabi_dfcmple_guts:
+ ldr r7,=#0x7ff @ flush NaNs and denormals
+ lsls r4,r1,#1
+ lsrs r4,#21
+ beq 1f
+ cmp r4,r7
+ bne 2f
+ lsls r4, r1, #12
+ bhi 7f
+1:
+ movs r0,#0
+ lsrs r1,#20
+ lsls r1,#20
+2:
+ lsls r4,r3,#1
+ lsrs r4,#21
+ beq 1f
+ cmp r4,r7
+ bne 2f
+ lsls r4, r3, #12
+ bhi 7f
+1:
+ movs r2,#0
+ lsrs r3,#20
+ lsls r3,#20
+2:
+ movs r6,#1
+ eors r3,r1
+ bmi 4f @ opposite signs? then can proceed on basis of sign of x
+ eors r3,r1 @ restore r3
+ bpl 2f
+ cmp r3,r1
+ bne 7f
+1:
+ cmp r2,r0
+7:
+ pop {r0-r7,r15}
+2:
+ cmp r1,r3
+ bne 7b
+1:
+ cmp r0,r2
+ pop {r0-r7,r15}
+4:
+ orrs r3,r1 @ make -0==+0
+ adds r3,r3
+ orrs r3,r0
+ orrs r3,r2
+ beq 7b
+ mvns r1, r1 @ carry inverse of r1 sign
+ adds r1, r1
+ pop {r0-r7,r15}
+
+
+// int FUNC_NAME(__aeabi_dcmpeq)(double, double) result (1, 0) denotes (=, ?<>) [2], use for C == and !=
+double_wrapper_section __aeabi_dcmpeq
+.align 2
+wrapper_func __aeabi_dcmpeq
+ push {lr}
+ bl __aeabi_cdcmpeq
+ beq 1f
+ movs r0, #0
+ pop {pc}
+1:
+ movs r0, #1
+ pop {pc}
+
+// int FUNC_NAME(__aeabi_dcmplt)(double, double) result (1, 0) denotes (<, ?>=) [2], use for C <
+double_wrapper_section __aeabi_dcmplt
+.align 2
+wrapper_func __aeabi_dcmplt
+ push {lr}
+ bl __aeabi_cdcmple
+ sbcs r0, r0
+ pop {pc}
+
+// int FUNC_NAME(__aeabi_dcmple)(double, double) result (1, 0) denotes (<=, ?>) [2], use for C <=
+double_wrapper_section __aeabi_dcmple
+.align 2
+wrapper_func __aeabi_dcmple
+ push {lr}
+ bl __aeabi_cdcmple
+ bls 1f
+ movs r0, #0
+ pop {pc}
+1:
+ movs r0, #1
+ pop {pc}
+
+// int FUNC_NAME(__aeabi_dcmpge)(double, double) result (1, 0) denotes (>=, ?<) [2], use for C >=
+double_wrapper_section __aeabi_dcmpge
+.align 2
+wrapper_func __aeabi_dcmpge
+ push {lr}
+ // because of NaNs it is better to reverse the args than the result
+ bl __aeabi_cdrcmple
+ bls 1f
+ movs r0, #0
+ pop {pc}
+1:
+ movs r0, #1
+ pop {pc}
+
+// int FUNC_NAME(__aeabi_dcmpgt)(double, double) result (1, 0) denotes (>, ?<=) [2], use for C >
+double_wrapper_section __aeabi_dcmpgt
+wrapper_func __aeabi_dcmpgt
+ push {lr}
+ // because of NaNs it is better to reverse the args than the result
+ bl __aeabi_cdrcmple
+ sbcs r0, r0
+ pop {pc}
+
+// int FUNC_NAME(__aeabi_dcmpun)(double, double) result (1, 0) denotes (?, <=>) [2], use for C99 isunordered()
+double_wrapper_section __aeabi_dcmpun
+wrapper_func __aeabi_dcmpun
+ movs r0, #1
+ lsls r0, #21
+ lsls r2, r1, #1
+ adds r2, r0
+ bhi 1f
+ lsls r2, r3, #1
+ adds r2, r0
+ bhi 1f
+ movs r0, #0
+ bx lr
+1:
+ movs r0, #1
+ bx lr
+
+ movs r0, #0
+ bx lr
+
+// double FUNC_NAME(__aeabi_ui2d)(unsigned) unsigned to double (double precision) conversion
+double_wrapper_section __aeabi_ui2d
+ shimmable_table_tail_call SF_TABLE_UINT2FLOAT uint2double_shim
+
+double_wrapper_section __aeabi_i2d
+
+wrapper_func __aeabi_ui2d
+ movs r1, #0
+ cmp r0, #0
+ bne 2f
+1:
+ bx lr
+// double FUNC_NAME(__aeabi_i2d)(int) integer to double (double precision) conversion
+wrapper_func __aeabi_i2d
+ asrs r1, r0, #31
+ eors r0, r1
+ subs r0, r1
+ beq 1b
+ lsls r1, #31
+2:
+ push {r0, r1, r4, lr}
+ ldr r3, =sf_clz_func
+ ldr r3, [r3]
+ blx r3
+ pop {r2, r3}
+ adds r4, r0, #1
+ lsls r2, r4
+ lsls r0, r2, #20
+ lsrs r2, #12
+ ldr r1,=#1055
+ subs r1, r4
+ lsls r1, #20
+ orrs r1, r3
+ orrs r1, r2
+ pop {r4, pc}
+
+// int FUNC_NAME(__aeabi_d2iz)(double) double (double precision) to integer C-style conversion [3]
+double_wrapper_section __aeabi_d2iz
+wrapper_func __aeabi_d2iz
+regular_func double2int_z
+ push {r4, lr}
+ lsls r4, r1, #1
+ lsrs r2, r4, #21
+ movs r3, #0x80
+ adds r2, r3
+ lsls r3, #3
+ subs r2, r3
+ lsls r3, #21
+ cmp r2, #126
+ ble 1f
+ subs r2, #158
+ bge 2f
+ asrs r4, r1, #31
+ lsls r1, #12
+ lsrs r1, #1
+ orrs r1, r3
+ negs r2, r2
+ lsrs r1, r2
+ lsls r4, #1
+ adds r4, #1
+ adds r2, #21
+ cmp r2, #32
+ bge 3f
+ lsrs r0, r2
+ orrs r0, r1
+ muls r0, r4
+ pop {r4, pc}
+1:
+ movs r0, #0
+ pop {r4, pc}
+3:
+ mov r0, r1
+ muls r0, r4
+ pop {r4, pc}
+2:
+ // overflow
+ lsrs r0, r1, #31
+ adds r0, r3
+ subs r0, #1
+ pop {r4, pc}
+
+double_section double2int
+regular_func double2int
+ shimmable_table_tail_call SF_TABLE_FLOAT2INT double2int_shim
+
+// unsigned FUNC_NAME(__aeabi_d2uiz)(double) double (double precision) to unsigned C-style conversion [3]
+double_wrapper_section __aeabi_d2uiz
+wrapper_func __aeabi_d2uiz
+regular_func double2uint
+ shimmable_table_tail_call SF_TABLE_FLOAT2UINT double2uint_shim
+
+double_section fix2double
+regular_func fix2double
+ shimmable_table_tail_call SF_TABLE_FIX2FLOAT fix2double_shim
+
+double_section ufix2double
+regular_func ufix2double
+ shimmable_table_tail_call SF_TABLE_UFIX2FLOAT ufix2double_shim
+
+double_section fix642double
+regular_func fix642double
+ shimmable_table_tail_call SF_TABLE_FIX642FLOAT fix642double_shim
+
+double_section ufix2double
+regular_func ufix642double
+ shimmable_table_tail_call SF_TABLE_UFIX642FLOAT ufix642double_shim
+
+// double FUNC_NAME(__aeabi_l2d)(long long) long long to double (double precision) conversion
+double_wrapper_section __aeabi_l2d
+wrapper_func __aeabi_l2d
+ shimmable_table_tail_call SF_TABLE_INT642FLOAT int642double_shim
+
+// double FUNC_NAME(__aeabi_l2f)(long long) long long to double (double precision) conversion
+double_wrapper_section __aeabi_ul2d
+wrapper_func __aeabi_ul2d
+ shimmable_table_tail_call SF_TABLE_UINT642FLOAT uint642double_shim
+
+// long long FUNC_NAME(__aeabi_d2lz)(double) double (double precision) to long long C-style conversion [3]
+double_wrapper_section __aeabi_d2lz
+wrapper_func __aeabi_d2lz
+regular_func double2int64_z
+ cmn r1, r1
+ bcc double2int64
+ push {lr}
+ lsls r1, #1
+ lsrs r1, #1
+ movs r2, #0
+ bl double2ufix64
+ cmp r1, #0
+ bmi 1f
+ movs r2, #0
+ rsbs r0, #0
+ sbcs r2, r1
+ mov r1, r2
+ pop {pc}
+1:
+ movs r1, #128
+ lsls r1, #24
+ movs r0, #0
+ pop {pc}
+
+double_section double2int64
+regular_func double2int64
+ shimmable_table_tail_call SF_TABLE_FLOAT2INT64 double2int64_shim
+
+// unsigned long long FUNC_NAME(__aeabi_d2ulz)(double) double to unsigned long long C-style conversion [3]
+double_wrapper_section __aeabi_d2ulz
+wrapper_func __aeabi_d2ulz
+ shimmable_table_tail_call SF_TABLE_FLOAT2UINT64 double2uint64_shim
+
+double_section double2fix64
+regular_func double2fix64
+ shimmable_table_tail_call SF_TABLE_FLOAT2FIX64 double2fix64_shim
+
+double_section double2ufix64
+regular_func double2ufix64
+ shimmable_table_tail_call SF_TABLE_FLOAT2UFIX64 double2ufix64_shim
+
+double_section double2fix
+regular_func double2fix
+ shimmable_table_tail_call SF_TABLE_FLOAT2FIX double2fix_shim
+
+double_section double2ufix
+regular_func double2ufix
+ shimmable_table_tail_call SF_TABLE_FLOAT2UFIX double2ufix_shim
+
+double_wrapper_section __aeabi_d2f
+1:
+#if PICO_DOUBLE_PROPAGATE_NANS
+ // copy sign bit and 23 NAN id bits into sign bit and significant id bits, also set high id bit
+
+ lsrs r0, #30
+ lsls r2, r1, #12
+ lsrs r2, #9
+ asrs r1, #22
+ lsls r1, #22
+ orrs r0, r1
+ orrs r0, r2
+ bx lr
+#endif
+wrapper_func __aeabi_d2f
+#if PICO_DOUBLE_PROPAGATE_NANS
+ movs r3, #1
+ lsls r3, #21
+ lsls r2, r1, #1
+ adds r2, r3
+ bhi 1b
+#endif
+ // note double->float in double table at same index as float->double in double table
+ shimmable_table_tail_call SF_TABLE_FLOAT2DOUBLE double2float_shim
+
+double_wrapper_section srqt
+wrapper_func_d1 sqrt
+ shimmable_table_tail_call SF_TABLE_FSQRT dsqrt_shim
+
+double_wrapper_section sincostan_remainder
+regular_func sincostan_remainder
+ ldr r2, =0x54442D18 // 2 * M_PI
+ ldr r3, =0x401921FB
+ push {lr}
+ bl remainder
+ pop {pc}
+
+double_wrapper_section cos
+#don't use _d1 as we're doing a range check anyway and infinites/nans are bigger than 1024
+wrapper_func cos
+ // rom version only works for -1024 < angle < 1024
+ lsls r2, r1, #2
+ bcc 1f
+ lsrs r2, #22
+ cmp r2, #9
+ bge 2f
+1:
+ shimmable_table_tail_call SF_TABLE_FCOS dcos_shim
+2:
+#if PICO_DOUBLE_PROPAGATE_NANS
+ lsls r2, r1, #1
+ asrs r2, #21
+ adds r2, #1
+ bne 3f
+ // infinite to nan
+ movs r2, #1
+ lsls r2, #19
+ orrs r1, r2
+ bx lr
+3:
+#endif
+ push {lr}
+ bl sincostan_remainder
+ pop {r2}
+ mov lr, r2
+ b 1b
+
+double_wrapper_section sin
+#don't use _d1 as we're doing a range check anyway and infinites/nans are bigger than 1024
+wrapper_func sin
+ // rom version only works for -1024 < angle < 1024
+ lsls r2, r1, #2
+ bcc 1f
+ lsrs r2, #22
+ cmp r2, #9
+ bge 2f
+1:
+ shimmable_table_tail_call SF_TABLE_FSIN dsin_shim
+2:
+#if PICO_DOUBLE_PROPAGATE_NANS
+ lsls r2, r1, #1
+ asrs r2, #21
+ adds r2, #1
+ bne 3f
+ // infinite to nan
+ movs r2, #1
+ lsls r2, #19
+ orrs r1, r2
+ bx lr
+3:
+#endif
+ push {lr}
+ bl sincostan_remainder
+ pop {r2}
+ mov lr, r2
+ b 1b
+
+double_wrapper_section sincos
+ // out of line remainder code for abs(angle)>=1024
+2:
+#if PICO_DOUBLE_PROPAGATE_NANS
+ lsls r2, r1, #1
+ asrs r2, #21
+ adds r2, #1
+ bne 3f
+ // infinite to nan
+ movs r2, #1
+ lsls r2, #19
+ orrs r1, r2
+ pop {r4-r5}
+ stmia r4!, {r0, r1}
+ stmia r5!, {r0, r1}
+ pop {r4, r5, pc}
+3:
+#endif
+ push {lr}
+ bl sincostan_remainder
+ pop {r2}
+ mov lr, r2
+ b 1f
+
+wrapper_func sincos
+ push {r2-r5, lr}
+ // rom version only works for -1024 < angle < 1024
+ lsls r2, r1, #2
+ bcc 1f
+ lsrs r2, #22
+ cmp r2, #9
+ bge 2b
+1:
+
+ bl 2f
+ pop {r4-r5}
+ stmia r4!, {r0, r1}
+ stmia r5!, {r2, r3}
+ pop {r4, r5, pc}
+
+2:
+ shimmable_table_tail_call SF_TABLE_V3_FSINCOS sincos_shim_bootstrap
+#if PICO_DOUBLE_PROPAGATE_NANS
+.align 2
+1:
+ pop {r2, r3}
+ stmia r2!, {r0, r1}
+ mov lr, r3
+ pop {r3}
+ stmia r3!, {r0, r1}
+ bx lr
+#endif
+.thumb_func
+sincos_shim_bootstrap:
+ push {r2, r3, r4}
+ movs r3, #0x13
+ ldrb r3, [r3]
+#if PICO_DOUBLE_SUPPORT_ROM_V1
+ cmp r3, #1
+ bne 1f
+ ldr r3, =dsincos_shim
+ b 2f
+#endif
+1:
+ ldr r3, =dsincos_shim_v2
+2:
+ ldr r2, =sd_table
+ str r3, [r2, #SF_TABLE_V3_FSINCOS]
+ str r3, [sp, #8]
+ pop {r2, r3, pc}
+.thumb_func
+dsincos_shim_v2:
+ push {r4-r7,r14}
+ bl push_r8_r11
+ bl v2_rom_dsincos_internal
+ mov r12,r0 @ save ε
+ bl v2_rom_dcos_finish
+ push {r0,r1}
+ mov r0,r12
+ bl v2_rom_dsin_finish
+ pop {r2,r3}
+ bl pop_r8_r11
+ pop {r4-r7,r15}
+.thumb_func
+v2_rom_dsincos_internal:
+ push {r0, lr}
+ ldr r0, =0x3855
+ str r0, [sp, #4]
+ pop {r0, pc}
+.thumb_func
+v2_rom_dcos_finish:
+ push {r0, r1}
+ ldr r0, =0x389d
+ str r0, [sp, #4]
+ pop {r0, pc}
+.thumb_func
+v2_rom_dsin_finish:
+ push {r0, r1}
+ ldr r0, =0x38d9
+ str r0, [sp, #4]
+ pop {r0, pc}
+
+double_wrapper_section tan
+#don't use _d1 as we're doing a range check anyway and infinites/nans are bigger than 1024
+wrapper_func tan
+ // rom version only works for -1024 < angle < 1024
+ lsls r2, r1, #2
+ bcc 1f
+ lsrs r2, #22
+ cmp r2, #9
+ bge 2f
+1:
+ shimmable_table_tail_call SF_TABLE_FTAN dtan_shim
+2:
+#if PICO_DOUBLE_PROPAGATE_NANS
+ lsls r2, r1, #1
+ asrs r2, #21
+ adds r2, #1
+ bne 3f
+ // infinite to nan
+ movs r2, #1
+ lsls r2, #19
+ orrs r1, r2
+ bx lr
+3:
+#endif
+ push {lr}
+ bl sincostan_remainder
+ pop {r2}
+ mov lr, r2
+ b 1b
+
+double_wrapper_section atan2
+wrapper_func_d2 atan2
+ shimmable_table_tail_call SF_TABLE_FATAN2 datan2_shim
+
+double_wrapper_section exp
+wrapper_func_d1 exp
+ shimmable_table_tail_call SF_TABLE_FEXP dexp_shim
+
+double_wrapper_section log
+wrapper_func_d1 log
+ shimmable_table_tail_call SF_TABLE_FLN dln_shim
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_init_rom.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_init_rom.c
new file mode 100644
index 00000000000..82950b41500
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_init_rom.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include
+#include "pico/bootrom.h"
+#include "pico/bootrom/sf_table.h"
+
+// NOTE THIS FUNCTION TABLE IS NOT PUBLIC OR NECESSARILY COMPLETE...
+// IT IS ***NOT*** SAFE TO CALL THESE FUNCTION POINTERS FROM ARBITRARY CODE
+uint32_t sd_table[SF_TABLE_V2_SIZE / 2];
+
+#if !PICO_DOUBLE_SUPPORT_ROM_V1
+static __attribute__((noreturn)) void missing_double_func_shim() {
+ panic("missing double function");
+}
+#endif
+extern void double_table_shim_on_use_helper();
+
+void __aeabi_double_init() {
+ int rom_version = rp2040_rom_version();
+#if PICO_DOUBLE_SUPPORT_ROM_V1
+ if (rom_version == 1) {
+
+ // this is a little tricky.. we only want to pull in a shim if the corresponding function
+ // is called. to that end we include a SVC instruction with the table offset as the call number
+ // followed by the shim function pointer inside the actual wrapper function. that way if the wrapper
+ // function is garbage collected, so is the shim function.
+ //
+ // double_table_shim_on_use_helper expects this SVC instruction in the calling code soon after the address
+ // pointed to by IP and patches the double_table entry with the real shim the first time the function is called.
+ for(uint i=0; i= 2) {
+ void *rom_table = rom_data_lookup(rom_table_code('S', 'D'));
+ assert(*((uint8_t *)(((void *)rom_data_lookup(rom_table_code('S', 'F')))-2)) * 4 >= SF_TABLE_V2_SIZE);
+ memcpy(&sd_table, rom_table, SF_TABLE_V2_SIZE);
+ if (rom_version == 2) {
+#ifndef NDEBUG
+ if (*(uint16_t *)0x3854 != 0xb500 || // this is dsincos(_internal)
+
+ *(uint16_t *)0x38d8 != 0x4649 || // this is dsin_finish
+ *(uint16_t *)0x389c != 0x4659 // this is dcos_finish
+ ) {
+ panic(NULL);
+ }
+#endif
+ }
+ }
+ if (rom_version < 3) {
+ // we use the unused entry for SINCOS
+ sd_table[SF_TABLE_V3_FSINCOS / 4] = (uintptr_t) double_table_shim_on_use_helper;
+ }
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_math.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_math.c
new file mode 100644
index 00000000000..41d4380e7c8
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_math.c
@@ -0,0 +1,607 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include
+#include "pico/types.h"
+#include "pico/double.h"
+#include "pico/platform.h"
+
+typedef uint64_t ui64;
+typedef uint32_t ui32;
+typedef int64_t i64;
+
+#define PINF ( HUGE_VAL)
+#define MINF (-HUGE_VAL)
+#define PZERO (+0.0)
+#define MZERO (-0.0)
+
+
+#define PI 3.14159265358979323846
+#define LOG2 0.69314718055994530941
+// Unfortunately in double precision ln(10) is very close to half-way between to representable numbers
+#define LOG10 2.30258509299404568401
+#define LOG2E 1.44269504088896340737
+#define LOG10E 0.43429448190325182765
+#define ONETHIRD 0.33333333333333333333
+
+#define PIf 3.14159265358979323846f
+#define LOG2f 0.69314718055994530941f
+#define LOG2Ef 1.44269504088896340737f
+#define LOG10Ef 0.43429448190325182765f
+#define ONETHIRDf 0.33333333333333333333f
+
+#define DUNPACK(x,e,m) e=((x)>>52)&0x7ff,m=((x)&0x000fffffffffffffULL)|0x0010000000000000ULL
+#define DUNPACKS(x,s,e,m) s=((x)>>63),DUNPACK((x),(e),(m))
+
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wstrict-aliasing\"")
+
+static inline bool disnan(double x) {
+ ui64 ix=*(i64*)&x;
+ // checks the top bit of the low 32 bit of the NAN, but it I think that is ok
+ return ((uint32_t)(ix >> 31)) > 0xffe00000u;
+}
+
+#if PICO_DOUBLE_PROPAGATE_NANS
+#define check_nan_d1(x) if (disnan((x))) return (x)
+#define check_nan_d2(x,y) if (disnan((x))) return (x); else if (disnan((y))) return (y);
+#else
+#define check_nan_d1(x) ((void)0)
+#define check_nan_d2(x,y) ((void)0)
+#endif
+
+static inline int dgetsignexp(double x) {
+ ui64 ix=*(ui64*)&x;
+ return (ix>>52)&0xfff;
+}
+
+static inline int dgetexp(double x) {
+ ui64 ix=*(ui64*)&x;
+ return (ix>>52)&0x7ff;
+}
+
+static inline double dldexp(double x,int de) {
+ ui64 ix=*(ui64*)&x,iy;
+ int e;
+ e=dgetexp(x);
+ if(e==0||e==0x7ff) return x;
+ e+=de;
+ if(e<=0) iy=ix&0x8000000000000000ULL; // signed zero for underflow
+ else if(e>=0x7ff) iy=(ix&0x8000000000000000ULL)|0x7ff0000000000000ULL; // signed infinity on overflow
+ else iy=ix+((ui64)de<<52);
+ return *(double*)&iy;
+}
+
+double WRAPPER_FUNC(ldexp)(double x, int de) {
+ check_nan_d1(x);
+ return dldexp(x, de);
+}
+
+
+static inline double dcopysign(double x,double y) {
+ ui64 ix=*(ui64*)&x,iy=*(ui64*)&y;
+ ix=((ix&0x7fffffffffffffffULL)|(iy&0x8000000000000000ULL));
+ return *(double*)&ix;
+}
+
+double WRAPPER_FUNC(copysign)(double x, double y) {
+ check_nan_d2(x,y);
+ return dcopysign(x, y);
+}
+static inline int diszero(double x) { return dgetexp (x)==0; }
+static inline int dispzero(double x) { return dgetsignexp(x)==0; }
+static inline int dismzero(double x) { return dgetsignexp(x)==0x800; }
+static inline int disinf(double x) { return dgetexp (x)==0x7ff; }
+static inline int dispinf(double x) { return dgetsignexp(x)==0x7ff; }
+static inline int disminf(double x) { return dgetsignexp(x)==0xfff; }
+
+static inline int disint(double x) {
+ ui64 ix=*(ui64*)&x,m;
+ int e=dgetexp(x);
+ if(e==0) return 1; // 0 is an integer
+ e-=0x3ff; // remove exponent bias
+ if(e<0) return 0; // |x|<1
+ e=52-e; // bit position in mantissa with significance 1
+ if(e<=0) return 1; // |x| large, so must be an integer
+ m=(1ULL<>e)&1;
+}
+
+static inline int disstrictneg(double x) {
+ ui64 ix=*(ui64*)&x;
+ if(diszero(x)) return 0;
+ return ix>>63;
+}
+
+static inline int disneg(double x) {
+ ui64 ix=*(ui64*)&x;
+ return ix>>63;
+}
+
+static inline double dneg(double x) {
+ ui64 ix=*(ui64*)&x;
+ ix^=0x8000000000000000ULL;
+ return *(double*)&ix;
+}
+
+static inline int dispo2(double x) {
+ ui64 ix=*(ui64*)&x;
+ if(diszero(x)) return 0;
+ if(disinf(x)) return 0;
+ ix&=0x000fffffffffffffULL;
+ return ix==0;
+}
+
+static inline double dnan_or(double x) {
+#if PICO_DOUBLE_PROPAGATE_NANS
+ return NAN;
+#else
+ return x;
+#endif
+}
+
+double WRAPPER_FUNC(trunc)(double x) {
+ check_nan_d1(x);
+ ui64 ix=*(ui64*)&x,m;
+ int e=dgetexp(x);
+ e-=0x3ff; // remove exponent bias
+ if(e<0) { // |x|<1
+ ix&=0x8000000000000000ULL;
+ return *(double*)&ix;
+ }
+ e=52-e; // bit position in mantissa with significance 1
+ if(e<=0) return x; // |x| large, so must be an integer
+ m=(1ULL<=5+0x3ff) { // |x|>=32?
+ if(!disneg(x)) return 1; // 1 << exp 2x; avoid generating infinities later
+ else return -1; // 1 >> exp 2x
+ }
+ u=exp(dldexp(x,1));
+ return (u-1)/(u+1);
+}
+
+double WRAPPER_FUNC(asinh)(double x) {
+ check_nan_d1(x);
+ int e;
+ e=dgetexp(x);
+ if(e>=32+0x3ff) { // |x|>=2^32?
+ if(!disneg(x)) return log( x )+LOG2; // 1/x^2 << 1
+ else return dneg(log(dneg(x))+LOG2); // 1/x^2 << 1
+ }
+ if(x>0) return log(sqrt(x*x+1)+x);
+ else return dneg(log(sqrt(x*x+1)-x));
+}
+
+double WRAPPER_FUNC(acosh)(double x) {
+ check_nan_d1(x);
+ int e;
+ if(disneg(x)) x=dneg(x);
+ e=dgetexp(x);
+ if(e>=32+0x3ff) return log(x)+LOG2; // |x|>=2^32?
+ return log(sqrt((x-1)*(x+1))+x);
+}
+
+double WRAPPER_FUNC(atanh)(double x) {
+ check_nan_d1(x);
+ return dldexp(log((1+x)/(1-x)),-1);
+}
+
+double WRAPPER_FUNC(exp2)(double x) {
+ check_nan_d1(x);
+ int e;
+ // extra check for disminf as this catches -Nan, and x<=-4096 doesn't.
+ if (disminf(x) || x<=-4096) return 0; // easily underflows
+ else if (x>=4096) return PINF; // easily overflows
+ e=(int)round(x);
+ x-=e;
+ return dldexp(exp(x*LOG2),e);
+}
+double WRAPPER_FUNC(log2)(double x) { check_nan_d1(x); return log(x)*LOG2E; }
+double WRAPPER_FUNC(exp10)(double x) { check_nan_d1(x); return pow(10,x); }
+double WRAPPER_FUNC(log10)(double x) { check_nan_d1(x); return log(x)*LOG10E; }
+
+// todo these are marked as lofi
+double WRAPPER_FUNC(expm1(double x) { check_nan_d1(x); return exp)(x)-1; }
+double WRAPPER_FUNC(log1p(double x) { check_nan_d1(x); return log)(1+x); }
+double WRAPPER_FUNC(fma)(double x,double y,double z) { check_nan_d1(x); return x*y+z; }
+
+// general power, x>0, finite
+static double dpow_1(double x,double y) {
+ int a,b,c;
+ double t,rt,u,v,v0,v1,w,ry;
+ a=dgetexp(x)-0x3ff;
+ u=log2(dldexp(x,-a)); // now log_2 x = a+u
+ if(u>0.5) u-=1,a++; // |u|<=~0.5
+ if(a==0) return exp2(u*y);
+ // here |log_2 x| >~0.5
+ if(y>= 4096) { // then easily over/underflows
+ if(a<0) return 0;
+ return PINF;
+ }
+ if(y<=-4096) { // then easily over/underflows
+ if(a<0) return PINF;
+ return 0;
+ }
+ ry=round(y);
+ v=y-ry;
+ v0=dldexp(round(ldexp(v,26)),-26);
+ v1=v-v0;
+ b=(int)ry; // guaranteed to fit in an int; y=b+v0+v1
+ // now the result is exp2( (a+u) * (b+v0+v1) )
+ c=a*b; // integer
+ t=a*v0;
+ rt=round(t);
+ c+=(int)rt;
+ w=t-rt;
+ t=a*v1;
+ w+=t;
+ t=u*b;
+ rt=round(t);
+ c+=(int)rt;
+ w+=t-rt;
+ w+=u*v;
+ return dldexp(exp2(w),c);
+}
+
+static double dpow_int2(double x,int y) {
+ double u;
+ if(y==1) return x;
+ u=dpow_int2(x,y/2);
+ u*=u;
+ if(y&1) u*=x;
+ return u;
+}
+
+// for the case where x not zero or infinity, y small and not zero
+static inline double dpowint_1(double x,int y) {
+ if(y<0) x=1/x,y=-y;
+ return dpow_int2(x,y);
+}
+
+// for the case where x not zero or infinity
+static double dpowint_0(double x,int y) {
+ int e;
+ if(disneg(x)) {
+ if(disoddint(y)) return dneg(dpowint_0(dneg(x),y));
+ else return dpowint_0(dneg(x),y);
+ }
+ if(dispo2(x)) {
+ e=dgetexp(x)-0x3ff;
+ if(y>=2048) y= 2047; // avoid overflow
+ if(y<-2048) y=-2048;
+ y*=e;
+ return dldexp(1,y);
+ }
+ if(y==0) return 1;
+ if(y>=-32&&y<=32) return dpowint_1(x,y);
+ return dpow_1(x,y);
+}
+
+double WRAPPER_FUNC(powint)(double x,int y) {
+ _Pragma("GCC diagnostic push")
+ _Pragma("GCC diagnostic ignored \"-Wfloat-equal\"")
+ if(x==1.0||y==0) return 1;
+ _Pragma("GCC diagnostic pop")
+ check_nan_d1(x);
+ if(diszero(x)) {
+ if(y>0) {
+ if(y&1) return x;
+ else return 0;
+ }
+ if((y&1)) return dcopysign(PINF,x);
+ return PINF;
+ }
+ if(dispinf(x)) {
+ if(y<0) return 0;
+ else return PINF;
+ }
+ if(disminf(x)) {
+ if(y>0) {
+ if((y&1)) return MINF;
+ else return PINF;
+ }
+ if((y&1)) return MZERO;
+ else return PZERO;
+ }
+ return dpowint_0(x,y);
+}
+
+// for the case where y is guaranteed a finite integer, x not zero or infinity
+static double dpow_0(double x,double y) {
+ int e,p;
+ if(disneg(x)) {
+ if(disoddint(y)) return dneg(dpow_0(dneg(x),y));
+ else return dpow_0(dneg(x),y);
+ }
+ p=(int)y;
+ if(dispo2(x)) {
+ e=dgetexp(x)-0x3ff;
+ if(p>=2048) p= 2047; // avoid overflow
+ if(p<-2048) p=-2048;
+ p*=e;
+ return dldexp(1,p);
+ }
+ if(p==0) return 1;
+ if(p>=-32&&p<=32) return dpowint_1(x,p);
+ return dpow_1(x,y);
+}
+
+double WRAPPER_FUNC(pow)(double x,double y) {
+ _Pragma("GCC diagnostic push")
+ _Pragma("GCC diagnostic ignored \"-Wfloat-equal\"")
+
+ if(x==1.0||diszero(y)) return 1;
+ check_nan_d2(x, y);
+ if(x==-1.0&&disinf(y)) return 1;
+ _Pragma("GCC diagnostic pop")
+
+ if(diszero(x)) {
+ if(!disneg(y)) {
+ if(disoddint(y)) return x;
+ else return 0;
+ }
+ if(disoddint(y)) return dcopysign(PINF,x);
+ return PINF;
+ }
+ if(dispinf(x)) {
+ if(disneg(y)) return 0;
+ else return PINF;
+ }
+ if(disminf(x)) {
+ if(!disneg(y)) {
+ if(disoddint(y)) return MINF;
+ else return PINF;
+ }
+ if(disoddint(y)) return MZERO;
+ else return PZERO;
+ }
+ if(dispinf(y)) {
+ if(dgetexp(x)<0x3ff) return PZERO;
+ else return PINF;
+ }
+ if(disminf(y)) {
+ if(dgetexp(x)<0x3ff) return PINF;
+ else return PZERO;
+ }
+ if(disint(y)) return dpow_0(x,y);
+ if(disneg(x)) return PINF;
+ return dpow_1(x,y);
+}
+
+double WRAPPER_FUNC(hypot)(double x,double y) {
+ check_nan_d2(x, y);
+ int ex,ey;
+ ex=dgetexp(x); ey=dgetexp(y);
+ if(ex>=0x3ff+400||ey>=0x3ff+400) { // overflow, or nearly so
+ x=dldexp(x,-600),y=dldexp(y,-600);
+ return dldexp(sqrt(x*x+y*y), 600);
+ }
+ else if(ex<=0x3ff-400&&ey<=0x3ff-400) { // underflow, or nearly so
+ x=dldexp(x, 600),y=dldexp(y, 600);
+ return dldexp(sqrt(x*x+y*y),-600);
+ }
+ return sqrt(x*x+y*y);
+}
+
+double WRAPPER_FUNC(cbrt)(double x) {
+ check_nan_d1(x);
+ int e;
+ if(disneg(x)) return dneg(cbrt(dneg(x)));
+ if(diszero(x)) return dcopysign(PZERO,x);
+ e=dgetexp(x)-0x3ff;
+ e=(e*0x5555+0x8000)>>16; // ~e/3, rounded
+ x=dldexp(x,-e*3);
+ x=exp(log(x)*ONETHIRD);
+ return dldexp(x,e);
+}
+
+// reduces mx*2^e modulo my, returning bottom bits of quotient at *pquo
+// 2^52<=|mx|,my<2^53, e>=0; 0<=result0) {
+ r=0xffffffffU/(ui32)(my>>36); // reciprocal estimate Q16
+ }
+ while(e>0) {
+ s=e; if(s>12) s=12; // gain up to 12 bits on each iteration
+ q=(mx>>38)*r; // Q30
+ q=((q>>(29-s))+1)>>1; // Q(s), rounded
+ mx=(mx<=my) mx-=my,quo++; // when e==0 mx can be nearly as big as 2my
+ if(mx>=my) mx-=my,quo++;
+ if(mx<0) mx+=my,quo--;
+ if(mx<0) mx+=my,quo--;
+ if(pquo) *pquo=quo;
+ return mx;
+}
+
+double WRAPPER_FUNC(fmod)(double x,double y) {
+ check_nan_d2(x, y);
+ ui64 ix=*(ui64*)&x,iy=*(ui64*)&y;
+ int sx,ex,ey;
+ i64 mx,my;
+ DUNPACKS(ix,sx,ex,mx);
+ DUNPACK(iy,ey,my);
+ if(ex==0x7ff) return dnan_or(PINF);
+ if(ey==0) return PINF;
+ if(ex==0) {
+ if(!disneg(x)) return PZERO;
+ return MZERO;
+ }
+ if(ex|y|/2
+ mx-=my+my;
+ ey--;
+ q=1;
+ } else { // x<-|y|/2
+ mx=my+my-mx;
+ ey--;
+ q=-1;
+ }
+ }
+ else {
+ if(sx) mx=-mx;
+ mx=drem_0(mx,my,ex-ey,&q);
+ if(mx+mx>my || (mx+mx==my&&(q&1)) ) { // |x|>|y|/2, or equality and an odd quotient?
+ mx-=my;
+ q++;
+ }
+ }
+ if(sy) q=-q;
+ if(quo) *quo=q;
+ return fix642double(mx,0x3ff-ey+52);
+}
+
+double WRAPPER_FUNC(drem)(double x,double y) { check_nan_d2(x, y); return remquo(x,y,0); }
+
+double WRAPPER_FUNC(remainder)(double x,double y) { check_nan_d2(x, y); return remquo(x,y,0); }
+
+_Pragma("GCC diagnostic pop") // strict-aliasing
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_none.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_none.S
new file mode 100644
index 00000000000..feded31cb6b
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_none.S
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico/asm_helper.S"
+#include "pico/bootrom/sf_table.h"
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+ wrapper_func __aeabi_dadd
+ wrapper_func __aeabi_ddiv
+ wrapper_func __aeabi_dmul
+ wrapper_func __aeabi_drsub
+ wrapper_func __aeabi_dsub
+ wrapper_func __aeabi_cdcmpeq
+ wrapper_func __aeabi_cdrcmple
+ wrapper_func __aeabi_cdcmple
+ wrapper_func __aeabi_dcmpeq
+ wrapper_func __aeabi_dcmplt
+ wrapper_func __aeabi_dcmple
+ wrapper_func __aeabi_dcmpge
+ wrapper_func __aeabi_dcmpgt
+ wrapper_func __aeabi_dcmpun
+ wrapper_func __aeabi_i2d
+ wrapper_func __aeabi_l2d
+ wrapper_func __aeabi_ui2d
+ wrapper_func __aeabi_ul2d
+ wrapper_func __aeabi_d2iz
+ wrapper_func __aeabi_d2lz
+ wrapper_func __aeabi_d2uiz
+ wrapper_func __aeabi_d2ulz
+ wrapper_func __aeabi_d2f
+ wrapper_func sqrt
+ wrapper_func cos
+ wrapper_func sin
+ wrapper_func tan
+ wrapper_func atan2
+ wrapper_func exp
+ wrapper_func log
+
+ wrapper_func ldexp
+ wrapper_func copysign
+ wrapper_func trunc
+ wrapper_func floor
+ wrapper_func ceil
+ wrapper_func round
+ wrapper_func sincos
+ wrapper_func asin
+ wrapper_func acos
+ wrapper_func atan
+ wrapper_func sinh
+ wrapper_func cosh
+ wrapper_func tanh
+ wrapper_func asinh
+ wrapper_func acosh
+ wrapper_func atanh
+ wrapper_func exp2
+ wrapper_func log2
+ wrapper_func exp10
+ wrapper_func log10
+ wrapper_func pow
+ wrapper_func powint
+ wrapper_func hypot
+ wrapper_func cbrt
+ wrapper_func fmod
+ wrapper_func drem
+ wrapper_func remainder
+ wrapper_func remquo
+ wrapper_func expm1
+ wrapper_func log1p
+ wrapper_func fma
+
+ push {lr} // keep stack trace sane
+ ldr r0, =str
+ bl panic
+
+str:
+ .asciz "double support is disabled"
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_v1_rom_shim.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_v1_rom_shim.S
new file mode 100644
index 00000000000..63e7be32dc8
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/double_v1_rom_shim.S
@@ -0,0 +1,2184 @@
+/**
+ * Copyright (c) 2020 Mark Owen https://www.quinapalus.com .
+ *
+ * Raspberry Pi (Trading) Ltd (Licensor) hereby grants to you a non-exclusive license to use the software solely on a
+ * Raspberry Pi Pico device. No other use is permitted under the terms of this license.
+ *
+ * This software is also available from the copyright owner under GPLv2 licence.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pico/asm_helper.S"
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+.macro double_section name
+// todo separate flag for shims?
+#if PICO_DOUBLE_IN_RAM
+.section RAM_SECTION_NAME(\name), "ax"
+#else
+.section SECTION_NAME(\name), "ax"
+#endif
+.endm
+
+double_section double_table_shim_on_use_helper
+regular_func double_table_shim_on_use_helper
+ push {r0-r2, lr}
+ mov r0, ip
+#ifndef NDEBUG
+ // sanity check to make sure we weren't called by non (shimmable_) table_tail_call macro
+ cmp r0, #0
+ bne 1f
+ bkpt #0
+#endif
+1:
+ ldrh r1, [r0]
+ lsrs r2, r1, #8
+ adds r0, #2
+ cmp r2, #0xdf
+ bne 1b
+ uxtb r1, r1 // r1 holds table offset
+ lsrs r2, r0, #2
+ bcc 1f
+ // unaligned
+ ldrh r2, [r0, #0]
+ ldrh r0, [r0, #2]
+ lsls r0, #16
+ orrs r0, r2
+ b 2f
+1:
+ ldr r0, [r0]
+2:
+ ldr r2, =sd_table
+ str r0, [r2, r1]
+ str r0, [sp, #12]
+ pop {r0-r2, pc}
+
+#if PICO_DOUBLE_SUPPORT_ROM_V1
+// Note that the V1 ROM has no double support, so this is basically the identical
+// library, and shim inter-function calls do not bother to redirect back thru the
+// wrapper functions
+
+.equ use_hw_div,1
+.equ IOPORT ,0xd0000000
+.equ DIV_UDIVIDEND,0x00000060
+.equ DIV_UDIVISOR ,0x00000064
+.equ DIV_QUOTIENT ,0x00000070
+.equ DIV_CSR ,0x00000078
+
+@ Notation:
+@ rx:ry means the concatenation of rx and ry with rx having the less significant bits
+
+.equ debug,0
+.macro mdump k
+.if debug
+ push {r0-r3}
+ push {r14}
+ push {r0-r3}
+ bl osp
+ movs r0,#\k
+ bl o1ch
+ pop {r0-r3}
+ bl dump
+ bl osp
+ bl osp
+ ldr r0,[r13]
+ bl o8hex @ r14
+ bl onl
+ pop {r0}
+ mov r14,r0
+ pop {r0-r3}
+.endif
+.endm
+
+
+@ IEEE double in ra:rb ->
+@ mantissa in ra:rb 12Q52 (53 significant bits) with implied 1 set
+@ exponent in re
+@ sign in rs
+@ trashes rt
+.macro mdunpack ra,rb,re,rs,rt
+ lsrs \re,\rb,#20 @ extract sign and exponent
+ subs \rs,\re,#1
+ lsls \rs,#20
+ subs \rb,\rs @ clear sign and exponent in mantissa; insert implied 1
+ lsrs \rs,\re,#11 @ sign
+ lsls \re,#21
+ lsrs \re,#21 @ exponent
+ beq l\@_1 @ zero exponent?
+ adds \rt,\re,#1
+ lsrs \rt,#11
+ beq l\@_2 @ exponent != 0x7ff? then done
+l\@_1:
+ movs \ra,#0
+ movs \rb,#1
+ lsls \rb,#20
+ subs \re,#128
+ lsls \re,#12
+l\@_2:
+.endm
+
+@ IEEE double in ra:rb ->
+@ signed mantissa in ra:rb 12Q52 (53 significant bits) with implied 1
+@ exponent in re
+@ trashes rt0 and rt1
+@ +zero, +denormal -> exponent=-0x80000
+@ -zero, -denormal -> exponent=-0x80000
+@ +Inf, +NaN -> exponent=+0x77f000
+@ -Inf, -NaN -> exponent=+0x77e000
+.macro mdunpacks ra,rb,re,rt0,rt1
+ lsrs \re,\rb,#20 @ extract sign and exponent
+ lsrs \rt1,\rb,#31 @ sign only
+ subs \rt0,\re,#1
+ lsls \rt0,#20
+ subs \rb,\rt0 @ clear sign and exponent in mantissa; insert implied 1
+ lsls \re,#21
+ bcc l\@_1 @ skip on positive
+ mvns \rb,\rb @ negate mantissa
+ rsbs \ra,#0
+ bcc l\@_1
+ adds \rb,#1
+l\@_1:
+ lsrs \re,#21
+ beq l\@_2 @ zero exponent?
+ adds \rt0,\re,#1
+ lsrs \rt0,#11
+ beq l\@_3 @ exponent != 0x7ff? then done
+ subs \re,\rt1
+l\@_2:
+ movs \ra,#0
+ lsls \rt1,#1 @ +ve: 0 -ve: 2
+ adds \rb,\rt1,#1 @ +ve: 1 -ve: 3
+ lsls \rb,#30 @ create +/-1 mantissa
+ asrs \rb,#10
+ subs \re,#128
+ lsls \re,#12
+l\@_3:
+.endm
+
+double_section WRAPPER_FUNC_NAME(__aeabi_dsub)
+
+# frsub first because it is the only one that needs alignment
+regular_func drsub_shim
+ push {r0-r3}
+ pop {r0-r1}
+ pop {r2-r3}
+ // fall thru
+
+regular_func dsub_shim
+ push {r4-r7,r14}
+ movs r4,#1
+ lsls r4,#31
+ eors r3,r4 @ flip sign on second argument
+ b da_entry @ continue in dadd
+
+.align 2
+double_section dadd_shim
+regular_func dadd_shim
+ push {r4-r7,r14}
+da_entry:
+ mdunpacks r0,r1,r4,r6,r7
+ mdunpacks r2,r3,r5,r6,r7
+ subs r7,r5,r4 @ ye-xe
+ subs r6,r4,r5 @ xe-ye
+ bmi da_ygtx
+@ here xe>=ye: need to shift y down r6 places
+ mov r12,r4 @ save exponent
+ cmp r6,#32
+ bge da_xrgty @ xe rather greater than ye?
+ adds r7,#32
+ movs r4,r2
+ lsls r4,r4,r7 @ rounding bit + sticky bits
+da_xgty0:
+ movs r5,r3
+ lsls r5,r5,r7
+ lsrs r2,r6
+ asrs r3,r6
+ orrs r2,r5
+da_add:
+ adds r0,r2
+ adcs r1,r3
+da_pack:
+@ here unnormalised signed result (possibly 0) is in r0:r1 with exponent r12, rounding + sticky bits in r4
+@ Note that if a large normalisation shift is required then the arguments were close in magnitude and so we
+@ cannot have not gone via the xrgty/yrgtx paths. There will therefore always be enough high bits in r4
+@ to provide a correct continuation of the exact result.
+@ now pack result back up
+ lsrs r3,r1,#31 @ get sign bit
+ beq 1f @ skip on positive
+ mvns r1,r1 @ negate mantissa
+ mvns r0,r0
+ movs r2,#0
+ rsbs r4,#0
+ adcs r0,r2
+ adcs r1,r2
+1:
+ mov r2,r12 @ get exponent
+ lsrs r5,r1,#21
+ bne da_0 @ shift down required?
+ lsrs r5,r1,#20
+ bne da_1 @ normalised?
+ cmp r0,#0
+ beq da_5 @ could mantissa be zero?
+da_2:
+ adds r4,r4
+ adcs r0,r0
+ adcs r1,r1
+ subs r2,#1 @ adjust exponent
+ lsrs r5,r1,#20
+ beq da_2
+da_1:
+ lsls r4,#1 @ check rounding bit
+ bcc da_3
+da_4:
+ adds r0,#1 @ round up
+ bcc 2f
+ adds r1,#1
+2:
+ cmp r4,#0 @ sticky bits zero?
+ bne da_3
+ lsrs r0,#1 @ round to even
+ lsls r0,#1
+da_3:
+ subs r2,#1
+ bmi da_6
+ adds r4,r2,#2 @ check if exponent is overflowing
+ lsrs r4,#11
+ bne da_7
+ lsls r2,#20 @ pack exponent and sign
+ add r1,r2
+ lsls r3,#31
+ add r1,r3
+ pop {r4-r7,r15}
+
+da_7:
+@ here exponent overflow: return signed infinity
+ lsls r1,r3,#31
+ ldr r3,=#0x7ff00000
+ orrs r1,r3
+ b 1f
+da_6:
+@ here exponent underflow: return signed zero
+ lsls r1,r3,#31
+1:
+ movs r0,#0
+ pop {r4-r7,r15}
+
+da_5:
+@ here mantissa could be zero
+ cmp r1,#0
+ bne da_2
+ cmp r4,#0
+ bne da_2
+@ inputs must have been of identical magnitude and opposite sign, so return +0
+ pop {r4-r7,r15}
+
+da_0:
+@ here a shift down by one place is required for normalisation
+ adds r2,#1 @ adjust exponent
+ lsls r6,r0,#31 @ save rounding bit
+ lsrs r0,#1
+ lsls r5,r1,#31
+ orrs r0,r5
+ lsrs r1,#1
+ cmp r6,#0
+ beq da_3
+ b da_4
+
+da_xrgty: @ xe>ye and shift>=32 places
+ cmp r6,#60
+ bge da_xmgty @ xe much greater than ye?
+ subs r6,#32
+ adds r7,#64
+
+ movs r4,r2
+ lsls r4,r4,r7 @ these would be shifted off the bottom of the sticky bits
+ beq 1f
+ movs r4,#1
+1:
+ lsrs r2,r2,r6
+ orrs r4,r2
+ movs r2,r3
+ lsls r3,r3,r7
+ orrs r4,r3
+ asrs r3,r2,#31 @ propagate sign bit
+ b da_xgty0
+
+da_ygtx:
+@ here ye>xe: need to shift x down r7 places
+ mov r12,r5 @ save exponent
+ cmp r7,#32
+ bge da_yrgtx @ ye rather greater than xe?
+ adds r6,#32
+ movs r4,r0
+ lsls r4,r4,r6 @ rounding bit + sticky bits
+da_ygtx0:
+ movs r5,r1
+ lsls r5,r5,r6
+ lsrs r0,r7
+ asrs r1,r7
+ orrs r0,r5
+ b da_add
+
+da_yrgtx:
+ cmp r7,#60
+ bge da_ymgtx @ ye much greater than xe?
+ subs r7,#32
+ adds r6,#64
+
+ movs r4,r0
+ lsls r4,r4,r6 @ these would be shifted off the bottom of the sticky bits
+ beq 1f
+ movs r4,#1
+1:
+ lsrs r0,r0,r7
+ orrs r4,r0
+ movs r0,r1
+ lsls r1,r1,r6
+ orrs r4,r1
+ asrs r1,r0,#31 @ propagate sign bit
+ b da_ygtx0
+
+da_ymgtx: @ result is just y
+ movs r0,r2
+ movs r1,r3
+da_xmgty: @ result is just x
+ movs r4,#0 @ clear sticky bits
+ b da_pack
+
+.ltorg
+
+@ equivalent of UMULL
+@ needs five temporary registers
+@ can have rt3==rx, in which case rx trashed
+@ can have rt4==ry, in which case ry trashed
+@ can have rzl==rx
+@ can have rzh==ry
+@ can have rzl,rzh==rt3,rt4
+.macro mul32_32_64 rx,ry,rzl,rzh,rt0,rt1,rt2,rt3,rt4
+ @ t0 t1 t2 t3 t4
+ @ (x) (y)
+ uxth \rt0,\rx @ xl
+ uxth \rt1,\ry @ yl
+ muls \rt0,\rt1 @ xlyl=L
+ lsrs \rt2,\rx,#16 @ xh
+ muls \rt1,\rt2 @ xhyl=M0
+ lsrs \rt4,\ry,#16 @ yh
+ muls \rt2,\rt4 @ xhyh=H
+ uxth \rt3,\rx @ xl
+ muls \rt3,\rt4 @ xlyh=M1
+ adds \rt1,\rt3 @ M0+M1=M
+ bcc l\@_1 @ addition of the two cross terms can overflow, so add carry into H
+ movs \rt3,#1 @ 1
+ lsls \rt3,#16 @ 0x10000
+ adds \rt2,\rt3 @ H'
+l\@_1:
+ @ t0 t1 t2 t3 t4
+ @ (zl) (zh)
+ lsls \rzl,\rt1,#16 @ ML
+ lsrs \rzh,\rt1,#16 @ MH
+ adds \rzl,\rt0 @ ZL
+ adcs \rzh,\rt2 @ ZH
+.endm
+
+@ SUMULL: x signed, y unsigned
+@ in table below ¯ means signed variable
+@ needs five temporary registers
+@ can have rt3==rx, in which case rx trashed
+@ can have rt4==ry, in which case ry trashed
+@ can have rzl==rx
+@ can have rzh==ry
+@ can have rzl,rzh==rt3,rt4
+.macro muls32_32_64 rx,ry,rzl,rzh,rt0,rt1,rt2,rt3,rt4
+ @ t0 t1 t2 t3 t4
+ @ ¯(x) (y)
+ uxth \rt0,\rx @ xl
+ uxth \rt1,\ry @ yl
+ muls \rt0,\rt1 @ xlyl=L
+ asrs \rt2,\rx,#16 @ ¯xh
+ muls \rt1,\rt2 @ ¯xhyl=M0
+ lsrs \rt4,\ry,#16 @ yh
+ muls \rt2,\rt4 @ ¯xhyh=H
+ uxth \rt3,\rx @ xl
+ muls \rt3,\rt4 @ xlyh=M1
+ asrs \rt4,\rt1,#31 @ M0sx (M1 sign extension is zero)
+ adds \rt1,\rt3 @ M0+M1=M
+ movs \rt3,#0 @ 0
+ adcs \rt4,\rt3 @ ¯Msx
+ lsls \rt4,#16 @ ¯Msx<<16
+ adds \rt2,\rt4 @ H'
+
+ @ t0 t1 t2 t3 t4
+ @ (zl) (zh)
+ lsls \rzl,\rt1,#16 @ M~
+ lsrs \rzh,\rt1,#16 @ M~
+ adds \rzl,\rt0 @ ZL
+ adcs \rzh,\rt2 @ ¯ZH
+.endm
+
+@ SSMULL: x signed, y signed
+@ in table below ¯ means signed variable
+@ needs five temporary registers
+@ can have rt3==rx, in which case rx trashed
+@ can have rt4==ry, in which case ry trashed
+@ can have rzl==rx
+@ can have rzh==ry
+@ can have rzl,rzh==rt3,rt4
+.macro muls32_s32_64 rx,ry,rzl,rzh,rt0,rt1,rt2,rt3,rt4
+ @ t0 t1 t2 t3 t4
+ @ ¯(x) (y)
+ uxth \rt0,\rx @ xl
+ uxth \rt1,\ry @ yl
+ muls \rt0,\rt1 @ xlyl=L
+ asrs \rt2,\rx,#16 @ ¯xh
+ muls \rt1,\rt2 @ ¯xhyl=M0
+ asrs \rt4,\ry,#16 @ ¯yh
+ muls \rt2,\rt4 @ ¯xhyh=H
+ uxth \rt3,\rx @ xl
+ muls \rt3,\rt4 @ ¯xlyh=M1
+ adds \rt1,\rt3 @ ¯M0+M1=M
+ asrs \rt3,\rt1,#31 @ Msx
+ bvc l\@_1 @
+ mvns \rt3,\rt3 @ ¯Msx flip sign extension bits if overflow
+l\@_1:
+ lsls \rt3,#16 @ ¯Msx<<16
+ adds \rt2,\rt3 @ H'
+
+ @ t0 t1 t2 t3 t4
+ @ (zl) (zh)
+ lsls \rzl,\rt1,#16 @ M~
+ lsrs \rzh,\rt1,#16 @ M~
+ adds \rzl,\rt0 @ ZL
+ adcs \rzh,\rt2 @ ¯ZH
+.endm
+
+@ can have rt2==rx, in which case rx trashed
+@ can have rzl==rx
+@ can have rzh==rt1
+.macro square32_64 rx,rzl,rzh,rt0,rt1,rt2
+ @ t0 t1 t2 zl zh
+ uxth \rt0,\rx @ xl
+ muls \rt0,\rt0 @ xlxl=L
+ uxth \rt1,\rx @ xl
+ lsrs \rt2,\rx,#16 @ xh
+ muls \rt1,\rt2 @ xlxh=M
+ muls \rt2,\rt2 @ xhxh=H
+ lsls \rzl,\rt1,#17 @ ML
+ lsrs \rzh,\rt1,#15 @ MH
+ adds \rzl,\rt0 @ ZL
+ adcs \rzh,\rt2 @ ZH
+.endm
+
+double_section dmul_shim
+ regular_func dmul_shim
+ push {r4-r7,r14}
+ mdunpack r0,r1,r4,r6,r5
+ mov r12,r4
+ mdunpack r2,r3,r4,r7,r5
+ eors r7,r6 @ sign of result
+ add r4,r12 @ exponent of result
+ push {r0-r2,r4,r7}
+
+@ accumulate full product in r12:r5:r6:r7
+ mul32_32_64 r0,r2, r0,r5, r4,r6,r7,r0,r5 @ XL*YL
+ mov r12,r0 @ save LL bits
+
+ mul32_32_64 r1,r3, r6,r7, r0,r2,r4,r6,r7 @ XH*YH
+
+ pop {r0} @ XL
+ mul32_32_64 r0,r3, r0,r3, r1,r2,r4,r0,r3 @ XL*YH
+ adds r5,r0
+ adcs r6,r3
+ movs r0,#0
+ adcs r7,r0
+
+ pop {r1,r2} @ XH,YL
+ mul32_32_64 r1,r2, r1,r2, r0,r3,r4, r1,r2 @ XH*YL
+ adds r5,r1
+ adcs r6,r2
+ movs r0,#0
+ adcs r7,r0
+
+@ here r5:r6:r7 holds the product [1..4) in Q(104-32)=Q72, with extra LSBs in r12
+ pop {r3,r4} @ exponent in r3, sign in r4
+ lsls r1,r7,#11
+ lsrs r2,r6,#21
+ orrs r1,r2
+ lsls r0,r6,#11
+ lsrs r2,r5,#21
+ orrs r0,r2
+ lsls r5,#11 @ now r5:r0:r1 Q83=Q(51+32), extra LSBs in r12
+ lsrs r2,r1,#20
+ bne 1f @ skip if in range [2..4)
+ adds r5,r5 @ shift up so always [2..4) Q83, i.e. [1..2) Q84=Q(52+32)
+ adcs r0,r0
+ adcs r1,r1
+ subs r3,#1 @ correct exponent
+1:
+ ldr r6,=#0x3ff
+ subs r3,r6 @ correct for exponent bias
+ lsls r6,#1 @ 0x7fe
+ cmp r3,r6
+ bhs dm_0 @ exponent over- or underflow
+ lsls r5,#1 @ rounding bit to carry
+ bcc 1f @ result is correctly rounded
+ adds r0,#1
+ movs r6,#0
+ adcs r1,r6 @ round up
+ mov r6,r12 @ remaining sticky bits
+ orrs r5,r6
+ bne 1f @ some sticky bits set?
+ lsrs r0,#1
+ lsls r0,#1 @ round to even
+1:
+ lsls r3,#20
+ adds r1,r3
+dm_2:
+ lsls r4,#31
+ add r1,r4
+ pop {r4-r7,r15}
+
+@ here for exponent over- or underflow
+dm_0:
+ bge dm_1 @ overflow?
+ adds r3,#1 @ would-be zero exponent?
+ bne 1f
+ adds r0,#1
+ bne 1f @ all-ones mantissa?
+ adds r1,#1
+ lsrs r7,r1,#21
+ beq 1f
+ lsrs r1,#1
+ b dm_2
+1:
+ lsls r1,r4,#31
+ movs r0,#0
+ pop {r4-r7,r15}
+
+@ here for exponent overflow
+dm_1:
+ adds r6,#1 @ 0x7ff
+ lsls r1,r6,#20
+ movs r0,#0
+ b dm_2
+
+.ltorg
+
+@ Approach to division y/x is as follows.
+@
+@ First generate u1, an approximation to 1/x to about 29 bits. Multiply this by the top
+@ 32 bits of y to generate a0, a first approximation to the result (good to 28 bits or so).
+@ Calculate the exact remainder r0=y-a0*x, which will be about 0. Calculate a correction
+@ d0=r0*u1, and then write a1=a0+d0. If near a rounding boundary, compute the exact
+@ remainder r1=y-a1*x (which can be done using r0 as a basis) to determine whether to
+@ round up or down.
+@
+@ The calculation of 1/x is as given in dreciptest.c. That code verifies exhaustively
+@ that | u1*x-1 | < 10*2^-32.
+@
+@ More precisely:
+@
+@ x0=(q16)x;
+@ x1=(q30)x;
+@ y0=(q31)y;
+@ u0=(q15~)"(0xffffffffU/(unsigned int)roundq(x/x_ulp))/powq(2,16)"(x0); // q15 approximation to 1/x; "~" denotes rounding rather than truncation
+@ v=(q30)(u0*x1-1);
+@ u1=(q30)u0-(q30~)(u0*v);
+@
+@ a0=(q30)(u1*y0);
+@ r0=(q82)y-a0*x;
+@ r0x=(q57)r0;
+@ d0=r0x*u1;
+@ a1=d0+a0;
+@
+@ Error analysis
+@
+@ Use Greek letters to represent the errors introduced by rounding and truncation.
+@
+@ r₀ = y - a₀x
+@ = y - [ u₁ ( y - α ) - β ] x where 0 ≤ α < 2^-31, 0 ≤ β < 2^-30
+@ = y ( 1 - u₁x ) + ( u₁α + β ) x
+@
+@ Hence
+@
+@ | r₀ / x | < 2 * 10*2^-32 + 2^-31 + 2^-30
+@ = 26*2^-32
+@
+@ r₁ = y - a₁x
+@ = y - a₀x - d₀x
+@ = r₀ - d₀x
+@ = r₀ - u₁ ( r₀ - γ ) x where 0 ≤ γ < 2^-57
+@ = r₀ ( 1 - u₁x ) + u₁γx
+@
+@ Hence
+@
+@ | r₁ / x | < 26*2^-32 * 10*2^-32 + 2^-57
+@ = (260+128)*2^-64
+@ < 2^-55
+@
+@ Empirically it seems to be nearly twice as good as this.
+@
+@ To determine correctly whether the exact remainder calculation can be skipped we need a result
+@ accurate to < 0.25ulp. In the case where x>y the quotient will be shifted up one place for normalisation
+@ and so 1ulp is 2^-53 and so the calculation above suffices.
+
+double_section ddiv_shim
+ regular_func ddiv_shim
+ push {r4-r7,r14}
+ddiv0: @ entry point from dtan
+ mdunpack r2,r3,r4,r7,r6 @ unpack divisor
+
+.if use_hw_div
+
+ movs r5,#IOPORT>>24
+ lsls r5,#24
+ movs r6,#0
+ mvns r6,r6
+ str r6,[r5,#DIV_UDIVIDEND]
+ lsrs r6,r3,#4 @ x0=(q16)x
+ str r6,[r5,#DIV_UDIVISOR]
+@ if there are not enough cycles from now to the read of the quotient for
+@ the divider to do its stuff we need a busy-wait here
+
+.endif
+
+@ unpack dividend by hand to save on register use
+ lsrs r6,r1,#31
+ adds r6,r7
+ mov r12,r6 @ result sign in r12b0; r12b1 trashed
+ lsls r1,#1
+ lsrs r7,r1,#21 @ exponent
+ beq 1f @ zero exponent?
+ adds r6,r7,#1
+ lsrs r6,#11
+ beq 2f @ exponent != 0x7ff? then done
+1:
+ movs r0,#0
+ movs r1,#0
+ subs r7,#64 @ less drastic fiddling of exponents to get 0/0, Inf/Inf correct
+ lsls r7,#12
+2:
+ subs r6,r7,r4
+ lsls r6,#2
+ add r12,r12,r6 @ (signed) exponent in r12[31..8]
+ subs r7,#1 @ implied 1
+ lsls r7,#21
+ subs r1,r7
+ lsrs r1,#1
+
+.if use_hw_div
+
+ ldr r6,[r5,#DIV_QUOTIENT]
+ adds r6,#1
+ lsrs r6,#1
+
+.else
+
+@ this is not beautiful; could be replaced by better code that uses knowledge of divisor range
+ push {r0-r3}
+ movs r0,#0
+ mvns r0,r0
+ lsrs r1,r3,#4 @ x0=(q16)x
+ bl __aeabi_uidiv @ !!! this could (but apparently does not) trash R12
+ adds r6,r0,#1
+ lsrs r6,#1
+ pop {r0-r3}
+
+.endif
+
+@ here
+@ r0:r1 y mantissa
+@ r2:r3 x mantissa
+@ r6 u0, first approximation to 1/x Q15
+@ r12: result sign, exponent
+
+ lsls r4,r3,#10
+ lsrs r5,r2,#22
+ orrs r5,r4 @ x1=(q30)x
+ muls r5,r6 @ u0*x1 Q45
+ asrs r5,#15 @ v=u0*x1-1 Q30
+ muls r5,r6 @ u0*v Q45
+ asrs r5,#14
+ adds r5,#1
+ asrs r5,#1 @ round u0*v to Q30
+ lsls r6,#15
+ subs r6,r5 @ u1 Q30
+
+@ here
+@ r0:r1 y mantissa
+@ r2:r3 x mantissa
+@ r6 u1, second approximation to 1/x Q30
+@ r12: result sign, exponent
+
+ push {r2,r3}
+ lsls r4,r1,#11
+ lsrs r5,r0,#21
+ orrs r4,r5 @ y0=(q31)y
+ mul32_32_64 r4,r6, r4,r5, r2,r3,r7,r4,r5 @ y0*u1 Q61
+ adds r4,r4
+ adcs r5,r5 @ a0=(q30)(y0*u1)
+
+@ here
+@ r0:r1 y mantissa
+@ r5 a0, first approximation to y/x Q30
+@ r6 u1, second approximation to 1/x Q30
+@ r12 result sign, exponent
+
+ ldr r2,[r13,#0] @ xL
+ mul32_32_64 r2,r5, r2,r3, r1,r4,r7,r2,r3 @ xL*a0
+ ldr r4,[r13,#4] @ xH
+ muls r4,r5 @ xH*a0
+ adds r3,r4 @ r2:r3 now x*a0 Q82
+ lsrs r2,#25
+ lsls r1,r3,#7
+ orrs r2,r1 @ r2 now x*a0 Q57; r7:r2 is x*a0 Q89
+ lsls r4,r0,#5 @ y Q57
+ subs r0,r4,r2 @ r0x=y-x*a0 Q57 (signed)
+
+@ here
+@ r0 r0x Q57
+@ r5 a0, first approximation to y/x Q30
+@ r4 yL Q57
+@ r6 u1 Q30
+@ r12 result sign, exponent
+
+ muls32_32_64 r0,r6, r7,r6, r1,r2,r3, r7,r6 @ r7:r6 r0x*u1 Q87
+ asrs r3,r6,#25
+ adds r5,r3
+ lsls r3,r6,#7 @ r3:r5 a1 Q62 (but bottom 7 bits are zero so 55 bits of precision after binary point)
+@ here we could recover another 7 bits of precision (but not accuracy) from the top of r7
+@ but these bits are thrown away in the rounding and conversion to Q52 below
+
+@ here
+@ r3:r5 a1 Q62 candidate quotient [0.5,2) or so
+@ r4 yL Q57
+@ r12 result sign, exponent
+
+ movs r6,#0
+ adds r3,#128 @ for initial rounding to Q53
+ adcs r5,r5,r6
+ lsrs r1,r5,#30
+ bne dd_0
+@ here candidate quotient a1 is in range [0.5,1)
+@ so 30 significant bits in r5
+
+ lsls r4,#1 @ y now Q58
+ lsrs r1,r5,#9 @ to Q52
+ lsls r0,r5,#23
+ lsrs r3,#9 @ 0.5ulp-significance bit in carry: if this is 1 we may need to correct result
+ orrs r0,r3
+ bcs dd_1
+ b dd_2
+dd_0:
+@ here candidate quotient a1 is in range [1,2)
+@ so 31 significant bits in r5
+
+ movs r2,#4
+ add r12,r12,r2 @ fix exponent; r3:r5 now effectively Q61
+ adds r3,#128 @ complete rounding to Q53
+ adcs r5,r5,r6
+ lsrs r1,r5,#10
+ lsls r0,r5,#22
+ lsrs r3,#10 @ 0.5ulp-significance bit in carry: if this is 1 we may need to correct result
+ orrs r0,r3
+ bcc dd_2
+dd_1:
+
+@ here
+@ r0:r1 rounded result Q53 [0.5,1) or Q52 [1,2), but may not be correctly rounded-to-nearest
+@ r4 yL Q58 or Q57
+@ r12 result sign, exponent
+@ carry set
+
+ adcs r0,r0,r0
+ adcs r1,r1,r1 @ z Q53 with 1 in LSB
+ lsls r4,#16 @ Q105-32=Q73
+ ldr r2,[r13,#0] @ xL Q52
+ ldr r3,[r13,#4] @ xH Q20
+
+ movs r5,r1 @ zH Q21
+ muls r5,r2 @ zH*xL Q73
+ subs r4,r5
+ muls r3,r0 @ zL*xH Q73
+ subs r4,r3
+ mul32_32_64 r2,r0, r2,r3, r5,r6,r7,r2,r3 @ xL*zL
+ rsbs r2,#0 @ borrow from low half?
+ sbcs r4,r3 @ y-xz Q73 (remainder bits 52..73)
+
+ cmp r4,#0
+
+ bmi 1f
+ movs r2,#0 @ round up
+ adds r0,#1
+ adcs r1,r2
+1:
+ lsrs r0,#1 @ shift back down to Q52
+ lsls r2,r1,#31
+ orrs r0,r2
+ lsrs r1,#1
+dd_2:
+ add r13,#8
+ mov r2,r12
+ lsls r7,r2,#31 @ result sign
+ asrs r2,#2 @ result exponent
+ ldr r3,=#0x3fd
+ adds r2,r3
+ ldr r3,=#0x7fe
+ cmp r2,r3
+ bhs dd_3 @ over- or underflow?
+ lsls r2,#20
+ adds r1,r2 @ pack exponent
+dd_5:
+ adds r1,r7 @ pack sign
+ pop {r4-r7,r15}
+
+dd_3:
+ movs r0,#0
+ cmp r2,#0
+ bgt dd_4 @ overflow?
+ movs r1,r7
+ pop {r4-r7,r15}
+
+dd_4:
+ adds r3,#1 @ 0x7ff
+ lsls r1,r3,#20
+ b dd_5
+
+.section SECTION_NAME(dsqrt_shim)
+/*
+Approach to square root x=sqrt(y) is as follows.
+
+First generate a3, an approximation to 1/sqrt(y) to about 30 bits. Multiply this by y
+to give a4~sqrt(y) to about 28 bits and a remainder r4=y-a4^2. Then, because
+d sqrt(y) / dy = 1 / (2 sqrt(y)) let d4=r4*a3/2 and then the value a5=a4+d4 is
+a better approximation to sqrt(y). If this is near a rounding boundary we
+compute an exact remainder y-a5*a5 to decide whether to round up or down.
+
+The calculation of a3 and a4 is as given in dsqrttest.c. That code verifies exhaustively
+that | 1 - a3a4 | < 10*2^-32, | r4 | < 40*2^-32 and | r4/y | < 20*2^-32.
+
+More precisely, with "y" representing y truncated to 30 binary places:
+
+u=(q3)y; // 24-entry table
+a0=(q8~)"1/sqrtq(x+x_ulp/2)"(u); // first approximation from table
+p0=(q16)(a0*a0) * (q16)y;
+r0=(q20)(p0-1);
+dy0=(q15)(r0*a0); // Newton-Raphson correction term
+a1=(q16)a0-dy0/2; // good to ~9 bits
+
+p1=(q19)(a1*a1)*(q19)y;
+r1=(q23)(p1-1);
+dy1=(q15~)(r1*a1); // second Newton-Raphson correction
+a2x=(q16)a1-dy1/2; // good to ~16 bits
+a2=a2x-a2x/1t16; // prevent overflow of a2*a2 in 32 bits
+
+p2=(a2*a2)*(q30)y; // Q62
+r2=(q36)(p2-1+1t-31);
+dy2=(q30)(r2*a2); // Q52->Q30
+a3=(q31)a2-dy2/2; // good to about 30 bits
+a4=(q30)(a3*(q30)y+1t-31); // good to about 28 bits
+
+Error analysis
+
+ r₄ = y - a₄²
+ d₄ = 1/2 a₃r₄
+ a₅ = a₄ + d₄
+ r₅ = y - a₅²
+ = y - ( a₄ + d₄ )²
+ = y - a₄² - a₃a₄r₄ - 1/4 a₃²r₄²
+ = r₄ - a₃a₄r₄ - 1/4 a₃²r₄²
+
+ | r₅ | < | r₄ | | 1 - a₃a₄ | + 1/4 r₄²
+
+ a₅ = √y √( 1 - r₅/y )
+ = √y ( 1 - 1/2 r₅/y + ... )
+
+So to first order (second order being very tiny)
+
+ √y - a₅ = 1/2 r₅/y
+
+and
+
+ | √y - a₅ | < 1/2 ( | r₄/y | | 1 - a₃a₄ | + 1/4 r₄²/y )
+
+From dsqrttest.c (conservatively):
+
+ < 1/2 ( 20*2^-32 * 10*2^-32 + 1/4 * 40*2^-32*20*2^-32 )
+ = 1/2 ( 200 + 200 ) * 2^-64
+ < 2^-56
+
+Empirically we see about 1ulp worst-case error including rounding at Q57.
+
+To determine correctly whether the exact remainder calculation can be skipped we need a result
+accurate to < 0.25ulp at Q52, or 2^-54.
+*/
+
+dq_2:
+ bge dq_3 @ +Inf?
+ movs r1,#0
+ b dq_4
+
+dq_0:
+ lsrs r1,#31
+ lsls r1,#31 @ preserve sign bit
+ lsrs r2,#21 @ extract exponent
+ beq dq_4 @ -0? return it
+ asrs r1,#11 @ make -Inf
+ b dq_4
+
+dq_3:
+ ldr r1,=#0x7ff
+ lsls r1,#20 @ return +Inf
+dq_4:
+ movs r0,#0
+dq_1:
+ bx r14
+
+.align 2
+regular_func dsqrt_shim
+ lsls r2,r1,#1
+ bcs dq_0 @ negative?
+ lsrs r2,#21 @ extract exponent
+ subs r2,#1
+ ldr r3,=#0x7fe
+ cmp r2,r3
+ bhs dq_2 @ catches 0 and +Inf
+ push {r4-r7,r14}
+ lsls r4,r2,#20
+ subs r1,r4 @ insert implied 1
+ lsrs r2,#1
+ bcc 1f @ even exponent? skip
+ adds r0,r0,r0 @ odd exponent: shift up mantissa
+ adcs r1,r1,r1
+1:
+ lsrs r3,#2
+ adds r2,r3
+ lsls r2,#20
+ mov r12,r2 @ save result exponent
+
+@ here
+@ r0:r1 y mantissa Q52 [1,4)
+@ r12 result exponent
+
+ adr r4,drsqrtapp-8 @ first eight table entries are never accessed because of the mantissa's leading 1
+ lsrs r2,r1,#17 @ y Q3
+ ldrb r2,[r4,r2] @ initial approximation to reciprocal square root a0 Q8
+ lsrs r3,r1,#4 @ first Newton-Raphson iteration
+ muls r3,r2
+ muls r3,r2 @ i32 p0=a0*a0*(y>>14); // Q32
+ asrs r3,r3,#12 @ i32 r0=p0>>12; // Q20
+ muls r3,r2
+ asrs r3,#13 @ i32 dy0=(r0*a0)>>13; // Q15
+ lsls r2,#8
+ subs r2,r3 @ i32 a1=(a0<<8)-dy0; // Q16
+
+ movs r3,r2
+ muls r3,r3
+ lsrs r3,#13
+ lsrs r4,r1,#1
+ muls r3,r4 @ i32 p1=((a1*a1)>>11)*(y>>11); // Q19*Q19=Q38
+ asrs r3,#15 @ i32 r1=p1>>15; // Q23
+ muls r3,r2
+ asrs r3,#23
+ adds r3,#1
+ asrs r3,#1 @ i32 dy1=(r1*a1+(1<<23))>>24; // Q23*Q16=Q39; Q15
+ subs r2,r3 @ i32 a2=a1-dy1; // Q16
+ lsrs r3,r2,#16
+ subs r2,r3 @ if(a2>=0x10000) a2=0xffff; to prevent overflow of a2*a2
+
+@ here
+@ r0:r1 y mantissa
+@ r2 a2 ~ 1/sqrt(y) Q16
+@ r12 result exponent
+
+ movs r3,r2
+ muls r3,r3
+ lsls r1,#10
+ lsrs r4,r0,#22
+ orrs r1,r4 @ y Q30
+ mul32_32_64 r1,r3, r4,r3, r5,r6,r7,r4,r3 @ i64 p2=(ui64)(a2*a2)*(ui64)y; // Q62 r4:r3
+ lsls r5,r3,#6
+ lsrs r4,#26
+ orrs r4,r5
+ adds r4,#0x20 @ i32 r2=(p2>>26)+0x20; // Q36 r4
+ uxth r5,r4
+ muls r5,r2
+ asrs r4,#16
+ muls r4,r2
+ lsrs r5,#16
+ adds r4,r5
+ asrs r4,#6 @ i32 dy2=((i64)r2*(i64)a2)>>22; // Q36*Q16=Q52; Q30
+ lsls r2,#15
+ subs r2,r4
+
+@ here
+@ r0 y low bits
+@ r1 y Q30
+@ r2 a3 ~ 1/sqrt(y) Q31
+@ r12 result exponent
+
+ mul32_32_64 r2,r1, r3,r4, r5,r6,r7,r3,r4
+ adds r3,r3,r3
+ adcs r4,r4,r4
+ adds r3,r3,r3
+ movs r3,#0
+ adcs r3,r4 @ ui32 a4=((ui64)a3*(ui64)y+(1U<<31))>>31; // Q30
+
+@ here
+@ r0 y low bits
+@ r1 y Q30
+@ r2 a3 Q31 ~ 1/sqrt(y)
+@ r3 a4 Q30 ~ sqrt(y)
+@ r12 result exponent
+
+ square32_64 r3, r4,r5, r6,r5,r7
+ lsls r6,r0,#8
+ lsrs r7,r1,#2
+ subs r6,r4
+ sbcs r7,r5 @ r4=(q60)y-a4*a4
+
+@ by exhaustive testing, r4 = fffffffc0e134fdc .. 00000003c2bf539c Q60
+
+ lsls r5,r7,#29
+ lsrs r6,#3
+ adcs r6,r5 @ r4 Q57 with rounding
+ muls32_32_64 r6,r2, r6,r2, r4,r5,r7,r6,r2 @ d4=a3*r4/2 Q89
+@ r4+d4 is correct to 1ULP at Q57, tested on ~9bn cases including all extreme values of r4 for each possible y Q30
+
+ adds r2,#8
+ asrs r2,#5 @ d4 Q52, rounded to Q53 with spare bit in carry
+
+@ here
+@ r0 y low bits
+@ r1 y Q30
+@ r2 d4 Q52, rounded to Q53
+@ C flag contains d4_b53
+@ r3 a4 Q30
+
+ bcs dq_5
+
+ lsrs r5,r3,#10 @ a4 Q52
+ lsls r4,r3,#22
+
+ asrs r1,r2,#31
+ adds r0,r2,r4
+ adcs r1,r5 @ a4+d4
+
+ add r1,r12 @ pack exponent
+ pop {r4-r7,r15}
+
+.ltorg
+
+
+@ round(sqrt(2^22./[68:8:252]))
+drsqrtapp:
+.byte 0xf8,0xeb,0xdf,0xd6,0xcd,0xc5,0xbe,0xb8
+.byte 0xb2,0xad,0xa8,0xa4,0xa0,0x9c,0x99,0x95
+.byte 0x92,0x8f,0x8d,0x8a,0x88,0x85,0x83,0x81
+
+dq_5:
+@ here we are near a rounding boundary, C is set
+ adcs r2,r2,r2 @ d4 Q53+1ulp
+ lsrs r5,r3,#9
+ lsls r4,r3,#23 @ r4:r5 a4 Q53
+ asrs r1,r2,#31
+ adds r4,r2,r4
+ adcs r5,r1 @ r4:r5 a5=a4+d4 Q53+1ulp
+ movs r3,r5
+ muls r3,r4
+ square32_64 r4,r1,r2,r6,r2,r7
+ adds r2,r3
+ adds r2,r3 @ r1:r2 a5^2 Q106
+ lsls r0,#22 @ y Q84
+
+ rsbs r1,#0
+ sbcs r0,r2 @ remainder y-a5^2
+ bmi 1f @ y=0
+@ ω+=dω
+@ x+=y>>i, y-=x>>i
+ adds r0,r3
+ adcs r1,r4
+
+ mov r3,r11
+ asrs r3,r7
+ mov r4,r11
+ lsls r4,r6
+ mov r2,r10
+ lsrs r2,r7
+ orrs r2,r4 @ r2:r3 y>>i, rounding in carry
+ mov r4,r8
+ mov r5,r9 @ r4:r5 x
+ adcs r2,r4
+ adcs r3,r5 @ r2:r3 x+(y>>i)
+ mov r8,r2
+ mov r9,r3
+
+ mov r3,r5
+ lsls r3,r6
+ asrs r5,r7
+ lsrs r4,r7
+ orrs r4,r3 @ r4:r5 x>>i, rounding in carry
+ mov r2,r10
+ mov r3,r11
+ sbcs r2,r4
+ sbcs r3,r5 @ r2:r3 y-(x>>i)
+ mov r10,r2
+ mov r11,r3
+ bx r14
+
+
+@ ω>0 / y<0
+@ ω-=dω
+@ x-=y>>i, y+=x>>i
+1:
+ subs r0,r3
+ sbcs r1,r4
+
+ mov r3,r9
+ asrs r3,r7
+ mov r4,r9
+ lsls r4,r6
+ mov r2,r8
+ lsrs r2,r7
+ orrs r2,r4 @ r2:r3 x>>i, rounding in carry
+ mov r4,r10
+ mov r5,r11 @ r4:r5 y
+ adcs r2,r4
+ adcs r3,r5 @ r2:r3 y+(x>>i)
+ mov r10,r2
+ mov r11,r3
+
+ mov r3,r5
+ lsls r3,r6
+ asrs r5,r7
+ lsrs r4,r7
+ orrs r4,r3 @ r4:r5 y>>i, rounding in carry
+ mov r2,r8
+ mov r3,r9
+ sbcs r2,r4
+ sbcs r3,r5 @ r2:r3 x-(y>>i)
+ mov r8,r2
+ mov r9,r3
+ bx r14
+
+ret_dzero:
+ movs r0,#0
+ movs r1,#0
+ bx r14
+
+@ convert packed double in r0:r1 to signed/unsigned 32/64-bit integer/fixed-point value in r0:r1 [with r2 places after point], with rounding towards -Inf
+@ fixed-point versions only work with reasonable values in r2 because of the way dunpacks works
+
+double_section double2int_shim
+ regular_func double2int_shim
+ movs r2,#0 @ and fall through
+regular_func double2fix_shim
+ push {r14}
+ adds r2,#32
+ bl double2fix64_shim
+ movs r0,r1
+ pop {r15}
+
+double_section double2uint_shim
+ regular_func double2uint_shim
+ movs r2,#0 @ and fall through
+regular_func double2ufix_shim
+ push {r14}
+ adds r2,#32
+ bl double2ufix64_shim
+ movs r0,r1
+ pop {r15}
+
+double_section double2int64_shim
+ regular_func double2int64_shim
+ movs r2,#0 @ and fall through
+regular_func double2fix64_shim
+ push {r14}
+ bl d2fix
+
+ asrs r2,r1,#31
+ cmp r2,r3
+ bne 1f @ sign extension bits fail to match sign of result?
+ pop {r15}
+1:
+ mvns r0,r3
+ movs r1,#1
+ lsls r1,#31
+ eors r1,r1,r0 @ generate extreme fixed-point values
+ pop {r15}
+
+double_section double2uint64_shim
+ regular_func double2uint64_shim
+ movs r2,#0 @ and fall through
+regular_func double2ufix64_shim
+ asrs r3,r1,#20 @ negative? return 0
+ bmi ret_dzero
+@ and fall through
+
+@ convert double in r0:r1 to signed fixed point in r0:r1:r3, r2 places after point, rounding towards -Inf
+@ result clamped so that r3 can only be 0 or -1
+@ trashes r12
+.thumb_func
+d2fix:
+ push {r4,r14}
+ mov r12,r2
+ bl dunpacks
+ asrs r4,r2,#16
+ adds r4,#1
+ bge 1f
+ movs r1,#0 @ -0 -> +0
+1:
+ asrs r3,r1,#31
+ ldr r4, =d2fix_a
+ bx r4
+
+.weak d2fix_a // weak because it exists in float code too
+regular_func d2fix_a
+@ here
+@ r0:r1 two's complement mantissa
+@ r2 unbaised exponent
+@ r3 mantissa sign extension bits
+ add r2,r12 @ exponent plus offset for required binary point position
+ subs r2,#52 @ required shift
+ bmi 1f @ shift down?
+@ here a shift up by r2 places
+ cmp r2,#12 @ will clamp?
+ bge 2f
+ movs r4,r0
+ lsls r1,r2
+ lsls r0,r2
+ rsbs r2,#0
+ adds r2,#32 @ complementary shift
+ lsrs r4,r2
+ orrs r1,r4
+ pop {r4,r15}
+2:
+ mvns r0,r3
+ mvns r1,r3 @ overflow: clamp to extreme fixed-point values
+ pop {r4,r15}
+1:
+@ here a shift down by -r2 places
+ adds r2,#32
+ bmi 1f @ long shift?
+ mov r4,r1
+ lsls r4,r2
+ rsbs r2,#0
+ adds r2,#32 @ complementary shift
+ asrs r1,r2
+ lsrs r0,r2
+ orrs r0,r4
+ pop {r4,r15}
+1:
+@ here a long shift down
+ movs r0,r1
+ asrs r1,#31 @ shift down 32 places
+ adds r2,#32
+ bmi 1f @ very long shift?
+ rsbs r2,#0
+ adds r2,#32
+ asrs r0,r2
+ pop {r4,r15}
+1:
+ movs r0,r3 @ result very near zero: use sign extension bits
+ movs r1,r3
+ pop {r4,r15}
+
+double_section double2float_shim
+ regular_func double2float_shim
+ lsls r2,r1,#1
+ lsrs r2,#21 @ exponent
+ ldr r3,=#0x3ff-0x7f
+ subs r2,r3 @ fix exponent bias
+ ble 1f @ underflow or zero
+ cmp r2,#0xff
+ bge 2f @ overflow or infinity
+ lsls r2,#23 @ position exponent of result
+ lsrs r3,r1,#31
+ lsls r3,#31
+ orrs r2,r3 @ insert sign
+ lsls r3,r0,#3 @ rounding bits
+ lsrs r0,#29
+ lsls r1,#12
+ lsrs r1,#9
+ orrs r0,r1 @ assemble mantissa
+ orrs r0,r2 @ insert exponent and sign
+ lsls r3,#1
+ bcc 3f @ no rounding
+ beq 4f @ all sticky bits 0?
+5:
+ adds r0,#1
+3:
+ bx r14
+4:
+ lsrs r3,r0,#1 @ odd? then round up
+ bcs 5b
+ bx r14
+1:
+ beq 6f @ check case where value is just less than smallest normal
+7:
+ lsrs r0,r1,#31
+ lsls r0,#31
+ bx r14
+6:
+ lsls r2,r1,#12 @ 20 1:s at top of mantissa?
+ asrs r2,#12
+ adds r2,#1
+ bne 7b
+ lsrs r2,r0,#29 @ and 3 more 1:s?
+ cmp r2,#7
+ bne 7b
+ movs r2,#1 @ return smallest normal with correct sign
+ b 8f
+2:
+ movs r2,#0xff
+8:
+ lsrs r0,r1,#31 @ return signed infinity
+ lsls r0,#8
+ adds r0,r2
+ lsls r0,#23
+ bx r14
+
+double_section x2double_shims
+@ convert signed/unsigned 32/64-bit integer/fixed-point value in r0:r1 [with r2 places after point] to packed double in r0:r1, with rounding
+
+.align 2
+regular_func uint2double_shim
+ movs r1,#0 @ and fall through
+regular_func ufix2double_shim
+ movs r2,r1
+ movs r1,#0
+ b ufix642double_shim
+
+.align 2
+regular_func int2double_shim
+ movs r1,#0 @ and fall through
+regular_func fix2double_shim
+ movs r2,r1
+ asrs r1,r0,#31 @ sign extend
+ b fix642double_shim
+
+.align 2
+regular_func uint642double_shim
+ movs r2,#0 @ and fall through
+regular_func ufix642double_shim
+ movs r3,#0
+ b uf2d
+
+.align 2
+regular_func int642double_shim
+ movs r2,#0 @ and fall through
+regular_func fix642double_shim
+ asrs r3,r1,#31 @ sign bit across all bits
+ eors r0,r3
+ eors r1,r3
+ subs r0,r3
+ sbcs r1,r3
+uf2d:
+ push {r4,r5,r14}
+ ldr r4,=#0x432
+ subs r2,r4,r2 @ form biased exponent
+@ here
+@ r0:r1 unnormalised mantissa
+@ r2 -Q (will become exponent)
+@ r3 sign across all bits
+ cmp r1,#0
+ bne 1f @ short normalising shift?
+ movs r1,r0
+ beq 2f @ zero? return it
+ movs r0,#0
+ subs r2,#32 @ fix exponent
+1:
+ asrs r4,r1,#21
+ bne 3f @ will need shift down (and rounding?)
+ bcs 4f @ normalised already?
+5:
+ subs r2,#1
+ adds r0,r0 @ shift up
+ adcs r1,r1
+ lsrs r4,r1,#21
+ bcc 5b
+4:
+ ldr r4,=#0x7fe
+ cmp r2,r4
+ bhs 6f @ over/underflow? return signed zero/infinity
+7:
+ lsls r2,#20 @ pack and return
+ adds r1,r2
+ lsls r3,#31
+ adds r1,r3
+2:
+ pop {r4,r5,r15}
+6: @ return signed zero/infinity according to unclamped exponent in r2
+ mvns r2,r2
+ lsrs r2,#21
+ movs r0,#0
+ movs r1,#0
+ b 7b
+
+3:
+@ here we need to shift down to normalise and possibly round
+ bmi 1f @ already normalised to Q63?
+2:
+ subs r2,#1
+ adds r0,r0 @ shift up
+ adcs r1,r1
+ bpl 2b
+1:
+@ here we have a 1 in b63 of r0:r1
+ adds r2,#11 @ correct exponent for subsequent shift down
+ lsls r4,r0,#21 @ save bits for rounding
+ lsrs r0,#11
+ lsls r5,r1,#21
+ orrs r0,r5
+ lsrs r1,#11
+ lsls r4,#1
+ beq 1f @ sticky bits are zero?
+8:
+ movs r4,#0
+ adcs r0,r4
+ adcs r1,r4
+ b 4b
+1:
+ bcc 4b @ sticky bits are zero but not on rounding boundary
+ lsrs r4,r0,#1 @ increment if odd (force round to even)
+ b 8b
+
+
+.ltorg
+
+double_section dunpacks
+ regular_func dunpacks
+ mdunpacks r0,r1,r2,r3,r4
+ ldr r3,=#0x3ff
+ subs r2,r3 @ exponent without offset
+ bx r14
+
+@ r0:r1 signed mantissa Q52
+@ r2 unbiased exponent < 10 (i.e., |x|<2^10)
+@ r4 pointer to:
+@ - divisor reciprocal approximation r=1/d Q15
+@ - divisor d Q62 0..20
+@ - divisor d Q62 21..41
+@ - divisor d Q62 42..62
+@ returns:
+@ r0:r1 reduced result y Q62, -0.6 d < y < 0.6 d (better in practice)
+@ r2 quotient q (number of reductions)
+@ if exponent >=10, returns r0:r1=0, r2=1024*mantissa sign
+@ designed to work for 0.5=0: in quadrant 0
+ cmp r1,r3
+ ble 2f @ y<~x so 0≤θ<~π/4: skip
+ adds r6,#1
+ eors r1,r5 @ negate x
+ b 3f @ and exchange x and y = rotate by -π/2
+1:
+ cmp r3,r7
+ bge 2f @ -y<~x so -π/4<~θ≤0: skip
+ subs r6,#1
+ eors r3,r5 @ negate y and ...
+3:
+ movs r7,r0 @ exchange x and y
+ movs r0,r2
+ movs r2,r7
+ movs r7,r1
+ movs r1,r3
+ movs r3,r7
+2:
+@ here -π/4<~θ<~π/4
+@ r6 has quadrant offset
+ push {r6}
+ cmp r2,#0
+ bne 1f
+ cmp r3,#0
+ beq 10f @ x==0 going into division?
+ lsls r4,r3,#1
+ asrs r4,#21
+ adds r4,#1
+ bne 1f @ x==Inf going into division?
+ lsls r4,r1,#1
+ asrs r4,#21
+ adds r4,#1 @ y also ±Inf?
+ bne 10f
+ subs r1,#1 @ make them both just finite
+ subs r3,#1
+ b 1f
+
+10:
+ movs r0,#0
+ movs r1,#0
+ b 12f
+
+1:
+ bl ddiv_shim
+ movs r2,#62
+ bl double2fix64_shim
+@ r0:r1 y/x
+ mov r10,r0
+ mov r11,r1
+ movs r0,#0 @ ω=0
+ movs r1,#0
+ mov r8,r0
+ movs r2,#1
+ lsls r2,#30
+ mov r9,r2 @ x=1
+
+ adr r4,dtab_cc
+ mov r12,r4
+ movs r7,#1
+ movs r6,#31
+1:
+ bl dcordic_vec_step
+ adds r7,#1
+ subs r6,#1
+ cmp r7,#33
+ bne 1b
+@ r0:r1 atan(y/x) Q62
+@ r8:r9 x residual Q62
+@ r10:r11 y residual Q62
+ mov r2,r9
+ mov r3,r10
+ subs r2,#12 @ this makes atan(0)==0
+@ the following is basically a division residual y/x ~ atan(residual y/x)
+ movs r4,#1
+ lsls r4,#29
+ movs r7,#0
+2:
+ lsrs r2,#1
+ movs r3,r3 @ preserve carry
+ bmi 1f
+ sbcs r3,r2
+ adds r0,r4
+ adcs r1,r7
+ lsrs r4,#1
+ bne 2b
+ b 3f
+1:
+ adcs r3,r2
+ subs r0,r4
+ sbcs r1,r7
+ lsrs r4,#1
+ bne 2b
+3:
+ lsls r6,r1,#31
+ asrs r1,#1
+ lsrs r0,#1
+ orrs r0,r6 @ Q61
+
+12:
+ pop {r6}
+
+ cmp r6,#0
+ beq 1f
+ ldr r4,=#0x885A308D @ π/2 Q61
+ ldr r5,=#0x3243F6A8
+ bpl 2f
+ mvns r4,r4 @ negative quadrant offset
+ mvns r5,r5
+2:
+ lsls r6,#31
+ bne 2f @ skip if quadrant offset is ±1
+ adds r0,r4
+ adcs r1,r5
+2:
+ adds r0,r4
+ adcs r1,r5
+1:
+ movs r2,#61
+ bl fix642double_shim
+
+ bl pop_r8_r11
+ pop {r4-r7,r15}
+
+.ltorg
+
+dtab_cc:
+.word 0x61bb4f69, 0x1dac6705 @ atan 2^-1 Q62
+.word 0x96406eb1, 0x0fadbafc @ atan 2^-2 Q62
+.word 0xab0bdb72, 0x07f56ea6 @ atan 2^-3 Q62
+.word 0xe59fbd39, 0x03feab76 @ atan 2^-4 Q62
+.word 0xba97624b, 0x01ffd55b @ atan 2^-5 Q62
+.word 0xdddb94d6, 0x00fffaaa @ atan 2^-6 Q62
+.word 0x56eeea5d, 0x007fff55 @ atan 2^-7 Q62
+.word 0xaab7776e, 0x003fffea @ atan 2^-8 Q62
+.word 0x5555bbbc, 0x001ffffd @ atan 2^-9 Q62
+.word 0xaaaaadde, 0x000fffff @ atan 2^-10 Q62
+.word 0xf555556f, 0x0007ffff @ atan 2^-11 Q62
+.word 0xfeaaaaab, 0x0003ffff @ atan 2^-12 Q62
+.word 0xffd55555, 0x0001ffff @ atan 2^-13 Q62
+.word 0xfffaaaab, 0x0000ffff @ atan 2^-14 Q62
+.word 0xffff5555, 0x00007fff @ atan 2^-15 Q62
+.word 0xffffeaab, 0x00003fff @ atan 2^-16 Q62
+.word 0xfffffd55, 0x00001fff @ atan 2^-17 Q62
+.word 0xffffffab, 0x00000fff @ atan 2^-18 Q62
+.word 0xfffffff5, 0x000007ff @ atan 2^-19 Q62
+.word 0xffffffff, 0x000003ff @ atan 2^-20 Q62
+.word 0x00000000, 0x00000200 @ atan 2^-21 Q62 @ consider optimising these
+.word 0x00000000, 0x00000100 @ atan 2^-22 Q62
+.word 0x00000000, 0x00000080 @ atan 2^-23 Q62
+.word 0x00000000, 0x00000040 @ atan 2^-24 Q62
+.word 0x00000000, 0x00000020 @ atan 2^-25 Q62
+.word 0x00000000, 0x00000010 @ atan 2^-26 Q62
+.word 0x00000000, 0x00000008 @ atan 2^-27 Q62
+.word 0x00000000, 0x00000004 @ atan 2^-28 Q62
+.word 0x00000000, 0x00000002 @ atan 2^-29 Q62
+.word 0x00000000, 0x00000001 @ atan 2^-30 Q62
+.word 0x80000000, 0x00000000 @ atan 2^-31 Q62
+.word 0x40000000, 0x00000000 @ atan 2^-32 Q62
+
+double_section dexp_guts
+regular_func dexp_shim
+ push {r4-r7,r14}
+ bl dunpacks
+ adr r4,dreddata1
+ bl dreduce
+ cmp r1,#0
+ bge 1f
+ ldr r4,=#0xF473DE6B
+ ldr r5,=#0x2C5C85FD @ ln2 Q62
+ adds r0,r4
+ adcs r1,r5
+ subs r2,#1
+1:
+ push {r2}
+ movs r7,#1 @ shift
+ adr r6,dtab_exp
+ movs r2,#0
+ movs r3,#1
+ lsls r3,#30 @ x=1 Q62
+
+3:
+ ldmia r6!,{r4,r5}
+ mov r12,r6
+ subs r0,r4
+ sbcs r1,r5
+ bmi 1f
+
+ rsbs r6,r7,#0
+ adds r6,#32 @ complementary shift
+ movs r5,r3
+ asrs r5,r7
+ movs r4,r3
+ lsls r4,r6
+ movs r6,r2
+ lsrs r6,r7 @ rounding bit in carry
+ orrs r4,r6
+ adcs r2,r4
+ adcs r3,r5 @ x+=x>>i
+ b 2f
+
+1:
+ adds r0,r4 @ restore argument
+ adcs r1,r5
+2:
+ mov r6,r12
+ adds r7,#1
+ cmp r7,#33
+ bne 3b
+
+@ here
+@ r0:r1 ε (residual x, where x=a+ε) Q62, |ε|≤2^-32 (so fits in r0)
+@ r2:r3 exp a Q62
+@ and we wish to calculate exp x=exp a exp ε~(exp a)(1+ε)
+ muls32_32_64 r0,r3, r4,r1, r5,r6,r7,r4,r1
+@ r4:r1 ε exp a Q(62+62-32)=Q92
+ lsrs r4,#30
+ lsls r0,r1,#2
+ orrs r0,r4
+ asrs r1,#30
+ adds r0,r2
+ adcs r1,r3
+
+ pop {r2}
+ rsbs r2,#0
+ adds r2,#62
+ bl fix642double_shim @ in principle we can pack faster than this because we know the exponent
+ pop {r4-r7,r15}
+
+.ltorg
+
+.align 2
+regular_func dln_shim
+ push {r4-r7,r14}
+ lsls r7,r1,#1
+ bcs 5f @ <0 ...
+ asrs r7,#21
+ beq 5f @ ... or =0? return -Inf
+ adds r7,#1
+ beq 6f @ Inf/NaN? return +Inf
+ bl dunpacks
+ push {r2}
+ lsls r1,#9
+ lsrs r2,r0,#23
+ orrs r1,r2
+ lsls r0,#9
+@ r0:r1 m Q61 = m/2 Q62 0.5≤m/2<1
+
+ movs r7,#1 @ shift
+ adr r6,dtab_exp
+ mov r12,r6
+ movs r2,#0
+ movs r3,#0 @ y=0 Q62
+
+3:
+ rsbs r6,r7,#0
+ adds r6,#32 @ complementary shift
+ movs r5,r1
+ asrs r5,r7
+ movs r4,r1
+ lsls r4,r6
+ movs r6,r0
+ lsrs r6,r7
+ orrs r4,r6 @ x>>i, rounding bit in carry
+ adcs r4,r0
+ adcs r5,r1 @ x+(x>>i)
+
+ lsrs r6,r5,#30
+ bne 1f @ x+(x>>i)>1?
+ movs r0,r4
+ movs r1,r5 @ x+=x>>i
+ mov r6,r12
+ ldmia r6!,{r4,r5}
+ subs r2,r4
+ sbcs r3,r5
+
+1:
+ movs r4,#8
+ add r12,r4
+ adds r7,#1
+ cmp r7,#33
+ bne 3b
+@ here:
+@ r0:r1 residual x, nearly 1 Q62
+@ r2:r3 y ~ ln m/2 = ln m - ln2 Q62
+@ result is y + ln2 + ln x ~ y + ln2 + (x-1)
+ lsls r1,#2
+ asrs r1,#2 @ x-1
+ adds r2,r0
+ adcs r3,r1
+
+ pop {r7}
+@ here:
+@ r2:r3 ln m/2 = ln m - ln2 Q62
+@ r7 unbiased exponent
+
+ adr r4,dreddata1+4
+ ldmia r4,{r0,r1,r4}
+ adds r7,#1
+ muls r0,r7 @ Q62
+ muls r1,r7 @ Q41
+ muls r4,r7 @ Q20
+ lsls r7,r1,#21
+ asrs r1,#11
+ asrs r5,r1,#31
+ adds r0,r7
+ adcs r1,r5
+ lsls r7,r4,#10
+ asrs r4,#22
+ asrs r5,r1,#31
+ adds r1,r7
+ adcs r4,r5
+@ r0:r1:r4 exponent*ln2 Q62
+ asrs r5,r3,#31
+ adds r0,r2
+ adcs r1,r3
+ adcs r4,r5
+@ r0:r1:r4 result Q62
+ movs r2,#62
+1:
+ asrs r5,r1,#31
+ cmp r4,r5
+ beq 2f @ r4 a sign extension of r1?
+ lsrs r0,#4 @ no: shift down 4 places and try again
+ lsls r6,r1,#28
+ orrs r0,r6
+ lsrs r1,#4
+ lsls r6,r4,#28
+ orrs r1,r6
+ asrs r4,#4
+ subs r2,#4
+ b 1b
+2:
+ bl fix642double_shim
+ pop {r4-r7,r15}
+
+5:
+ ldr r1,=#0xfff00000
+ movs r0,#0
+ pop {r4-r7,r15}
+
+6:
+ ldr r1,=#0x7ff00000
+ movs r0,#0
+ pop {r4-r7,r15}
+
+.ltorg
+
+.align 2
+dreddata1:
+.word 0x0000B8AA @ 1/ln2 Q15
+.word 0x0013DE6B @ ln2 Q62 Q62=2C5C85FDF473DE6B split into 21-bit pieces
+.word 0x000FEFA3
+.word 0x000B1721
+
+dtab_exp:
+.word 0xbf984bf3, 0x19f323ec @ log 1+2^-1 Q62
+.word 0xcd4d10d6, 0x0e47fbe3 @ log 1+2^-2 Q62
+.word 0x8abcb97a, 0x0789c1db @ log 1+2^-3 Q62
+.word 0x022c54cc, 0x03e14618 @ log 1+2^-4 Q62
+.word 0xe7833005, 0x01f829b0 @ log 1+2^-5 Q62
+.word 0x87e01f1e, 0x00fe0545 @ log 1+2^-6 Q62
+.word 0xac419e24, 0x007f80a9 @ log 1+2^-7 Q62
+.word 0x45621781, 0x003fe015 @ log 1+2^-8 Q62
+.word 0xa9ab10e6, 0x001ff802 @ log 1+2^-9 Q62
+.word 0x55455888, 0x000ffe00 @ log 1+2^-10 Q62
+.word 0x0aa9aac4, 0x0007ff80 @ log 1+2^-11 Q62
+.word 0x01554556, 0x0003ffe0 @ log 1+2^-12 Q62
+.word 0x002aa9ab, 0x0001fff8 @ log 1+2^-13 Q62
+.word 0x00055545, 0x0000fffe @ log 1+2^-14 Q62
+.word 0x8000aaaa, 0x00007fff @ log 1+2^-15 Q62
+.word 0xe0001555, 0x00003fff @ log 1+2^-16 Q62
+.word 0xf80002ab, 0x00001fff @ log 1+2^-17 Q62
+.word 0xfe000055, 0x00000fff @ log 1+2^-18 Q62
+.word 0xff80000b, 0x000007ff @ log 1+2^-19 Q62
+.word 0xffe00001, 0x000003ff @ log 1+2^-20 Q62
+.word 0xfff80000, 0x000001ff @ log 1+2^-21 Q62
+.word 0xfffe0000, 0x000000ff @ log 1+2^-22 Q62
+.word 0xffff8000, 0x0000007f @ log 1+2^-23 Q62
+.word 0xffffe000, 0x0000003f @ log 1+2^-24 Q62
+.word 0xfffff800, 0x0000001f @ log 1+2^-25 Q62
+.word 0xfffffe00, 0x0000000f @ log 1+2^-26 Q62
+.word 0xffffff80, 0x00000007 @ log 1+2^-27 Q62
+.word 0xffffffe0, 0x00000003 @ log 1+2^-28 Q62
+.word 0xfffffff8, 0x00000001 @ log 1+2^-29 Q62
+.word 0xfffffffe, 0x00000000 @ log 1+2^-30 Q62
+.word 0x80000000, 0x00000000 @ log 1+2^-31 Q62
+.word 0x40000000, 0x00000000 @ log 1+2^-32 Q62
+
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/include/pico/double.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/include/pico/double.h
new file mode 100644
index 00000000000..0893233feef
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_double/include/pico/double.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_DOUBLE_H
+#define _PICO_DOUBLE_H
+
+#include
+#include "pico/types.h"
+#include "pico/bootrom/sf_table.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file double.h
+* \defgroup pico_double pico_double
+*
+* Optimized double-precision floating point functions
+*
+* (Replacement) optimized implementations are provided of the following compiler built-ins
+* and math library functions:
+*
+* - __aeabi_dadd, __aeabi_ddiv, __aeabi_dmul, __aeabi_drsub, __aeabi_dsub, __aeabi_cdcmpeq, __aeabi_cdrcmple, __aeabi_cdcmple, __aeabi_dcmpeq, __aeabi_dcmplt, __aeabi_dcmple, __aeabi_dcmpge, __aeabi_dcmpgt, __aeabi_dcmpun, __aeabi_i2d, __aeabi_l2d, __aeabi_ui2d, __aeabi_ul2d, __aeabi_d2iz, __aeabi_d2lz, __aeabi_d2uiz, __aeabi_d2ulz, __aeabi_d2f
+* - sqrt, cos, sin, tan, atan2, exp, log, ldexp, copysign, trunc, floor, ceil, round, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh, exp2, log2, exp10, log10, pow,, hypot, cbrt, fmod, drem, remainder, remquo, expm1, log1p, fma
+* - powint, sincos (GNU extensions)
+*
+* The following additional optimized functions are also provided:
+*
+* - fix2double, ufix2double, fix642double, ufix642double, double2fix, double2ufix, double2fix64, double2ufix64, double2int, double2int64, double2int_z, double2int64_z
+*/
+
+double fix2double(int32_t m, int e);
+double ufix2double(uint32_t m, int e);
+double fix642double(int64_t m, int e);
+double ufix642double(uint64_t m, int e);
+
+// These methods round towards -Infinity.
+int32_t double2fix(double f, int e);
+uint32_t double2ufix(double f, int e);
+int64_t double2fix64(double f, int e);
+uint64_t double2ufix64(double f, int e);
+int32_t double2int(double f);
+int64_t double2int64(double f);
+
+// These methods round towards 0.
+int32_t double2int_z(double f);
+int64_t double2int64_z(double f);
+
+double exp10(double x);
+void sincos(double x, double *sinx, double *cosx);
+double powint(double x, int y);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/CMakeLists.txt
new file mode 100644
index 00000000000..81a9eaafb98
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/CMakeLists.txt
@@ -0,0 +1 @@
+pico_add_subdirectory(rp2040_usb_device_enumeration)
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/rp2040_usb_device_enumeration/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/rp2040_usb_device_enumeration/CMakeLists.txt
new file mode 100644
index 00000000000..0d682ab4eca
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/rp2040_usb_device_enumeration/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_library(pico_fix_rp2040_usb_device_enumeration INTERFACE)
+
+target_sources(pico_fix_rp2040_usb_device_enumeration INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/rp2040_usb_device_enumeration.c
+ )
+
+target_include_directories(pico_fix_rp2040_usb_device_enumeration INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
+target_link_libraries(pico_fix_rp2040_usb_device_enumeration INTERFACE hardware_structs pico_time)
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/rp2040_usb_device_enumeration/include/pico/fix/rp2040_usb_device_enumeration.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/rp2040_usb_device_enumeration/include/pico/fix/rp2040_usb_device_enumeration.h
new file mode 100644
index 00000000000..49f115e907e
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/rp2040_usb_device_enumeration/include/pico/fix/rp2040_usb_device_enumeration.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_FIX_RP2040_USB_DEVICE_ENUMERATION_H
+#define _PICO_FIX_RP2040_USB_DEVICE_ENUMERATION_H
+
+/*! \brief Perform a brute force workaround for USB device enumeration issue
+ * \ingroup pico_fix
+ *
+ * This method should be called during the IRQ handler for a bus reset
+ */
+void rp2040_usb_device_enumeration_fix(void);
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c
new file mode 100644
index 00000000000..91583205bbb
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico.h"
+#include "pico/time.h"
+#include "hardware/structs/usb.h"
+#include "hardware/gpio.h"
+#include "hardware/structs/iobank0.h"
+#include "hardware/structs/padsbank0.h"
+#include "pico/fix/rp2040_usb_device_enumeration.h"
+
+#define LS_SE0 0b00
+#define LS_J 0b01
+#define LS_K 0b10
+#define LS_SE1 0b11
+
+static void hw_enumeration_fix_wait_se0(void);
+static void hw_enumeration_fix_force_ls_j(void);
+static void hw_enumeration_fix_finish(void);
+
+void rp2040_usb_device_enumeration_fix(void) {
+ // After coming out of reset, the hardware expects 800us of LS_J (linestate J) time
+ // before it will move to the connected state. However on a hub that broadcasts packets
+ // for other devices this isn't the case. The plan here is to wait for the end of the bus
+ // reset, force an LS_J for 1ms and then switch control back to the USB phy. Unfortunately
+ // this requires us to use GPIO15 as there is no other way to force the input path.
+ // We only need to force DP as DM can be left at zero. It will be gated off by GPIO
+ // logic if it isn't func selected.
+
+ // Wait SE0 phase will call force ls_j phase which will call finish phase
+ hw_enumeration_fix_wait_se0();
+}
+
+static inline uint8_t hw_line_state(void) {
+ return (usb_hw->sie_status & USB_SIE_STATUS_LINE_STATE_BITS) >> USB_SIE_STATUS_LINE_STATE_LSB;
+}
+
+int64_t hw_enumeration_fix_wait_se0_callback(__unused alarm_id_t id, __unused void *user_data) {
+ if (hw_line_state() == LS_SE0) {
+ // Come back in 1ms and check again
+ return 1000;
+ } else {
+ // Now force LS_J (next stage of fix)
+ hw_enumeration_fix_force_ls_j();
+ // No more repeats
+ return 0;
+ }
+}
+
+static inline void hw_enumeration_fix_busy_wait_se0(void) {
+ while (hw_line_state() == LS_SE0) tight_loop_contents();
+ // Now force LS_J (next stage of fix)
+ hw_enumeration_fix_force_ls_j();
+}
+
+static void hw_enumeration_fix_wait_se0(void) {
+ // Wait for SE0 to end (i.e. the host to stop resetting). This reset can last quite long.
+ // 10-15ms so we are going to set a timer callback.
+
+#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
+ if (add_alarm_in_ms(1, hw_enumeration_fix_wait_se0_callback, NULL, true) >= 0) {
+ // hw_enumeration_fix_wait_se0_callback will be called in 1ms to check if se0 has finished
+ // (and will poll every 1ms from there)
+ return;
+ }
+#endif
+ // if timer pool disabled, or no timer available, have to busy wait.
+ hw_enumeration_fix_busy_wait_se0();
+}
+
+int64_t hw_enumeration_fix_force_ls_j_done(__unused alarm_id_t id, __unused void *user_data) {
+ hw_enumeration_fix_finish();
+ return 0;
+}
+
+static uint32_t gpio_ctrl_prev = 0;
+static uint32_t pad_ctrl_prev = 0;
+static const uint dp = 15;
+static const uint dm = 16;
+
+static void hw_enumeration_fix_force_ls_j(void) {
+ // DM must be 0 for this to work. This is true if it is selected
+ // to any other function. fn 8 on this pin is only for debug so shouldn't
+ // be selected
+ if (gpio_get_function(dm) == 8) {
+ panic("Not expecting DM to be function 8");
+ }
+
+ // Before changing any pin state, take a copy of the current gpio control register
+ gpio_ctrl_prev = iobank0_hw->io[dp].ctrl;
+ // Also take a copy of the pads register
+ pad_ctrl_prev = padsbank0_hw->io[dp];
+
+ // Enable bus keep and force pin to tristate, so USB DP muxing doesn't affect
+ // pin state
+ gpio_set_pulls(dp, true, true);
+ gpio_set_oeover(dp, GPIO_OVERRIDE_LOW);
+ // Select function 8 (USB debug muxing) without disturbing other controls
+ hw_write_masked(&iobank0_hw->io[dp].ctrl,
+ 8 << IO_BANK0_GPIO15_CTRL_FUNCSEL_LSB, IO_BANK0_GPIO15_CTRL_FUNCSEL_BITS);
+
+ // J state is a differential 1 for a full speed device so
+ // DP = 1 and DM = 0. Don't actually need to set DM low as it
+ // is already gated assuming it isn't funcseld.
+ gpio_set_inover(dp, GPIO_OVERRIDE_HIGH);
+
+ // Force PHY pull up to stay before switching away from the phy
+ hw_set_alias(usb_hw)->phy_direct = USB_USBPHY_DIRECT_DP_PULLUP_EN_BITS;
+ hw_set_alias(usb_hw)->phy_direct_override = USB_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN_BITS;
+
+ // Switch to GPIO phy with LS_J forced
+ usb_hw->muxing = USB_USB_MUXING_TO_DIGITAL_PAD_BITS | USB_USB_MUXING_SOFTCON_BITS;
+
+ // LS_J is now forced but while loop here just to check
+ hard_assert(hw_line_state() == LS_J); // "LS_J not forced!"
+
+#if !PICO_TIME_DEFAULT_ALARM_POOL_DISABLED
+ if (add_alarm_in_ms(1, hw_enumeration_fix_force_ls_j_done, NULL, true) >= 0) {
+ // hw_enumeration_fix_force_ls_j_done will be called in 1ms
+ return;
+ }
+#endif
+ // if timer pool disabled, or no timer available, have to busy wait.
+ busy_wait_us(1000);
+ hw_enumeration_fix_finish();
+}
+
+static void hw_enumeration_fix_finish(void) {
+ // Should think we are connected now
+ while (!(usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS)) tight_loop_contents();
+
+ // Switch back to USB phy
+ usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
+
+ // Get rid of DP pullup override
+ hw_clear_alias(usb_hw)->phy_direct_override = USB_USBPHY_DIRECT_OVERRIDE_DP_PULLUP_EN_OVERRIDE_EN_BITS;
+
+ // Finally, restore the gpio ctrl value back to GPIO15
+ iobank0_hw->io[dp].ctrl = gpio_ctrl_prev;
+ // Restore the pad ctrl value
+ padsbank0_hw->io[dp] = pad_ctrl_prev;
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/CMakeLists.txt
new file mode 100644
index 00000000000..a6e78957040
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/CMakeLists.txt
@@ -0,0 +1,126 @@
+if (NOT TARGET pico_float)
+ # library to be depended on - we make this depend on particular implementations using per target generator expressions
+ add_library(pico_float INTERFACE)
+
+ # no custom implementation; falls thru to compiler
+ add_library(pico_float_compiler INTERFACE)
+ # PICO_BUILD_DEFINE: PICO_FLOAT_COMPILER, whether compiler provided float support is being used, type=bool, default=0, but dependent on CMake options, group=pico_float
+ target_compile_definitions(pico_float_compiler INTERFACE
+ PICO_FLOAT_COMPILER=1
+ )
+
+ add_library(pico_float_headers INTERFACE)
+ target_include_directories(pico_float_headers INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
+ # add alias "default" which is just rom.
+ add_library(pico_float_default INTERFACE)
+ target_link_libraries(pico_float_default INTERFACE pico_float_pico)
+
+ set(PICO_DEFAULT_FLOAT_IMPL pico_float_default)
+
+ target_link_libraries(pico_float INTERFACE
+ $>,$,${PICO_DEFAULT_FLOAT_IMPL}>)
+
+ add_library(pico_float_pico INTERFACE)
+ target_sources(pico_float_pico INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/float_aeabi.S
+ ${CMAKE_CURRENT_LIST_DIR}/float_init_rom.c
+ ${CMAKE_CURRENT_LIST_DIR}/float_math.c
+ ${CMAKE_CURRENT_LIST_DIR}/float_v1_rom_shim.S
+ )
+ # PICO_BUILD_DEFINE: PICO_FLOAT_PICO, whether optimized pico/bootrom provided float support is being used, type=bool, default=1, but dependent on CMake options, group=pico_float
+ target_compile_definitions(pico_float_pico INTERFACE
+ PICO_FLOAT_PICO=1
+ )
+
+ target_link_libraries(pico_float_pico INTERFACE pico_bootrom pico_float_headers)
+
+ add_library(pico_float_none INTERFACE)
+ target_sources(pico_float_none INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/float_none.S
+ )
+
+ target_link_libraries(pico_float_none INTERFACE pico_float_headers)
+
+ # PICO_BUILD_DEFINE: PICO_FLOAT_NONE, whether float support is disabled and functions will panic, type=bool, default=0, but dependent on CMake options, group=pico_float
+ target_compile_definitions(pico_float_none INTERFACE
+ PICO_FLOAT_NONE=1
+ )
+
+ function(wrap_float_functions TARGET)
+ pico_wrap_function(${TARGET} __aeabi_fadd)
+ pico_wrap_function(${TARGET} __aeabi_fdiv)
+ pico_wrap_function(${TARGET} __aeabi_fmul)
+ pico_wrap_function(${TARGET} __aeabi_frsub)
+ pico_wrap_function(${TARGET} __aeabi_fsub)
+ pico_wrap_function(${TARGET} __aeabi_cfcmpeq)
+ pico_wrap_function(${TARGET} __aeabi_cfrcmple)
+ pico_wrap_function(${TARGET} __aeabi_cfcmple)
+ pico_wrap_function(${TARGET} __aeabi_fcmpeq)
+ pico_wrap_function(${TARGET} __aeabi_fcmplt)
+ pico_wrap_function(${TARGET} __aeabi_fcmple)
+ pico_wrap_function(${TARGET} __aeabi_fcmpge)
+ pico_wrap_function(${TARGET} __aeabi_fcmpgt)
+ pico_wrap_function(${TARGET} __aeabi_fcmpun)
+ pico_wrap_function(${TARGET} __aeabi_i2f)
+ pico_wrap_function(${TARGET} __aeabi_l2f)
+ pico_wrap_function(${TARGET} __aeabi_ui2f)
+ pico_wrap_function(${TARGET} __aeabi_ul2f)
+ pico_wrap_function(${TARGET} __aeabi_f2iz)
+ pico_wrap_function(${TARGET} __aeabi_f2lz)
+ pico_wrap_function(${TARGET} __aeabi_f2uiz)
+ pico_wrap_function(${TARGET} __aeabi_f2ulz)
+ pico_wrap_function(${TARGET} __aeabi_f2d)
+ pico_wrap_function(${TARGET} sqrtf)
+ pico_wrap_function(${TARGET} cosf)
+ pico_wrap_function(${TARGET} sinf)
+ pico_wrap_function(${TARGET} tanf)
+ pico_wrap_function(${TARGET} atan2f)
+ pico_wrap_function(${TARGET} expf)
+ pico_wrap_function(${TARGET} logf)
+
+ pico_wrap_function(${TARGET} ldexpf)
+ pico_wrap_function(${TARGET} copysignf)
+ pico_wrap_function(${TARGET} truncf)
+ pico_wrap_function(${TARGET} floorf)
+ pico_wrap_function(${TARGET} ceilf)
+ pico_wrap_function(${TARGET} roundf)
+ pico_wrap_function(${TARGET} sincosf) # gnu
+ pico_wrap_function(${TARGET} asinf)
+ pico_wrap_function(${TARGET} acosf)
+ pico_wrap_function(${TARGET} atanf)
+ pico_wrap_function(${TARGET} sinhf)
+ pico_wrap_function(${TARGET} coshf)
+ pico_wrap_function(${TARGET} tanhf)
+ pico_wrap_function(${TARGET} asinhf)
+ pico_wrap_function(${TARGET} acoshf)
+ pico_wrap_function(${TARGET} atanhf)
+ pico_wrap_function(${TARGET} exp2f)
+ pico_wrap_function(${TARGET} log2f)
+ pico_wrap_function(${TARGET} exp10f)
+ pico_wrap_function(${TARGET} log10f)
+ pico_wrap_function(${TARGET} powf)
+ pico_wrap_function(${TARGET} powintf) #gnu
+ pico_wrap_function(${TARGET} hypotf)
+ pico_wrap_function(${TARGET} cbrtf)
+ pico_wrap_function(${TARGET} fmodf)
+ pico_wrap_function(${TARGET} dremf)
+ pico_wrap_function(${TARGET} remainderf)
+ pico_wrap_function(${TARGET} remquof)
+ pico_wrap_function(${TARGET} expm1f)
+ pico_wrap_function(${TARGET} log1pf)
+ pico_wrap_function(${TARGET} fmaf)
+ endfunction()
+
+ wrap_float_functions(pico_float_pico)
+ wrap_float_functions(pico_float_none)
+
+ macro(pico_set_float_implementation TARGET IMPL)
+ get_target_property(target_type ${TARGET} TYPE)
+ if ("EXECUTABLE" STREQUAL "${target_type}")
+ set_target_properties(${TARGET} PROPERTIES PICO_TARGET_FLOAT_IMPL "pico_float_${IMPL}")
+ else()
+ message(FATAL_ERROR "float implementation must be set on executable not library")
+ endif()
+ endmacro()
+endif()
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_aeabi.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_aeabi.S
new file mode 100644
index 00000000000..2aee5f250ad
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_aeabi.S
@@ -0,0 +1,724 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico/asm_helper.S"
+#include "pico/bootrom/sf_table.h"
+
+__pre_init __aeabi_float_init, 00020
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+.macro float_section name
+#if PICO_FLOAT_IN_RAM
+.section RAM_SECTION_NAME(\name), "ax"
+#else
+.section SECTION_NAME(\name), "ax"
+#endif
+.endm
+
+.macro float_wrapper_section func
+float_section WRAPPER_FUNC_NAME(\func)
+.endm
+
+.macro _float_wrapper_func x
+ wrapper_func \x
+.endm
+
+.macro wrapper_func_f1 x
+ _float_wrapper_func \x
+#if PICO_FLOAT_PROPAGATE_NANS
+ mov ip, lr
+ bl __check_nan_f1
+ mov lr, ip
+#endif
+.endm
+
+.macro wrapper_func_f2 x
+ _float_wrapper_func \x
+#if PICO_FLOAT_PROPAGATE_NANS
+ mov ip, lr
+ bl __check_nan_f2
+ mov lr, ip
+#endif
+.endm
+
+.section .text
+
+#if PICO_FLOAT_PROPAGATE_NANS
+.thumb_func
+__check_nan_f1:
+ movs r3, #1
+ lsls r3, #24
+ lsls r2, r0, #1
+ adds r2, r3
+ bhi 1f
+ bx lr
+1:
+ bx ip
+
+.thumb_func
+__check_nan_f2:
+ movs r3, #1
+ lsls r3, #24
+ lsls r2, r0, #1
+ adds r2, r3
+ bhi 1f
+ lsls r2, r1, #1
+ adds r2, r3
+ bhi 2f
+ bx lr
+2:
+ mov r0, r1
+1:
+ bx ip
+#endif
+
+.macro table_tail_call SF_TABLE_OFFSET
+#if PICO_FLOAT_SUPPORT_ROM_V1
+#ifndef NDEBUG
+ movs r3, #0
+ mov ip, r3
+#endif
+#endif
+ ldr r3, =sf_table
+ ldr r3, [r3, #\SF_TABLE_OFFSET]
+ bx r3
+.endm
+
+.macro shimmable_table_tail_call SF_TABLE_OFFSET shim
+ ldr r3, =sf_table
+ ldr r3, [r3, #\SF_TABLE_OFFSET]
+#if PICO_FLOAT_SUPPORT_ROM_V1
+ mov ip, pc
+#endif
+ bx r3
+#if PICO_FLOAT_SUPPORT_ROM_V1
+.byte \SF_TABLE_OFFSET, 0xdf
+.word \shim
+#endif
+.endm
+
+
+# note generally each function is in a separate section unless there is fall thru or branching between them
+# note fadd, fsub, fmul, fdiv are so tiny and just defer to rom so are lumped together so they can share constant pool
+
+# note functions are word aligned except where they are an odd number of linear instructions
+
+// float FUNC_NAME(__aeabi_fadd)(float, float) single-precision addition
+float_wrapper_section __aeabi_farithmetic
+// float FUNC_NAME(__aeabi_frsub)(float x, float y) single-precision reverse subtraction, y - x
+
+# frsub first because it is the only one that needs alignment
+.align 2
+wrapper_func __aeabi_frsub
+ eors r0, r1
+ eors r1, r0
+ eors r0, r1
+ // fall thru
+
+// float FUNC_NAME(__aeabi_fsub)(float x, float y) single-precision subtraction, x - y
+wrapper_func_f2 __aeabi_fsub
+#if PICO_FLOAT_PROPAGATE_NANS
+ // we want to return nan for inf-inf or -inf - -inf, but without too much upfront cost
+ mov r2, r0
+ eors r2, r1
+ bmi 1f // different signs
+ push {r0, r1, lr}
+ bl 1f
+ b fdiv_fsub_nan_helper
+1:
+#endif
+ table_tail_call SF_TABLE_FSUB
+
+wrapper_func_f2 __aeabi_fadd
+ table_tail_call SF_TABLE_FADD
+
+// float FUNC_NAME(__aeabi_fdiv)(float n, float d) single-precision division, n / d
+wrapper_func_f2 __aeabi_fdiv
+#if PICO_FLOAT_PROPAGATE_NANS
+ push {r0, r1, lr}
+ bl 1f
+ b fdiv_fsub_nan_helper
+1:
+#endif
+ table_tail_call SF_TABLE_FDIV
+
+fdiv_fsub_nan_helper:
+#if PICO_FLOAT_PROPAGATE_NANS
+ pop {r1, r2}
+
+ // check for infinite op infinite (or rather check for infinite result with both
+ // operands being infinite)
+ lsls r3, r0, #1
+ asrs r3, r3, #24
+ adds r3, #1
+ beq 2f
+ pop {pc}
+2:
+ lsls r1, #1
+ asrs r1, r1, #24
+ lsls r2, #1
+ asrs r2, r2, #24
+ ands r1, r2
+ adds r1, #1
+ bne 3f
+ // infinite to nan
+ movs r1, #1
+ lsls r1, #22
+ orrs r0, r1
+3:
+ pop {pc}
+#endif
+
+// float FUNC_NAME(__aeabi_fmul)(float, float) single-precision multiplication
+wrapper_func_f2 __aeabi_fmul
+#if PICO_FLOAT_PROPAGATE_NANS
+ push {r0, r1, lr}
+ bl 1f
+ pop {r1, r2}
+
+ // check for multiplication of infinite by zero (or rather check for infinite result with either
+ // operand 0)
+ lsls r3, r0, #1
+ asrs r3, r3, #24
+ adds r3, #1
+ beq 2f
+ pop {pc}
+2:
+ ands r1, r2
+ bne 3f
+ // infinite to nan
+ movs r1, #1
+ lsls r1, #22
+ orrs r0, r1
+3:
+ pop {pc}
+1:
+#endif
+ table_tail_call SF_TABLE_FMUL
+
+// void FUNC_NAME(__aeabi_cfrcmple)(float, float) reversed 3-way (<, =, ?>) compare [1], result in PSR ZC flags
+float_wrapper_section __aeabi_cfcmple
+.align 2
+wrapper_func __aeabi_cfrcmple
+ push {r0-r2, lr}
+ eors r0, r1
+ eors r1, r0
+ eors r0, r1
+ b __aeabi_cfcmple_guts
+
+// NOTE these share an implementation as we have no excepting NaNs.
+// void FUNC_NAME(__aeabi_cfcmple)(float, float) 3-way (<, =, ?>) compare [1], result in PSR ZC flags
+// void FUNC_NAME(__aeabi_cfcmpeq)(float, float) non-excepting equality comparison [1], result in PSR ZC flags
+.align 2
+wrapper_func __aeabi_cfcmple
+wrapper_func __aeabi_cfcmpeq
+ push {r0-r2, lr}
+
+__aeabi_cfcmple_guts:
+ lsls r2,r0,#1
+ lsrs r2,#24
+ beq 1f
+ cmp r2,#0xff
+ bne 2f
+ lsls r2, r0, #9
+ bhi 3f
+1:
+ lsrs r0,#23 @ clear mantissa if denormal or infinite
+ lsls r0,#23
+2:
+ lsls r2,r1,#1
+ lsrs r2,#24
+ beq 1f
+ cmp r2,#0xff
+ bne 2f
+ lsls r2, r1, #9
+ bhi 3f
+1:
+ lsrs r1,#23 @ clear mantissa if denormal or infinite
+ lsls r1,#23
+2:
+ movs r2,#1 @ initialise result
+ eors r1,r0
+ bmi 2f @ opposite signs? then can proceed on basis of sign of x
+ eors r1,r0 @ restore y
+ bpl 1f
+ cmp r1,r0
+ pop {r0-r2, pc}
+1:
+ cmp r0,r1
+ pop {r0-r2, pc}
+2:
+ orrs r1, r0 @ handle 0/-0
+ adds r1, r1 @ note this always sets C
+ beq 3f
+ mvns r0, r0 @ carry inverse of r0 sign
+ adds r0, r0
+3:
+ pop {r0-r2, pc}
+
+
+// int FUNC_NAME(__aeabi_fcmpeq)(float, float) result (1, 0) denotes (=, ?<>) [2], use for C == and !=
+float_wrapper_section __aeabi_fcmpeq
+.align 2
+wrapper_func __aeabi_fcmpeq
+ push {lr}
+ bl __aeabi_cfcmpeq
+ beq 1f
+ movs r0, #0
+ pop {pc}
+1:
+ movs r0, #1
+ pop {pc}
+
+// int FUNC_NAME(__aeabi_fcmplt)(float, float) result (1, 0) denotes (<, ?>=) [2], use for C <
+float_wrapper_section __aeabi_fcmplt
+.align 2
+wrapper_func __aeabi_fcmplt
+ push {lr}
+ bl __aeabi_cfcmple
+ sbcs r0, r0
+ pop {pc}
+
+// int FUNC_NAME(__aeabi_fcmple)(float, float) result (1, 0) denotes (<=, ?>) [2], use for C <=
+float_wrapper_section __aeabi_fcmple
+.align 2
+wrapper_func __aeabi_fcmple
+ push {lr}
+ bl __aeabi_cfcmple
+ bls 1f
+ movs r0, #0
+ pop {pc}
+1:
+ movs r0, #1
+ pop {pc}
+
+// int FUNC_NAME(__aeabi_fcmpge)(float, float) result (1, 0) denotes (>=, ?<) [2], use for C >=
+float_wrapper_section __aeabi_fcmpge
+.align 2
+wrapper_func __aeabi_fcmpge
+ push {lr}
+ // because of NaNs it is better to reverse the args than the result
+ bl __aeabi_cfrcmple
+ bls 1f
+ movs r0, #0
+ pop {pc}
+1:
+ movs r0, #1
+ pop {pc}
+
+// int FUNC_NAME(__aeabi_fcmpgt)(float, float) result (1, 0) denotes (>, ?<=) [2], use for C >
+float_wrapper_section __aeabi_fcmpgt
+wrapper_func __aeabi_fcmpgt
+ push {lr}
+ // because of NaNs it is better to reverse the args than the result
+ bl __aeabi_cfrcmple
+ sbcs r0, r0
+ pop {pc}
+
+// int FUNC_NAME(__aeabi_fcmpun)(float, float) result (1, 0) denotes (?, <=>) [2], use for C99 isunordered()
+float_wrapper_section __aeabi_fcmpun
+wrapper_func __aeabi_fcmpun
+ movs r3, #1
+ lsls r3, #24
+ lsls r2, r0, #1
+ adds r2, r3
+ bhi 1f
+ lsls r2, r1, #1
+ adds r2, r3
+ bhi 1f
+ movs r0, #0
+ bx lr
+1:
+ movs r0, #1
+ bx lr
+
+
+// float FUNC_NAME(__aeabi_ui2f)(unsigned) unsigned to float (single precision) conversion
+float_wrapper_section __aeabi_ui2f
+wrapper_func __aeabi_ui2f
+ subs r1, r1
+ cmp r0, #0
+ bne __aeabi_i2f_main
+ mov r0, r1
+ bx lr
+
+float_wrapper_section __aeabi_i2f
+// float FUNC_NAME(__aeabi_i2f)(int) integer to float (single precision) conversion
+wrapper_func __aeabi_i2f
+ lsrs r1, r0, #31
+ lsls r1, #31
+ bpl 1f
+ rsbs r0, #0
+1:
+ cmp r0, #0
+ beq 7f
+__aeabi_i2f_main:
+
+ mov ip, lr
+ push {r0, r1}
+ ldr r3, =sf_clz_func
+ ldr r3, [r3]
+ blx r3
+ pop {r1, r2}
+ lsls r1, r0
+ subs r0, #158
+ rsbs r0, #0
+
+ adds r1,#0x80 @ rounding
+ bcs 5f @ tripped carry? then have leading 1 in C as required (and result is even so can ignore sticky bits)
+
+ lsls r3,r1,#24 @ check bottom 8 bits of r1
+ beq 6f @ in rounding-tie case?
+ lsls r1,#1 @ remove leading 1
+3:
+ lsrs r1,#9 @ align mantissa
+ lsls r0,#23 @ align exponent
+ orrs r0,r2 @ assemble exponent and mantissa
+4:
+ orrs r0,r1 @ apply sign
+1:
+ bx ip
+5:
+ adds r0,#1 @ correct exponent offset
+ b 3b
+6:
+ lsrs r1,#9 @ ensure even result
+ lsls r1,#10
+ b 3b
+7:
+ bx lr
+
+
+// int FUNC_NAME(__aeabi_f2iz)(float) float (single precision) to integer C-style conversion [3]
+float_wrapper_section __aeabi_f2iz
+wrapper_func __aeabi_f2iz
+regular_func float2int_z
+ lsls r1, r0, #1
+ lsrs r2, r1, #24
+ movs r3, #0x80
+ lsls r3, #24
+ cmp r2, #126
+ ble 1f
+ subs r2, #158
+ bge 2f
+ asrs r1, r0, #31
+ lsls r0, #9
+ lsrs r0, #1
+ orrs r0, r3
+ negs r2, r2
+ lsrs r0, r2
+ lsls r1, #1
+ adds r1, #1
+ muls r0, r1
+ bx lr
+1:
+ movs r0, #0
+ bx lr
+2:
+ lsrs r0, #31
+ adds r0, r3
+ subs r0, #1
+ bx lr
+
+ cmn r0, r0
+ bcc float2int
+ push {lr}
+ lsls r0, #1
+ lsrs r0, #1
+ movs r1, #0
+ bl __aeabi_f2uiz
+ cmp r0, #0
+ bmi 1f
+ rsbs r0, #0
+ pop {pc}
+1:
+ movs r0, #128
+ lsls r0, #24
+ pop {pc}
+
+float_section float2int
+regular_func float2int
+ shimmable_table_tail_call SF_TABLE_FLOAT2INT float2int_shim
+
+float_section float2fix
+regular_func float2fix
+ shimmable_table_tail_call SF_TABLE_FLOAT2FIX float2fix_shim
+
+float_section float2ufix
+regular_func float2ufix
+ table_tail_call SF_TABLE_FLOAT2UFIX
+
+// unsigned FUNC_NAME(__aeabi_f2uiz)(float) float (single precision) to unsigned C-style conversion [3]
+float_wrapper_section __aeabi_f2uiz
+wrapper_func __aeabi_f2uiz
+ table_tail_call SF_TABLE_FLOAT2UINT
+
+float_section fix2float
+regular_func fix2float
+ table_tail_call SF_TABLE_FIX2FLOAT
+
+float_section ufix2float
+regular_func ufix2float
+ table_tail_call SF_TABLE_UFIX2FLOAT
+
+float_section fix642float
+regular_func fix642float
+ shimmable_table_tail_call SF_TABLE_FIX642FLOAT fix642float_shim
+
+float_section ufix642float
+regular_func ufix642float
+ shimmable_table_tail_call SF_TABLE_UFIX642FLOAT ufix642float_shim
+
+// float FUNC_NAME(__aeabi_l2f)(long long) long long to float (single precision) conversion
+float_wrapper_section __aeabi_l2f
+1:
+ ldr r2, =__aeabi_i2f
+ bx r2
+wrapper_func __aeabi_l2f
+ asrs r2, r0, #31
+ cmp r1, r2
+ beq 1b
+ shimmable_table_tail_call SF_TABLE_INT642FLOAT int642float_shim
+
+// float FUNC_NAME(__aeabi_l2f)(long long) long long to float (single precision) conversion
+float_wrapper_section __aeabi_ul2f
+1:
+ ldr r2, =__aeabi_ui2f
+ bx r2
+wrapper_func __aeabi_ul2f
+ cmp r1, #0
+ beq 1b
+ shimmable_table_tail_call SF_TABLE_UINT642FLOAT uint642float_shim
+
+// long long FUNC_NAME(__aeabi_f2lz)(float) float (single precision) to long long C-style conversion [3]
+float_wrapper_section __aeabi_f2lz
+wrapper_func __aeabi_f2lz
+regular_func float2int64_z
+ cmn r0, r0
+ bcc float2int64
+ push {lr}
+ lsls r0, #1
+ lsrs r0, #1
+ movs r1, #0
+ bl float2ufix64
+ cmp r1, #0
+ bmi 1f
+ movs r2, #0
+ rsbs r0, #0
+ sbcs r2, r1
+ mov r1, r2
+ pop {pc}
+1:
+ movs r1, #128
+ lsls r1, #24
+ movs r0, #0
+ pop {pc}
+
+float_section float2int64
+regular_func float2int64
+ shimmable_table_tail_call SF_TABLE_FLOAT2INT64 float2int64_shim
+
+float_section float2fix64
+regular_func float2fix64
+ shimmable_table_tail_call SF_TABLE_FLOAT2FIX64 float2fix64_shim
+
+// unsigned long long FUNC_NAME(__aeabi_f2ulz)(float) float to unsigned long long C-style conversion [3]
+float_wrapper_section __aeabi_f2ulz
+wrapper_func __aeabi_f2ulz
+ shimmable_table_tail_call SF_TABLE_FLOAT2UINT64 float2uint64_shim
+
+float_section float2ufix64
+regular_func float2ufix64
+ shimmable_table_tail_call SF_TABLE_FLOAT2UFIX64 float2ufix64_shim
+
+float_wrapper_section __aeabi_f2d
+1:
+#if PICO_FLOAT_PROPAGATE_NANS
+ // copy sign bit and 25 NAN id bits into sign bit and significant ID bits, also setting the high id bit
+ asrs r1, r0, #3
+ movs r2, #0xf
+ lsls r2, #27
+ orrs r1, r2
+ lsls r0, #25
+ bx lr
+#endif
+wrapper_func __aeabi_f2d
+#if PICO_FLOAT_PROPAGATE_NANS
+ movs r3, #1
+ lsls r3, #24
+ lsls r2, r0, #1
+ adds r2, r3
+ bhi 1b
+#endif
+ shimmable_table_tail_call SF_TABLE_FLOAT2DOUBLE float2double_shim
+
+float_wrapper_section srqtf
+wrapper_func_f1 sqrtf
+#if PICO_FLOAT_SUPPORT_ROM_V1
+ // check for negative
+ asrs r1, r0, #23
+ bmi 1f
+#endif
+ table_tail_call SF_TABLE_FSQRT
+#if PICO_FLOAT_SUPPORT_ROM_V1
+1:
+ mvns r0, r1
+ cmp r0, #255
+ bne 2f
+ // -0 or -Denormal return -0 (0x80000000)
+ lsls r0, #31
+ bx lr
+2:
+ // return -Inf (0xff800000)
+ asrs r0, r1, #31
+ lsls r0, #23
+ bx lr
+#endif
+
+float_wrapper_section cosf
+// note we don't use _f1 since we do an infinity/nan check for outside of range
+wrapper_func cosf
+ // rom version only works for -128 < angle < 128
+ lsls r1, r0, #1
+ lsrs r1, #24
+ cmp r1, #127 + 7
+ bge 1f
+2:
+ table_tail_call SF_TABLE_FCOS
+1:
+#if PICO_FLOAT_PROPAGATE_NANS
+ // also check for infinites
+ cmp r1, #255
+ bne 3f
+ // infinite to nan
+ movs r1, #1
+ lsls r1, #22
+ orrs r0, r1
+ bx lr
+3:
+#endif
+ ldr r1, =0x40c90fdb // 2 * M_PI
+ push {lr}
+ bl remainderf
+ pop {r1}
+ mov lr, r1
+ b 2b
+
+float_wrapper_section sinf
+// note we don't use _f1 since we do an infinity/nan check for outside of range
+wrapper_func sinf
+ // rom version only works for -128 < angle < 128
+ lsls r1, r0, #1
+ lsrs r1, #24
+ cmp r1, #127 + 7
+ bge 1f
+2:
+ table_tail_call SF_TABLE_FSIN
+1:
+#if PICO_FLOAT_PROPAGATE_NANS
+ // also check for infinites
+ cmp r1, #255
+ bne 3f
+ // infinite to nan
+ movs r1, #1
+ lsls r1, #22
+ orrs r0, r1
+ bx lr
+3:
+#endif
+ ldr r1, =0x40c90fdb // 2 * M_PI
+ push {lr}
+ bl remainderf
+ pop {r1}
+ mov lr, r1
+ b 2b
+
+float_wrapper_section sincosf
+// note we don't use _f1 since we do an infinity/nan check for outside of range
+wrapper_func sincosf
+ push {r1, r2, lr}
+ // rom version only works for -128 < angle < 128
+ lsls r3, r0, #1
+ lsrs r3, #24
+ cmp r3, #127 + 7
+ bge 3f
+2:
+ ldr r3, =sf_table
+ ldr r3, [r3, #SF_TABLE_FSIN]
+ blx r3
+ pop {r2, r3}
+ str r0, [r2]
+ str r1, [r3]
+ pop {pc}
+#if PICO_FLOAT_PROPAGATE_NANS
+.align 2
+ pop {pc}
+#endif
+3:
+#if PICO_FLOAT_PROPAGATE_NANS
+ // also check for infinites
+ cmp r3, #255
+ bne 4f
+ // infinite to nan
+ movs r3, #1
+ lsls r3, #22
+ orrs r0, r3
+ str r0, [r1]
+ str r0, [r2]
+ add sp, #12
+ bx lr
+4:
+#endif
+ ldr r1, =0x40c90fdb // 2 * M_PI
+ push {lr}
+ bl remainderf
+ pop {r1}
+ mov lr, r1
+ b 2b
+
+float_wrapper_section tanf
+// note we don't use _f1 since we do an infinity/nan check for outside of range
+wrapper_func tanf
+ // rom version only works for -128 < angle < 128
+ lsls r1, r0, #1
+ lsrs r1, #24
+ cmp r1, #127 + 7
+ bge 1f
+2:
+ table_tail_call SF_TABLE_FTAN
+1:
+#if PICO_FLOAT_PROPAGATE_NANS
+ // also check for infinites
+ cmp r1, #255
+ bne 3f
+ // infinite to nan
+ movs r1, #1
+ lsls r1, #22
+ orrs r0, r1
+ bx lr
+3:
+#endif
+ ldr r1, =0x40c90fdb // 2 * M_PI
+ push {lr}
+ bl remainderf
+ pop {r1}
+ mov lr, r1
+ b 2b
+
+float_wrapper_section atan2f
+wrapper_func_f2 atan2f
+ shimmable_table_tail_call SF_TABLE_FATAN2 fatan2_shim
+
+float_wrapper_section expf
+wrapper_func_f1 expf
+ table_tail_call SF_TABLE_FEXP
+
+float_wrapper_section logf
+wrapper_func_f1 logf
+ table_tail_call SF_TABLE_FLN
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_init_rom.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_init_rom.c
new file mode 100644
index 00000000000..3dbefa67465
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_init_rom.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include
+#include "pico/bootrom.h"
+#include "pico/bootrom/sf_table.h"
+
+// NOTE THIS FUNCTION TABLE IS NOT PUBLIC OR NECESSARILY COMPLETE...
+// IT IS ***NOT*** SAFE TO CALL THESE FUNCTION POINTERS FROM ARBITRARY CODE
+uint32_t sf_table[SF_TABLE_V2_SIZE / 2];
+void *sf_clz_func;
+
+#if !PICO_FLOAT_SUPPORT_ROM_V1
+static __attribute__((noreturn)) void missing_float_func_shim() {
+ panic("");
+}
+#endif
+
+void __aeabi_float_init() {
+ int rom_version = rp2040_rom_version();
+ void *rom_table = rom_data_lookup(rom_table_code('S', 'F'));
+#if PICO_FLOAT_SUPPORT_ROM_V1
+ if (rom_version == 1) {
+ memcpy(&sf_table, rom_table, SF_TABLE_V1_SIZE);
+ extern void float_table_shim_on_use_helper();
+ // todo replace NDEBUG with a more exclusive assertion guard
+#ifndef NDEBUG
+ if (*(uint16_t *)0x29ee != 0x0fc4 || // this is packx
+ *(uint16_t *)0x29c0 != 0x0dc2 || // this is upackx
+ *(uint16_t *)0x2b96 != 0xb5c0 || // this is cordic_vec
+ *(uint16_t *)0x2b18 != 0x2500 || // this is packretns
+ *(uint16_t *)0x2acc != 0xb510 || // this is float2fix
+ *(uint32_t *)0x2cfc != 0x6487ed51 // pi_q29
+ ) {
+ panic("");
+ }
+#endif
+
+ // this is a little tricky.. we only want to pull in a shim if the corresponding function
+ // is called. to that end we include a SVC instruction with the table offset as the call number
+ // followed by the shim function pointer inside the actual wrapper function. that way if the wrapper
+ // function is garbage collected, so is the shim function.
+ //
+ // float_table_shim_on_use_helper expects this SVC instruction in the calling code soon after the address
+ // pointed to by IP and patches the float_table entry with the real shim the first time the function is called.
+
+ for(uint i=SF_TABLE_V1_SIZE/4; i= 2) {
+ assert(*((uint8_t *)(rom_table-2)) * 4 >= SF_TABLE_V2_SIZE);
+ memcpy(&sf_table, rom_table, SF_TABLE_V2_SIZE);
+ }
+ sf_clz_func = rom_func_lookup(rom_table_code('L', '3'));
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_math.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_math.c
new file mode 100644
index 00000000000..e54c8688039
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_math.c
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico/types.h"
+#include "pico/float.h"
+#include "pico/platform.h"
+
+typedef uint32_t ui32;
+typedef int32_t i32;
+
+#define PINF ( HUGE_VAL)
+#define MINF (-HUGE_VAL)
+#define NANF ((float)NAN)
+#define PZERO (+0.0)
+#define MZERO (-0.0)
+
+#define PI 3.14159265358979323846
+#define LOG2 0.69314718055994530941
+// Unfortunately in double precision ln(10) is very close to half-way between to representable numbers
+#define LOG10 2.30258509299404568401
+#define LOG2E 1.44269504088896340737
+#define LOG10E 0.43429448190325182765
+#define ONETHIRD 0.33333333333333333333
+
+#define PIf 3.14159265358979323846f
+#define LOG2f 0.69314718055994530941f
+#define LOG2Ef 1.44269504088896340737f
+#define LOG10Ef 0.43429448190325182765f
+#define ONETHIRDf 0.33333333333333333333f
+
+#define FUNPACK(x,e,m) e=((x)>>23)&0xff,m=((x)&0x007fffff)|0x00800000
+#define FUNPACKS(x,s,e,m) s=((x)>>31),FUNPACK((x),(e),(m))
+
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wstrict-aliasing\"")
+
+static inline bool fisnan(float x) {
+ ui32 ix=*(i32*)&x;
+ return ix * 2 > 0xff000000u;
+}
+
+#if PICO_FLOAT_PROPAGATE_NANS
+#define check_nan_f1(x) if (fisnan((x))) return (x)
+#define check_nan_f2(x,y) if (fisnan((x))) return (x); else if (fisnan((y))) return (y);
+#else
+#define check_nan_f1(x) ((void)0)
+#define check_nan_f2(x,y) ((void)0)
+#endif
+
+static inline int fgetsignexp(float x) {
+ ui32 ix=*(ui32*)&x;
+ return (ix>>23)&0x1ff;
+}
+
+static inline int fgetexp(float x) {
+ ui32 ix=*(ui32*)&x;
+ return (ix>>23)&0xff;
+}
+
+static inline float fldexp(float x,int de) {
+ ui32 ix=*(ui32*)&x,iy;
+ int e;
+ e=fgetexp(x);
+ if(e==0||e==0xff) return x;
+ e+=de;
+ if(e<=0) iy=ix&0x80000000; // signed zero for underflow
+ else if(e>=0xff) iy=(ix&0x80000000)|0x7f800000ULL; // signed infinity on overflow
+ else iy=ix+((ui32)de<<23);
+ return *(float*)&iy;
+}
+
+float WRAPPER_FUNC(ldexpf)(float x, int de) {
+ check_nan_f1(x);
+ return fldexp(x, de);
+}
+
+static inline float fcopysign(float x,float y) {
+ ui32 ix=*(ui32*)&x,iy=*(ui32*)&y;
+ ix=((ix&0x7fffffff)|(iy&0x80000000));
+ return *(float*)&ix;
+}
+
+float WRAPPER_FUNC(copysignf)(float x, float y) {
+ check_nan_f2(x,y);
+ return fcopysign(x, y);
+}
+
+static inline int fiszero(float x) { return fgetexp (x)==0; }
+static inline int fispzero(float x) { return fgetsignexp(x)==0; }
+static inline int fismzero(float x) { return fgetsignexp(x)==0x100; }
+static inline int fisinf(float x) { return fgetexp (x)==0xff; }
+static inline int fispinf(float x) { return fgetsignexp(x)==0xff; }
+static inline int fisminf(float x) { return fgetsignexp(x)==0x1ff; }
+
+static inline int fisint(float x) {
+ ui32 ix=*(ui32*)&x,m;
+ int e=fgetexp(x);
+ if(e==0) return 1; // 0 is an integer
+ e-=0x7f; // remove exponent bias
+ if(e<0) return 0; // |x|<1
+ e=23-e; // bit position in mantissa with significance 1
+ if(e<=0) return 1; // |x| large, so must be an integer
+ m=(1<>e)&1;
+}
+
+static inline int fisstrictneg(float x) {
+ ui32 ix=*(ui32*)&x;
+ if(fiszero(x)) return 0;
+ return ix>>31;
+}
+
+static inline int fisneg(float x) {
+ ui32 ix=*(ui32*)&x;
+ return ix>>31;
+}
+
+static inline float fneg(float x) {
+ ui32 ix=*(ui32*)&x;
+ ix^=0x80000000;
+ return *(float*)&ix;
+}
+
+static inline int fispo2(float x) {
+ ui32 ix=*(ui32*)&x;
+ if(fiszero(x)) return 0;
+ if(fisinf(x)) return 0;
+ ix&=0x007fffff;
+ return ix==0;
+}
+
+static inline float fnan_or(float x) {
+#if PICO_FLOAT_PROPAGATE_NANS
+ return NANF;
+#else
+ return x;
+#endif
+}
+
+float WRAPPER_FUNC(truncf)(float x) {
+ check_nan_f1(x);
+ ui32 ix=*(ui32*)&x,m;
+ int e=fgetexp(x);
+ e-=0x7f; // remove exponent bias
+ if(e<0) { // |x|<1
+ ix&=0x80000000;
+ return *(float*)&ix;
+ }
+ e=23-e; // bit position in mantissa with significance 1
+ if(e<=0) return x; // |x| large, so must be an integer
+ m=(1<=4+0x7f) { // |x|>=16?
+ if(!fisneg(x)) return 1; // 1 << exp 2x; avoid generating infinities later
+ else return -1; // 1 >> exp 2x
+ }
+ u=expf(fldexp(x,1));
+ return (u-1.0f)/(u+1.0f);
+}
+
+float WRAPPER_FUNC(asinhf)(float x) {
+ check_nan_f1(x);
+ int e;
+ e=fgetexp(x);
+ if(e>=16+0x7f) { // |x|>=2^16?
+ if(!fisneg(x)) return logf( x )+LOG2f; // 1/x^2 << 1
+ else return fneg(logf(fneg(x))+LOG2f); // 1/x^2 << 1
+ }
+ if(x>0) return (float)log(sqrt((double)x*(double)x+1.0)+(double)x);
+ else return fneg((float)log(sqrt((double)x*(double)x+1.0)-(double)x));
+}
+
+float WRAPPER_FUNC(acoshf)(float x) {
+ check_nan_f1(x);
+ int e;
+ if(fisneg(x)) x=fneg(x);
+ e=fgetexp(x);
+ if(e>=16+0x7f) return logf(x)+LOG2f; // |x|>=2^16?
+ return (float)log(sqrt(((double)x+1.0)*((double)x-1.0))+(double)x);
+}
+
+float WRAPPER_FUNC(atanhf)(float x) {
+ check_nan_f1(x);
+ return fldexp(logf((1.0f+x)/(1.0f-x)),-1);
+}
+
+float WRAPPER_FUNC(exp2f)(float x) { check_nan_f1(x); return (float)exp((double)x*LOG2); }
+float WRAPPER_FUNC(log2f)(float x) { check_nan_f1(x); return logf(x)*LOG2Ef; }
+float WRAPPER_FUNC(exp10f)(float x) { check_nan_f1(x); return (float)exp((double)x*LOG10); }
+float WRAPPER_FUNC(log10f)(float x) { check_nan_f1(x); return logf(x)*LOG10Ef; }
+
+float WRAPPER_FUNC(expm1f)(float x) { check_nan_f1(x); return (float)(exp((double)x)-1); }
+float WRAPPER_FUNC(log1pf)(float x) { check_nan_f1(x); return (float)(log(1+(double)x)); }
+float WRAPPER_FUNC(fmaf)(float x,float y,float z) {
+ check_nan_f2(x,y);
+ check_nan_f1(z);
+ return (float)((double)x*(double)y+(double)z);
+} // has double rounding so not exact
+
+// general power, x>0
+static inline float fpow_1(float x,float y) {
+ return (float)exp(log((double)x)*(double)y); // using double-precision intermediates for better accuracy
+}
+
+static float fpow_int2(float x,int y) {
+ float u;
+ if(y==1) return x;
+ u=fpow_int2(x,y/2);
+ u*=u;
+ if(y&1) u*=x;
+ return u;
+}
+
+// for the case where x not zero or infinity, y small and not zero
+static inline float fpowint_1(float x,int y) {
+ if(y<0) x=1.0f/x,y=-y;
+ return fpow_int2(x,y);
+}
+
+// for the case where x not zero or infinity
+static float fpowint_0(float x,int y) {
+ int e;
+ if(fisneg(x)) {
+ if(fisoddint(y)) return fneg(fpowint_0(fneg(x),y));
+ else return fpowint_0(fneg(x),y);
+ }
+ if(fispo2(x)) {
+ e=fgetexp(x)-0x7f;
+ if(y>=256) y= 255; // avoid overflow
+ if(y<-256) y=-256;
+ y*=e;
+ return fldexp(1,y);
+ }
+ if(y==0) return 1;
+ if(y>=-32&&y<=32) return fpowint_1(x,y);
+ return fpow_1(x,y);
+}
+
+float WRAPPER_FUNC(powintf)(float x,int y) {
+ _Pragma("GCC diagnostic push")
+ _Pragma("GCC diagnostic ignored \"-Wfloat-equal\"")
+ if(x==1.0f||y==0) return 1;
+ if(x==0.0f) {
+ if(y>0) {
+ if(y&1) return x;
+ else return 0;
+ }
+ if((y&1)) return fcopysign(PINF,x);
+ return PINF;
+ }
+ _Pragma("GCC diagnostic pop")
+ check_nan_f1(x);
+ if(fispinf(x)) {
+ if(y<0) return 0;
+ else return PINF;
+ }
+ if(fisminf(x)) {
+ if(y>0) {
+ if((y&1)) return MINF;
+ else return PINF;
+ }
+ if((y&1)) return MZERO;
+ else return PZERO;
+ }
+ return fpowint_0(x,y);
+}
+
+// for the case where y is guaranteed a finite integer, x not zero or infinity
+static float fpow_0(float x,float y) {
+ int e,p;
+ if(fisneg(x)) {
+ if(fisoddint(y)) return fneg(fpow_0(fneg(x),y));
+ else return fpow_0(fneg(x),y);
+ }
+ p=(int)y;
+ if(fispo2(x)) {
+ e=fgetexp(x)-0x7f;
+ if(p>=256) p= 255; // avoid overflow
+ if(p<-256) p=-256;
+ p*=e;
+ return fldexp(1,p);
+ }
+ if(p==0) return 1;
+ if(p>=-32&&p<=32) return fpowint_1(x,p);
+ return fpow_1(x,y);
+}
+
+float WRAPPER_FUNC(powf)(float x,float y) {
+ _Pragma("GCC diagnostic push")
+ _Pragma("GCC diagnostic ignored \"-Wfloat-equal\"")
+ if(x==1.0f||fiszero(y)) return 1;
+ check_nan_f2(x,y);
+ if(x==-1.0f&&fisinf(y)) return 1;
+ _Pragma("GCC diagnostic pop")
+ if(fiszero(x)) {
+ if(!fisneg(y)) {
+ if(fisoddint(y)) return x;
+ else return 0;
+ }
+ if(fisoddint(y)) return fcopysign(PINF,x);
+ return PINF;
+ }
+ if(fispinf(x)) {
+ if(fisneg(y)) return 0;
+ else return PINF;
+ }
+ if(fisminf(x)) {
+ if(!fisneg(y)) {
+ if(fisoddint(y)) return MINF;
+ else return PINF;
+ }
+ if(fisoddint(y)) return MZERO;
+ else return PZERO;
+ }
+ if(fispinf(y)) {
+ if(fgetexp(x)<0x7f) return PZERO;
+ else return PINF;
+ }
+ if(fisminf(y)) {
+ if(fgetexp(x)<0x7f) return PINF;
+ else return PZERO;
+ }
+ if(fisint(y)) return fpow_0(x,y);
+ if(fisneg(x)) return PINF;
+ return fpow_1(x,y);
+}
+
+float WRAPPER_FUNC(hypotf)(float x,float y) {
+ check_nan_f2(x,y);
+ int ex,ey;
+ ex=fgetexp(x); ey=fgetexp(y);
+ if(ex>=0x7f+50||ey>=0x7f+50) { // overflow, or nearly so
+ x=fldexp(x,-70),y=fldexp(y,-70);
+ return fldexp(sqrtf(x*x+y*y), 70);
+ }
+ else if(ex<=0x7f-50&&ey<=0x7f-50) { // underflow, or nearly so
+ x=fldexp(x, 70),y=fldexp(y, 70);
+ return fldexp(sqrtf(x*x+y*y),-70);
+ }
+ return sqrtf(x*x+y*y);
+}
+
+float WRAPPER_FUNC(cbrtf)(float x) {
+ check_nan_f1(x);
+ int e;
+ if(fisneg(x)) return fneg(cbrtf(fneg(x)));
+ if(fiszero(x)) return fcopysign(PZERO,x);
+ e=fgetexp(x)-0x7f;
+ e=(e*0x5555+0x8000)>>16; // ~e/3, rounded
+ x=fldexp(x,-e*3);
+ x=expf(logf(x)*ONETHIRDf);
+ return fldexp(x,e);
+}
+
+// reduces mx*2^e modulo my, returning bottom bits of quotient at *pquo
+// 2^23<=|mx|,my<2^24, e>=0; 0<=result0) {
+ r=0xffffffffU/(ui32)(my>>7); // reciprocal estimate Q16
+ }
+ while(e>0) {
+ s=e; if(s>12) s=12; // gain up to 12 bits on each iteration
+ q=(mx>>9)*r; // Q30
+ q=((q>>(29-s))+1)>>1; // Q(s), rounded
+ mx=(mx<=my) mx-=my,quo++; // when e==0 mx can be nearly as big as 2my
+ if(mx>=my) mx-=my,quo++;
+ if(mx<0) mx+=my,quo--;
+ if(mx<0) mx+=my,quo--;
+ if(pquo) *pquo=quo;
+ return mx;
+}
+
+float WRAPPER_FUNC(fmodf)(float x,float y) {
+ check_nan_f2(x,y);
+ ui32 ix=*(ui32*)&x,iy=*(ui32*)&y;
+ int sx,ex,ey;
+ i32 mx,my;
+ FUNPACKS(ix,sx,ex,mx);
+ FUNPACK(iy,ey,my);
+ if(ex==0xff) {
+ return fnan_or(PINF);
+ }
+ if(ey==0) return PINF;
+ if(ex==0) {
+ if(!fisneg(x)) return PZERO;
+ return MZERO;
+ }
+ if(ex|y|/2
+ mx-=my+my;
+ ey--;
+ q=1;
+ } else { // x<-|y|/2
+ mx=my+my-mx;
+ ey--;
+ q=-1;
+ }
+ }
+ else {
+ if(sx) mx=-mx;
+ mx=frem_0(mx,my,ex-ey,&q);
+ if(mx+mx>my || (mx+mx==my&&(q&1)) ) { // |x|>|y|/2, or equality and an odd quotient?
+ mx-=my;
+ q++;
+ }
+ }
+ if(sy) q=-q;
+ if(quo) *quo=q;
+ return fix2float(mx,0x7f-ey+23);
+}
+
+float WRAPPER_FUNC(dremf)(float x,float y) { check_nan_f2(x,y); return remquof(x,y,0); }
+
+float WRAPPER_FUNC(remainderf)(float x,float y) { check_nan_f2(x,y); return remquof(x,y,0); }
+
+_Pragma("GCC diagnostic pop") // strict-aliasing
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_none.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_none.S
new file mode 100644
index 00000000000..743a75e3908
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_none.S
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico/asm_helper.S"
+#include "pico/bootrom/sf_table.h"
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+wrapper_func __aeabi_fadd
+wrapper_func __aeabi_fdiv
+wrapper_func __aeabi_fmul
+wrapper_func __aeabi_frsub
+wrapper_func __aeabi_fsub
+wrapper_func __aeabi_cfcmpeq
+wrapper_func __aeabi_cfrcmple
+wrapper_func __aeabi_cfcmple
+wrapper_func __aeabi_fcmpeq
+wrapper_func __aeabi_fcmplt
+wrapper_func __aeabi_fcmple
+wrapper_func __aeabi_fcmpge
+wrapper_func __aeabi_fcmpgt
+wrapper_func __aeabi_fcmpun
+wrapper_func __aeabi_i2f
+wrapper_func __aeabi_l2f
+wrapper_func __aeabi_ui2f
+wrapper_func __aeabi_ul2f
+wrapper_func __aeabi_i2f
+wrapper_func __aeabi_f2iz
+wrapper_func __aeabi_f2lz
+wrapper_func __aeabi_f2uiz
+wrapper_func __aeabi_f2ulz
+wrapper_func sqrtf
+wrapper_func cosf
+wrapper_func sinf
+wrapper_func tanf
+wrapper_func atan2f
+wrapper_func expf
+wrapper_func logf
+wrapper_func ldexpf
+wrapper_func copysignf
+wrapper_func truncf
+wrapper_func floorf
+wrapper_func ceilf
+wrapper_func roundf
+wrapper_func sincosf
+wrapper_func asinf
+wrapper_func acosf
+wrapper_func atanf
+wrapper_func sinhf
+wrapper_func coshf
+wrapper_func tanhf
+wrapper_func asinhf
+wrapper_func acoshf
+wrapper_func atanhf
+wrapper_func exp2f
+wrapper_func log2f
+wrapper_func exp10f
+wrapper_func log10f
+wrapper_func powf
+wrapper_func powintf
+wrapper_func hypotf
+wrapper_func cbrtf
+wrapper_func fmodf
+wrapper_func dremf
+wrapper_func remainderf
+wrapper_func remquof
+wrapper_func expm1f
+wrapper_func log1pf
+wrapper_func fmaf
+ push {lr} // keep stack trace sane
+ ldr r0, =str
+ bl panic
+
+str:
+ .asciz "float support is disabled"
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_v1_rom_shim.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_v1_rom_shim.S
new file mode 100644
index 00000000000..a29925ed376
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/float_v1_rom_shim.S
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico/asm_helper.S"
+
+#if PICO_FLOAT_SUPPORT_ROM_V1
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+#ifndef PICO_FLOAT_IN_RAM
+#define PICO_FLOAT_IN_RAM 0
+#endif
+
+.macro float_section name
+// todo separate flag for shims?
+#if PICO_FLOAT_IN_RAM
+.section RAM_SECTION_NAME(\name), "ax"
+#else
+.section SECTION_NAME(\name), "ax"
+#endif
+.endm
+
+float_section float_table_shim_on_use_helper
+regular_func float_table_shim_on_use_helper
+ push {r0-r2, lr}
+ mov r0, ip
+#ifndef NDEBUG
+ // sanity check to make sure we weren't called by non (shimmable_) table_tail_call macro
+ cmp r0, #0
+ bne 1f
+ bkpt #0
+#endif
+1:
+ ldrh r1, [r0]
+ lsrs r2, r1, #8
+ adds r0, #2
+ cmp r2, #0xdf
+ bne 1b
+ uxtb r1, r1 // r1 holds table offset
+ lsrs r2, r0, #2
+ bcc 1f
+ // unaligned
+ ldrh r2, [r0, #0]
+ ldrh r0, [r0, #2]
+ lsls r0, #16
+ orrs r0, r2
+ b 2f
+1:
+ ldr r0, [r0]
+2:
+ ldr r2, =sf_table
+ str r0, [r2, r1]
+ str r0, [sp, #12]
+ pop {r0-r2, pc}
+
+float_section 642float_shims
+
+@ convert uint64 to float, rounding
+regular_func uint642float_shim
+ movs r2,#0 @ fall through
+
+@ convert unsigned 64-bit fix to float, rounding; number of r0:r1 bits after point in r2
+regular_func ufix642float_shim
+ push {r4,r5,r14}
+ cmp r1,#0
+ bpl 3f @ positive? we can use signed code
+ lsls r5,r1,#31 @ contribution to sticky bits
+ orrs r5,r0
+ lsrs r0,r1,#1
+ subs r2,#1
+ b 4f
+
+@ convert int64 to float, rounding
+regular_func int642float_shim
+ movs r2,#0 @ fall through
+
+@ convert signed 64-bit fix to float, rounding; number of r0:r1 bits after point in r2
+regular_func fix642float_shim
+ push {r4,r5,r14}
+3:
+ movs r5,r0
+ orrs r5,r1
+ beq ret_pop45 @ zero? return +0
+ asrs r5,r1,#31 @ sign bits
+2:
+ asrs r4,r1,#24 @ try shifting 7 bits at a time
+ cmp r4,r5
+ bne 1f @ next shift will overflow?
+ lsls r1,#7
+ lsrs r4,r0,#25
+ orrs r1,r4
+ lsls r0,#7
+ adds r2,#7
+ b 2b
+1:
+ movs r5,r0
+ movs r0,r1
+4:
+ rsbs r2,#0
+ adds r2,#32+29
+
+ // bl packx
+ ldr r1, =0x29ef // packx
+ blx r1
+ret_pop45:
+ pop {r4,r5,r15}
+
+float_section fatan2_shim
+regular_func fatan2_shim
+ push {r4,r5,r14}
+
+ ldr r4, =0x29c1 // unpackx
+ mov ip, r4
+@ unpack arguments and shift one down to have common exponent
+ blx ip
+ mov r4,r0
+ mov r0,r1
+ mov r1,r4
+ mov r4,r2
+ mov r2,r3
+ mov r3,r4
+ blx ip
+ lsls r0,r0,#5 @ Q28
+ lsls r1,r1,#5 @ Q28
+ adds r4,r2,r3 @ this is -760 if both arguments are 0 and at least -380-126=-506 otherwise
+ asrs r4,#9
+ adds r4,#1
+ bmi 2f @ force y to 0 proper, so result will be zero
+ subs r4,r2,r3 @ calculate shift
+ bge 1f @ ex>=ey?
+ rsbs r4,#0 @ make shift positive
+ asrs r0,r4
+ cmp r4,#28
+ blo 3f
+ asrs r0,#31
+ b 3f
+1:
+ asrs r1,r4
+ cmp r4,#28
+ blo 3f
+2:
+@ here |x|>>|y| or both x and y are ±0
+ cmp r0,#0
+ bge 4f @ x positive, return signed 0
+ ldr r3, =0x2cfc @ &pi_q29, circular coefficients
+ ldr r0,[r3] @ x negative, return +/- pi
+ asrs r1,#31
+ eors r0,r1
+ b 7f
+4:
+ asrs r0,r1,#31
+ b 7f
+3:
+ movs r2,#0 @ initial angle
+ ldr r3, =0x2cfc @ &pi_q29, circular coefficients
+ cmp r0,#0 @ x negative
+ bge 5f
+ rsbs r0,#0 @ rotate to 1st/4th quadrants
+ rsbs r1,#0
+ ldr r2,[r3] @ pi Q29
+5:
+ movs r4,#1 @ m=1
+ ldr r5, =0x2b97 @ cordic_vec
+ blx r5 @ also produces magnitude (with scaling factor 1.646760119), which is discarded
+ mov r0,r2 @ result here is -pi/2..3pi/2 Q29
+@ asrs r2,#29
+@ subs r0,r2
+ ldr r3, =0x2cfc @ &pi_q29, circular coefficients
+ ldr r2,[r3] @ pi Q29
+ adds r4,r0,r2 @ attempt to fix -3pi/2..-pi case
+ bcs 6f @ -pi/2..0? leave result as is
+ subs r4,r0,r2 @ pi: take off 2pi
+6:
+ subs r0,#1 @ fiddle factor so atan2(0,1)==0
+7:
+ movs r2,#0 @ exponent for pack
+ ldr r3, =0x2b19
+ bx r3
+
+float_section float232_shims
+
+regular_func float2int_shim
+ movs r1,#0 @ fall through
+regular_func float2fix_shim
+ // check for -0 or -denormal upfront
+ asrs r2, r0, #23
+ adds r2, #128
+ adds r2, #128
+ beq 1f
+ // call original
+ ldr r2, =0x2acd
+ bx r2
+ 1:
+ movs r0, #0
+ bx lr
+
+float_section float264_shims
+
+regular_func float2int64_shim
+ movs r1,#0 @ and fall through
+regular_func float2fix64_shim
+ push {r14}
+ bl f2fix
+ b d2f64_a
+
+regular_func float2uint64_shim
+ movs r1,#0 @ and fall through
+regular_func float2ufix64_shim
+ asrs r3,r0,#23 @ negative? return 0
+ bmi ret_dzero
+@ and fall through
+
+@ convert float in r0 to signed fixed point in r0:r1:r3, r1 places after point, rounding towards -Inf
+@ result clamped so that r3 can only be 0 or -1
+@ trashes r12
+.thumb_func
+f2fix:
+ push {r4,r14}
+ mov r12,r1
+ asrs r3,r0,#31
+ lsls r0,#1
+ lsrs r2,r0,#24
+ beq 1f @ zero?
+ cmp r2,#0xff @ Inf?
+ beq 2f
+ subs r1,r2,#1
+ subs r2,#0x7f @ remove exponent bias
+ lsls r1,#24
+ subs r0,r1 @ insert implied 1
+ eors r0,r3
+ subs r0,r3 @ top two's complement
+ asrs r1,r0,#4 @ convert to double format
+ lsls r0,#28
+ ldr r4, =d2fix_a
+ bx r4
+1:
+ movs r0,#0
+ movs r1,r0
+ movs r3,r0
+ pop {r4,r15}
+2:
+ mvns r0,r3 @ return max/min value
+ mvns r1,r3
+ pop {r4,r15}
+
+ret_dzero:
+ movs r0,#0
+ movs r1,#0
+ bx r14
+
+float_section d2fix_a_float
+
+.weak d2fix_a // weak because it exists in float shims too
+.thumb_func
+d2fix_a:
+@ here
+@ r0:r1 two's complement mantissa
+@ r2 unbaised exponent
+@ r3 mantissa sign extension bits
+ add r2,r12 @ exponent plus offset for required binary point position
+ subs r2,#52 @ required shift
+ bmi 1f @ shift down?
+@ here a shift up by r2 places
+ cmp r2,#12 @ will clamp?
+ bge 2f
+ movs r4,r0
+ lsls r1,r2
+ lsls r0,r2
+ rsbs r2,#0
+ adds r2,#32 @ complementary shift
+ lsrs r4,r2
+ orrs r1,r4
+ pop {r4,r15}
+2:
+ mvns r0,r3
+ mvns r1,r3 @ overflow: clamp to extreme fixed-point values
+ pop {r4,r15}
+1:
+@ here a shift down by -r2 places
+ adds r2,#32
+ bmi 1f @ long shift?
+ mov r4,r1
+ lsls r4,r2
+ rsbs r2,#0
+ adds r2,#32 @ complementary shift
+ asrs r1,r2
+ lsrs r0,r2
+ orrs r0,r4
+ pop {r4,r15}
+1:
+@ here a long shift down
+ movs r0,r1
+ asrs r1,#31 @ shift down 32 places
+ adds r2,#32
+ bmi 1f @ very long shift?
+ rsbs r2,#0
+ adds r2,#32
+ asrs r0,r2
+ pop {r4,r15}
+1:
+ movs r0,r3 @ result very near zero: use sign extension bits
+ movs r1,r3
+ pop {r4,r15}
+d2f64_a:
+ asrs r2,r1,#31
+ cmp r2,r3
+ bne 1f @ sign extension bits fail to match sign of result?
+ pop {r15}
+1:
+ mvns r0,r3
+ movs r1,#1
+ lsls r1,#31
+ eors r1,r1,r0 @ generate extreme fixed-point values
+ pop {r15}
+
+float_section float2double_shim
+regular_func float2double_shim
+ lsrs r3,r0,#31 @ sign bit
+ lsls r3,#31
+ lsls r1,r0,#1
+ lsrs r2,r1,#24 @ exponent
+ beq 1f @ zero?
+ cmp r2,#0xff @ Inf?
+ beq 2f
+ lsrs r1,#4 @ exponent and top 20 bits of mantissa
+ ldr r2,=#(0x3ff-0x7f)<<20 @ difference in exponent offsets
+ adds r1,r2
+ orrs r1,r3
+ lsls r0,#29 @ bottom 3 bits of mantissa
+ bx r14
+1:
+ movs r1,r3 @ return signed zero
+3:
+ movs r0,#0
+ bx r14
+2:
+ ldr r1,=#0x7ff00000 @ return signed infinity
+ adds r1,r3
+ b 3b
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/include/pico/float.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/include/pico/float.h
new file mode 100644
index 00000000000..8b06ea8c025
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/include/pico/float.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_FLOAT_H
+#define _PICO_FLOAT_H
+
+#include
+#include
+#include "pico/types.h"
+#include "pico/bootrom/sf_table.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file float.h
+* \defgroup pico_float pico_float
+*
+* Optimized single-precision floating point functions
+*
+* (Replacement) optimized implementations are provided of the following compiler built-ins
+* and math library functions:
+*
+* - __aeabi_fadd, __aeabi_fdiv, __aeabi_fmul, __aeabi_frsub, __aeabi_fsub, __aeabi_cfcmpeq, __aeabi_cfrcmple, __aeabi_cfcmple, __aeabi_fcmpeq, __aeabi_fcmplt, __aeabi_fcmple, __aeabi_fcmpge, __aeabi_fcmpgt, __aeabi_fcmpun, __aeabi_i2f, __aeabi_l2f, __aeabi_ui2f, __aeabi_ul2f, __aeabi_f2iz, __aeabi_f2lz, __aeabi_f2uiz, __aeabi_f2ulz, __aeabi_f2d, sqrtf, cosf, sinf, tanf, atan2f, expf, logf
+* - ldexpf, copysignf, truncf, floorf, ceilf, roundf, asinf, acosf, atanf, sinhf, coshf, tanhf, asinhf, acoshf, atanhf, exp2f, log2f, exp10f, log10f, powf, hypotf, cbrtf, fmodf, dremf, remainderf, remquof, expm1f, log1pf, fmaf
+* - powintf, sincosf (GNU extensions)
+*
+* The following additional optimized functions are also provided:
+*
+* - fix2float, ufix2float, fix642float, ufix642float, float2fix, float2ufix, float2fix64, float2ufix64, float2int, float2int64, float2int_z, float2int64_z
+*/
+
+float fix2float(int32_t m, int e);
+float ufix2float(uint32_t m, int e);
+float fix642float(int64_t m, int e);
+float ufix642float(uint64_t m, int e);
+
+// These methods round towards -Infinity.
+int32_t float2fix(float f, int e);
+uint32_t float2ufix(float f, int e);
+int64_t float2fix64(float f, int e);
+uint64_t float2ufix64(float f, int e);
+int32_t float2int(float f);
+int64_t float2int64(float f);
+
+// These methods round towards 0.
+int32_t float2int_z(float f);
+int64_t float2int64_z(float f);
+
+float exp10f(float x);
+void sincosf(float x, float *sinx, float *cosx);
+float powintf(float x, int y);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/include/placeholder.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_float/include/placeholder.h
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_int64_ops/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_int64_ops/CMakeLists.txt
new file mode 100644
index 00000000000..b589bed22a6
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_int64_ops/CMakeLists.txt
@@ -0,0 +1,44 @@
+if (NOT TARGET pico_int64_ops)
+
+ #shims for ROM functions for -lgcc functions (listed below)
+ add_library(pico_int64_ops INTERFACE)
+
+ # no custom implementation; falls thru to compiler
+ add_library(pico_int64_ops_compiler INTERFACE)
+ # PICO_BUILD_DEFINE: PICO_INT64_OPS_COMPILER, whether compiler provided int64_ops multiplication support is being used, type=bool, default=0, but dependent on CMake options, group=pico_int64_ops
+ target_compile_definitions(pico_int64_ops_compiler INTERFACE
+ PICO_INT64_OPS_COMPILER=1
+ )
+
+ # add alias "default" which is just pico.
+ add_library(pico_int64_ops_default INTERFACE)
+ target_link_libraries(pico_int64_ops_default INTERFACE pico_int64_ops_pico)
+
+ set(PICO_DEFAULT_INT64_OPS_IMPL pico_int64_ops_default)
+
+ target_link_libraries(pico_int64_ops INTERFACE
+ $>,$,${PICO_DEFAULT_INT64_OPS_IMPL}>)
+
+ add_library(pico_int64_ops_pico INTERFACE)
+ target_include_directories(pico_int64_ops_pico INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
+ target_sources(pico_int64_ops_pico INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/pico_int64_ops_aeabi.S
+ )
+
+ # PICO_BUILD_DEFINE: PICO_INT64_OPS_PICO, whether optimized pico/bootrom provided int64_ops multiplication support is being used, type=bool, default=1, but dependent on CMake options, group=pico_int64_ops
+ target_compile_definitions(pico_int64_ops_pico INTERFACE
+ PICO_INT64_OPS_PICO=1
+ )
+
+ pico_wrap_function(pico_int64_ops_pico __aeabi_lmul)
+
+ macro(pico_set_int64_ops_implementation TARGET IMPL)
+ get_target_property(target_type ${TARGET} TYPE)
+ if ("EXECUTABLE" STREQUAL "${target_type}")
+ set_target_properties(${TARGET} PROPERTIES PICO_TARGET_INT64_OPS_IMPL "pico_int64_ops_${IMPL}")
+ else()
+ message(FATAL_ERROR "int64_ops implementation must be set on executable not library")
+ endif()
+ endmacro()
+endif()
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_int64_ops/include/pico/int64_ops.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_int64_ops/include/pico/int64_ops.h
new file mode 100644
index 00000000000..db3213ef92b
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_int64_ops/include/pico/int64_ops.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_INT64_H
+#define _PICO_INT64_H
+
+#include "pico/types.h"
+
+/** \file int64_ops.h
+ * \defgroup pico_int64_ops pico_int64_ops
+ *
+ * Optimized replacement implementations of the compiler built-in 64 bit multiplication
+ *
+ * This library does not provide any additional functions
+*/
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S
new file mode 100644
index 00000000000..903820bff33
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+#include "pico/asm_helper.S"
+
+.section SECTION_NAME(__aeabi_lmul)
+wrapper_func __aeabi_lmul
+ muls r1, r2
+ muls r3, r0
+ adds r1, r3
+ mov r12, r1
+ lsrs r1, r2, #16
+ uxth r3, r0
+ muls r3, r1
+ push {r4}
+ lsrs r4, r0, #16
+ muls r1, r4
+ uxth r2, r2
+ uxth r0, r0
+ muls r0, r2
+ muls r2, r4
+ lsls r4, r3, #16
+ lsrs r3, #16
+ adds r0, r4
+ pop {r4}
+ adcs r1, r3
+ lsls r3, r2, #16
+ lsrs r2, #16
+ adds r0, r3
+ adcs r1, r2
+ add r1, r12
+ bx lr
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_malloc/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_malloc/CMakeLists.txt
new file mode 100644
index 00000000000..fddacc90c7a
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_malloc/CMakeLists.txt
@@ -0,0 +1,14 @@
+if (NOT TARGET pico_malloc)
+ #shims for ROM functions for -lgcc functions (listed below)
+ add_library(pico_malloc INTERFACE)
+
+ target_sources(pico_malloc INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/pico_malloc.c
+ )
+
+ pico_wrap_function(pico_malloc malloc)
+ pico_wrap_function(pico_malloc calloc)
+ pico_wrap_function(pico_malloc free)
+
+ target_link_libraries(pico_malloc INTERFACE pico_sync)
+endif()
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_malloc/include/pico/malloc.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_malloc/include/pico/malloc.h
new file mode 100644
index 00000000000..e84dd4d16cf
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_malloc/include/pico/malloc.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_MALLOC_H
+#define _PICO_MALLOC_H
+
+/** \file malloc.h
+* \defgroup pico_malloc pico_malloc
+*
+* Multi-core safety for malloc, calloc and free
+*
+* This library does not provide any additional functions
+*/
+
+// PICO_CONFIG: PICO_USE_MALLOC_MUTEX, Whether to protect malloc etc with a mutex, type=bool, default=1 with pico_multicore, 0 otherwise, group=pico_malloc
+#if PICO_MULTICORE && !defined(PICO_USE_MALLOC_MUTEX)
+#define PICO_USE_MALLOC_MUTEX 1
+#endif
+
+// PICO_CONFIG: PICO_MALLOC_PANIC, Enable/disable panic when an allocation failure occurs, type=bool, default=1, group=pico_malloc
+#ifndef PICO_MALLOC_PANIC
+#define PICO_MALLOC_PANIC 1
+#endif
+
+// PICO_CONFIG: PICO_DEBUG_MALLOC, Enable/disable debug printf from malloc, type=bool, default=0, group=pico_malloc
+#ifndef PICO_DEBUG_MALLOC
+#define PICO_DEBUG_MALLOC 0
+#endif
+
+// PICO_CONFIG: PICO_DEBUG_MALLOC_LOW_WATER, Define the lower bound for allocation addresses to be printed by PICO_DEBUG_MALLOC, min=0, default=0, group=pico_malloc
+#ifndef PICO_DEBUG_MALLOC_LOW_WATER
+#define PICO_DEBUG_MALLOC_LOW_WATER 0
+#endif
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_malloc/pico_malloc.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_malloc/pico_malloc.c
new file mode 100644
index 00000000000..548a48b9e08
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_malloc/pico_malloc.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include
+#include
+#include "pico.h"
+
+#if PICO_USE_MALLOC_MUTEX
+#include "pico/mutex.h"
+auto_init_mutex(malloc_mutex);
+#endif
+
+extern void *__real_malloc(size_t size);
+extern void *__real_calloc(size_t count, size_t size);
+extern void __real_free(void *mem);
+
+extern char __StackLimit; /* Set by linker. */
+
+static inline void check_alloc(void *mem, uint8_t size) {
+#if PICO_MALLOC_PANIC
+ if (!mem || (((char *)mem) + size) > &__StackLimit) {
+ panic("Out of memory");
+ }
+#endif
+}
+
+void *__wrap_malloc(size_t size) {
+#if PICO_USE_MALLOC_MUTEX
+ mutex_enter_blocking(&malloc_mutex);
+#endif
+ void *rc = __real_malloc(size);
+#if PICO_USE_MALLOC_MUTEX
+ mutex_exit(&malloc_mutex);
+#endif
+#ifdef PICO_DEBUG_MALLOC
+ if (!rc || ((uint8_t *)rc) + size > (uint8_t*)PICO_DEBUG_MALLOC_LOW_WATER) {
+ printf("malloc %d %p->%p\n", (uint) size, rc, ((uint8_t *) rc) + size);
+ }
+#endif
+ check_alloc(rc, size);
+ return rc;
+}
+
+void *__wrap_calloc(size_t count, size_t size) {
+#if PICO_USE_MALLOC_MUTEX
+ mutex_enter_blocking(&malloc_mutex);
+#endif
+ void *rc = __real_calloc(count, size);
+#if PICO_USE_MALLOC_MUTEX
+ mutex_exit(&malloc_mutex);
+#endif
+#ifdef PICO_DEBUG_MALLOC
+ if (!rc || ((uint8_t *)rc) + size > (uint8_t*)PICO_DEBUG_MALLOC_LOW_WATER) {
+ printf("calloc %d %p->%p\n", (uint) (count * size), rc, ((uint8_t *) rc) + size);
+ }
+#endif
+ check_alloc(rc, size);
+ return rc;
+}
+
+void __wrap_free(void *mem) {
+#if PICO_USE_MALLOC_MUTEX
+ mutex_enter_blocking(&malloc_mutex);
+#endif
+ __real_free(mem);
+#if PICO_USE_MALLOC_MUTEX
+ mutex_exit(&malloc_mutex);
+#endif
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_mem_ops/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_mem_ops/CMakeLists.txt
new file mode 100644
index 00000000000..20d410a361f
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_mem_ops/CMakeLists.txt
@@ -0,0 +1,52 @@
+if (NOT TARGET pico_mem_ops)
+ #shims for ROM functions for -lgcc functions (listed below)
+ add_library(pico_mem_ops INTERFACE)
+
+ # no custom implementation; falls thru to compiler
+ add_library(pico_mem_ops_compiler INTERFACE)
+ # PICO_BUILD_DEFINE: PICO_MEM_OPS_COMPILER, whether compiler provided mem_ops memcpy etc. support is being used, type=bool, default=0, but dependent on CMake options, group=pico_mem_ops
+ target_compile_definitions(pico_mem_ops_compiler INTERFACE
+ PICO_MEM_OPS_COMPILER=1
+ )
+
+ # add alias "default" which is just pico.
+ add_library(pico_mem_ops_default INTERFACE)
+ target_link_libraries(pico_mem_ops_default INTERFACE pico_mem_ops_pico)
+
+ set(PICO_DEFAULT_MEM_OPS_IMPL pico_mem_ops_default)
+
+ add_library(pico_mem_ops_pico INTERFACE)
+ target_link_libraries(pico_mem_ops INTERFACE
+ $>,$,${PICO_DEFAULT_MEM_OPS_IMPL}>)
+
+ # PICO_BUILD_DEFINE: PICO_MEM_OPS_PICO, whether optimized pico/bootrom provided mem_ops memcpy etc. support is being used, type=bool, default=1, but dependent on CMake options, group=pico_mem_ops
+ target_compile_definitions(pico_mem_ops_pico INTERFACE
+ PICO_MEM_OPS_PICO=1
+ )
+
+
+ target_sources(pico_mem_ops_pico INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/mem_ops_aeabi.S
+ )
+
+
+ target_link_libraries(pico_mem_ops INTERFACE pico_bootrom)
+
+ pico_wrap_function(pico_mem_ops_pico memcpy)
+ pico_wrap_function(pico_mem_ops_pico memset)
+ pico_wrap_function(pico_mem_ops_pico __aeabi_memcpy)
+ pico_wrap_function(pico_mem_ops_pico __aeabi_memset)
+ pico_wrap_function(pico_mem_ops_pico __aeabi_memcpy4)
+ pico_wrap_function(pico_mem_ops_pico __aeabi_memset4)
+ pico_wrap_function(pico_mem_ops_pico __aeabi_memcpy8)
+ pico_wrap_function(pico_mem_ops_pico __aeabi_memset8)
+
+ macro(pico_set_mem_ops_implementation TARGET IMPL)
+ get_target_property(target_type ${TARGET} TYPE)
+ if ("EXECUTABLE" STREQUAL "${target_type}")
+ set_target_properties(${TARGET} PROPERTIES PICO_TARGET_MEM_OPS_IMPL "pico_mem_ops_${IMPL}")
+ else()
+ message(FATAL_ERROR "mem_ops implementation must be set on executable not library")
+ endif()
+ endmacro()
+endif()
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_mem_ops/include/pico/mem_ops.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_mem_ops/include/pico/mem_ops.h
new file mode 100644
index 00000000000..0c224fb7f70
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_mem_ops/include/pico/mem_ops.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_MEMORY_H
+#define _PICO_MEMORY_H
+
+#include "pico/types.h"
+
+/** \file mem_ops.h
+ * \defgroup pico_mem_ops pico_mem_ops
+ *
+ * Provides optimized replacement implementations of the compiler built-in memcpy, memset and related functions:
+ *
+ * - memset, memcpy
+ * - __aeabi_memset, __aeabi_memset4, __aeabi_memset8, __aeabi_memcpy, __aeabi_memcpy4, __aeabi_memcpy8
+ *
+ * This library does not provide any additional functions
+ */
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_mem_ops/mem_ops.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_mem_ops/mem_ops.c
new file mode 100644
index 00000000000..4047d231bcd
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_mem_ops/mem_ops.c
@@ -0,0 +1,7 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico/mem_ops.h"
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_mem_ops/mem_ops_aeabi.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_mem_ops/mem_ops_aeabi.S
new file mode 100644
index 00000000000..e07a9feeec7
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_mem_ops/mem_ops_aeabi.S
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+#include "pico/asm_helper.S"
+
+__pre_init __aeabi_mem_init, 00001
+
+.macro mem_section name
+#if PICO_MEM_IN_RAM
+.section RAM_SECTION_NAME(\name), "ax"
+#else
+.section SECTION_NAME(\name), "ax"
+#endif
+.endm
+
+.equ MEMSET, 0
+.equ MEMCPY, 4
+.equ MEMSET4, 8
+.equ MEMCPY4, 12
+.equ MEM_FUNC_COUNT, 4
+
+# NOTE: All code sections are placed in RAM (at the expense of some veneer cost for calls from flash) because
+# otherwise code using basic c division operators will require XIP flash access.
+
+.section .data.aeabi_mem_funcs
+.global aeabi_mem_funcs, aeabi_mem_funcs_end
+
+.align 2
+aeabi_mem_funcs:
+ .word rom_table_code('M','S')
+ .word rom_table_code('M','C')
+ .word rom_table_code('S','4')
+ .word rom_table_code('C','4')
+aeabi_mem_funcs_end:
+
+.section .text
+regular_func __aeabi_mem_init
+ ldr r0, =aeabi_mem_funcs
+ movs r1, #MEM_FUNC_COUNT
+ ldr r3, =rom_funcs_lookup
+ bx r3
+
+# lump them both together because likely both to be used, in which case doing so saves 1 word
+# and it only costs 1 word if not
+
+// Note from Run-time ABI for the ARM architecture 4.3.4:
+// If there is an attached device with efficient memory copying or clearing operations
+// (such as a DMA engine), its device supplement specifies whether it may be used in
+// implementations of these functions and what effect such use has on the device’s state.
+
+mem_section aeabi_memset_memcpy
+
+wrapper_func __aeabi_memset
+ // args are backwards
+ eors r0, r1
+ eors r1, r0
+ eors r0, r1
+ ldr r3, =aeabi_mem_funcs
+ ldr r3, [r3, #MEMSET]
+ bx r3
+
+wrapper_func __aeabi_memset4
+wrapper_func __aeabi_memset8
+ // args are backwards
+ eors r0, r1
+ eors r1, r0
+ eors r0, r1
+ ldr r3, =aeabi_mem_funcs
+ ldr r3, [r3, #MEMSET4]
+ bx r3
+
+wrapper_func __aeabi_memcpy4
+wrapper_func __aeabi_memcpy8
+ ldr r3, =aeabi_mem_funcs
+ ldr r3, [r3, #MEMCPY4]
+ bx r3
+
+mem_section memset
+
+wrapper_func memset
+ ldr r3, =aeabi_mem_funcs
+ ldr r3, [r3, #MEMSET]
+ bx r3
+
+mem_section memcpy
+wrapper_func __aeabi_memcpy
+wrapper_func memcpy
+ ldr r3, =aeabi_mem_funcs
+ ldr r3, [r3, #MEMCPY]
+ bx r3
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_multicore/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_multicore/CMakeLists.txt
new file mode 100644
index 00000000000..06f378230cd
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_multicore/CMakeLists.txt
@@ -0,0 +1,17 @@
+if (NOT TARGET pico_multicore)
+ add_library(pico_multicore INTERFACE)
+
+ target_sources(pico_multicore INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/multicore.c)
+
+ target_include_directories(pico_multicore INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
+ target_compile_definitions(pico_multicore INTERFACE
+ PICO_MULTICORE=1
+ )
+
+ target_link_libraries(pico_multicore INTERFACE pico_sync)
+endif()
+
+
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_multicore/include/pico/multicore.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_multicore/include/pico/multicore.h
new file mode 100644
index 00000000000..bc0c64d21f7
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_multicore/include/pico/multicore.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_MULTICORE_H
+#define _PICO_MULTICORE_H
+
+#include "pico/types.h"
+#include "pico/sync.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file multicore.h
+ * \defgroup pico_multicore pico_multicore
+ * Adds support for running code on the second processor core (core1)
+ *
+ * \subsection multicore_example Example
+ * \addtogroup pico_multicore
+ * \include multicore.c
+*/
+
+// PICO_CONFIG: PICO_CORE1_STACK_SIZE, Stack size for core 1, min=0x100, max=0x10000, default=PICO_STACK_SIZE/0x800, group=pico_multicore
+#ifndef PICO_CORE1_STACK_SIZE
+#ifdef PICO_STACK_SIZE
+#define PICO_CORE1_STACK_SIZE PICO_STACK_SIZE
+#else
+#define PICO_CORE1_STACK_SIZE 0x800
+#endif
+#endif
+
+/*! \brief Reset Core 1
+ * \ingroup pico_multicore
+ *
+ */
+void multicore_reset_core1();
+
+/*! \brief Run code on core 1
+ * \ingroup pico_multicore
+ *
+ * Reset core1 and enter the given function on core 1 using the default core 1 stack (below core 0 stack)
+ *
+ * \param entry Function entry point, this function should not return.
+ */
+void multicore_launch_core1(void (*entry)(void));
+
+/*! \brief Launch code on core 1 with stack
+ * \ingroup pico_multicore
+ *
+ * Reset core1 and enter the given function on core 1 using the passed stack for core 1
+ */
+void multicore_launch_core1_with_stack(void (*entry)(void), uint32_t *stack_bottom, size_t stack_size_bytes);
+
+/*! \brief Send core 1 to sleep.
+ * \ingroup pico_multicore
+ *
+ */
+void multicore_sleep_core1();
+
+/*! \brief Launch code on core 1 with no stack protection
+ * \ingroup pico_multicore
+ *
+ * Reset core1 and enter the given function using the passed sp as the initial stack pointer.
+ * This is a bare bones functions that does not provide a stack guard even if USE_STACK_GUARDS is defined
+ *
+ */
+void multicore_launch_core1_raw(void (*entry)(void), uint32_t *sp, uint32_t vector_table);
+
+/*!
+ * \defgroup multicore_fifo fifo
+ * \ingroup pico_multicore
+ * \brief Functions for inter-core FIFO
+ *
+ * The RP2040 contains two FIFOs for passing data, messages or ordered events between the two cores. Each FIFO is 32 bits
+ * wide, and 8 entries deep. One of the FIFOs can only be written by core 0, and read by core 1. The other can only be written
+ * by core 1, and read by core 0.
+ */
+
+
+/*! \brief Check the read FIFO to see if there is data waiting
+ * \ingroup multicore_fifo
+ *
+ * \return true if the FIFO has data in it, false otherwise
+ */
+static inline bool multicore_fifo_rvalid() {
+ return !!(sio_hw->fifo_st & SIO_FIFO_ST_VLD_BITS);
+}
+
+/*! \brief Check the FIFO to see if the write FIFO is full
+ * \ingroup multicore_fifo
+ *
+ * @return true if the FIFO is full, false otherwise
+ */
+static inline bool multicore_fifo_wready() {
+ return !!(sio_hw->fifo_st & SIO_FIFO_ST_RDY_BITS);
+}
+
+/*! \brief Push data on to the FIFO.
+ * \ingroup multicore_fifo
+ *
+ * This function will block until there is space for the data to be sent.
+ * Use multicore_fifo_wready() to check if it is possible to write to the
+ * FIFO if you don't want to block.
+ *
+ * \param data A 32 bit value to push on to the FIFO
+ */
+void multicore_fifo_push_blocking(uint32_t data);
+
+bool multicore_fifo_push_timeout_us(uint32_t data, uint64_t timeout_us);
+
+/*! \brief Pop data from the FIFO.
+ * \ingroup multicore_fifo
+ *
+ * This function will block until there is data ready to be read
+ * Use multicore_fifo_rvalid() to check if data is ready to be read if you don't
+ * want to block.
+ *
+ * \return 32 bit unsigned data from the FIFO.
+ */
+uint32_t multicore_fifo_pop_blocking();
+
+bool multicore_fifo_pop_timeout_us(uint64_t timeout_us, uint32_t *out);
+
+/*! \brief Flush any data in the outgoing FIFO
+ * \ingroup multicore_fifo
+ *
+ */
+static inline void multicore_fifo_drain() {
+ while (multicore_fifo_rvalid())
+ (void) sio_hw->fifo_rd;
+}
+
+/*! \brief Clear FIFO interrupt
+ * \ingroup multicore_fifo
+*/
+static inline void multicore_fifo_clear_irq() {
+ // Write any value to clear any interrupts
+ sio_hw->fifo_st = 0xff;
+}
+
+/*! \brief Get FIFO status
+ * \ingroup multicore_fifo
+ *
+ * \return The status as a bitfield
+ *
+ * Bit | Description
+ * ----|------------
+ * 3 | Sticky flag indicating the RX FIFO was read when empty. This read was ignored by the FIFO.
+ * 2 | Sticky flag indicating the TX FIFO was written when full. This write was ignored by the FIFO.
+ * 1 | Value is 1 if this core’s TX FIFO is not full (i.e. if FIFO_WR is ready for more data)
+ * 0 | Value is 1 if this core’s RX FIFO is not empty (i.e. if FIFO_RD is valid)
+*/
+static inline int32_t multicore_fifo_get_status() {
+ return sio_hw->fifo_st;
+}
+
+// call this from the lockout victim thread
+void multicore_lockout_victim_init();
+
+// start locking out the other core (it will be
+bool multicore_lockout_start_timeout_us(uint64_t timeout_us);
+void multicore_lockout_start_blocking();
+
+bool multicore_lockout_end_timeout_us(uint64_t timeout_us);
+void multicore_lockout_end_blocking();
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_multicore/multicore.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_multicore/multicore.c
new file mode 100644
index 00000000000..6b2321f12fc
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_multicore/multicore.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/structs/sio.h"
+#include "pico/time.h"
+#include "hardware/sync.h"
+#include "pico/multicore.h"
+#include "hardware/irq.h"
+#include "hardware/structs/scb.h"
+#include "hardware/regs/psm.h"
+#include "hardware/claim.h"
+#if PICO_USE_STACK_GUARDS
+#include "pico/runtime.h"
+#endif
+
+static inline void multicore_fifo_push_blocking_inline(uint32_t data) {
+ // We wait for the fifo to have some space
+ while (!multicore_fifo_wready())
+ tight_loop_contents();
+
+ sio_hw->fifo_wr = data;
+
+ // Fire off an event to the other core
+ __sev();
+}
+
+void multicore_fifo_push_blocking(uint32_t data) {
+ multicore_fifo_push_blocking_inline(data);
+}
+
+bool multicore_fifo_push_timeout_us(uint32_t data, uint64_t timeout_us) {
+ absolute_time_t end_time = make_timeout_time_us(timeout_us);
+ // We wait for the fifo to have some space
+ while (!multicore_fifo_wready()) {
+ tight_loop_contents();
+ if (time_reached(end_time)) return false;
+ }
+
+ sio_hw->fifo_wr = data;
+
+ // Fire off an event to the other core
+ __sev();
+ return true;
+}
+
+static inline uint32_t multicore_fifo_pop_blocking_inline() {
+ // If nothing there yet, we wait for an event first,
+ // to try and avoid too much busy waiting
+ while (!multicore_fifo_rvalid())
+ __wfe();
+
+ return sio_hw->fifo_rd;
+}
+
+uint32_t multicore_fifo_pop_blocking() {
+ return multicore_fifo_pop_blocking_inline();
+}
+
+bool multicore_fifo_pop_timeout_us(uint64_t timeout_us, uint32_t *out) {
+ absolute_time_t end_time = make_timeout_time_us(timeout_us);
+ // If nothing there yet, we wait for an event first,
+ // to try and avoid too much busy waiting
+ while (!multicore_fifo_rvalid()) {
+ __wfe();
+ if (time_reached(end_time)) return false;
+ }
+
+ *out = sio_hw->fifo_rd;
+ return true;
+}
+
+// Default stack for core1 ... if multicore_launch_core1 is not included then .stack1 section will be garbage collected
+static uint32_t __attribute__((section(".stack1"))) core1_stack[PICO_CORE1_STACK_SIZE / sizeof(uint32_t)];
+
+static void __attribute__ ((naked)) core1_trampoline() {
+ __asm("pop {r0, r1, pc}");
+}
+
+int core1_wrapper(int (*entry)(void), void *stack_base) {
+#if PICO_USE_STACK_GUARDS
+ // install core1 stack guard
+ runtime_install_stack_guard(stack_base);
+#endif
+ irq_init_priorities();
+ return (*entry)();
+}
+
+void multicore_reset_core1() {
+ // Use atomic aliases just in case core 1 is also manipulating some posm state
+ io_rw_32 *power_off = (io_rw_32 *) (PSM_BASE + PSM_FRCE_OFF_OFFSET);
+ io_rw_32 *power_off_set = hw_set_alias(power_off);
+ io_rw_32 *power_off_clr = hw_clear_alias(power_off);
+
+ // Hard-reset core 1.
+ // Reading back confirms the core 1 reset is in the correct state, but also
+ // forces APB IO bridges to fence on any internal store buffering
+ *power_off_set = PSM_FRCE_OFF_PROC1_BITS;
+ while (!(*power_off & PSM_FRCE_OFF_PROC1_BITS)) tight_loop_contents();
+
+ // Bring core 1 back out of reset. It will drain its own mailbox FIFO, then push
+ // a 0 to our mailbox to tell us it has done this.
+ *power_off_clr = PSM_FRCE_OFF_PROC1_BITS;
+}
+
+void multicore_sleep_core1() {
+ multicore_reset_core1();
+ // note we give core1 an invalid stack pointer, as it should not be used
+ // note also if we ge simply passed a function that returned immediately, we'd end up in core1_hang anyway
+ // however that would waste 2 bytes for that function (the horror!)
+ extern void core1_hang(); // in crt0.S
+ multicore_launch_core1_raw(core1_hang, (uint32_t *) -1, scb_hw->vtor);
+}
+
+void multicore_launch_core1_with_stack(void (*entry)(void), uint32_t *stack_bottom, size_t stack_size_bytes) {
+ assert(!(stack_size_bytes & 3u));
+ uint32_t *stack_ptr = stack_bottom + stack_size_bytes / sizeof(uint32_t);
+ // push 2 values onto top of stack for core1_trampoline
+ stack_ptr -= 3;
+ stack_ptr[0] = (uintptr_t) entry;
+ stack_ptr[1] = (uintptr_t) stack_bottom;
+ stack_ptr[2] = (uintptr_t) core1_wrapper;
+ multicore_launch_core1_raw(core1_trampoline, stack_ptr, scb_hw->vtor);
+}
+
+void multicore_launch_core1(void (*entry)(void)) {
+ extern char __StackOneBottom;
+ uint32_t *stack_limit = (uint32_t *) &__StackOneBottom;
+ // hack to reference core1_stack although that pointer is wrong.... core1_stack should always be <= stack_limit, if not boom!
+ uint32_t *stack = core1_stack <= stack_limit ? stack_limit : (uint32_t *) -1;
+ multicore_launch_core1_with_stack(entry, stack, sizeof(core1_stack));
+}
+
+void multicore_launch_core1_raw(void (*entry)(void), uint32_t *sp, uint32_t vector_table) {
+ uint32_t cmd_sequence[] = {0, 0, 1, (uintptr_t) vector_table, (uintptr_t) sp, (uintptr_t) entry};
+
+ uint seq = 0;
+ do {
+ uint cmd = cmd_sequence[seq];
+ // we drain before sending a 0
+ if (!cmd) {
+ multicore_fifo_drain();
+ __sev(); // core 1 may be waiting for fifo space
+ }
+ multicore_fifo_push_blocking(cmd);
+ uint32_t response = multicore_fifo_pop_blocking();
+ // move to next state on correct response otherwise start over
+ seq = cmd == response ? seq + 1 : 0;
+ } while (seq < count_of(cmd_sequence));
+}
+
+#define LOCKOUT_MAGIC_START 0x73a8831e
+#define LOCKOUT_MAGIC_END (LOCKOUT_MAGIC_START ^ -1)
+
+static_assert(SIO_IRQ_PROC1 == SIO_IRQ_PROC0 + 1, "");
+
+static mutex_t lockout_mutex;
+static bool lockout_in_progress;
+
+// note this method is in RAM because lockout is used when writing to flash
+// it only makes inline calls
+static void __isr __not_in_flash_func(multicore_lockout_handler)() {
+ multicore_fifo_clear_irq();
+ while (multicore_fifo_rvalid()) {
+ if (sio_hw->fifo_rd == LOCKOUT_MAGIC_START) {
+ uint32_t save = save_and_disable_interrupts();
+ multicore_fifo_push_blocking_inline(LOCKOUT_MAGIC_START);
+ while (multicore_fifo_pop_blocking_inline() != LOCKOUT_MAGIC_END) {
+ tight_loop_contents(); // not tight but endless potentially
+ }
+ restore_interrupts(save);
+ multicore_fifo_push_blocking_inline(LOCKOUT_MAGIC_END);
+ }
+ }
+}
+
+static void check_lockout_mutex_init() {
+ // use known available lock - we only need it briefly
+ uint32_t save = hw_claim_lock();
+ if (!mutex_is_initialzed(&lockout_mutex)) {
+ mutex_init(&lockout_mutex);
+ }
+ hw_claim_unlock(save);
+}
+
+void multicore_lockout_victim_init() {
+ check_lockout_mutex_init();
+ uint core_num = get_core_num();
+ irq_set_exclusive_handler(SIO_IRQ_PROC0 + core_num, multicore_lockout_handler);
+ irq_set_enabled(SIO_IRQ_PROC0 + core_num, true);
+}
+
+static bool multicore_lockout_handshake(uint32_t magic, absolute_time_t until) {
+ uint irq_num = SIO_IRQ_PROC0 + get_core_num();
+ bool enabled = irq_is_enabled(irq_num);
+ if (enabled) irq_set_enabled(irq_num, false);
+ bool rc = false;
+ do {
+ int64_t next_timeout_us = absolute_time_diff_us(get_absolute_time(), until);
+ if (next_timeout_us < 0) {
+ break;
+ }
+ multicore_fifo_push_timeout_us(magic, next_timeout_us);
+ next_timeout_us = absolute_time_diff_us(get_absolute_time(), until);
+ if (next_timeout_us < 0) {
+ break;
+ }
+ uint32_t word = 0;
+ if (!multicore_fifo_pop_timeout_us(next_timeout_us, &word)) {
+ break;
+ }
+ if (word == magic) {
+ rc = true;
+ }
+ } while (!rc);
+ if (enabled) irq_set_enabled(irq_num, true);
+ return rc;
+}
+
+static bool multicore_lockout_start_block_until(absolute_time_t until) {
+ check_lockout_mutex_init();
+ if (!mutex_enter_block_until(&lockout_mutex, until)) {
+ return false;
+ }
+ hard_assert(!lockout_in_progress);
+ bool rc = multicore_lockout_handshake(LOCKOUT_MAGIC_START, until);
+ lockout_in_progress = rc;
+ mutex_exit(&lockout_mutex);
+ return rc;
+}
+
+bool multicore_lockout_start_timeout_us(uint64_t timeout_us) {
+ return multicore_lockout_start_block_until(make_timeout_time_us(timeout_us));
+}
+
+void multicore_lockout_start_blocking() {
+ multicore_lockout_start_block_until(at_the_end_of_time);
+}
+
+static bool multicore_lockout_end_block_until(absolute_time_t until) {
+ assert(mutex_is_initialzed(&lockout_mutex));
+ if (!mutex_enter_block_until(&lockout_mutex, until)) {
+ return false;
+ }
+ assert(lockout_in_progress);
+ bool rc = multicore_lockout_handshake(LOCKOUT_MAGIC_END, until);
+ if (rc) {
+ lockout_in_progress = false;
+ }
+ mutex_exit(&lockout_mutex);
+ return rc;
+}
+
+bool multicore_lockout_end_timeout_us(uint64_t timeout_us) {
+ return multicore_lockout_end_block_until(make_timeout_time_us(timeout_us));
+}
+
+void multicore_lockout_end_blocking() {
+ multicore_lockout_end_block_until(at_the_end_of_time);
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/CMakeLists.txt
new file mode 100644
index 00000000000..00000f38cf0
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/CMakeLists.txt
@@ -0,0 +1,25 @@
+if (NOT TARGET pico_platform_headers)
+ add_library(pico_platform_headers INTERFACE)
+
+ target_compile_definitions(pico_platform_headers INTERFACE
+ PICO_NO_HARDWARE=0
+ PICO_ON_DEVICE=1
+ PICO_BUILD=1
+ )
+
+ target_include_directories(pico_platform_headers INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
+ target_link_libraries(pico_platform_headers INTERFACE hardware_regs)
+endif()
+
+if (NOT TARGET pico_platform)
+ add_library(pico_platform INTERFACE)
+ target_sources(pico_platform INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/platform.c)
+
+ target_link_libraries(pico_platform INTERFACE pico_platform_headers)
+endif()
+
+function(pico_add_platform_library TARGET)
+ target_link_libraries(pico_platform INTERFACE ${TARGET})
+endfunction()
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/include/pico/asm_helper.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/include/pico/asm_helper.S
new file mode 100644
index 00000000000..050e6a5fb51
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/include/pico/asm_helper.S
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/platform_defs.h"
+#include "pico/config.h"
+
+#define WRAPPER_FUNC_NAME(x) __wrap_##x
+#define SECTION_NAME(x) .text.##x
+#define RAM_SECTION_NAME(x) .time_critical.##x
+#define rom_table_code(c1, c2) ((c1) | ((c2) << 8))
+
+// do not put align in here as it is used mid function sometimes
+.macro regular_func x
+.global \x
+.type \x,%function
+.thumb_func
+\x:
+.endm
+
+.macro regular_func_with_section x
+.section .text.\x
+regular_func \x
+.endm
+
+// do not put align in here as it is used mid function sometimes
+.macro wrapper_func x
+regular_func WRAPPER_FUNC_NAME(\x)
+.endm
+
+.macro __pre_init func, priority_string
+.section .preinit_array.\priority_string
+.align 2
+.word \func
+.endm
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/include/pico/platform.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/include/pico/platform.h
new file mode 100644
index 00000000000..718a5ecab28
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/include/pico/platform.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_PLATFORM_H_
+#define _PICO_PLATFORM_H_
+
+#include
+#include "pico/types.h"
+#include "hardware/platform_defs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file platform.h
+* \defgroup pico_platform pico_platform
+* Compiler definitions for the selected PICO_PLATFORM
+*/
+
+#define __isr
+
+#define __not_in_flash(group) __attribute__((section(".time_critical." group)))
+#define __not_in_flash_func(x) __not_in_flash(__STRING(x)) x
+#define __no_inline_not_in_flash_func(x) __attribute__((noinline)) __not_in_flash_func(x)
+
+// For use with PICO_COPY_TO_RAM:
+#define __in_flash(group) __attribute__((section(".flashdata" group)))
+
+#define __scratch_x(group) __attribute__((section(".scratch_x." group)))
+#define __scratch_y(group) __attribute__((section(".scratch_y." group)))
+
+#define __time_critical_func(x) __not_in_flash_func(x)
+#define __after_data(group) __attribute__((section(".after_data." group)))
+#define __packed_aligned __packed __aligned(4)
+
+#ifndef count_of
+#define count_of(a) (sizeof(a)/sizeof((a)[0]))
+#endif
+
+#ifndef MAX
+#define MAX(a, b) ((a)>(b)?(a):(b))
+#endif
+
+#ifndef MIN
+#define MIN(a, b) ((b)>(a)?(a):(b))
+#endif
+
+#define __uninitialized_ram(group) __attribute__((section(".uninitialized_ram." #group))) group
+
+inline static void __breakpoint() {
+ __asm__("bkpt #0");
+}
+
+// return a 32 bit handle for a raw ptr; DMA chaining for example embeds pointers in 32 bit values
+// which of course does not work if we're running the code natively on a 64 bit platforms. Therefore
+// we provide this macro which allows that code to provide a 64->32 bit mapping in host mode
+#define host_safe_hw_ptr(x) ((uintptr_t)(x))
+
+void __attribute__((noreturn)) panic_unsupported();
+
+void __attribute__((noreturn)) panic(const char *fmt, ...);
+
+bool running_on_fpga();
+uint8_t rp2040_chip_version();
+
+static inline uint8_t rp2040_rom_version() {
+ return *(uint8_t*)0x13;
+}
+
+// called by any tight hardware polling loop... nominally empty, but can be modified for debugging
+static inline void tight_loop_contents() {}
+
+// return a 32 bit handle for a raw ptr; DMA chaining for example embeds pointers in 32 bit values
+// which of course does not work if we're running the code natively on a 64 bit platform for testing.
+// Therefore we provide this function which allows the host runtime to provide a mapping
+#define native_safe_hw_ptr(x) ((uintptr_t)(x))
+
+// multiplies a by b using multiply instruction using the ARM mul instruction regardless of values
+inline static int32_t __mul_instruction(int32_t a, int32_t b) {
+asm ("mul %0, %1" : "+l" (a) : "l" (b) : );
+return a;
+}
+
+#define WRAPPER_FUNC(x) __wrap_ ## x
+#define REAL_FUNC(x) __real_ ## x
+
+// macro to multiply value a by possibly constant value b
+// if b is known to be constant and not zero or a power of 2, then a mul instruction is used rather than gcc's default
+#define __fast_mul(a, b) __builtin_choose_expr(__builtin_constant_p(b) && !__builtin_constant_p(a), \
+(__builtin_popcount(b) >= 2 ? __mul_instruction(a,b) : (a)*(b)), \
+(a)*(b))
+
+#define __check_type_compatible(type_a, type_b) static_assert(__builtin_types_compatible_p(type_a, type_b), __STRING(type_a) " is not compatible with " __STRING(type_b));
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/platform.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/platform.c
new file mode 100644
index 00000000000..86167ab2dff
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_platform/platform.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico.h"
+#include "hardware/address_mapped.h"
+#include "hardware/regs/tbman.h"
+#include "hardware/regs/sysinfo.h"
+
+bool running_on_fpga() {
+ return !!((*(io_ro_32 *)TBMAN_BASE) & TBMAN_PLATFORM_FPGA_BITS);
+}
+
+#define MANUFACTURER_RPI 0x927
+#define PART_RP2 0x2
+
+uint8_t rp2040_chip_version() {
+ // First register of sysinfo is chip id
+ uint32_t chip_id = *((io_ro_32*)(SYSINFO_BASE + SYSINFO_CHIP_ID_OFFSET));
+ uint32_t __unused manufacturer = chip_id & SYSINFO_CHIP_ID_MANUFACTURER_BITS;
+ uint32_t __unused part = (chip_id & SYSINFO_CHIP_ID_PART_BITS) >> SYSINFO_CHIP_ID_PART_LSB;
+ assert(manufacturer == MANUFACTURER_RPI);
+ assert(part == PART_RP2);
+ // Version 1 == B0/B1
+ int version = (chip_id & SYSINFO_CHIP_ID_REVISION_BITS) >> SYSINFO_CHIP_ID_REVISION_LSB;
+ return version;
+}
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_printf/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_printf/CMakeLists.txt
new file mode 100644
index 00000000000..cf2082e81b8
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_printf/CMakeLists.txt
@@ -0,0 +1,63 @@
+if (NOT TARGET pico_printf)
+ # library to be depended on - we make this depend on particular implementations using per target generator expressions
+ add_library(pico_printf INTERFACE)
+
+ # no custom implementation; falls thru to compiler
+ add_library(pico_printf_compiler INTERFACE)
+ target_compile_definitions(pico_printf_compiler INTERFACE
+ PICO_PRINTF_COMPILER=1
+ )
+
+ add_library(pico_printf_headers INTERFACE)
+ target_include_directories(pico_printf_headers INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
+ # add alias "default" which is just pico.
+ add_library(pico_printf_default INTERFACE)
+ target_link_libraries(pico_printf_default INTERFACE pico_printf_pico)
+
+ set(PICO_DEFAULT_PRINTF_IMPL pico_printf_default)
+
+ target_link_libraries(pico_printf INTERFACE
+ $>,$,${PICO_DEFAULT_PRINTF_IMPL}>)
+
+ add_library(pico_printf_pico INTERFACE)
+ target_sources(pico_printf_pico INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/printf.c
+ )
+
+ target_compile_definitions(pico_printf_pico INTERFACE
+ PICO_PRINTF_PICO=1
+ )
+
+ target_link_libraries(pico_printf_pico INTERFACE pico_printf_headers)
+
+ add_library(pico_printf_none INTERFACE)
+ target_sources(pico_printf_none INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/printf_none.S
+ )
+
+ target_link_libraries(pico_printf_none INTERFACE pico_printf_headers)
+
+ target_compile_definitions(pico_printf_none INTERFACE
+ PICO_PRINTF_NONE=1
+ )
+
+ function(wrap_printf_functions TARGET)
+ # note that printf and vprintf are in pico_stdio so we can provide thread safety
+ pico_wrap_function(${TARGET} sprintf)
+ pico_wrap_function(${TARGET} snprintf)
+ pico_wrap_function(${TARGET} vsnprintf)
+ endfunction()
+
+ wrap_printf_functions(pico_printf_pico)
+ wrap_printf_functions(pico_printf_none)
+
+ macro(pico_set_printf_implementation TARGET IMPL)
+ get_target_property(target_type ${TARGET} TYPE)
+ if ("EXECUTABLE" STREQUAL "${target_type}")
+ set_target_properties(${TARGET} PROPERTIES PICO_TARGET_PRINTF_IMPL "pico_printf_${IMPL}")
+ else()
+ message(FATAL_ERROR "printf implementation must be set on executable not library")
+ endif()
+ endmacro()
+endif()
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_printf/include/pico/printf.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_printf/include/pico/printf.h
new file mode 100644
index 00000000000..6a82b8db4a0
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_printf/include/pico/printf.h
@@ -0,0 +1,93 @@
+///////////////////////////////////////////////////////////////////////////////
+// \author (c) Marco Paland (info@paland.com)
+// 2014-2019, PALANDesign Hannover, Germany
+//
+// \license The MIT License (MIT)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
+// embedded systems with a very limited resources.
+// Use this instead of bloated standard/newlib printf.
+// These routines are thread safe and reentrant.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef PICO_PRINTF_H_
+#define PICO_PRINTF_H_
+
+/** \file printf.h
+ * \defgroup pico_printf pico_printf
+ *
+ * Compact replacement for printf by Marco Paland (info@paland.com)
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "pico.h"
+#include
+#include
+
+// PICO_CONFIG: PICO_PRINTF_ALWAYS_INCLUDED, Whether to always include printf code even if only called weakly (by panic), type=bool, default=1 in debug build 0 otherwise, group=pico_printf
+#ifndef PICO_PRINTF_ALWAYS_INCLUDED
+#ifndef NDEBUG
+#define PICO_PRINTF_ALWAYS_INCLUDED 1
+#else
+#define PICO_PRINTF_ALWAYS_INCLUDED 0
+#endif
+#endif
+
+#if PICO_PRINTF_PICO
+// weak raw printf may be a puts if printf has not been called,
+// so that we can support gc of printf when it isn't called
+//
+// it is called raw to distinguish it from the regular printf which
+// is in stdio.c and does mutex protection
+#if !PICO_PRINTF_ALWAYS_INCLUDED
+bool __printflike(1, 0) weak_raw_printf(const char *fmt, ...);
+bool weak_raw_vprintf(const char *fmt, va_list args);
+#else
+#define weak_raw_printf(...) ({printf(__VA_ARGS__); true;})
+#define weak_raw_vprintf(fmt,va) ({vprintf(fmt,va); true;})
+#endif
+
+/**
+ * printf with output function
+ * You may use this as dynamic alternative to printf() with its fixed _putchar() output
+ * \param out An output function which takes one character and an argument pointer
+ * \param arg An argument pointer for user data passed to output function
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are sent to the output function, not counting the terminating null character
+ */
+int vfctprintf(void (*out)(char character, void *arg), void *arg, const char *format, va_list va);
+
+#else
+
+#define weak_raw_printf(...) ({printf(__VA_ARGS__); true;})
+#define weak_raw_vprintf(fmt,va) ({vprintf(fmt,va); true;})
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _PRINTF_H_
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_printf/printf.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_printf/printf.c
new file mode 100644
index 00000000000..833bd7fcf1c
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_printf/printf.c
@@ -0,0 +1,937 @@
+///////////////////////////////////////////////////////////////////////////////
+// \author (c) Marco Paland (info@paland.com)
+// 2014-2019, PALANDesign Hannover, Germany
+//
+// \license The MIT License (MIT)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
+// embedded systems with a very limited resources. These routines are thread
+// safe and reentrant!
+// Use this instead of the bloated standard/newlib printf cause these use
+// malloc for printf (and may not be thread safe).
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+
+#include "pico/platform.h"
+#include "pico/printf.h"
+
+// PICO_CONFIG: PICO_PRINTF_NTOA_BUFFER_SIZE, Define printf ntoa buffer size, min=0, max=128, default=32, group=pico_printf
+// 'ntoa' conversion buffer size, this must be big enough to hold one converted
+// numeric number including padded zeros (dynamically created on stack)
+#ifndef PICO_PRINTF_NTOA_BUFFER_SIZE
+#define PICO_PRINTF_NTOA_BUFFER_SIZE 32U
+#endif
+
+// PICO_CONFIG: PICO_PRINTF_FTOA_BUFFER_SIZE, Define printf ftoa buffer size, min=0, max=128, default=32, group=pico_printf
+// 'ftoa' conversion buffer size, this must be big enough to hold one converted
+// float number including padded zeros (dynamically created on stack)
+#ifndef PICO_PRINTF_FTOA_BUFFER_SIZE
+#define PICO_PRINTF_FTOA_BUFFER_SIZE 32U
+#endif
+
+// PICO_CONFIG: PICO_PRINTF_SUPPORT_FLOAT, Enable floating point printing, default=1, group=pico_printf
+// support for the floating point type (%f)
+#ifndef PICO_PRINTF_SUPPORT_FLOAT
+#define PICO_PRINTF_SUPPORT_FLOAT 1
+#endif
+
+// PICO_CONFIG: PICO_PRINTF_SUPPORT_EXPONENTIAL, Enable exponential floating point printing, default=1, group=pico_printf
+// support for exponential floating point notation (%e/%g)
+#ifndef PICO_PRINTF_SUPPORT_EXPONENTIAL
+#define PICO_PRINTF_SUPPORT_EXPONENTIAL 1
+#endif
+
+// PICO_CONFIG: PICO_PRINTF_DEFAULT_FLOAT_PRECISION, Define default floating point precision, min=1, max=16, default=6, group=pico_printf
+#ifndef PICO_PRINTF_DEFAULT_FLOAT_PRECISION
+#define PICO_PRINTF_DEFAULT_FLOAT_PRECISION 6U
+#endif
+
+// PICO_CONFIG: PICO_PRINTF_MAX_FLOAT, Define the largest float suitable to print with %f, min=1, max=1e9, default=1e9, group=pico_printf
+#ifndef PICO_PRINTF_MAX_FLOAT
+#define PICO_PRINTF_MAX_FLOAT 1e9
+#endif
+
+// PICO_CONFIG: PICO_PRINTF_SUPPORT_LONG_LONG, Enable support for long long types (%llu or %p), default=1, group=pico_printf
+#ifndef PICO_PRINTF_SUPPORT_LONG_LONG
+#define PICO_PRINTF_SUPPORT_LONG_LONG 1
+#endif
+
+// PICO_CONFIG: PICO_PRINTF_SUPPORT_PTRDIFF_T, Enable support for the ptrdiff_t type (%t), default=1, group=pico_printf
+// ptrdiff_t is normally defined in as long or long long type
+#ifndef PICO_PRINTF_SUPPORT_PTRDIFF_T
+#define PICO_PRINTF_SUPPORT_PTRDIFF_T 1
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+// internal flag definitions
+#define FLAGS_ZEROPAD (1U << 0U)
+#define FLAGS_LEFT (1U << 1U)
+#define FLAGS_PLUS (1U << 2U)
+#define FLAGS_SPACE (1U << 3U)
+#define FLAGS_HASH (1U << 4U)
+#define FLAGS_UPPERCASE (1U << 5U)
+#define FLAGS_CHAR (1U << 6U)
+#define FLAGS_SHORT (1U << 7U)
+#define FLAGS_LONG (1U << 8U)
+#define FLAGS_LONG_LONG (1U << 9U)
+#define FLAGS_PRECISION (1U << 10U)
+#define FLAGS_ADAPT_EXP (1U << 11U)
+
+// import float.h for DBL_MAX
+#if PICO_PRINTF_SUPPORT_FLOAT
+
+#include
+
+#endif
+
+/**
+ * Output a character to a custom device like UART, used by the printf() function
+ * This function is declared here only. You have to write your custom implementation somewhere
+ * \param character Character to output
+ */
+static void _putchar(char character) {
+ putchar(character);
+}
+
+// output function type
+typedef void (*out_fct_type)(char character, void *buffer, size_t idx, size_t maxlen);
+
+#if !PICO_PRINTF_ALWAYS_INCLUDED
+// we don't have a way to specify a truly weak symbol reference (the linker will always include targets in a single link step,
+// so we make a function pointer that is initialized on the first printf called... if printf is not included in the binary
+// (or has never been called - we can't tell) then this will be null. the assumption is that if you are using printf
+// you are likely to have printed something.
+static int (*lazy_vsnprintf)(out_fct_type out, char *buffer, const size_t maxlen, const char *format, va_list va);
+#endif
+
+// wrapper (used as buffer) for output function type
+typedef struct {
+ void (*fct)(char character, void *arg);
+ void *arg;
+} out_fct_wrap_type;
+
+// internal buffer output
+static inline void _out_buffer(char character, void *buffer, size_t idx, size_t maxlen) {
+ if (idx < maxlen) {
+ ((char *) buffer)[idx] = character;
+ }
+}
+
+// internal null output
+static inline void _out_null(char character, void *buffer, size_t idx, size_t maxlen) {
+ (void) character;
+ (void) buffer;
+ (void) idx;
+ (void) maxlen;
+}
+
+// internal _putchar wrapper
+static inline void _out_char(char character, void *buffer, size_t idx, size_t maxlen) {
+ (void) buffer;
+ (void) idx;
+ (void) maxlen;
+ if (character) {
+ _putchar(character);
+ }
+}
+
+
+// internal output function wrapper
+static inline void _out_fct(char character, void *buffer, size_t idx, size_t maxlen) {
+ (void) idx;
+ (void) maxlen;
+ if (character) {
+ // buffer is the output fct pointer
+ ((out_fct_wrap_type *) buffer)->fct(character, ((out_fct_wrap_type *) buffer)->arg);
+ }
+}
+
+
+// internal secure strlen
+// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
+static inline unsigned int _strnlen_s(const char *str, size_t maxsize) {
+ const char *s;
+ for (s = str; *s && maxsize--; ++s);
+ return (unsigned int) (s - str);
+}
+
+
+// internal test if char is a digit (0-9)
+// \return true if char is a digit
+static inline bool _is_digit(char ch) {
+ return (ch >= '0') && (ch <= '9');
+}
+
+
+// internal ASCII string to unsigned int conversion
+static unsigned int _atoi(const char **str) {
+ unsigned int i = 0U;
+ while (_is_digit(**str)) {
+ i = i * 10U + (unsigned int) (*((*str)++) - '0');
+ }
+ return i;
+}
+
+
+// output the specified string in reverse, taking care of any zero-padding
+static size_t _out_rev(out_fct_type out, char *buffer, size_t idx, size_t maxlen, const char *buf, size_t len,
+ unsigned int width, unsigned int flags) {
+ const size_t start_idx = idx;
+
+ // pad spaces up to given width
+ if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
+ for (size_t i = len; i < width; i++) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+
+ // reverse string
+ while (len) {
+ out(buf[--len], buffer, idx++, maxlen);
+ }
+
+ // append pad spaces up to given width
+ if (flags & FLAGS_LEFT) {
+ while (idx - start_idx < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+
+ return idx;
+}
+
+
+// internal itoa format
+static size_t _ntoa_format(out_fct_type out, char *buffer, size_t idx, size_t maxlen, char *buf, size_t len,
+ bool negative, unsigned int base, unsigned int prec, unsigned int width,
+ unsigned int flags) {
+ // pad leading zeros
+ if (!(flags & FLAGS_LEFT)) {
+ if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
+ width--;
+ }
+ while ((len < prec) && (len < PICO_PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = '0';
+ }
+ while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PICO_PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = '0';
+ }
+ }
+
+ // handle hash
+ if (flags & FLAGS_HASH) {
+ if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
+ len--;
+ if (len && (base == 16U)) {
+ len--;
+ }
+ }
+ if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PICO_PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = 'x';
+ } else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PICO_PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = 'X';
+ } else if ((base == 2U) && (len < PICO_PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = 'b';
+ }
+ if (len < PICO_PRINTF_NTOA_BUFFER_SIZE) {
+ buf[len++] = '0';
+ }
+ }
+
+ if (len < PICO_PRINTF_NTOA_BUFFER_SIZE) {
+ if (negative) {
+ buf[len++] = '-';
+ } else if (flags & FLAGS_PLUS) {
+ buf[len++] = '+'; // ignore the space if the '+' exists
+ } else if (flags & FLAGS_SPACE) {
+ buf[len++] = ' ';
+ }
+ }
+
+ return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
+}
+
+
+// internal itoa for 'long' type
+static size_t _ntoa_long(out_fct_type out, char *buffer, size_t idx, size_t maxlen, unsigned long value, bool negative,
+ unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) {
+ char buf[PICO_PRINTF_NTOA_BUFFER_SIZE];
+ size_t len = 0U;
+
+ // no hash for 0 values
+ if (!value) {
+ flags &= ~FLAGS_HASH;
+ }
+
+ // write if precision != 0 and value is != 0
+ if (!(flags & FLAGS_PRECISION) || value) {
+ do {
+ const char digit = (char) (value % base);
+ buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
+ value /= base;
+ } while (value && (len < PICO_PRINTF_NTOA_BUFFER_SIZE));
+ }
+
+ return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int) base, prec, width, flags);
+}
+
+
+// internal itoa for 'long long' type
+#if PICO_PRINTF_SUPPORT_LONG_LONG
+
+static size_t _ntoa_long_long(out_fct_type out, char *buffer, size_t idx, size_t maxlen, unsigned long long value,
+ bool negative, unsigned long long base, unsigned int prec, unsigned int width,
+ unsigned int flags) {
+ char buf[PICO_PRINTF_NTOA_BUFFER_SIZE];
+ size_t len = 0U;
+
+ // no hash for 0 values
+ if (!value) {
+ flags &= ~FLAGS_HASH;
+ }
+
+ // write if precision != 0 and value is != 0
+ if (!(flags & FLAGS_PRECISION) || value) {
+ do {
+ const char digit = (char) (value % base);
+ buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
+ value /= base;
+ } while (value && (len < PICO_PRINTF_NTOA_BUFFER_SIZE));
+ }
+
+ return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int) base, prec, width, flags);
+}
+
+#endif // PICO_PRINTF_SUPPORT_LONG_LONG
+
+
+#if PICO_PRINTF_SUPPORT_FLOAT
+
+#if PICO_PRINTF_SUPPORT_EXPONENTIAL
+// forward declaration so that _ftoa can switch to exp notation for values > PICO_PRINTF_MAX_FLOAT
+static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec,
+ unsigned int width, unsigned int flags);
+#endif
+
+#define is_nan __builtin_isnan
+
+// internal ftoa for fixed decimal floating point
+static size_t _ftoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec,
+ unsigned int width, unsigned int flags) {
+ char buf[PICO_PRINTF_FTOA_BUFFER_SIZE];
+ size_t len = 0U;
+ double diff = 0.0;
+
+ // powers of 10
+ static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
+
+ // test for special values
+ if (is_nan(value))
+ return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
+ if (value < -DBL_MAX)
+ return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
+ if (value > DBL_MAX)
+ return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U,
+ width, flags);
+
+ // test for very large values
+ // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
+ if ((value > PICO_PRINTF_MAX_FLOAT) || (value < -PICO_PRINTF_MAX_FLOAT)) {
+#if PICO_PRINTF_SUPPORT_EXPONENTIAL
+ return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
+#else
+ return 0U;
+#endif
+ }
+
+ // test for negative
+ bool negative = false;
+ if (value < 0) {
+ negative = true;
+ value = 0 - value;
+ }
+
+ // set default precision, if not set explicitly
+ if (!(flags & FLAGS_PRECISION)) {
+ prec = PICO_PRINTF_DEFAULT_FLOAT_PRECISION;
+ }
+ // limit precision to 9, cause a prec >= 10 can lead to overflow errors
+ while ((len < PICO_PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
+ buf[len++] = '0';
+ prec--;
+ }
+
+ int whole = (int) value;
+ double tmp = (value - whole) * pow10[prec];
+ unsigned long frac = (unsigned long) tmp;
+ diff = tmp - frac;
+
+ if (diff > 0.5) {
+ ++frac;
+ // handle rollover, e.g. case 0.99 with prec 1 is 1.0
+ if (frac >= pow10[prec]) {
+ frac = 0;
+ ++whole;
+ }
+ } else if (diff < 0.5) {
+ } else if ((frac == 0U) || (frac & 1U)) {
+ // if halfway, round up if odd OR if last digit is 0
+ ++frac;
+ }
+
+ if (prec == 0U) {
+ diff = value - (double) whole;
+ if (!((diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
+ // exactly 0.5 and ODD, then round up
+ // 1.5 -> 2, but 2.5 -> 2
+ ++whole;
+ }
+ } else {
+ unsigned int count = prec;
+ // now do fractional part, as an unsigned number
+ while (len < PICO_PRINTF_FTOA_BUFFER_SIZE) {
+ --count;
+ buf[len++] = (char) (48U + (frac % 10U));
+ if (!(frac /= 10U)) {
+ break;
+ }
+ }
+ // add extra 0s
+ while ((len < PICO_PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
+ buf[len++] = '0';
+ }
+ if (len < PICO_PRINTF_FTOA_BUFFER_SIZE) {
+ // add decimal
+ buf[len++] = '.';
+ }
+ }
+
+ // do whole part, number is reversed
+ while (len < PICO_PRINTF_FTOA_BUFFER_SIZE) {
+ buf[len++] = (char) (48 + (whole % 10));
+ if (!(whole /= 10)) {
+ break;
+ }
+ }
+
+ // pad leading zeros
+ if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
+ if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
+ width--;
+ }
+ while ((len < width) && (len < PICO_PRINTF_FTOA_BUFFER_SIZE)) {
+ buf[len++] = '0';
+ }
+ }
+
+ if (len < PICO_PRINTF_FTOA_BUFFER_SIZE) {
+ if (negative) {
+ buf[len++] = '-';
+ } else if (flags & FLAGS_PLUS) {
+ buf[len++] = '+'; // ignore the space if the '+' exists
+ } else if (flags & FLAGS_SPACE) {
+ buf[len++] = ' ';
+ }
+ }
+
+ return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
+}
+
+
+#if PICO_PRINTF_SUPPORT_EXPONENTIAL
+
+// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse
+static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec,
+ unsigned int width, unsigned int flags) {
+ // check for NaN and special values
+ if (is_nan(value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
+ return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
+ }
+
+ // determine the sign
+ const bool negative = value < 0;
+ if (negative) {
+ value = -value;
+ }
+
+ // default precision
+ if (!(flags & FLAGS_PRECISION)) {
+ prec = PICO_PRINTF_DEFAULT_FLOAT_PRECISION;
+ }
+
+ // determine the decimal exponent
+ // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
+ union {
+ uint64_t U;
+ double F;
+ } conv;
+
+ conv.F = value;
+ int exp2 = (int) ((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
+ conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
+ // now approximate log10 from the log2 integer part and an expansion of ln around 1.5
+ int expval = (int) (0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
+ // now we want to compute 10^expval but we want to be sure it won't overflow
+ exp2 = (int) (expval * 3.321928094887362 + 0.5);
+ const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
+ const double z2 = z * z;
+ conv.U = (uint64_t) (exp2 + 1023) << 52U;
+ // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
+ conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
+ // correct for rounding errors
+ if (value < conv.F) {
+ expval--;
+ conv.F /= 10;
+ }
+
+ // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
+ unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
+
+ // in "%g" mode, "prec" is the number of *significant figures* not decimals
+ if (flags & FLAGS_ADAPT_EXP) {
+ // do we want to fall-back to "%f" mode?
+ if ((value >= 1e-4) && (value < 1e6)) {
+ if ((int) prec > expval) {
+ prec = (unsigned) ((int) prec - expval - 1);
+ } else {
+ prec = 0;
+ }
+ flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
+ // no characters in exponent
+ minwidth = 0U;
+ expval = 0;
+ } else {
+ // we use one sigfig for the whole part
+ if ((prec > 0) && (flags & FLAGS_PRECISION)) {
+ --prec;
+ }
+ }
+ }
+
+ // will everything fit?
+ unsigned int fwidth = width;
+ if (width > minwidth) {
+ // we didn't fall-back so subtract the characters required for the exponent
+ fwidth -= minwidth;
+ } else {
+ // not enough characters, so go back to default sizing
+ fwidth = 0U;
+ }
+ if ((flags & FLAGS_LEFT) && minwidth) {
+ // if we're padding on the right, DON'T pad the floating part
+ fwidth = 0U;
+ }
+
+ // rescale the float value
+ if (expval) {
+ value /= conv.F;
+ }
+
+ // output the floating part
+ const size_t start_idx = idx;
+ idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
+
+ // output the exponent part
+ if (minwidth) {
+ // output the exponential symbol
+ out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
+ // output the exponent value
+ idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth - 1,
+ FLAGS_ZEROPAD | FLAGS_PLUS);
+ // might need to right-pad spaces
+ if (flags & FLAGS_LEFT) {
+ while (idx - start_idx < width) out(' ', buffer, idx++, maxlen);
+ }
+ }
+ return idx;
+}
+
+#endif // PICO_PRINTF_SUPPORT_EXPONENTIAL
+#endif // PICO_PRINTF_SUPPORT_FLOAT
+
+// internal vsnprintf
+static int _vsnprintf(out_fct_type out, char *buffer, const size_t maxlen, const char *format, va_list va) {
+#if !PICO_PRINTF_ALWAYS_INCLUDED
+ lazy_vsnprintf = _vsnprintf;
+#endif
+ unsigned int flags, width, precision, n;
+ size_t idx = 0U;
+
+ if (!buffer) {
+ // use null output function
+ out = _out_null;
+ }
+
+ while (*format) {
+ // format specifier? %[flags][width][.precision][length]
+ if (*format != '%') {
+ // no
+ out(*format, buffer, idx++, maxlen);
+ format++;
+ continue;
+ } else {
+ // yes, evaluate it
+ format++;
+ }
+
+ // evaluate flags
+ flags = 0U;
+ do {
+ switch (*format) {
+ case '0':
+ flags |= FLAGS_ZEROPAD;
+ format++;
+ n = 1U;
+ break;
+ case '-':
+ flags |= FLAGS_LEFT;
+ format++;
+ n = 1U;
+ break;
+ case '+':
+ flags |= FLAGS_PLUS;
+ format++;
+ n = 1U;
+ break;
+ case ' ':
+ flags |= FLAGS_SPACE;
+ format++;
+ n = 1U;
+ break;
+ case '#':
+ flags |= FLAGS_HASH;
+ format++;
+ n = 1U;
+ break;
+ default :
+ n = 0U;
+ break;
+ }
+ } while (n);
+
+ // evaluate width field
+ width = 0U;
+ if (_is_digit(*format)) {
+ width = _atoi(&format);
+ } else if (*format == '*') {
+ const int w = va_arg(va, int);
+ if (w < 0) {
+ flags |= FLAGS_LEFT; // reverse padding
+ width = (unsigned int) -w;
+ } else {
+ width = (unsigned int) w;
+ }
+ format++;
+ }
+
+ // evaluate precision field
+ precision = 0U;
+ if (*format == '.') {
+ flags |= FLAGS_PRECISION;
+ format++;
+ if (_is_digit(*format)) {
+ precision = _atoi(&format);
+ } else if (*format == '*') {
+ const int prec = (int) va_arg(va, int);
+ precision = prec > 0 ? (unsigned int) prec : 0U;
+ format++;
+ }
+ }
+
+ // evaluate length field
+ switch (*format) {
+ case 'l' :
+ flags |= FLAGS_LONG;
+ format++;
+ if (*format == 'l') {
+ flags |= FLAGS_LONG_LONG;
+ format++;
+ }
+ break;
+ case 'h' :
+ flags |= FLAGS_SHORT;
+ format++;
+ if (*format == 'h') {
+ flags |= FLAGS_CHAR;
+ format++;
+ }
+ break;
+#if PICO_PRINTF_SUPPORT_PTRDIFF_T
+ case 't' :
+ flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+ format++;
+ break;
+#endif
+ case 'j' :
+ flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+ format++;
+ break;
+ case 'z' :
+ flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+ format++;
+ break;
+ default :
+ break;
+ }
+
+ // evaluate specifier
+ switch (*format) {
+ case 'd' :
+ case 'i' :
+ case 'u' :
+ case 'x' :
+ case 'X' :
+ case 'o' :
+ case 'b' : {
+ // set the base
+ unsigned int base;
+ if (*format == 'x' || *format == 'X') {
+ base = 16U;
+ } else if (*format == 'o') {
+ base = 8U;
+ } else if (*format == 'b') {
+ base = 2U;
+ } else {
+ base = 10U;
+ flags &= ~FLAGS_HASH; // no hash for dec format
+ }
+ // uppercase
+ if (*format == 'X') {
+ flags |= FLAGS_UPPERCASE;
+ }
+
+ // no plus or space flag for u, x, X, o, b
+ if ((*format != 'i') && (*format != 'd')) {
+ flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
+ }
+
+ // ignore '0' flag when precision is given
+ if (flags & FLAGS_PRECISION) {
+ flags &= ~FLAGS_ZEROPAD;
+ }
+
+ // convert the integer
+ if ((*format == 'i') || (*format == 'd')) {
+ // signed
+ if (flags & FLAGS_LONG_LONG) {
+#if PICO_PRINTF_SUPPORT_LONG_LONG
+ const long long value = va_arg(va, long long);
+ idx = _ntoa_long_long(out, buffer, idx, maxlen,
+ (unsigned long long) (value > 0 ? value : 0 - value), value < 0, base,
+ precision, width, flags);
+#endif
+ } else if (flags & FLAGS_LONG) {
+ const long value = va_arg(va, long);
+ idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long) (value > 0 ? value : 0 - value),
+ value < 0, base, precision, width, flags);
+ } else {
+ const int value = (flags & FLAGS_CHAR) ? (char) va_arg(va, int) : (flags & FLAGS_SHORT)
+ ? (short int) va_arg(va, int)
+ : va_arg(va, int);
+ idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int) (value > 0 ? value : 0 - value),
+ value < 0, base, precision, width, flags);
+ }
+ } else {
+ // unsigned
+ if (flags & FLAGS_LONG_LONG) {
+#if PICO_PRINTF_SUPPORT_LONG_LONG
+ idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base,
+ precision, width, flags);
+#endif
+ } else if (flags & FLAGS_LONG) {
+ idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision,
+ width, flags);
+ } else {
+ const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char) va_arg(va, unsigned int)
+ : (flags & FLAGS_SHORT)
+ ? (unsigned short int) va_arg(va,
+ unsigned int)
+ : va_arg(va, unsigned int);
+ idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
+ }
+ }
+ format++;
+ break;
+ }
+ case 'f' :
+ case 'F' :
+#if PICO_PRINTF_SUPPORT_FLOAT
+ if (*format == 'F') flags |= FLAGS_UPPERCASE;
+ idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
+#else
+ for(int i=0;i<2;i++) out('?', buffer, idx++, maxlen);
+ va_arg(va, double);
+#endif
+ format++;
+ break;
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+#if PICO_PRINTF_SUPPORT_FLOAT && PICO_PRINTF_SUPPORT_EXPONENTIAL
+ if ((*format == 'g') || (*format == 'G')) flags |= FLAGS_ADAPT_EXP;
+ if ((*format == 'E') || (*format == 'G')) flags |= FLAGS_UPPERCASE;
+ idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
+#else
+ for(int i=0;i<2;i++) out('?', buffer, idx++, maxlen);
+ va_arg(va, double);
+#endif
+ format++;
+ break;
+ case 'c' : {
+ unsigned int l = 1U;
+ // pre padding
+ if (!(flags & FLAGS_LEFT)) {
+ while (l++ < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+ // char output
+ out((char) va_arg(va, int), buffer, idx++, maxlen);
+ // post padding
+ if (flags & FLAGS_LEFT) {
+ while (l++ < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+ format++;
+ break;
+ }
+
+ case 's' : {
+ const char *p = va_arg(va, char*);
+ unsigned int l = _strnlen_s(p, precision ? precision : (size_t) -1);
+ // pre padding
+ if (flags & FLAGS_PRECISION) {
+ l = (l < precision ? l : precision);
+ }
+ if (!(flags & FLAGS_LEFT)) {
+ while (l++ < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+ // string output
+ while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
+ out(*(p++), buffer, idx++, maxlen);
+ }
+ // post padding
+ if (flags & FLAGS_LEFT) {
+ while (l++ < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+ format++;
+ break;
+ }
+
+ case 'p' : {
+ width = sizeof(void *) * 2U;
+ flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
+#if PICO_PRINTF_SUPPORT_LONG_LONG
+ const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
+ if (is_ll) {
+ idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t) va_arg(va, void*), false, 16U,
+ precision, width, flags);
+ } else {
+#endif
+ idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long) ((uintptr_t) va_arg(va, void*)), false,
+ 16U, precision, width, flags);
+#if PICO_PRINTF_SUPPORT_LONG_LONG
+ }
+#endif
+ format++;
+ break;
+ }
+
+ case '%' :
+ out('%', buffer, idx++, maxlen);
+ format++;
+ break;
+
+ default :
+ out(*format, buffer, idx++, maxlen);
+ format++;
+ break;
+ }
+ }
+
+ // termination
+ out((char) 0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
+
+ // return written chars without terminating \0
+ return (int) idx;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+int WRAPPER_FUNC(sprintf)(char *buffer, const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ const int ret = _vsnprintf(_out_buffer, buffer, (size_t) -1, format, va);
+ va_end(va);
+ return ret;
+}
+
+int WRAPPER_FUNC(snprintf)(char *buffer, size_t count, const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
+ va_end(va);
+ return ret;
+}
+
+int WRAPPER_FUNC(vsnprintf)(char *buffer, size_t count, const char *format, va_list va) {
+ return _vsnprintf(_out_buffer, buffer, count, format, va);
+}
+
+int vfctprintf(void (*out)(char character, void *arg), void *arg, const char *format, va_list va) {
+ const out_fct_wrap_type out_fct_wrap = {out, arg};
+ return _vsnprintf(_out_fct, (char *) (uintptr_t) &out_fct_wrap, (size_t) -1, format, va);
+}
+
+#if PICO_PRINTF_PICO
+#if !PICO_PRINTF_ALWAYS_INCLUDED
+bool weak_raw_printf(const char *fmt, ...) {
+ va_list va;
+ va_start(va, fmt);
+ bool rc = weak_raw_vprintf(fmt, va);
+ va_end(va);
+ return rc;
+}
+
+bool weak_raw_vprintf(const char *fmt, va_list args) {
+ if (lazy_vsnprintf) {
+ char buffer[1];
+ lazy_vsnprintf(_out_char, buffer, (size_t) -1, fmt, args);
+ return true;
+ } else {
+ puts(fmt);
+ return false;
+ }
+}
+#endif
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_printf/printf_none.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_printf/printf_none.S
new file mode 100644
index 00000000000..adc00ee54aa
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_printf/printf_none.S
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico/asm_helper.S"
+#include "pico/bootrom/sf_table.h"
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+wrapper_func sprintf
+wrapper_func snprintf
+wrapper_func vsnprintf
+regular_func printf_none_assert
+ push {lr} // keep stack trace sane
+ ldr r0, =str
+ bl panic
+
+str:
+ .asciz "printf support is disabled"
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_runtime/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_runtime/CMakeLists.txt
new file mode 100644
index 00000000000..83c08f61e04
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_runtime/CMakeLists.txt
@@ -0,0 +1,44 @@
+add_library(pico_runtime INTERFACE)
+
+target_sources(pico_runtime INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/runtime.c
+)
+
+target_include_directories(pico_runtime INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
+target_link_libraries(pico_runtime INTERFACE
+ hardware_uart
+ hardware_clocks
+ hardware_irq
+ pico_printf
+ pico_sync
+ )
+
+if (TARGET pico_bit_ops)
+ target_link_libraries(pico_runtime INTERFACE pico_bit_ops)
+endif()
+if (TARGET pico_divider)
+ target_link_libraries(pico_runtime INTERFACE pico_divider)
+endif()
+if (TARGET pico_double)
+ target_link_libraries(pico_runtime INTERFACE pico_double)
+endif()
+if (TARGET pico_int64_ops)
+ target_link_libraries(pico_runtime INTERFACE pico_int64_ops)
+endif()
+if (TARGET pico_float)
+ target_link_libraries(pico_runtime INTERFACE pico_float)
+endif()
+if (TARGET pico_malloc)
+ target_link_libraries(pico_runtime INTERFACE pico_malloc)
+endif()
+if (TARGET pico_mem_ops)
+ target_link_libraries(pico_runtime INTERFACE pico_mem_ops)
+endif()
+if (TARGET pico_standard_link)
+ target_link_libraries(pico_runtime INTERFACE pico_standard_link)
+endif()
+
+# todo is this correct/needed?
+target_link_options(pico_runtime INTERFACE "--specs=nosys.specs")
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_runtime/include/pico/runtime.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_runtime/include/pico/runtime.h
new file mode 100644
index 00000000000..752ec6cdefc
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_runtime/include/pico/runtime.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_RUNTIME_H
+#define _PICO_RUNTIME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file runtime.h
+* \defgroup pico_runtime pico_runtime
+* Aggregate runtime support including @ref pico_bit_ops, @ref pico_divider, @ref pico_double, @ref pico_int64_ops, @ref pico_float, @ref pico_malloc, @ref pico_mem_ops and @ref pico_standard_link
+*/
+
+
+void runtime_install_stack_guard(void *stack_bottom);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_runtime/runtime.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_runtime/runtime.c
new file mode 100644
index 00000000000..22ff5208e62
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_runtime/runtime.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include
+#include
+#include "pico.h"
+
+#include "hardware/regs/m0plus.h"
+#include "hardware/regs/resets.h"
+#include "hardware/structs/mpu.h"
+#include "hardware/structs/scb.h"
+#include "hardware/structs/padsbank0.h"
+
+#include "hardware/clocks.h"
+#include "hardware/irq.h"
+#include "hardware/resets.h"
+
+#include "pico/mutex.h"
+#include "pico/time.h"
+// Use mbed printf
+//#include "pico/printf.h"
+
+#if PICO_ENTER_USB_BOOT_ON_EXIT
+#include "pico/bootrom.h"
+#endif
+
+#ifndef PICO_NO_RAM_VECTOR_TABLE
+#define PICO_NO_RAM_VECTOR_TABLE 0
+#endif
+
+extern char __StackLimit; /* Set by linker. */
+
+uint32_t __attribute__((section(".ram_vector_table"))) ram_vector_table[48];
+
+// this is called for each thread since they have their own MPU
+void runtime_install_stack_guard(void *stack_bottom) {
+ // this is called b4 runtime_init is complete, so beware printf or assert
+
+ // make sure no one is using the MPU yet
+ if (mpu_hw->ctrl) {
+ // Note that it would be tempting to change this to a panic, but it happens so early, printing is not a good idea
+ __breakpoint();
+ }
+
+ uintptr_t addr = (uintptr_t) stack_bottom;
+ // the minimum we can protect is 32 bytes on a 32 byte boundary, so round up which will
+ // just shorten the valid stack range a tad
+ addr = (addr + 31u) & ~31u;
+
+ // mask is 1 bit per 32 bytes of the 256 byte range... clear the bit for the segment we want
+ uint32_t subregion_select = 0xffu ^ (1u << ((addr >> 5u) & 7u));
+ mpu_hw->ctrl = 5; // enable mpu with background default map
+ mpu_hw->rbar = (addr & ~0xff) | 0x8 | 0;
+ mpu_hw->rasr = 1 // enable region
+ | (0x7 << 1) // size 2^(7 + 1) = 256
+ | (subregion_select << 8)
+ | 0x10000000; // XN = disable instruction fetch; no other bits means no permissions
+}
+
+void runtime_init(void) {
+ // Reset all peripherals to put system into a known state,
+ // - except for QSPI pads and the XIP IO bank, as this is fatal if running from flash
+ // - and the PLLs, as this is fatal if clock muxing has not been reset on this boot
+ reset_block(~(
+ RESETS_RESET_IO_QSPI_BITS |
+ RESETS_RESET_PADS_QSPI_BITS |
+ RESETS_RESET_PLL_USB_BITS |
+ RESETS_RESET_PLL_SYS_BITS
+ ));
+
+ // Remove reset from peripherals which are clocked only by clk_sys and
+ // clk_ref. Other peripherals stay in reset until we've configured clocks.
+ unreset_block_wait(RESETS_RESET_BITS & ~(
+ RESETS_RESET_ADC_BITS |
+ RESETS_RESET_RTC_BITS |
+ RESETS_RESET_SPI0_BITS |
+ RESETS_RESET_SPI1_BITS |
+ RESETS_RESET_UART0_BITS |
+ RESETS_RESET_UART1_BITS |
+ RESETS_RESET_USBCTRL_BITS
+ ));
+
+ // pre-init runs really early since we need it even for memcpy and divide!
+ // (basically anything in aeabi that uses bootrom)
+
+ // Start and end points of the constructor list,
+ // defined by the linker script.
+ extern void (*__preinit_array_start)();
+ extern void (*__preinit_array_end)();
+
+ // Call each function in the list.
+ // We have to take the address of the symbols, as __preinit_array_start *is*
+ // the first function pointer, not the address of it.
+ for (void (**p)() = &__preinit_array_start; p < &__preinit_array_end; ++p) {
+ (*p)();
+ }
+
+ // After calling preinit we have enough runtime to do the exciting maths
+ // in clocks_init
+ clocks_init();
+
+ // Peripheral clocks should now all be running
+ unreset_block_wait(RESETS_RESET_BITS);
+
+#if !PICO_IE_26_29_UNCHANGED_ON_RESET
+ // after resetting BANK0 we should disable IE on 26-29
+ hw_clear_alias(padsbank0_hw)->io[26] = hw_clear_alias(padsbank0_hw)->io[27] =
+ hw_clear_alias(padsbank0_hw)->io[28] = hw_clear_alias(padsbank0_hw)->io[29] = PADS_BANK0_GPIO0_IE_BITS;
+#endif
+
+ extern mutex_t __mutex_array_start;
+ extern mutex_t __mutex_array_end;
+
+ // the first function pointer, not the address of it.
+ for (mutex_t *m = &__mutex_array_start; m < &__mutex_array_end; m++) {
+ mutex_init(m);
+ }
+
+#if !(PICO_NO_RAM_VECTOR_TABLE || PICO_NO_FLASH)
+ __builtin_memcpy(ram_vector_table, (uint32_t *) scb_hw->vtor, sizeof(ram_vector_table));
+ scb_hw->vtor = (intptr_t) ram_vector_table;
+#endif
+
+#ifndef NDEBUG
+ uint32_t xpsr;
+ __asm volatile ("mrs %0, XPSR" : "=r" (xpsr)::);
+ if (xpsr & 0xffu) {
+ // crap; started in exception handler
+ __asm ("bkpt #0");
+ }
+#endif
+
+#if PICO_USE_STACK_GUARDS
+ // install core0 stack guard
+ extern char __StackBottom;
+ runtime_install_stack_guard(&__StackBottom);
+#endif
+
+ spin_locks_reset();
+ irq_init_priorities();
+ alarm_pool_init_default();
+}
+
+void __exit(int status) {
+#if PICO_ENTER_USB_BOOT_ON_EXIT
+ reset_usb_boot(0,0);
+#else
+ while (1) {
+ __breakpoint();
+ }
+#endif
+}
+
+void *__sbrk(int incr) {
+ extern char end; /* Set by linker. */
+ static char *heap_end;
+ char *prev_heap_end;
+
+ if (heap_end == 0)
+ heap_end = &end;
+
+ prev_heap_end = heap_end;
+ char *next_heap_end = heap_end + incr;
+
+ if (__builtin_expect(next_heap_end >= (&__StackLimit), false)) {
+#if PICO_USE_OPTIMISTIC_SBRK
+ if (next_heap_end == &__StackLimit) {
+// errno = ENOMEM;
+ return (char *) -1;
+ }
+ next_heap_end = &__StackLimit;
+#else
+ return (char *) -1;
+#endif
+ }
+
+ heap_end = next_heap_end;
+ return (void *) prev_heap_end;
+}
+
+// exit is not useful... no desire to pull in __call_exitprocs
+void exit(int status) {
+ __exit(status);
+}
+
+// incorrect warning from GCC 6
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
+void __assert_func(const char *file, int line, const char *func, const char *failedexpr) {
+ printf("assertion \"%s\" failed: file \"%s\", line %d%s%s\n",
+ failedexpr, file, line, func ? ", function: " : "",
+ func ? func : "");
+
+ exit(1);
+}
+
+#pragma GCC diagnostic pop
+
+void __attribute__((noreturn)) panic_unsupported() {
+ panic("not supported");
+}
+
+// todo consider making this try harder to output if we panic early
+// right now, print mutex may be uninitialised (in which case it deadlocks - although after printing "PANIC")
+// more importantly there may be no stdout/UART initialized yet
+// todo we may want to think about where we print panic messages to; writing to USB appears to work
+// though it doesn't seem like we can expect it to... fine for now
+//
+void __attribute__((noreturn)) __printflike(1, 0) panic(const char *fmt, ...) {
+ puts("\n*** PANIC ***\n");
+ if (fmt) {
+#if PICO_PRINTF_NONE
+ puts(fmt);
+#else
+ va_list args;
+ va_start(args, fmt);
+#if PICO_PRINTF_ALWAYS_INCLUDED
+ vprintf(fmt, args);
+#else
+ vprintf(fmt, args);
+#endif
+ va_end(args);
+ puts("\n");
+#endif
+ }
+
+ exit(1);
+}
+
+void hard_assertion_failure(void) {
+ panic("Hard assert");
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/CMakeLists.txt
new file mode 100644
index 00000000000..8dc8ab8c3a4
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/CMakeLists.txt
@@ -0,0 +1,93 @@
+if (NOT TARGET pico_standard_link)
+ add_library(pico_standard_link INTERFACE)
+
+ target_sources(pico_standard_link INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/crt0.S
+ ${CMAKE_CURRENT_LIST_DIR}/new_delete.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/binary_info.c
+ )
+
+ pico_add_map_output(pico_standard_link)
+
+ # todo revisit when we do Clang
+ if (CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ target_link_options(pico_standard_link INTERFACE "LINKER:-nostdlib")
+ endif ()
+
+ target_link_libraries(pico_standard_link INTERFACE hardware_regs pico_bootrom pico_binary_info pico_cxx_options)
+
+ function(pico_add_link_depend TARGET dependency)
+ get_target_property(target_type ${TARGET} TYPE)
+ if (${target_type} STREQUAL "INTERFACE_LIBRARY")
+ set(PROP "INTERFACE_LINK_DEPENDS")
+ else()
+ set(PROP "LINK_DEPENDS")
+ endif()
+ get_target_property(_LINK_DEPENDS ${TARGET} ${PROP})
+ if (NOT _LINK_DEPENDS)
+ set(_LINK_DEPENDS ${dependency})
+ else()
+ list(APPEND _LINK_DEPENDS ${dependency})
+ endif()
+ set_target_properties(${TARGET} PROPERTIES ${PROP} "${_LINK_DEPENDS}")
+ endfunction()
+
+ # need this because cmake does not appear to have a way to override an INTERFACE variable
+ function(pico_set_linker_script TARGET LDSCRIPT)
+ set_target_properties(${TARGET} PROPERTIES PICO_TARGET_LINKER_SCRIPT ${LDSCRIPT})
+ pico_add_link_depend(${TARGET} ${LDSCRIPT})
+ endfunction()
+
+ function(pico_set_binary_type TARGET TYPE)
+ set_target_properties(${TARGET} PROPERTIES PICO_TARGET_BINARY_TYPE ${TYPE})
+ endfunction()
+
+ if (PICO_NO_FLASH)
+ set(PICO_DEFAULT_BINARY_TYPE no_flash)
+ elseif (PICO_USE_BLOCKED_RAM)
+ set(PICO_DEFAULT_BINARY_TYPE blocked_ram)
+ elseif (PICO_COPY_TO_RAM)
+ set(PICO_DEFAULT_BINARY_TYPE copy_to_ram)
+ else()
+ set(PICO_DEFAULT_BINARY_TYPE default)
+ endif()
+
+ # LINKER script will be PICO_TARGET_LINKER_SCRIPT if set on target, or ${CMAKE_CURRENT_LIST_DIR}/memmap_foo.ld
+ # if PICO_TARGET_BINARY_TYPE is set to foo on the target, otherwise ${CMAKE_CURRENT_LIST_DIR}/memmap_${PICO_DEFAULT_BINARY_TYPE).ld
+ target_link_options(pico_standard_link INTERFACE
+ "LINKER:--script=$>,$,${CMAKE_CURRENT_LIST_DIR}/memmap_$,>,${PICO_DEFAULT_BINARY_TYPE},$>.ld>"
+ )
+
+ # PICO_NO_FLASH will be set based on PICO_TARGET_BUILD_TYPE target property being equal to no_flash if set, otherwise to the value of the PICO_NO_FLASH cmake variable unless PICO_TARGET_TYPE is set to something else
+ # PICO_BUILD_DEFINE: PICO_NO_FLASH, whether this is a 'no_flash' build, type=bool, default=0, but dependent on CMake options, group=pico_standard_link
+ target_compile_definitions(pico_standard_link INTERFACE PICO_NO_FLASH=$,no_flash>,1,$,$>>>)
+ # PICO_USE_BLOCKED_RAM will be set based on PICO_TARGET_BUILD_TYPE target property being equal to use_blocked_ram if set, otherwise to the value of the PICO_USE_BLOCKED_RAM cmake variable unless PICO_TARGET_TYPE is set to something else
+ # PICO_BUILD_DEFINE: PICO_USE_BLOCKS_RAM, whether this is a 'blocked_ram' build, type=bool, default=0, but dependent on CMake options, group=pico_standard_link
+ target_compile_definitions(pico_standard_link INTERFACE PICO_USE_BLOCKED_RAM=$,use_blocked_ram>,1,$,$>>>)
+ # PICO_COPY_TO_RAM will be set based on PICO_TARGET_BUILD_TYPE target property being equal to copy_to_ram if set, otherwise to the value of the PICO_COPY_TO_RAM cmake variable unless PICO_TARGET_TYPE is set to something else
+ # PICO_BUILD_DEFINE: PICO_COPY_TO_RAM, whether this is a 'copy_to_ram' build, type=bool, default=0, but dependent on CMake options, group=pico_standard_link
+ target_compile_definitions(pico_standard_link INTERFACE PICO_COPY_TO_RAM=$,copy_to_ram>,1,$,$>>>)
+
+ target_compile_definitions(pico_standard_link INTERFACE PICO_CMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}")
+ if (PICO_DEOPTIMIZED_DEBUG AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
+ target_compile_definitions(pico_standard_link INTERFACE PICO_DEOPTIMIZED_DEBUG=1)
+ endif()
+
+ # todo revisit/recall reasoning for why not -nostartfiles always?
+ # -nostartfiles will be added if PICO_NO_FLASH would be defined to 1
+ target_link_options(pico_standard_link INTERFACE $<$,no_flash>,1,$,$>>>:-nostartfiles>)
+ # boot_stage2 will be linked if PICO_NO_FLASH would be defined to 0
+ target_link_libraries(pico_standard_link INTERFACE $<$,no_flash>,1,$,$>>>>:$>,$,bs2_default>_library>)
+
+ # done in compiler now
+ #target_link_options(pico_standard_link INTERFACE "LINKER:--build-id=none")
+
+ # this line occasionally useful for debugging ... todo maybe make a PICO_ var
+# target_compile_options(pico_standard_link INTERFACE --save-temps) #debugging only
+
+ # PICO_CMAKE_CONFIG: PICO_NO_GC_SECTIONS, Disable -ffunction-sections -fdata-sections, and --gc-sections, type=bool, default=0, advanced=true, group=pico_standard_link
+ if (NOT PICO_NO_GC_SECTIONS)
+ target_compile_options(pico_standard_link INTERFACE -ffunction-sections -fdata-sections)
+ target_link_options(pico_standard_link INTERFACE "LINKER:--gc-sections")
+ endif()
+endif()
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/binary_info.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/binary_info.c
new file mode 100644
index 00000000000..9a879c7bff7
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/binary_info.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if !PICO_NO_BINARY_INFO && !PICO_NO_PROGRAM_INFO
+#include "pico/binary_info.h"
+
+// Note we put at most 4 pieces of binary info in the reset section because that's how much spare space we had
+// (picked the most common ones)... if there is a link failure because of .reset section overflow then move
+// more out.
+#define reset_section_attr __attribute__((section(".reset")))
+
+#if !PICO_NO_FLASH
+#ifndef PICO_NO_BI_BINARY_SIZE
+extern char __flash_binary_end;
+bi_decl_with_attr(bi_binary_end((uintptr_t)&__flash_binary_end), reset_section_attr)
+#endif
+#endif
+
+#if !PICO_NO_BI_PROGRAM_BUILD_DATE
+#ifndef PICO_PROGRAM_BUILD_DATE
+#define PICO_PROGRAM_BUILD_DATE __DATE__
+#endif
+bi_decl_with_attr(bi_program_build_date_string(PICO_PROGRAM_BUILD_DATE), reset_section_attr);
+#endif
+
+#if !PICO_NO_BI_PROGRAM_NAME
+#if !defined(PICO_PROGRAM_NAME) && defined(PICO_TARGET_NAME)
+#define PICO_PROGRAM_NAME PICO_TARGET_NAME
+#endif
+#ifdef PICO_PROGRAM_NAME
+bi_decl_with_attr(bi_program_name(PICO_PROGRAM_NAME), reset_section_attr)
+#endif
+#endif
+
+#if !PICO_NO_BI_PICO_BOARD
+#ifdef PICO_BOARD
+bi_decl(bi_string(BINARY_INFO_TAG_RASPBERRY_PI, BINARY_INFO_ID_RP_PICO_BOARD, PICO_BOARD))
+#endif
+#endif
+
+#if !PICO_NO_BI_SDK_VERSION
+#ifdef PICO_SDK_VERSION_STRING
+bi_decl_with_attr(bi_string(BINARY_INFO_TAG_RASPBERRY_PI, BINARY_INFO_ID_RP_SDK_VERSION, PICO_SDK_VERSION_STRING),reset_section_attr)
+#endif
+#endif
+
+#if !PICO_NO_BI_PROGRAM_VERSION_STRING
+#ifdef PICO_PROGRAM_VERSION_STRING
+bi_decl(bi_program_version_string(PICO_PROGRAM_VERSION_STRING))
+#endif
+#endif
+
+
+#if !PICO_NO_BI_PROGRAM_DESCRIPTION
+#ifdef PICO_PROGRAM_DESCRIPTION
+bi_decl(bi_program_description(PICO_PROGRAM_DESCRIPTION))
+#endif
+#endif
+
+#if !PICO_NO_BI_PROGRAM_URL
+#ifdef PICO_PROGRAM_URL
+bi_decl(bi_program_url(PICO_PROGRAM_URL))
+#endif
+#endif
+
+#if !PICO_NO_BUILD_TYPE_FEATURE
+#ifdef PICO_CMAKE_BUILD_TYPE
+bi_decl(bi_program_build_attribute(PICO_CMAKE_BUILD_TYPE))
+#else
+#ifndef NDEBUG
+bi_decl(bi_program_build_attribute("Debug"))
+#else
+bi_decl(bi_program_build_attribute("Release"))
+#endif
+#endif
+
+#if PICO_DEOPTIMIZED_DEBUG
+bi_decl(bi_program_build_attribute("All optimization disabled"))
+#endif
+#endif
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/crt0.S b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/crt0.S
new file mode 100644
index 00000000000..97af458711d
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/crt0.S
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/regs/m0plus.h"
+#include "hardware/platform_defs.h"
+#include "hardware/regs/addressmap.h"
+#include "hardware/regs/sio.h"
+#include "pico/binary_info/defs.h"
+
+#ifdef NDEBUG
+#ifndef COLLAPSE_IRQS
+#define COLLAPSE_IRQS
+#endif
+#endif
+
+.syntax unified
+.cpu cortex-m0plus
+.thumb
+
+.section .vectors, "ax"
+.align 2
+
+.global __vectors
+__vectors:
+.word __StackTop
+.word _reset_handler
+.word isr_nmi
+.word HardFault_Handler
+.word MemManage_Handler
+.word BusFault_Handler
+.word UsageFault_Handler
+.word isr_invalid // Reserved, should never fire
+.word isr_invalid // Reserved, should never fire
+.word isr_invalid // Reserved, should never fire
+.word isr_invalid // Reserved, should never fire
+.word SVC_Handler
+.word isr_invalid // Reserved, should never fire
+.word isr_invalid // Reserved, should never fire
+.word PendSV_Handler
+.word SysTick_Handler
+.word isr_irq0
+.word isr_irq1
+.word isr_irq2
+.word isr_irq3
+.word isr_irq4
+.word isr_irq5
+.word isr_irq6
+.word isr_irq7
+.word isr_irq8
+.word isr_irq9
+.word isr_irq10
+.word isr_irq11
+.word isr_irq12
+.word isr_irq13
+.word isr_irq14
+.word isr_irq15
+.word isr_irq16
+.word isr_irq17
+.word isr_irq18
+.word isr_irq19
+.word isr_irq20
+.word isr_irq21
+.word isr_irq22
+.word isr_irq23
+.word isr_irq24
+.word isr_irq25
+.word isr_irq26
+.word isr_irq27
+.word isr_irq28
+.word isr_irq29
+.word isr_irq30
+.word isr_irq31
+
+// Declare a weak symbol for each ISR.
+// By default, they will fall through to the undefined IRQ handler below (breakpoint),
+// but can be overridden by C functions with correct name.
+
+.macro decl_isr_bkpt name
+.weak \name
+.type \name,%function
+.thumb_func
+\name:
+ bkpt #0
+.endm
+
+// these are separated out for clarity
+decl_isr_bkpt isr_invalid
+decl_isr_bkpt isr_nmi
+decl_isr_bkpt HardFault_Handler
+decl_isr_bkpt SVC_Handler
+decl_isr_bkpt PendSV_Handler
+decl_isr_bkpt SysTick_Handler
+
+.macro decl_isr name
+.weak \name
+.type \name,%function
+.thumb_func
+\name:
+.endm
+
+decl_isr isr_irq0
+decl_isr isr_irq1
+decl_isr isr_irq2
+decl_isr isr_irq3
+decl_isr isr_irq4
+decl_isr isr_irq5
+decl_isr isr_irq6
+decl_isr isr_irq7
+decl_isr isr_irq8
+decl_isr isr_irq9
+decl_isr isr_irq10
+decl_isr isr_irq11
+decl_isr isr_irq12
+decl_isr isr_irq13
+decl_isr isr_irq14
+decl_isr isr_irq15
+decl_isr isr_irq16
+decl_isr isr_irq17
+decl_isr isr_irq18
+decl_isr isr_irq19
+decl_isr isr_irq20
+decl_isr isr_irq21
+decl_isr isr_irq22
+decl_isr isr_irq23
+decl_isr isr_irq24
+decl_isr isr_irq25
+decl_isr isr_irq26
+decl_isr isr_irq27
+decl_isr isr_irq28
+decl_isr isr_irq29
+decl_isr isr_irq30
+decl_isr isr_irq31
+
+// All unhandled USER IRQs fall through to here
+.global __unhandled_user_irq
+.thumb_func
+__unhandled_user_irq:
+ bl __get_current_exception
+ subs r0, #16
+.global unhandled_user_irq_num_in_r0
+unhandled_user_irq_num_in_r0:
+ bkpt #0
+
+// ----------------------------------------------------------------------------
+
+.section .binary_info_header, "a"
+
+// Header must be in first 256 bytes of main image (i.e. excluding flash boot2).
+// For flash builds we put it immediately after vector table; for NO_FLASH the
+// vectors are at a +0x100 offset because the bootrom enters RAM images directly
+// at their lowest address, so we put the header in the VTOR alignment hole.
+
+#if !PICO_NO_BINARY_INFO
+binary_info_header:
+.word BINARY_INFO_MARKER_START
+.word __binary_info_start
+.word __binary_info_end
+.word data_cpy_table // we may need to decode pointers that are in RAM at runtime.
+.word BINARY_INFO_MARKER_END
+#endif
+
+// ----------------------------------------------------------------------------
+
+.section .reset, "ax"
+
+// On flash builds, the vector table comes first in the image (conventional).
+// On NO_FLASH builds, the reset handler section comes first, as the entry
+// point is at offset 0 (fixed due to bootrom), and VTOR is highly-aligned.
+// Image is entered in various ways:
+//
+// - NO_FLASH builds are entered from beginning by UF2 bootloader
+//
+// - Flash builds vector through the table into _reset_handler from boot2
+//
+// - Either type can be entered via _entry_point by the debugger, and flash builds
+// must then be sent back round the boot sequence to properly initialise flash
+
+// ELF entry point:
+.type _entry_point,%function
+.thumb_func
+.global _entry_point
+_entry_point:
+
+#if PICO_NO_FLASH
+ // Vector through our own table (SP, VTOR will not have been set up at
+ // this point). Same path for debugger entry and bootloader entry.
+ ldr r0, =__vectors
+#else
+ // Debugger tried to run code after loading, so SSI is in 03h-only mode.
+ // Go back through bootrom + boot2 to properly initialise flash.
+ movs r0, #0
+#endif
+ ldr r1, =(PPB_BASE + M0PLUS_VTOR_OFFSET)
+ str r0, [r1]
+ ldmia r0!, {r1, r2}
+ msr msp, r1
+ bx r2
+
+// Reset handler:
+// - initialises .data
+// - clears .bss
+// - calls runtime_init
+// - calls main
+// - calls exit (which should eventually hang the processor via _exit)
+
+.type _reset_handler,%function
+.thumb_func
+_reset_handler:
+ // Only core 0 should run the C runtime startup code; core 1 is normally
+ // sleeping in the bootrom at this point but check to be sure
+ ldr r0, =(SIO_BASE + SIO_CPUID_OFFSET)
+ ldr r0, [r0]
+ cmp r0, #0
+ bne hold_non_core0_in_bootrom
+
+ adr r4, data_cpy_table
+
+ // assume there is at least one entry
+1:
+ ldmia r4!, {r1-r3}
+ cmp r1, #0
+ beq 2f
+ bl data_cpy
+ b 1b
+2:
+
+ // Zero out the BSS
+ ldr r1, =__bss_start__
+ ldr r2, =__bss_end__
+ movs r0, #0
+ b bss_fill_test
+bss_fill_loop:
+ stm r1!, {r0}
+bss_fill_test:
+ cmp r1, r2
+ bne bss_fill_loop
+
+platform_entry: // symbol for stack traces
+ // Use 32-bit jumps, in case these symbols are moved out of branch range
+ // (e.g. if main is in SRAM and crt0 in flash)
+ //ldr r1, =runtime_init
+ //blx r1
+ ldr r1, =_start
+ blx r1
+ ldr r1, =exit
+ blx r1
+ // exit should not return. If it does, hang the core.
+ // (fall thru into our hang _exit impl
+.weak _exit
+.type _exit,%function
+.thumb_func
+_exit:
+1: // separate label because _exit can be moved out of branch range
+ bkpt #0
+ b 1b
+
+data_cpy_loop:
+ ldm r1!, {r0}
+ stm r2!, {r0}
+data_cpy:
+ cmp r2, r3
+ blo data_cpy_loop
+ bx lr
+
+.align 2
+data_cpy_table:
+#if PICO_COPY_TO_RAM
+.word __ram_text_source__
+.word __ram_text_start__
+.word __ram_text_end__
+#endif
+.word __etext
+.word __data_start__
+.word __data_end__
+
+.word __scratch_x_source__
+.word __scratch_x_start__
+.word __scratch_x_end__
+
+.word __scratch_y_source__
+.word __scratch_y_start__
+.word __scratch_y_end__
+
+.word 0 // null terminator
+
+// ----------------------------------------------------------------------------
+// Provide safe defaults for _exit and runtime_init
+// Full implementations usually provided by platform.c
+
+.weak runtime_init
+.type runtime_init,%function
+.thumb_func
+runtime_init:
+ bx lr
+
+// ----------------------------------------------------------------------------
+// If core 1 somehow gets into crt0 due to a spectacular VTOR mishap, we need to
+// catch it and send back to the sleep-and-launch code in the bootrom. Shouldn't
+// happen (it should sleep in the ROM until given an entry point via the
+// cross-core FIFOs) but it's good to be defensive.
+
+hold_non_core0_in_bootrom:
+ ldr r0, = 'W' | ('V' << 8)
+ bl rom_func_lookup
+ bx r0
+
+.global __get_current_exception
+.thumb_func
+__get_current_exception:
+ mrs r0, ipsr
+ uxtb r0, r0
+ bx lr
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/doc.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/doc.h
new file mode 100644
index 00000000000..d8ce3d49007
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/doc.h
@@ -0,0 +1,10 @@
+/**
+ * \defgroup pico_standard_link pico_standard_link
+ * \brief Standard link step providing the basics for creating a runnable binary
+ *
+ * This includes
+ * - C runtime initialization
+ * - Linker scripts for 'default', 'no_flash', 'blocked_ram' and 'copy_to_ram' binaries
+ * - 'Binary Information' support
+ * - Linker option control
+ */
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/memmap_blocked_ram.ld b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/memmap_blocked_ram.ld
new file mode 100644
index 00000000000..5b0afe65bd9
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/memmap_blocked_ram.ld
@@ -0,0 +1,252 @@
+/* Based on GCC ARM embedded samples.
+ Defines the following symbols for use by code:
+ __exidx_start
+ __exidx_end
+ __etext
+ __data_start__
+ __preinit_array_start
+ __preinit_array_end
+ __init_array_start
+ __init_array_end
+ __fini_array_start
+ __fini_array_end
+ __data_end__
+ __bss_start__
+ __bss_end__
+ __end__
+ end
+ __HeapLimit
+ __StackLimit
+ __StackTop
+ __stack (== StackTop)
+*/
+
+MEMORY
+{
+ FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 2048k
+ RAM(rwx) : ORIGIN = 0x21000000, LENGTH = 256k
+ SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k
+ SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k
+}
+
+ENTRY(_entry_point)
+
+SECTIONS
+{
+ /* Second stage bootloader is prepended to the image. It must be 256 bytes big
+ and checksummed. It is usually built by the boot_stage2 target
+ in the Raspberry Pi Pico SDK
+ */
+
+ .flash_begin : {
+ __flash_binary_start = .;
+ } > FLASH
+
+ .boot2 : {
+ __boot2_start__ = .;
+ KEEP (*(.boot2))
+ __boot2_end__ = .;
+ } > FLASH
+
+ ASSERT(__boot2_end__ - __boot2_start__ == 256,
+ "ERROR: Pico second stage bootloader must be 256 bytes in size")
+
+ /* The second stage will always enter the image at the start of .text.
+ The debugger will use the ELF entry point, which is the _entry_point
+ symbol if present, otherwise defaults to start of .text.
+ This can be used to transfer control back to the bootrom on debugger
+ launches only, to perform proper flash setup.
+ */
+
+ .text : {
+ __logical_binary_start = .;
+ KEEP (*(.vectors))
+ KEEP (*(.binary_info_header))
+ __binary_info_header_end = .;
+ KEEP (*(.reset))
+ /* TODO revisit this now memset/memcpy/float in ROM */
+ /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
+ * FLASH ... we will include any thing excluded here in .data below by default */
+ *(.init)
+ *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
+ *(.fini)
+ /* Pull all c'tors into .text */
+ *crtbegin.o(.ctors)
+ *crtbegin?.o(.ctors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+ *(SORT(.ctors.*))
+ *(.ctors)
+ /* Followed by destructors */
+ *crtbegin.o(.dtors)
+ *crtbegin?.o(.dtors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+ *(SORT(.dtors.*))
+ *(.dtors)
+
+ *(.eh_frame*)
+ . = ALIGN(4);
+ } > FLASH
+
+ .rodata : {
+ *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
+ . = ALIGN(4);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+ . = ALIGN(4);
+ } > FLASH
+
+ .ARM.extab :
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ } > FLASH
+
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > FLASH
+ __exidx_end = .;
+
+ /* Machine inspectable binary information */
+ . = ALIGN(4);
+ __binary_info_start = .;
+ .binary_info :
+ {
+ KEEP(*(.binary_info.keep.*))
+ *(.binary_info.*)
+ } > FLASH
+ __binary_info_end = .;
+ . = ALIGN(4);
+
+ /* End of .text-like segments */
+ __etext = .;
+
+ .ram_vector_table (COPY): {
+ *(.ram_vector_table)
+ } > RAM
+
+ .data : {
+ __data_start__ = .;
+ *(vtable)
+
+ *(.time_critical*)
+
+ /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */
+ *(.text*)
+ . = ALIGN(4);
+ *(.rodata*)
+ . = ALIGN(4);
+
+ *(.data*)
+
+ . = ALIGN(4);
+ *(.after_data.*)
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__mutex_array_start = .);
+ KEEP(*(SORT(.mutex_array.*)))
+ KEEP(*(.mutex_array))
+ PROVIDE_HIDDEN (__mutex_array_end = .);
+
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP(*(SORT(.preinit_array.*)))
+ KEEP(*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+
+ . = ALIGN(4);
+ /* init data */
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+
+ . = ALIGN(4);
+ /* finit data */
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ *(SORT(.fini_array.*))
+ *(.fini_array)
+ PROVIDE_HIDDEN (__fini_array_end = .);
+
+ *(.jcr)
+ . = ALIGN(4);
+ /* All data end */
+ __data_end__ = .;
+ } > RAM AT> FLASH
+
+ .uninitialized_data (COPY): {
+ . = ALIGN(4);
+ *(.uninitialized_data*)
+ } > RAM
+
+ /* Start and end symbols must be word-aligned */
+ .scratch_x : {
+ __scratch_x_start__ = .;
+ *(.scratch_x.*)
+ . = ALIGN(4);
+ __scratch_x_end__ = .;
+ } > SCRATCH_X AT > FLASH
+ __scratch_x_source__ = LOADADDR(.scratch_x);
+
+ .scratch_y : {
+ __scratch_y_start__ = .;
+ *(.scratch_y.*)
+ . = ALIGN(4);
+ __scratch_y_end__ = .;
+ } > SCRATCH_Y AT > FLASH
+ __scratch_y_source__ = LOADADDR(.scratch_y);
+
+ .bss : {
+ . = ALIGN(4);
+ __bss_start__ = .;
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+ *(COMMON)
+ . = ALIGN(4);
+ __bss_end__ = .;
+ } > RAM
+
+ .heap (COPY):
+ {
+ __end__ = .;
+ end = __end__;
+ *(.heap*)
+ __HeapLimit = .;
+ } > RAM
+
+ /* .stack*_dummy section doesn't contains any symbols. It is only
+ * used for linker to calculate size of stack sections, and assign
+ * values to stack symbols later
+ *
+ * stack1 section may be empty/missing if platform_launch_core1 is not used */
+
+ /* by default we put core 0 stack at the end of scratch Y, so that if core 1
+ * stack is not used then all of SCRATCH_X is free.
+ */
+ .stack1_dummy (COPY):
+ {
+ *(.stack1*)
+ } > SCRATCH_X
+ .stack_dummy (COPY):
+ {
+ *(.stack*)
+ } > SCRATCH_Y
+
+ .flash_end : {
+ __flash_binary_end = .;
+ } > FLASH
+
+ /* stack limit is poorly named, but historically is maximum heap ptr */
+ __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+ __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
+ __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
+ __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
+ __StackBottom = __StackTop - SIZEOF(.stack_dummy);
+ PROVIDE(__stack = __StackTop);
+
+ /* Check if data + heap + stack exceeds RAM limit */
+ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+ ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
+ /* todo assert on extra code */
+}
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/memmap_copy_to_ram.ld b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/memmap_copy_to_ram.ld
new file mode 100644
index 00000000000..90975b593f6
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/memmap_copy_to_ram.ld
@@ -0,0 +1,253 @@
+/* Based on GCC ARM embedded samples.
+ Defines the following symbols for use by code:
+ __exidx_start
+ __exidx_end
+ __etext
+ __data_start__
+ __preinit_array_start
+ __preinit_array_end
+ __init_array_start
+ __init_array_end
+ __fini_array_start
+ __fini_array_end
+ __data_end__
+ __bss_start__
+ __bss_end__
+ __end__
+ end
+ __HeapLimit
+ __StackLimit
+ __StackTop
+ __stack (== StackTop)
+*/
+
+MEMORY
+{
+ FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 2048k
+ RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k
+ SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k
+ SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k
+}
+
+ENTRY(_entry_point)
+
+SECTIONS
+{
+ /* Second stage bootloader is prepended to the image. It must be 256 bytes big
+ and checksummed. It is usually built by the boot_stage2 target
+ in the Raspberry Pi Pico SDK
+ */
+
+ .flash_begin : {
+ __flash_binary_start = .;
+ } > FLASH
+
+ .boot2 : {
+ __boot2_start__ = .;
+ KEEP (*(.boot2))
+ __boot2_end__ = .;
+ } > FLASH
+
+ ASSERT(__boot2_end__ - __boot2_start__ == 256,
+ "ERROR: Pico second stage bootloader must be 256 bytes in size")
+
+ /* The second stage will always enter the image at the start of .text.
+ The debugger will use the ELF entry point, which is the _entry_point
+ symbol if present, otherwise defaults to start of .text.
+ This can be used to transfer control back to the bootrom on debugger
+ launches only, to perform proper flash setup.
+ */
+
+ .flashtext : {
+ __logical_binary_start = .;
+ KEEP (*(.vectors))
+ KEEP (*(.binary_info_header))
+ __binary_info_header_end = .;
+ KEEP (*(.reset))
+ }
+
+ .rodata : {
+ /* segments not marked as .flashdata are instead pulled into .data (in RAM) to avoid accidental flash accesses */
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+ . = ALIGN(4);
+ } > FLASH
+
+ .ARM.extab :
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ } > FLASH
+
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > FLASH
+ __exidx_end = .;
+
+ /* Machine inspectable binary information */
+ . = ALIGN(4);
+ __binary_info_start = .;
+ .binary_info :
+ {
+ KEEP(*(.binary_info.keep.*))
+ *(.binary_info.*)
+ } > FLASH
+ __binary_info_end = .;
+ . = ALIGN(4);
+
+ /* Vector table goes first in RAM, to avoid large alignment hole */
+ .ram_vector_table (COPY): {
+ *(.ram_vector_table)
+ } > RAM
+
+ .text : {
+ __ram_text_start__ = .;
+ *(.init)
+ *(.text*)
+ *(.fini)
+ /* Pull all c'tors into .text */
+ *crtbegin.o(.ctors)
+ *crtbegin?.o(.ctors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+ *(SORT(.ctors.*))
+ *(.ctors)
+ /* Followed by destructors */
+ *crtbegin.o(.dtors)
+ *crtbegin?.o(.dtors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+ *(SORT(.dtors.*))
+ *(.dtors)
+
+ *(.eh_frame*)
+ . = ALIGN(4);
+ __ram_text_end__ = .;
+ } > RAM AT> FLASH
+ __ram_text_source__ = LOADADDR(.text);
+
+
+ .data : {
+ __data_start__ = .;
+ *(vtable)
+
+ *(.time_critical*)
+
+ . = ALIGN(4);
+ *(.rodata*)
+ . = ALIGN(4);
+
+ *(.data*)
+
+ . = ALIGN(4);
+ *(.after_data.*)
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__mutex_array_start = .);
+ KEEP(*(SORT(.mutex_array.*)))
+ KEEP(*(.mutex_array))
+ PROVIDE_HIDDEN (__mutex_array_end = .);
+
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP(*(SORT(.preinit_array.*)))
+ KEEP(*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+
+ . = ALIGN(4);
+ /* init data */
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+
+ . = ALIGN(4);
+ /* finit data */
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ *(SORT(.fini_array.*))
+ *(.fini_array)
+ PROVIDE_HIDDEN (__fini_array_end = .);
+
+ *(.jcr)
+ . = ALIGN(4);
+ /* All data end */
+ __data_end__ = .;
+ } > RAM AT> FLASH
+ /* __etext is the name of the .data init source pointer (...) */
+ __etext = LOADADDR(.data);
+
+ .uninitialized_data (COPY): {
+ . = ALIGN(4);
+ *(.uninitialized_data*)
+ } > RAM
+
+ /* Start and end symbols must be word-aligned */
+ .scratch_x : {
+ __scratch_x_start__ = .;
+ *(.scratch_x.*)
+ . = ALIGN(4);
+ __scratch_x_end__ = .;
+ } > SCRATCH_X AT > FLASH
+ __scratch_x_source__ = LOADADDR(.scratch_x);
+
+ .scratch_y : {
+ __scratch_y_start__ = .;
+ *(.scratch_y.*)
+ . = ALIGN(4);
+ __scratch_y_end__ = .;
+ } > SCRATCH_Y AT > FLASH
+ __scratch_y_source__ = LOADADDR(.scratch_y);
+
+ .bss : {
+ . = ALIGN(4);
+ __bss_start__ = .;
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+ *(COMMON)
+ . = ALIGN(4);
+ __bss_end__ = .;
+ } > RAM
+
+ .heap (COPY):
+ {
+ __end__ = .;
+ end = __end__;
+ *(.heap*)
+ __HeapLimit = .;
+ } > RAM
+
+ /* .stack*_dummy section doesn't contains any symbols. It is only
+ * used for linker to calculate size of stack sections, and assign
+ * values to stack symbols later
+ *
+ * stack1 section may be empty/missing if platform_launch_core1 is not used */
+
+ /* by default we put core 0 stack at the end of scratch Y, so that if core 1
+ * stack is not used then all of SCRATCH_X is free.
+ */
+ .stack1_dummy (COPY):
+ {
+ *(.stack1*)
+ } > SCRATCH_X
+ .stack_dummy (COPY):
+ {
+ *(.stack*)
+ } > SCRATCH_Y
+
+ .flash_end : {
+ __flash_binary_end = .;
+ } > FLASH
+
+ /* stack limit is poorly named, but historically is maximum heap ptr */
+ __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+ __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
+ __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
+ __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
+ __StackBottom = __StackTop - SIZEOF(.stack_dummy);
+ PROVIDE(__stack = __StackTop);
+
+ /* Check if data + heap + stack exceeds RAM limit */
+ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+ ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
+ /* todo assert on extra code */
+}
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/memmap_default.ld b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/memmap_default.ld
new file mode 100644
index 00000000000..07d5812db1f
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/memmap_default.ld
@@ -0,0 +1,252 @@
+/* Based on GCC ARM embedded samples.
+ Defines the following symbols for use by code:
+ __exidx_start
+ __exidx_end
+ __etext
+ __data_start__
+ __preinit_array_start
+ __preinit_array_end
+ __init_array_start
+ __init_array_end
+ __fini_array_start
+ __fini_array_end
+ __data_end__
+ __bss_start__
+ __bss_end__
+ __end__
+ end
+ __HeapLimit
+ __StackLimit
+ __StackTop
+ __stack (== StackTop)
+*/
+
+MEMORY
+{
+ FLASH(rx) : ORIGIN = 0x10000000, LENGTH = 2048k
+ RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k
+ SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k
+ SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k
+}
+
+ENTRY(_entry_point)
+
+SECTIONS
+{
+ /* Second stage bootloader is prepended to the image. It must be 256 bytes big
+ and checksummed. It is usually built by the boot_stage2 target
+ in the Raspberry Pi Pico SDK
+ */
+
+ .flash_begin : {
+ __flash_binary_start = .;
+ } > FLASH
+
+ .boot2 : {
+ __boot2_start__ = .;
+ KEEP (*(.boot2))
+ __boot2_end__ = .;
+ } > FLASH
+
+ ASSERT(__boot2_end__ - __boot2_start__ == 256,
+ "ERROR: Pico second stage bootloader must be 256 bytes in size")
+
+ /* The second stage will always enter the image at the start of .text.
+ The debugger will use the ELF entry point, which is the _entry_point
+ symbol if present, otherwise defaults to start of .text.
+ This can be used to transfer control back to the bootrom on debugger
+ launches only, to perform proper flash setup.
+ */
+
+ .text : {
+ __logical_binary_start = .;
+ KEEP (*(.vectors))
+ KEEP (*(.binary_info_header))
+ __binary_info_header_end = .;
+ KEEP (*(.reset))
+ /* TODO revisit this now memset/memcpy/float in ROM */
+ /* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
+ * FLASH ... we will include any thing excluded here in .data below by default */
+ *(.init)
+ *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
+ *(.fini)
+ /* Pull all c'tors into .text */
+ *crtbegin.o(.ctors)
+ *crtbegin?.o(.ctors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+ *(SORT(.ctors.*))
+ *(.ctors)
+ /* Followed by destructors */
+ *crtbegin.o(.dtors)
+ *crtbegin?.o(.dtors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+ *(SORT(.dtors.*))
+ *(.dtors)
+
+ *(.eh_frame*)
+ . = ALIGN(4);
+ } > FLASH
+
+ .rodata : {
+ *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .rodata*)
+ . = ALIGN(4);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+ . = ALIGN(4);
+ } > FLASH
+
+ .ARM.extab :
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ } > FLASH
+
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > FLASH
+ __exidx_end = .;
+
+ /* Machine inspectable binary information */
+ . = ALIGN(4);
+ __binary_info_start = .;
+ .binary_info :
+ {
+ KEEP(*(.binary_info.keep.*))
+ *(.binary_info.*)
+ } > FLASH
+ __binary_info_end = .;
+ . = ALIGN(4);
+
+ /* End of .text-like segments */
+ __etext = .;
+
+ .ram_vector_table (COPY): {
+ *(.ram_vector_table)
+ } > RAM
+
+ .data : {
+ __data_start__ = .;
+ *(vtable)
+
+ *(.time_critical*)
+
+ /* remaining .text and .rodata; i.e. stuff we exclude above because we want it in RAM */
+ *(.text*)
+ . = ALIGN(4);
+ *(.rodata*)
+ . = ALIGN(4);
+
+ *(.data*)
+
+ . = ALIGN(4);
+ *(.after_data.*)
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__mutex_array_start = .);
+ KEEP(*(SORT(.mutex_array.*)))
+ KEEP(*(.mutex_array))
+ PROVIDE_HIDDEN (__mutex_array_end = .);
+
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP(*(SORT(.preinit_array.*)))
+ KEEP(*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+
+ . = ALIGN(4);
+ /* init data */
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+
+ . = ALIGN(4);
+ /* finit data */
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ *(SORT(.fini_array.*))
+ *(.fini_array)
+ PROVIDE_HIDDEN (__fini_array_end = .);
+
+ *(.jcr)
+ . = ALIGN(4);
+ /* All data end */
+ __data_end__ = .;
+ } > RAM AT> FLASH
+
+ .uninitialized_data (COPY): {
+ . = ALIGN(4);
+ *(.uninitialized_data*)
+ } > RAM
+
+ /* Start and end symbols must be word-aligned */
+ .scratch_x : {
+ __scratch_x_start__ = .;
+ *(.scratch_x.*)
+ . = ALIGN(4);
+ __scratch_x_end__ = .;
+ } > SCRATCH_X AT > FLASH
+ __scratch_x_source__ = LOADADDR(.scratch_x);
+
+ .scratch_y : {
+ __scratch_y_start__ = .;
+ *(.scratch_y.*)
+ . = ALIGN(4);
+ __scratch_y_end__ = .;
+ } > SCRATCH_Y AT > FLASH
+ __scratch_y_source__ = LOADADDR(.scratch_y);
+
+ .bss : {
+ . = ALIGN(4);
+ __bss_start__ = .;
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+ *(COMMON)
+ . = ALIGN(4);
+ __bss_end__ = .;
+ } > RAM
+
+ .heap (COPY):
+ {
+ __end__ = .;
+ end = __end__;
+ *(.heap*)
+ __HeapLimit = .;
+ } > RAM
+
+ /* .stack*_dummy section doesn't contains any symbols. It is only
+ * used for linker to calculate size of stack sections, and assign
+ * values to stack symbols later
+ *
+ * stack1 section may be empty/missing if platform_launch_core1 is not used */
+
+ /* by default we put core 0 stack at the end of scratch Y, so that if core 1
+ * stack is not used then all of SCRATCH_X is free.
+ */
+ .stack1_dummy (COPY):
+ {
+ *(.stack1*)
+ } > SCRATCH_X
+ .stack_dummy (COPY):
+ {
+ *(.stack*)
+ } > SCRATCH_Y
+
+ .flash_end : {
+ __flash_binary_end = .;
+ } > FLASH
+
+ /* stack limit is poorly named, but historically is maximum heap ptr */
+ __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+ __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
+ __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
+ __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
+ __StackBottom = __StackTop - SIZEOF(.stack_dummy);
+ PROVIDE(__stack = __StackTop);
+
+ /* Check if data + heap + stack exceeds RAM limit */
+ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+ ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
+ /* todo assert on extra code */
+}
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/memmap_no_flash.ld b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/memmap_no_flash.ld
new file mode 100644
index 00000000000..7a5977fa552
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/memmap_no_flash.ld
@@ -0,0 +1,217 @@
+/* Based on GCC ARM embedded samples.
+ Defines the following symbols for use by code:
+ __exidx_start
+ __exidx_end
+ __etext
+ __data_start__
+ __preinit_array_start
+ __preinit_array_end
+ __init_array_start
+ __init_array_end
+ __fini_array_start
+ __fini_array_end
+ __data_end__
+ __bss_start__
+ __bss_end__
+ __end__
+ end
+ __HeapLimit
+ __StackLimit
+ __StackTop
+ __stack (== StackTop)
+*/
+
+MEMORY
+{
+ RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 256k
+ SCRATCH_X(rwx) : ORIGIN = 0x20040000, LENGTH = 4k
+ SCRATCH_Y(rwx) : ORIGIN = 0x20041000, LENGTH = 4k
+}
+
+ENTRY(_entry_point)
+
+SECTIONS
+{
+ /* Note in NO_FLASH builds the entry point for both the bootrom, and debugger
+ entry (ELF entry point), are *first* in the image, and the vector table
+ follows immediately afterward. This is because the bootrom enters RAM
+ binaries directly at their lowest address (preferring main RAM over XIP
+ cache-as-SRAM if both are used).
+ */
+
+ .text : {
+ __logical_binary_start = .;
+ __reset_start = .;
+ KEEP (*(.reset))
+ __reset_end = .;
+ KEEP (*(.binary_info_header))
+ __binary_info_header_end = .;
+ . = ALIGN(256);
+ KEEP (*(.vectors))
+ *(.time_critical*)
+ *(.text*)
+ . = ALIGN(4);
+ *(.init)
+ *(.fini)
+ /* Pull all c'tors into .text */
+ *crtbegin.o(.ctors)
+ *crtbegin?.o(.ctors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+ *(SORT(.ctors.*))
+ *(.ctors)
+ /* Followed by destructors */
+ *crtbegin.o(.dtors)
+ *crtbegin?.o(.dtors)
+ *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+ *(SORT(.dtors.*))
+ *(.dtors)
+
+ *(.eh_frame*)
+ } > RAM
+
+ .rodata : {
+ *(.rodata*)
+ . = ALIGN(4);
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.flashdata*)))
+ . = ALIGN(4);
+ } > RAM
+
+ .ARM.extab :
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ } > RAM
+
+ __exidx_start = .;
+ .ARM.exidx :
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ } > RAM
+ __exidx_end = .;
+
+ /* Machine inspectable binary information */
+ . = ALIGN(4);
+ __binary_info_start = .;
+ .binary_info :
+ {
+ KEEP(*(.binary_info.keep.*))
+ *(.binary_info.*)
+ } > RAM
+ __binary_info_end = .;
+ . = ALIGN(4);
+
+ .data : {
+ /* End of .text-like segments */
+ __etext = .;
+ __data_start__ = .;
+ *(vtable)
+ *(.data*)
+
+ . = ALIGN(4);
+ *(.after_data.*)
+
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__mutex_array_start = .);
+ KEEP(*(SORT(.mutex_array.*)))
+ KEEP(*(.mutex_array))
+ PROVIDE_HIDDEN (__mutex_array_end = .);
+
+ . = ALIGN(4);
+ /* preinit data */
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP(*(SORT(.preinit_array.*)))
+ KEEP(*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+
+ . = ALIGN(4);
+ /* init data */
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+
+ . = ALIGN(4);
+ /* finit data */
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ *(SORT(.fini_array.*))
+ *(.fini_array)
+ PROVIDE_HIDDEN (__fini_array_end = .);
+
+ *(.jcr)
+ . = ALIGN(4);
+ /* All data end */
+ __data_end__ = .;
+ } > RAM
+
+ .uninitialized_data (COPY): {
+ . = ALIGN(4);
+ *(.uninitialized_data*)
+ } > RAM
+
+ /* Start and end symbols must be word-aligned */
+ .scratch_x : {
+ __scratch_x_start__ = .;
+ *(.scratch_x.*)
+ . = ALIGN(4);
+ __scratch_x_end__ = .;
+ } > SCRATCH_X
+ __scratch_x_source__ = LOADADDR(.scratch_x);
+
+ .scratch_y : {
+ __scratch_y_start__ = .;
+ *(.scratch_y.*)
+ . = ALIGN(4);
+ __scratch_y_end__ = .;
+ } > SCRATCH_Y
+ __scratch_y_source__ = LOADADDR(.scratch_y);
+
+ .bss : {
+ . = ALIGN(4);
+ __bss_start__ = .;
+ *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
+ *(COMMON)
+ . = ALIGN(4);
+ __bss_end__ = .;
+ } > RAM
+
+ .heap (COPY):
+ {
+ __end__ = .;
+ end = __end__;
+ *(.heap*)
+ __HeapLimit = .;
+ } > RAM
+
+ /* .stack*_dummy section doesn't contains any symbols. It is only
+ * used for linker to calculate size of stack sections, and assign
+ * values to stack symbols later
+ *
+ * stack1 section may be empty/missing if platform_launch_core1 is not used */
+
+ /* by default we put core 0 stack at the end of scratch Y, so that if core 1
+ * stack is not used then all of SCRATCH_X is free.
+ */
+ .stack1_dummy (COPY):
+ {
+ *(.stack1*)
+ } > SCRATCH_X
+ .stack_dummy (COPY):
+ {
+ *(.stack*)
+ } > SCRATCH_Y
+
+ /* stack limit is poorly named, but historically is maximum heap ptr */
+ __StackLimit = ORIGIN(RAM) + LENGTH(RAM);
+ __StackOneTop = ORIGIN(SCRATCH_X) + LENGTH(SCRATCH_X);
+ __StackTop = ORIGIN(SCRATCH_Y) + LENGTH(SCRATCH_Y);
+ __StackOneBottom = __StackOneTop - SIZEOF(.stack1_dummy);
+ __StackBottom = __StackTop - SIZEOF(.stack_dummy);
+ PROVIDE(__stack = __StackTop);
+
+ /* Check if data + heap + stack exceeds RAM limit */
+ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed")
+
+ ASSERT( __binary_info_header_end - __logical_binary_start <= 256, "Binary info must be in first 256 bytes of the binary")
+ /* todo assert on extra code */
+}
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/new_delete.cpp b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/new_delete.cpp
new file mode 100644
index 00000000000..ecb04b4e6c0
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_standard_link/new_delete.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#if !PICO_CXX_ENABLE_EXCEPTIONS
+// Override the standard allocators to use regular malloc/free
+
+#include
+
+void *operator new(std::size_t n) {
+ return std::malloc(n);
+}
+
+void *operator new[](std::size_t n) {
+ return std::malloc(n);
+}
+
+void operator delete(void *p, std::size_t n) noexcept { std::free(p); }
+
+void operator delete(void *p) { std::free(p); }
+
+void operator delete[](void *p) noexcept { std::free(p); }
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/CMakeLists.txt
new file mode 100644
index 00000000000..15ca07ba4ab
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/CMakeLists.txt
@@ -0,0 +1,18 @@
+if (NOT TARGET pico_stdio)
+ add_library(pico_stdio INTERFACE)
+
+ target_include_directories(pico_stdio INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
+ target_sources(pico_stdio INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/stdio.c
+ )
+
+ pico_wrap_function(pico_stdio printf)
+ pico_wrap_function(pico_stdio vprintf)
+ pico_wrap_function(pico_stdio puts)
+ pico_wrap_function(pico_stdio putchar)
+
+ if (TARGET pico_printf)
+ target_link_libraries(pico_stdio INTERFACE pico_printf)
+ endif()
+endif()
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/LICENSE b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/LICENSE
new file mode 100644
index 00000000000..8f7ebd0b98d
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Marco Paland
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/include/pico/stdio.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/include/pico/stdio.h
new file mode 100644
index 00000000000..aec49dfb353
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/include/pico/stdio.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_STDIO_H
+#define _PICO_STDIO_H
+
+/** \file stdio.h
+* \defgroup pico_stdio pico_stdio
+* Customized stdio support allowing for input and output from UART, USB, semi-hosting etc.
+*
+* Note the API for adding additional input output devices is not yet considered stable
+*/
+
+#include "pico.h"
+
+// PICO_CONFIG: PICO_STDOUT_MUTEX, Enable/disable mutex around stdout, type=bool, default=1, group=pico_stdio
+#ifndef PICO_STDOUT_MUTEX
+#define PICO_STDOUT_MUTEX 1
+#endif
+
+// PICO_CONFIG: PICO_STDIO_ENABLE_CRLF_SUPPORT, Enable/disable CR/LF output conversion support, type=bool, default=1, group=pico_stdio
+#ifndef PICO_STDIO_ENABLE_CRLF_SUPPORT
+#define PICO_STDIO_ENABLE_CRLF_SUPPORT 1
+#endif
+
+// PICO_CONFIG: PICO_STDIO_DEFAULT_CRLF, Default for CR/LF conversion enabled on all stdio outputs, type=bool, default=1, depends=PICO_STDIO_ENABLE_CRLF_SUPPORT, group=pico_stdio
+#ifndef PICO_STDIO_DEFAULT_CRLF
+#define PICO_STDIO_DEFAULT_CRLF 1
+#endif
+
+// PICO_CONFIG: PICO_STDIO_STACK_BUFFER_SIZE, Define printf buffer size (on stack)... this is just a working buffer not a max output size, min=0, max=512, default=128, group=pico_stdio
+#ifndef PICO_STDIO_STACK_BUFFER_SIZE
+#define PICO_STDIO_STACK_BUFFER_SIZE 128
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct stdio_driver stdio_driver_t;
+
+/*! \brief Initialize all of the present standard stdio types that are linked into the binary.
+ * \ingroup pico_stdio
+ *
+ * Call this method once you have set up your clocks to enable the stdio support for UART, USB
+ * and semihosting based on the presence of the respective librariess in the binary.
+ *
+ * \see stdio_uart, stdio_usb, stdio_semihosting
+ */
+void stdio_init_all();
+
+/*! \brief Initialize all of the present standard stdio types that are linked into the binary.
+ * \ingroup pico_stdio
+ *
+ * Call this method once you have set up your clocks to enable the stdio support for UART, USB
+ * and semihosting based on the presence of the respective librariess in the binary.
+ *
+ * \see stdio_uart, stdio_usb, stdio_semihosting
+ */
+void stdio_flush();
+
+/*! \brief Return a character from stdin if there is one available within a timeout
+ * \ingroup pico_stdio
+ *
+ * \param timeout_us the timeout in microseconds, or 0 to not wait for a character if none available.
+ * \return the character from 0-255 or PICO_ERROR_TIMEOUT if timeout occurs
+ */
+int getchar_timeout_us(uint32_t timeout_us);
+
+/*! \brief Adds or removes a driver from the list of active drivers used for input/output
+ * \ingroup pico_stdio
+ *
+ * \note this method should always be called on an initialized driver
+ * \param driver the driver
+ * \param enabled true to add, false to remove
+ */
+void stdio_set_driver_enabled(stdio_driver_t *driver, bool enabled);
+
+/*! \brief Control limiting of output to a single driver
+ * \ingroup pico_stdio
+ *
+ * \note this method should always be called on an initialized driver
+ *
+ * \param driver if non-null then output only that driver will be used for input/output (assuming it is in the list of enabled drivers).
+ * if NULL then all enabled drivers will be used
+ */
+void stdio_filter_driver(stdio_driver_t *driver);
+
+/*! \brief control conversion of line feeds to carriage return on transmissions
+ * \ingroup pico_stdio
+ *
+ * \note this method should always be called on an initialized driver
+ *
+ * \param driver the driver
+ * \param translate If true, convert line feeds to carriage return on transmissions
+ */
+void stdio_set_translate_crlf(stdio_driver_t *driver, bool translate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/include/pico/stdio/driver.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/include/pico/stdio/driver.h
new file mode 100644
index 00000000000..017206d3cd2
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/include/pico/stdio/driver.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_STDIO_DRIVER_H
+#define _PICO_STDIO_DRIVER_H
+
+#include "pico/stdio.h"
+#include "pico/platform.h"
+
+struct stdio_driver {
+ void (*out_chars)(const char *buf, int len);
+ void (*out_flush)();
+ int (*in_chars)(char *buf, int len);
+ stdio_driver_t *next;
+#if PICO_STDIO_ENABLE_CRLF_SUPPORT
+ bool last_ended_with_cr;
+ bool crlf_enabled;
+#endif
+};
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/stdio.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/stdio.c
new file mode 100644
index 00000000000..aecc488891e
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio/stdio.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include
+#include
+#include
+
+#include "pico.h"
+#include "pico/mutex.h"
+#include "pico/printf.h"
+#include "pico/stdio.h"
+#include "pico/stdio/driver.h"
+#include "pico/time.h"
+
+#if PICO_STDIO_UART
+#include "pico/stdio_uart.h"
+#endif
+
+#if PICO_STDIO_USB
+#include "pico/stdio_usb.h"
+#endif
+
+#if PICO_STDIO_SEMIHOSTING
+#include "pico/stdio_semihosting.h"
+#endif
+
+static stdio_driver_t *drivers;
+static stdio_driver_t *filter;
+
+#if PICO_STDOUT_MUTEX
+auto_init_mutex(print_mutex);
+
+bool stdout_serialize_begin() {
+ int core_num = get_core_num();
+ uint32_t owner;
+ if (!mutex_try_enter(&print_mutex, &owner)) {
+ if (owner == core_num) {
+ return false;
+ }
+ // other core owns the mutex, so lets wait
+ mutex_enter_blocking(&print_mutex);
+ }
+ return true;
+}
+
+void stdout_serialize_end() {
+ mutex_exit(&print_mutex);
+}
+
+#else
+static bool print_serialize_begin() {
+ return true;
+}
+static void print_serialize_end() {
+}
+#endif
+
+static void stdio_out_chars_crlf(stdio_driver_t *driver, const char *s, int len) {
+#if PICO_STDIO_ENABLE_CRLF_SUPPORT
+ if (!driver->crlf_enabled) {
+ driver->out_chars(s, len);
+ return;
+ }
+ int first_of_chunk = 0;
+ static const char crlf_str[] = {'\r', '\n'};
+ for (int i = 0; i < len; i++) {
+ bool prev_char_was_cr = i > 0 ? s[i - 1] == '\r' : driver->last_ended_with_cr;
+ if (s[i] == '\n' && !prev_char_was_cr) {
+ if (i > first_of_chunk) {
+ driver->out_chars(&s[first_of_chunk], i - first_of_chunk);
+ }
+ driver->out_chars(crlf_str, 2);
+ first_of_chunk = i + 1;
+ }
+ }
+ if (first_of_chunk < len) {
+ driver->out_chars(&s[first_of_chunk], len - first_of_chunk);
+ }
+ if (len > 0) {
+ driver->last_ended_with_cr = s[len - 1] == '\r';
+ }
+#else
+ driver->out_chars(s, len);
+#endif
+}
+
+static bool stdio_put_string(const char *s, int len, bool newline) {
+ bool serialzed = stdout_serialize_begin();
+ if (!serialzed) {
+#if PICO_STDIO_IGNORE_NESTED_STDOUT
+ return false;
+#endif
+ }
+ if (len == -1) len = strlen(s);
+ for (stdio_driver_t *driver = drivers; driver; driver = driver->next) {
+ if (!driver->out_chars) continue;
+ if (filter && filter != driver) continue;
+ stdio_out_chars_crlf(driver, s, len);
+ if (newline) {
+ const char c = '\n';
+ stdio_out_chars_crlf(driver, &c, 1);
+ }
+ }
+ if (serialzed) {
+ stdout_serialize_end();
+ }
+ return len;
+}
+
+static int stdio_get_until(char *buf, int len, absolute_time_t until) {
+ do {
+ // todo round robin might be nice on each call, but then again hopefully
+ // no source will starve the others
+ for (stdio_driver_t *driver = drivers; driver; driver = driver->next) {
+ if (filter && filter != driver) continue;
+ if (driver->in_chars) {
+ int read = driver->in_chars(buf, len);
+ if (read > 0) {
+ return read;
+ }
+ }
+ }
+ // todo maybe a little sleep here?
+ } while (!time_reached(until));
+ return PICO_ERROR_TIMEOUT;
+}
+
+int WRAPPER_FUNC(putchar)(int c) {
+ char cc = c;
+ stdio_put_string(&cc, 1, false);
+ return c;
+}
+
+int WRAPPER_FUNC(puts)(const char *s) {
+ int len = strlen(s);
+ stdio_put_string(s, len, true);
+ stdio_flush();
+ return len;
+}
+
+int _read(int handle, char *buffer, int length) {
+ if (handle == 0) {
+ return stdio_get_until(buffer, length, at_the_end_of_time);
+ }
+ return -1;
+}
+
+int _write(int handle, char *buffer, int length) {
+ if (handle == 1) {
+ stdio_put_string(buffer, length, false);
+ return length;
+ }
+ return -1;
+}
+
+void stdio_set_driver_enabled(stdio_driver_t *driver, bool enable) {
+ stdio_driver_t *prev = drivers;
+ for (stdio_driver_t *d = drivers; d; d = d->next) {
+ if (d == driver) {
+ if (!enable) {
+ prev->next = d->next;
+ driver->next = NULL;
+ }
+ return;
+ }
+ prev = d;
+ }
+ if (enable) {
+ if (prev) prev->next = driver;
+ else drivers = driver;
+ }
+}
+
+void stdio_flush() {
+ for (stdio_driver_t *d = drivers; d; d = d->next) {
+ if (d->out_flush) d->out_flush();
+ }
+}
+
+typedef struct stdio_stack_buffer {
+ uint used;
+ char buf[PICO_STDIO_STACK_BUFFER_SIZE];
+} stdio_stack_buffer_t;
+
+static void stdio_stack_buffer_flush(stdio_stack_buffer_t *buffer) {
+ if (buffer->used) {
+ for (stdio_driver_t *d = drivers; d; d = d->next) {
+ if (!d->out_chars) continue;
+ if (filter && filter != d) continue;
+ stdio_out_chars_crlf(d, buffer->buf, buffer->used);
+ }
+ buffer->used = 0;
+ }
+}
+
+static void stdio_buffered_printer(char c, void *arg) {
+ stdio_stack_buffer_t *buffer = (stdio_stack_buffer_t *)arg;
+ if (buffer->used == PICO_STDIO_STACK_BUFFER_SIZE) {
+ stdio_stack_buffer_flush(buffer);
+ }
+ buffer->buf[buffer->used++] = c;
+}
+
+int WRAPPER_FUNC(vprintf)(const char *format, va_list va) {
+ bool serialzed = stdout_serialize_begin();
+ if (!serialzed) {
+#if PICO_STDIO_IGNORE_NESTED_STDOUT
+ return 0;
+#endif
+ }
+ int ret;
+#if PICO_PRINTF_PICO
+ struct stdio_stack_buffer buffer = {.used = 0};
+ ret = vfctprintf(stdio_buffered_printer, &buffer, format, va);
+ stdio_stack_buffer_flush(&buffer);
+ stdio_flush();
+#elif PICO_PRINTF_NONE
+ extern void printf_none_assert();
+ printf_none_assert();
+#else
+ extern int REAL_FUNC(vprintf)(const char *format, va_list va);
+ ret = REAL_FUNC(vprintf)(format, va);
+#endif
+ if (serialzed) {
+ stdout_serialize_end();
+ }
+ return ret;
+}
+
+int __printflike(1, 0) WRAPPER_FUNC(printf)(const char* format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ int ret = vprintf(format, va);
+ va_end(va);
+ return ret;
+}
+
+void stdio_init_all() {
+ // todo add explicit custom, or registered although you can call stdio_enable_driver explicitly anyway
+ // These are well known ones
+#if PICO_STDIO_UART
+ stdio_uart_init();
+#endif
+
+#if PICO_STDIO_SEMIHOSTING
+ stdio_semihosting_init();
+#endif
+
+#if PICO_STDIO_USB
+ stdio_usb_init();
+#endif
+}
+
+int WRAPPER_FUNC(getchar)() {
+ char buf[1];
+ if (0 == stdio_get_until(buf, sizeof(buf), at_the_end_of_time)) {
+ return PICO_ERROR_TIMEOUT;
+ }
+ return (uint8_t)buf[0];
+}
+
+int getchar_timeout_us(uint32_t timeout_us) {
+ char buf[1];
+ int rc = stdio_get_until(buf, sizeof(buf), make_timeout_time_us(timeout_us));
+ if (rc < 0) return rc;
+ assert(rc);
+ return (uint8_t)buf[0];
+}
+
+void stdio_filter_driver(stdio_driver_t *driver) {
+ filter = driver;
+}
+
+void stdio_set_translate_crlf(stdio_driver_t *driver, bool enabled) {
+#if PICO_STDIO_ENABLE_CRLF_SUPPORT
+ if (enabled && !driver->crlf_enabled) {
+ driver->last_ended_with_cr = false;
+ }
+ driver->crlf_enabled = enabled;
+#else
+ panic_unsupported();
+#endif
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio_semihosting/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio_semihosting/CMakeLists.txt
new file mode 100644
index 00000000000..c65aa91d55a
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio_semihosting/CMakeLists.txt
@@ -0,0 +1,13 @@
+add_library(pico_stdio_semihosting INTERFACE)
+
+target_sources(pico_stdio_semihosting INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/stdio_semihosting.c
+)
+
+target_include_directories(pico_stdio_semihosting INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
+target_compile_definitions(pico_stdio_semihosting INTERFACE
+ PICO_STDIO_SEMIHOSTING=1
+)
+
+target_link_libraries(pico_stdio_semihosting INTERFACE pico_stdio)
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio_semihosting/include/pico/stdio_semihosting.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio_semihosting/include/pico/stdio_semihosting.h
new file mode 100644
index 00000000000..0c2f00639b8
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio_semihosting/include/pico/stdio_semihosting.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_STDIO_SEMIHOSTING_H
+#define _PICO_STDIO_SEMIHOSTING_H
+
+#include "pico/stdio.h"
+
+/** \brief Experimental support for stdout using RAM semihosting
+ * \defgroup pico_stdio_semihosting pico_stdio_semihosting
+ * \ingroup pico_stdio
+ *
+ * Linking this library or calling `pico_enable_stdio_semihosting(TARGET)` in the CMake (which
+ * achieves the same thing) will add semihosting to the drivers used for standard output
+ */
+
+// PICO_CONFIG: PICO_STDIO_SEMIHOSTING_DEFAULT_CRLF, Default state of CR/LF translation for semihosting output, type=bool, default=PICO_STDIO_DEFAULT_CRLF, group=pico_stdio_semihosting
+#ifndef PICO_STDIO_SEMIHOSTING_DEFAULT_CRLF
+#define PICO_STDIO_SEMIHOSTING_DEFAULT_CRLF PICO_STDIO_DEFAULT_CRLF
+#endif
+
+extern stdio_driver_t stdio_semihosting;
+
+/*! \brief Explicitly initialize stdout over semihosting and add it to the current set of stdout targets
+ * \ingroup pico_stdio_semihosting
+ *
+ * \note this method is automatically called by \ref stdio_init_all() if `pico_stdio_semihosting` is included in the build
+ */
+void stdio_semihosting_init();
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio_semihosting/stdio_semihosting.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio_semihosting/stdio_semihosting.c
new file mode 100644
index 00000000000..89367702e4f
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio_semihosting/stdio_semihosting.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico/stdio/driver.h"
+#include "pico/stdio_semihosting.h"
+#include "pico/binary_info.h"
+
+//static void __attribute__((naked)) semihosting_puts(const char *s) {
+// __asm (
+//
+// "mov r1, r0\n"
+// "mov r0, #4\n"
+// "bkpt 0xab\n"
+// "bx lr\n"
+// );
+//}
+
+static void __attribute__((naked)) semihosting_putc(char c) {
+ __asm (
+
+ "mov r1, r0\n"
+ "mov r0, #3\n"
+ "bkpt 0xab\n"
+ "bx lr\n"
+ );
+}
+
+
+static void stdio_semihosting_out_chars(const char *buf, int length) {
+ for (uint i = 0; i RTC_IRQ, ""); // note RTC_IRQ is currently the last one
+static mutex_t stdio_usb_mutex;
+
+static void low_priority_worker_irq() {
+ // if the mutex is already owned, then we are in user code
+ // in this file which will do a tud_task itself, so we'll just do nothing
+ // until the next tick; we won't starve
+ if (mutex_try_enter(&stdio_usb_mutex, NULL)) {
+ tud_task();
+ mutex_exit(&stdio_usb_mutex);
+ }
+}
+
+static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
+ irq_set_pending(PICO_STDIO_USB_LOW_PRIORITY_IRQ);
+ return PICO_STDIO_USB_TASK_INTERVAL_US;
+}
+
+static void stdio_usb_out_chars(const char *buf, int length) {
+ static uint64_t last_avail_time;
+ uint32_t owner;
+ if (!mutex_try_enter(&stdio_usb_mutex, &owner)) {
+ if (owner == get_core_num()) return; // would deadlock otherwise
+ mutex_enter_blocking(&stdio_usb_mutex);
+ }
+ if (tud_cdc_connected()) {
+ for (int i = 0; i < length;) {
+ int n = length - i;
+ int avail = tud_cdc_write_available();
+ if (n > avail) n = avail;
+ if (n) {
+ int n2 = tud_cdc_write(buf + i, n);
+ tud_task();
+ tud_cdc_write_flush();
+ i += n2;
+ last_avail_time = time_us_64();
+ } else {
+ tud_task();
+ tud_cdc_write_flush();
+ if (!tud_cdc_connected() ||
+ (!tud_cdc_write_available() && time_us_64() > last_avail_time + PICO_STDIO_USB_STDOUT_TIMEOUT_US)) {
+ break;
+ }
+ }
+ }
+ } else {
+ // reset our timeout
+ last_avail_time = 0;
+ }
+ mutex_exit(&stdio_usb_mutex);
+}
+
+int stdio_usb_in_chars(char *buf, int length) {
+ uint32_t owner;
+ if (!mutex_try_enter(&stdio_usb_mutex, &owner)) {
+ if (owner == get_core_num()) return PICO_ERROR_NO_DATA; // would deadlock otherwise
+ mutex_enter_blocking(&stdio_usb_mutex);
+ }
+ int rc = PICO_ERROR_NO_DATA;
+ if (tud_cdc_connected() && tud_cdc_available()) {
+ int count = tud_cdc_read(buf, length);
+ rc = count ? count : PICO_ERROR_NO_DATA;
+ }
+ mutex_exit(&stdio_usb_mutex);
+ return rc;
+}
+
+stdio_driver_t stdio_usb = {
+ .out_chars = stdio_usb_out_chars,
+ .in_chars = stdio_usb_in_chars,
+#if PICO_STDIO_ENABLE_CRLF_SUPPORT
+ .crlf_enabled = PICO_STDIO_USB_DEFAULT_CRLF
+#endif
+};
+
+bool stdio_usb_init(void) {
+#if !PICO_NO_BI_STDIO_USB
+ bi_decl_if_func_used(bi_program_feature("USB stdin / stdout"));
+#endif
+
+ // initialize TinyUSB
+ tusb_init();
+
+ irq_set_exclusive_handler(PICO_STDIO_USB_LOW_PRIORITY_IRQ, low_priority_worker_irq);
+ irq_set_enabled(PICO_STDIO_USB_LOW_PRIORITY_IRQ, true);
+
+ mutex_init(&stdio_usb_mutex);
+ bool rc = add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true);
+ if (rc) {
+ stdio_set_driver_enabled(&stdio_usb, true);
+ }
+ return rc;
+}
+#else
+#include "pico/stdio_usb.h"
+#warning stdio USB was configured, but is being disabled as TinyUSB is explicitly linked
+bool stdio_usb_init(void) {
+ return false;
+}
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c
new file mode 100644
index 00000000000..3199886e88a
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c
@@ -0,0 +1,121 @@
+/*
+ * This file is based on a file originally part of the
+ * MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#if !defined(TINYUSB_HOST_LINKED) && !defined(TINYUSB_DEVICE_LINKED)
+
+#include "tusb.h"
+
+#define USBD_VID (0x2E8A) // Raspberry Pi
+#define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC
+
+#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
+#define USBD_MAX_POWER_MA (250)
+
+#define USBD_ITF_CDC (0) // needs 2 interfaces
+#define USBD_ITF_MAX (2)
+
+#define USBD_CDC_EP_CMD (0x81)
+#define USBD_CDC_EP_OUT (0x02)
+#define USBD_CDC_EP_IN (0x82)
+#define USBD_CDC_CMD_MAX_SIZE (8)
+#define USBD_CDC_IN_OUT_MAX_SIZE (64)
+
+#define USBD_STR_0 (0x00)
+#define USBD_STR_MANUF (0x01)
+#define USBD_STR_PRODUCT (0x02)
+#define USBD_STR_SERIAL (0x03)
+#define USBD_STR_CDC (0x04)
+
+// Note: descriptors returned from callbacks must exist long enough for transfer to complete
+
+static const tusb_desc_device_t usbd_desc_device = {
+ .bLength = sizeof(tusb_desc_device_t),
+ .bDescriptorType = TUSB_DESC_DEVICE,
+ .bcdUSB = 0x0200,
+ .bDeviceClass = TUSB_CLASS_MISC,
+ .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+ .bDeviceProtocol = MISC_PROTOCOL_IAD,
+ .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
+ .idVendor = USBD_VID,
+ .idProduct = USBD_PID,
+ .bcdDevice = 0x0100,
+ .iManufacturer = USBD_STR_MANUF,
+ .iProduct = USBD_STR_PRODUCT,
+ .iSerialNumber = USBD_STR_SERIAL,
+ .bNumConfigurations = 1,
+};
+
+static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
+ TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN,
+ TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA),
+
+ TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD,
+ USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE),
+};
+
+static const char *const usbd_desc_str[] = {
+ [USBD_STR_MANUF] = "Raspberry Pi",
+ [USBD_STR_PRODUCT] = "Pico",
+ [USBD_STR_SERIAL] = "000000000000", // TODO
+ [USBD_STR_CDC] = "Board CDC",
+};
+
+const uint8_t *tud_descriptor_device_cb(void) {
+ return (const uint8_t *)&usbd_desc_device;
+}
+
+const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
+ (void)index;
+ return usbd_desc_cfg;
+}
+
+const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
+ #define DESC_STR_MAX (20)
+ static uint16_t desc_str[DESC_STR_MAX];
+
+ uint8_t len;
+ if (index == 0) {
+ desc_str[1] = 0x0409; // supported language is English
+ len = 1;
+ } else {
+ if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
+ return NULL;
+ }
+ const char *str = usbd_desc_str[index];
+ for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) {
+ desc_str[1 + len] = str[len];
+ }
+ }
+
+ // first byte is length (including header), second byte is string type
+ desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * len + 2);
+
+ return desc_str;
+}
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdlib/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdlib/CMakeLists.txt
new file mode 100644
index 00000000000..900ae09fe70
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdlib/CMakeLists.txt
@@ -0,0 +1,45 @@
+# 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)
+# 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)
+# PICO_CMAKE_CONFIG: PICO_STDIO_USB, OPTIONS: Globally enable stdio semihosting, default=0, group=pico_stdlib
+option(PICO_STDIO_USB "Globablly enable stdio semihosting " 0)
+
+if (NOT TARGET pico_stdlib)
+ add_library(pico_stdlib INTERFACE)
+ target_sources(pico_stdlib INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/stdlib.c
+ )
+ target_link_libraries(pico_stdlib INTERFACE
+ pico_stdlib_headers
+ pico_platform
+ pico_runtime
+ pico_stdio
+ pico_time
+ )
+
+ function(pico_enable_stdio_uart TARGET ENABLED)
+ set_target_properties(${TARGET} PROPERTIES PICO_TARGET_STDIO_UART ${ENABLED})
+ endfunction()
+
+ function(pico_enable_stdio_usb TARGET ENABLED)
+ set_target_properties(${TARGET} PROPERTIES PICO_TARGET_STDIO_USB ${ENABLED})
+ endfunction()
+
+ function(pico_enable_stdio_semihosting TARGET ENABLED)
+ set_target_properties(${TARGET} PROPERTIES PICO_TARGET_STDIO_SEMIHOSTING ${ENABLED})
+ endfunction()
+
+ if (TARGET pico_stdio_uart)
+ target_link_libraries(pico_stdlib INTERFACE $,>,${PICO_STDIO_UART},$>>,pico_stdio_uart,>)
+ endif()
+
+ if (TARGET pico_stdio_usb)
+ target_link_libraries(pico_stdlib INTERFACE $,>,${PICO_STDIO_USB},$>>,pico_stdio_usb,>)
+ endif()
+
+ if (TARGET pico_stdio_semihosting)
+ target_link_libraries(pico_stdlib INTERFACE $,>,${PICO_STDIO_SEMIHOSTING},$>>,pico_stdio_semihosting,>)
+ endif()
+
+endif()
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdlib/stdlib.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdlib/stdlib.c
new file mode 100644
index 00000000000..28d5d386af1
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_stdlib/stdlib.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "pico/stdlib.h"
+#include "hardware/pll.h"
+#include "hardware/clocks.h"
+#if PICO_STDIO_UART
+#include "pico/stdio_uart.h"
+#else
+#include "pico/binary_info.h"
+#endif
+
+// everything running off the USB oscillator
+void set_sys_clock_48mhz() {
+ if (!running_on_fpga()) {
+ // Change clk_sys to be 48MHz. The simplest way is to take this from PLL_USB
+ // which has a source frequency of 48MHz
+ clock_configure(clk_sys,
+ CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
+ CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
+ 48 * MHZ,
+ 48 * MHZ);
+
+ // Turn off PLL sys for good measure
+ pll_deinit(pll_sys);
+
+ // CLK peri is clocked from clk_sys so need to change clk_peri's freq
+ clock_configure(clk_peri,
+ 0,
+ CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS,
+ 48 * MHZ,
+ 48 * MHZ);
+ }
+}
+
+void set_sys_clock_pll(uint32_t vco_freq, uint post_div1, uint post_div2) {
+ if (!running_on_fpga()) {
+ clock_configure(clk_sys,
+ CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
+ CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
+ 48 * MHZ,
+ 48 * MHZ);
+
+ pll_init(pll_sys, 1, vco_freq, post_div1, post_div2);
+ uint32_t freq = vco_freq / (post_div1 * post_div2);
+
+ // Configure clocks
+ // CLK_REF = XOSC (12MHz) / 1 = 12MHz
+ clock_configure(clk_ref,
+ CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC,
+ 0, // No aux mux
+ 12 * MHZ,
+ 12 * MHZ);
+
+ // CLK SYS = PLL SYS (125MHz) / 1 = 125MHz
+ clock_configure(clk_sys,
+ CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
+ CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
+ freq, freq);
+
+ clock_configure(clk_peri,
+ 0, // Only AUX mux on ADC
+ CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
+ 48 * MHZ,
+ 48 * MHZ);
+ }
+}
+
+bool check_sys_clock_khz(uint32_t freq_khz, uint *vco_out, uint *postdiv1_out, uint *postdiv_out) {
+ uint crystal_freq_khz = clock_get_hz(clk_ref) / 1000;
+ for (uint fbdiv = 320; fbdiv >= 16; fbdiv--) {
+ uint vco = fbdiv * crystal_freq_khz;
+ if (vco < 400000 || vco > 1600000) continue;
+ for (uint postdiv1 = 7; postdiv1 >= 1; postdiv1--) {
+ for (uint postdiv2 = postdiv1; postdiv2 >= 1; postdiv2--) {
+ uint out = vco / (postdiv1 * postdiv2);
+ if (out == freq_khz && !(vco % (postdiv1 * postdiv2))) {
+ *vco_out = vco * 1000;
+ *postdiv1_out = postdiv1;
+ *postdiv_out = postdiv2;
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void setup_default_uart() {
+#if PICO_STDIO_UART
+ stdio_uart_init();
+#elif defined(PICO_DEFAULT_UART_BAUD_RATE) && defined(PICO_DEFAULT_UART_TX_PIN) && defined(PICO_DEFAULT_UART_RX_PIN)
+ // this is mostly for backwards compatibility - stdio_uart_init is a bit more nuanced, and usually likely to be present
+ uart_init(uart_default, PICO_DEFAULT_UART_BAUD_RATE);
+ if (PICO_DEFAULT_UART_TX_PIN >= 0)
+ gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART);
+ if (PICO_DEFAULT_UART_RX_PIN >= 0)
+ gpio_set_function(PICO_DEFAULT_UART_RX_PIN, GPIO_FUNC_UART);
+ bi_decl_if_func_used(bi_2pins_with_func(PICO_DEFAULT_UART_RX_PIN, PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART));
+#endif
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_unique_id/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_unique_id/CMakeLists.txt
new file mode 100644
index 00000000000..4c367d79ba6
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_unique_id/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_library(pico_unique_id INTERFACE)
+
+target_sources(pico_unique_id INTERFACE
+ ${CMAKE_CURRENT_LIST_DIR}/unique_id.c
+)
+
+target_include_directories(pico_unique_id INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
+
+target_link_libraries(pico_unique_id INTERFACE hardware_flash)
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_unique_id/include/pico/unique_id.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_unique_id/include/pico/unique_id.h
new file mode 100644
index 00000000000..be956cae619
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_unique_id/include/pico/unique_id.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_UNIQUE_ID_H_
+#define _PICO_UNIQUE_ID_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file pico/unique_id.h
+ * \defgroup pico_unique_id pico_unique_id
+ *
+ * Unique device ID access API
+ *
+ * RP2040 does not have an on-board unique identifier (all instances of RP2040
+ * silicon are identical and have no persistent state). However, RP2040 boots
+ * from serial NOR flash devices which have a 64-bit unique ID as a standard
+ * feature, and there is a 1:1 association between RP2040 and flash, so this
+ * is suitable for use as a unique identifier for an RP2040-based board.
+ *
+ * This library injects a call to the flash_get_unique_id function from the
+ * hardware_flash library, to run before main, and stores the result in a
+ * static location which can safely be accessed at any time via
+ * pico_get_unique_id().
+ *
+ * This avoids some pitfalls of the hardware_flash API, which requires any
+ * flash-resident interrupt routines to be disabled when called into.
+ */
+
+#define PICO_UNIQUE_BOARD_ID_SIZE_BYTES 8
+
+/**
+ * \brief Unique board identifier
+ * \ingroup pico_unique_id
+ *
+ * This struct is suitable for holding the unique identifier of a NOR flash
+ * device on an RP2040-based board. It contains an array of
+ * PICO_UNIQUE_BOARD_ID_SIZE_BYTES identifier bytes.
+ */
+typedef struct {
+ uint8_t id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES];
+} pico_unique_board_id_t;
+
+/*! \brief Get unique ID
+ * \ingroup pico_unique_id
+ *
+ * Get the unique 64-bit device identifier which was retrieved from the
+ * external NOR flash device at boot.
+ *
+ * On PICO_NO_FLASH builds the unique identifier is set to all 0xEE.
+ *
+ * \param id_out a pointer to a pico_unique_board_id_t struct, to which the identifier will be written
+ */
+void pico_get_unique_board_id(pico_unique_board_id_t *id_out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_unique_id/unique_id.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_unique_id/unique_id.c
new file mode 100644
index 00000000000..dd2f96ddc67
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/pico_unique_id/unique_id.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/flash.h"
+#include "pico/unique_id.h"
+
+static_assert(PICO_UNIQUE_BOARD_ID_SIZE_BYTES == FLASH_UNIQUE_ID_SIZE_BYTES, "Board ID size must match flash ID size");
+
+static pico_unique_board_id_t retrieved_id;
+
+static void __attribute__((constructor)) _retrieve_unique_id_on_boot() {
+#if PICO_NO_FLASH
+ // The hardware_flash call will panic() if called directly on a NO_FLASH
+ // build. Since this constructor is pre-main it would be annoying to
+ // debug, so just produce something well-defined and obviously wrong.
+ for (int i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++)
+ retrieved_id.id[i] = 0xee;
+#else
+ flash_get_unique_id(retrieved_id.id);
+#endif
+}
+
+void pico_get_unique_board_id(pico_unique_board_id_t *id_out) {
+ *id_out = retrieved_id;
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/tinyusb/CMakeLists.txt b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/tinyusb/CMakeLists.txt
new file mode 100644
index 00000000000..a48c65475aa
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/tinyusb/CMakeLists.txt
@@ -0,0 +1,111 @@
+if (DEFINED ENV{PICO_TINYUSB_PATH} AND (NOT PICO_TINYUSB_PATH))
+ set(PICO_TINYUSB_PATH $ENV{PICO_TINYUSB_PATH})
+ message("Using PICO_TINYUSB_PATH from environment ('${PICO_TINYUSB_PATH}')")
+endif ()
+
+set(TINYUSB_TEST_PATH "src/portable/raspberrypi/rp2040")
+if (NOT PICO_TINYUSB_PATH)
+ set(PICO_TINYUSB_PATH ${PROJECT_SOURCE_DIR}/lib/tinyusb)
+ if (NOT EXISTS ${PICO_TINYUSB_PATH}/${TINYUSB_TEST_PATH})
+ message(WARNING "TinyUSB submodule has not been initialized; USB support will be unavailable
+ hint: try 'git submodule update --init'.")
+ endif()
+elseif (NOT EXISTS ${PICO_TINYUSB_PATH}/${TINYUSB_TEST_PATH})
+ message(WARNING "PICO_TINYUSB_PATH specified but content not present.")
+endif()
+
+if (EXISTS ${PICO_TINYUSB_PATH}/${TINYUSB_TEST_PATH})
+ message("TinyUSB available at ${PICO_TINYUSB_PATH}/${TINYUSB_TEST_PATH}; adding USB support.")
+
+ add_library(tinyusb_common INTERFACE)
+ target_link_libraries(tinyusb_common INTERFACE
+ hardware_structs
+ hardware_irq
+ hardware_resets
+ pico_sync
+ )
+
+ target_sources(tinyusb_common INTERFACE
+ ${PICO_TINYUSB_PATH}/src/tusb.c
+ ${PICO_TINYUSB_PATH}/src/common/tusb_fifo.c
+ )
+
+ set(TINYUSB_DEBUG_LEVEL 0)
+ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+ message("Compiling TinyUSB with CFG_TUSB_DEBUG=1")
+ set(TINYUSB_DEBUG_LEVEL 1)
+ endif ()
+
+ target_compile_definitions(tinyusb_common INTERFACE
+ CFG_TUSB_MCU=OPT_MCU_RP2040
+ CFG_TUSB_OS=OPT_OS_PICO #seems examples are hard coded to OPT_OS_NONE
+ CFG_TUSB_DEBUG=${TINYUSB_DEBUG_LEVEL}
+ )
+
+ target_include_directories(tinyusb_common INTERFACE
+ ${PICO_TINYUSB_PATH}/src
+ ${PICO_TINYUSB_PATH}/src/common
+ ${PICO_TINYUSB_PATH}/hw
+ )
+
+ add_library(tinyusb_device_unmarked INTERFACE)
+ target_sources(tinyusb_device_unmarked INTERFACE
+ ${PICO_TINYUSB_PATH}/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+ ${PICO_TINYUSB_PATH}/src/portable/raspberrypi/rp2040/rp2040_usb.c
+ ${PICO_TINYUSB_PATH}/src/device/usbd.c
+ ${PICO_TINYUSB_PATH}/src/device/usbd_control.c
+ ${PICO_TINYUSB_PATH}/src/class/audio/audio_device.c
+ ${PICO_TINYUSB_PATH}/src/class/cdc/cdc_device.c
+ ${PICO_TINYUSB_PATH}/src/class/dfu/dfu_rt_device.c
+ ${PICO_TINYUSB_PATH}/src/class/hid/hid_device.c
+ ${PICO_TINYUSB_PATH}/src/class/midi/midi_device.c
+ ${PICO_TINYUSB_PATH}/src/class/msc/msc_device.c
+ ${PICO_TINYUSB_PATH}/src/class/net/net_device.c
+ ${PICO_TINYUSB_PATH}/src/class/usbtmc/usbtmc_device.c
+ ${PICO_TINYUSB_PATH}/src/class/vendor/vendor_device.c
+ )
+
+ target_compile_definitions(tinyusb_device_unmarked INTERFACE
+ # off by default note TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX defaults from PICO_RP2040_USB_DEVICE_ENUMERATION_FIX
+# TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX=1
+ )
+
+ # unmarked version used by stdio USB
+ target_link_libraries(tinyusb_device_unmarked INTERFACE tinyusb_common pico_fix_rp2040_usb_device_enumeration)
+
+ add_library(tinyusb_device INTERFACE)
+ target_link_libraries(tinyusb_device INTERFACE tinyusb_device_unmarked)
+ target_compile_definitions(tinyusb_device INTERFACE
+ RP2040_USB_DEVICE_MODE=1
+ TINYUSB_DEVICE_LINKED=1
+ )
+
+ add_library(tinyusb_host INTERFACE)
+ target_sources(tinyusb_host INTERFACE
+ ${PICO_TINYUSB_PATH}/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+ ${PICO_TINYUSB_PATH}/src/portable/raspberrypi/rp2040/rp2040_usb.c
+ ${PICO_TINYUSB_PATH}/src/host/usbh.c
+ ${PICO_TINYUSB_PATH}/src/host/usbh_control.c
+ ${PICO_TINYUSB_PATH}/src/host/hub.c
+ ${PICO_TINYUSB_PATH}/src/class/cdc/cdc_host.c
+ ${PICO_TINYUSB_PATH}/src/class/hid/hid_host.c
+ ${PICO_TINYUSB_PATH}/src/class/msc/msc_host.c
+ ${PICO_TINYUSB_PATH}/src/class/vendor/vendor_host.c
+ )
+
+ # Sometimes have to do host specific actions in mostly
+ # common functions
+ target_compile_definitions(tinyusb_host INTERFACE
+ RP2040_USB_HOST_MODE=1
+ TINYUSB_HOST_LINKED=1
+ )
+
+ target_link_libraries(tinyusb_host INTERFACE tinyusb_common)
+
+ add_library(tinyusb_board INTERFACE)
+ target_sources(tinyusb_board INTERFACE
+ ${PICO_TINYUSB_PATH}/hw/bsp/raspberry_pi_pico/board_raspberry_pi_pico.c
+ )
+
+endif()
+
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/tinyusb/doc.h b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/tinyusb/doc.h
new file mode 100644
index 00000000000..6c361e0002a
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pico-sdk/rp2_common/tinyusb/doc.h
@@ -0,0 +1,7 @@
+/**
+ * \defgroup tinyusb_device tinyusb_device
+ * \brief TinyUSB Device-mode support for the RP2040
+ *
+ * \defgroup tinyusb_host tinyusb_host
+ * \brief TinyUSB Host-mode support for the RP2040
+ */
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pwmout_api.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pwmout_api.c
new file mode 100644
index 00000000000..e4bc4daa806
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/pwmout_api.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2018 Nordic Semiconductor ASA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic Semiconductor ASA
+ * integrated circuit in a product or a software update for such product, must reproduce
+ * the above copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary or object form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#if DEVICE_PWMOUT
+
+#include "hal/pwmout_api.h"
+#include "PeripheralPins.h"
+#include "pinmap.h"
+#include "hardware/pwm.h"
+#include "hardware/clocks.h"
+#include "mbed_assert.h"
+
+const uint count_top = 1000;
+
+/** Initialize the pwm out peripheral and configure the pin
+ *
+ * Parameter obj The pwmout object to initialize
+ * Parameter pin The pwmout pin to initialize
+ */
+void pwmout_init(pwmout_t *obj, PinName pin)
+{
+ MBED_ASSERT(obj != NULL);
+
+ /* Populate PWM object with default values. */
+ obj->slice = pwm_gpio_to_slice_num(pin);
+ obj->channel = pwm_gpio_to_channel(pin);
+ obj->pin = pin;
+ obj->period = 0;
+ obj->percent = 0.5f;
+
+ obj->cfg = pwm_get_default_config();
+ pwm_config_set_wrap(&(obj->cfg), count_top);
+
+ pwm_init(obj->slice, &(obj->cfg), false);
+ gpio_set_function(pin, GPIO_FUNC_PWM);
+}
+
+/** Deinitialize the pwmout object
+ *
+ * Parameter obj The pwmout object
+ */
+void pwmout_free(pwmout_t *obj)
+{
+ MBED_ASSERT(obj != NULL);
+ pwm_set_enabled(obj->slice, false);
+}
+
+/** Set the output duty-cycle in range <0.0f, 1.0f>
+ *
+ * pulse 0.0f represents 0 percentage, 1.0f represents 100 percent.
+ * Parameter obj The pwmout object
+ * Parameter percent The floating-point percentage number
+ */
+void pwmout_write(pwmout_t *obj, float percent)
+{
+ obj->percent = percent;
+ pwm_set_gpio_level(obj->pin, percent * (count_top + 1));
+ pwm_set_enabled(obj->slice, true);
+}
+
+/** Read the current float-point output duty-cycle
+ *
+ * Parameter obj The pwmout object
+ * Return A floating-point output duty-cycle
+ */
+float pwmout_read(pwmout_t *obj)
+{
+ /* Return percentage stored in object instead of calculating the value.
+ * This prevents floating point rounding errors.
+ */
+ return obj->percent;
+}
+
+/** Set the PWM period specified in seconds, keeping the duty cycle the same
+ *
+ * Periods smaller than microseconds (the lowest resolution) are set to zero.
+ * Parameter obj The pwmout object
+ * Parameter seconds The floating-point seconds period
+ */
+void pwmout_period(pwmout_t *obj, float period)
+{
+ /* Set new period. */
+ pwmout_period_us(obj, period * 1000000);
+}
+
+/** Set the PWM period specified in miliseconds, keeping the duty cycle the same
+ *
+ * Parameter obj The pwmout object
+ * Parameter ms The milisecond period
+ */
+void pwmout_period_ms(pwmout_t *obj, int period)
+{
+ /* Set new period. */
+ pwmout_period_us(obj, period * 1000);
+}
+
+/** Set the PWM period specified in microseconds, keeping the duty cycle the same
+ *
+ * Parameter obj The pwmout object
+ * Parameter us The microsecond period
+ */
+void pwmout_period_us(pwmout_t *obj, int period)
+{
+ obj->period = period;
+
+ // min_period should be 8us
+ uint32_t min_period = 1000000 * count_top / clock_get_hz(clk_sys);
+
+ pwm_config_set_clkdiv(&(obj->cfg), (float)period / (float)min_period);
+ pwm_init(obj->slice, &(obj->cfg), false);
+}
+
+int pwmout_read_period_us(pwmout_t *obj)
+{
+ return obj->period;
+}
+
+/** Set the PWM pulsewidth specified in seconds, keeping the period the same.
+ *
+ * Parameter obj The pwmout object
+ * Parameter seconds The floating-point pulsewidth in seconds
+ */
+void pwmout_pulsewidth(pwmout_t *obj, float pulse)
+{
+ pwmout_pulsewidth_us(obj, pulse * 1000000);
+}
+
+/** Set the PWM pulsewidth specified in miliseconds, keeping the period the same.
+ *
+ * Parameter obj The pwmout object
+ * Parameter ms The floating-point pulsewidth in miliseconds
+ */
+void pwmout_pulsewidth_ms(pwmout_t *obj, int pulse)
+{
+ pwmout_pulsewidth_us(obj, pulse * 1000);
+}
+
+/** Set the PWM pulsewidth specified in microseconds, keeping the period the same.
+ *
+ * Parameter obj The pwmout object
+ * Parameter us The floating-point pulsewidth in microseconds
+ */
+void pwmout_pulsewidth_us(pwmout_t *obj, int pulse)
+{
+ /* Cap pulsewidth to period. */
+ if (pulse > obj->period) {
+ pulse = obj->period;
+ }
+
+ obj->percent = (float) pulse / (float) obj->period;
+
+ /* Restart instance with new values. */
+ pwmout_write(obj, obj->percent);
+}
+
+int pwmout_read_pulsewidth_us(pwmout_t *obj) {
+ return (obj->period) * (obj->percent);
+}
+
+const PinMap *pwmout_pinmap()
+{
+ return PinMap_PWM_OUT;
+}
+
+#endif // DEVICE_PWMOUT
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/reset_reason.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/reset_reason.c
new file mode 100644
index 00000000000..83de2cfb9d7
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/reset_reason.c
@@ -0,0 +1,33 @@
+#include "reset_reason_api.h"
+#include "hardware/watchdog.h"
+
+#ifdef DEVICE_RESET_REASON
+
+#include "hardware/structs/resets.h"
+
+reset_reason_t hal_reset_reason_get(void)
+{
+ if (watchdog_caused_reboot()) {
+ return RESET_REASON_WATCHDOG;
+ } else {
+ return RESET_REASON_PIN_RESET;
+ }
+
+ return RESET_REASON_UNKNOWN;
+}
+
+
+uint32_t hal_reset_reason_get_raw(void)
+{
+ return resets_hw->reset;
+}
+
+
+void hal_reset_reason_clear(void)
+{
+ for (int i = 1; i < 25; i++) {
+ hw_clear_bits(&resets_hw->reset, i);
+ }
+}
+
+#endif // DEVICE_RESET_REASON
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/serial_api.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/serial_api.c
new file mode 100644
index 00000000000..8d95f6c2a32
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/serial_api.c
@@ -0,0 +1,215 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2019, Arm Limited and affiliates.
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hal/serial_api.h"
+#include "mbed_error.h"
+#include "PinNames.h"
+#include "PeripheralPins.h"
+#include
+
+#if DEVICE_SERIAL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int stdio_uart_inited = 0;
+serial_t stdio_uart;
+
+void serial_init(serial_t *obj, PinName tx, PinName rx)
+{
+ if (tx == STDIO_UART_TX && stdio_uart_inited != 0) {
+ memmove(obj, &stdio_uart, sizeof(serial_t));
+ return;
+ }
+ memset(obj, 0, sizeof(serial_t));
+ struct serial_s *ser = obj;
+ ser->pin_tx = tx;
+ ser->pin_rx = rx;
+ ser->pin_rts = NC;
+ ser->pin_cts = NC;
+
+ UARTName dev_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
+ UARTName dev_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
+
+ if (dev_tx != dev_rx) {
+ MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_SERIAL, MBED_ERROR_CODE_UNSUPPORTED), "Invalid serial pins");
+ }
+ if (dev_tx == UART_0) {
+ obj->dev = uart0;
+ } else {
+ obj->dev = uart1;
+ }
+
+ uart_init(obj->dev, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE);
+ gpio_set_function(tx, GPIO_FUNC_UART);
+ gpio_set_function(rx, GPIO_FUNC_UART);
+
+ //uart_set_translate_crlf(obj->dev, false);
+ uart_set_fifo_enabled(obj->dev, false);
+
+ if (tx == STDIO_UART_TX) {
+ memmove(&stdio_uart, obj, sizeof(serial_t));
+ stdio_uart_inited = 1;
+ }
+}
+
+void serial_free(serial_t *obj)
+{
+ uart_deinit(obj->dev);
+}
+
+void serial_baud(serial_t *obj, int baudrate)
+{
+ obj->baud = (uint32_t)baudrate;
+ uart_init(obj->dev, obj->baud);
+ uart_set_fifo_enabled(obj->dev, false);
+}
+
+void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits)
+{
+ uart_parity_t hal_parity;
+ switch (parity) {
+ case ParityNone:
+ hal_parity = UART_PARITY_NONE;
+ break;
+ case ParityOdd:
+ hal_parity = UART_PARITY_ODD;
+ break;
+ case ParityEven:
+ hal_parity = UART_PARITY_EVEN;
+ break;
+ default:
+ MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_SERIAL, MBED_ERROR_CODE_UNSUPPORTED), "Unsupported parity");
+ }
+ uart_set_format(obj->dev, data_bits, stop_bits, hal_parity);
+}
+
+static volatile uart_irq_handler irq_handler;
+static volatile uint32_t serial_irq_ids[2] = {0};
+
+static inline void uart0_irq(void)
+{
+ irq_handler(serial_irq_ids[0], RxIrq);
+}
+
+static inline void uart1_irq(void)
+{
+ irq_handler(serial_irq_ids[1], RxIrq);
+}
+
+void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
+{
+ int UART_IRQ = obj->dev == uart0 ? UART0_IRQ : UART1_IRQ;
+ if (obj->dev == uart0) {
+ serial_irq_ids[0] = id;
+ } else {
+ serial_irq_ids[1] = id;
+ }
+ irq_handler = handler;
+}
+
+void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
+{
+ int UART_IRQ = obj->dev == uart0 ? UART0_IRQ : UART1_IRQ;
+
+ irq_set_exclusive_handler(UART_IRQ, obj->dev == uart0 ? uart0_irq : uart1_irq);
+ irq_set_enabled(UART_IRQ, enable);
+
+ uart_set_irq_enables(obj->dev, irq == RxIrq, irq == TxIrq);
+}
+
+int serial_getc(serial_t *obj)
+{
+ return uart_getc(obj->dev);
+}
+
+void serial_putc(serial_t *obj, int c)
+{
+ uart_putc_raw(obj->dev, c);
+}
+
+int serial_readable(serial_t *obj)
+{
+ return uart_is_readable(obj->dev);
+}
+
+int serial_writable(serial_t *obj)
+{
+ return uart_is_writable(obj->dev);
+}
+
+void serial_clear(serial_t *obj)
+{
+ MBED_WARNING(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_SERIAL, MBED_ERROR_CODE_UNSUPPORTED), "serial_clear");
+}
+
+void serial_break_set(serial_t *obj)
+{
+ uart_set_break(obj->dev, true);
+}
+
+void serial_break_clear(serial_t *obj)
+{
+ uart_set_break(obj->dev, false);
+}
+
+void serial_pinout_tx(PinName tx)
+{
+ MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_SERIAL, MBED_ERROR_CODE_UNSUPPORTED), "serial_pinout_tx");
+}
+
+void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, PinName txflow)
+{
+ obj->pin_rts = rxflow;
+ obj->pin_cts = txflow;
+
+ if (obj->pin_rts != NC) {
+ gpio_set_function(obj->pin_rts, GPIO_FUNC_UART);
+ }
+ if (obj->pin_cts != NC) {
+ gpio_set_function(obj->pin_cts, GPIO_FUNC_UART);
+ }
+
+ if (type == FlowControlRTSCTS) {
+ uart_set_hw_flow(obj->dev, true, true);
+ } else {
+ uart_set_hw_flow(obj->dev, type == FlowControlCTS, type == FlowControlRTS);
+ }
+}
+
+const PinMap *serial_tx_pinmap(void)
+{
+ return PinMap_UART_TX;
+}
+
+const PinMap *serial_rx_pinmap(void)
+{
+ return PinMap_UART_RX;
+}
+
+const PinMap *serial_cts_pinmap(void)
+{
+ return PinMap_UART_CTS;
+}
+
+const PinMap *serial_rts_pinmap(void)
+{
+ return PinMap_UART_RTS;
+}
+
+#endif
\ No newline at end of file
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/spi_api.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/spi_api.c
new file mode 100644
index 00000000000..73129835fab
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/spi_api.c
@@ -0,0 +1,112 @@
+/******************************************************************************
+ * INCLUDE
+ ******************************************************************************/
+
+#include "mbed_assert.h"
+#include "mbed_critical.h"
+#include "spi_api.h"
+#include "PeripheralPins.h"
+#include "PeripheralNames.h"
+
+/******************************************************************************
+ * CONSTANT
+ ******************************************************************************/
+
+static unsigned int const SPI_MASTER_DEFAULT_BITRATE = 1000 * 1000; /* 1 MHz */
+
+/******************************************************************************
+ * FUNCTION DEFINITION
+ ******************************************************************************/
+
+void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
+{
+ /* Check if all pins do in fact belong to the same SPI module. */
+ SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
+ SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
+ SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
+ SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
+
+ MBED_ASSERT(spi_mosi == spi_miso);
+ MBED_ASSERT(spi_miso == spi_sclk);
+ if (spi_ssel != (SPIName)NC) {
+ MBED_ASSERT(spi_sclk == spi_ssel);
+ }
+
+ /* Obtain pointer to the SPI module. */
+ obj->dev = (spi_inst_t *)pinmap_function(mosi, PinMap_SPI_MOSI);
+
+ /* Configure GPIOs for SPI usage. */
+ gpio_set_function(mosi, GPIO_FUNC_SPI);
+ gpio_set_function(sclk, GPIO_FUNC_SPI);
+ gpio_set_function(miso, GPIO_FUNC_SPI);
+
+ /* Initialize SPI at 1 MHz bitrate */
+ _spi_init(obj->dev, SPI_MASTER_DEFAULT_BITRATE);
+}
+
+void spi_format(spi_t *obj, int bits, int mode, int slave)
+{
+ /* Doing some parameter sanity checks. */
+ MBED_ASSERT((bits >= 4) && (bits <= 16));
+ MBED_ASSERT((mode >= 0) && (mode <= 3));
+
+ /* Determine parameters for CPOL, CPHA */
+ typedef struct
+ {
+ spi_cpol_t cpol;
+ spi_cpha_t cpha;
+ } spi_mode_t;
+ spi_mode_t const SPI_MODE[4] =
+ {
+ {SPI_CPOL_0, SPI_CPHA_0}, /* MODE 0 */
+ {SPI_CPOL_0, SPI_CPHA_1}, /* MODE 1 */
+ {SPI_CPOL_1, SPI_CPHA_0}, /* MODE 2 */
+ {SPI_CPOL_1, SPI_CPHA_1} /* MODE 3 */
+ };
+
+ /* Configure the SPI. */
+ spi_set_format(obj->dev, bits, SPI_MODE[mode].cpol, SPI_MODE[mode].cpha, SPI_MSB_FIRST);
+ /* Set's the SPI up as slave if the value of slave is different from 0, e.g. a value of 1 or -1 set's this SPI up as a slave. */
+ spi_set_slave(obj->dev, slave != 0);
+}
+
+void spi_frequency(spi_t *obj, int hz)
+{
+ spi_set_baudrate(obj->dev, hz);
+}
+
+int spi_master_write(spi_t *obj, int value)
+{
+ uint8_t rx;
+ uint8_t const tx = (uint8_t)value;
+ spi_write_read_blocking(obj->dev, &tx, &rx, sizeof(rx));
+ return rx;
+}
+
+int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, char write_fill)
+{
+ /* The pico-sdk API does not support different length SPI buffers. */
+ MBED_ASSERT(tx_length == rx_length);
+ /* Perform the SPI transfer. */
+ return spi_write_read_blocking(obj->dev, (const uint8_t *)tx_buffer, (uint8_t *)rx_buffer, (size_t)tx_length);
+}
+
+const PinMap *spi_master_mosi_pinmap()
+{
+ return PinMap_SPI_MOSI;
+}
+
+const PinMap *spi_master_miso_pinmap()
+{
+ return PinMap_SPI_MISO;
+}
+
+const PinMap *spi_master_clk_pinmap()
+{
+ return PinMap_SPI_SCLK;
+}
+
+const PinMap *spi_master_cs_pinmap()
+{
+ return PinMap_SPI_SSEL;
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/us_ticker.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/us_ticker.c
new file mode 100644
index 00000000000..b3b8497188c
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/us_ticker.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013 Nordic Semiconductor ASA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic Semiconductor ASA
+ * integrated circuit in a product or a software update for such product, must reproduce
+ * the above copyright notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary or object form under this license must not be reverse
+ * engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "us_ticker_api.h"
+#include "mbed_critical.h"
+#include "hardware/timer.h"
+
+#define US_TICKER_COUNTER_BITS 32u
+#define US_TICKER_FREQ 1000000
+
+/* us ticker is driven by 1MHz clock and counter length is 32 bits */
+const ticker_info_t* us_ticker_get_info()
+{
+ static const ticker_info_t info = {
+ US_TICKER_FREQ,
+ US_TICKER_COUNTER_BITS
+ };
+ return &info;
+}
+
+static const uint8_t alarm_num = 0;
+
+static void us_ticker_irq_handler_internal(uint alarm_src) {
+ if (alarm_num == alarm_src) {
+ us_ticker_irq_handler();
+ }
+}
+
+void us_ticker_init(void)
+{
+ hardware_alarm_claim(alarm_num);
+ hardware_alarm_set_callback(alarm_num, us_ticker_irq_handler_internal);
+}
+
+uint32_t us_ticker_read()
+{
+ return time_us_32();
+}
+
+void us_ticker_set_interrupt(timestamp_t timestamp)
+{
+ core_util_critical_section_enter();
+
+ uint64_t _timestamp = (uint64_t)timestamp;
+
+ if (timestamp < time_us_32()) {
+ //32 bit timestamp has been wrapped
+ //We need to provide a 64 bit timestamp able to fire the irq for this round
+ _timestamp = (((time_us_64() >> 32) + 1) << 32) + timestamp;
+ } else {
+ //Then, at the next round, wrap the 64 bit timer to follow the 32 bit one
+ if ((time_us_64() >> 32) > 0) {
+ uint64_t current_time = time_us_64();
+ uint64_t wrapped_time = current_time - 0xFFFFFFFF;
+ timer_hw->timelw = (uint32_t)wrapped_time;
+ timer_hw->timehw = 0;
+ }
+ }
+ absolute_time_t target = { _timestamp };
+ hardware_alarm_set_target(alarm_num, target);
+
+ core_util_critical_section_exit();
+}
+
+void us_ticker_fire_interrupt(void)
+{
+ us_ticker_irq_handler();
+}
+
+void us_ticker_disable_interrupt(void)
+{
+ hardware_alarm_cancel(alarm_num);
+}
+
+void us_ticker_clear_interrupt(void)
+{
+ hardware_alarm_cancel(alarm_num);
+}
+
+void us_ticker_free(void)
+{
+ hardware_alarm_unclaim(alarm_num);
+}
diff --git a/targets/TARGET_RASPBERRYPI/TARGET_RP2040/watchdog_api.c b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/watchdog_api.c
new file mode 100644
index 00000000000..9263eb48d5c
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/TARGET_RP2040/watchdog_api.c
@@ -0,0 +1,53 @@
+#include "watchdog_api.h"
+#include "hardware/watchdog.h"
+#include "hardware/structs/watchdog.h"
+
+#if DEVICE_WATCHDOG
+
+static watchdog_config_t watchdogConfig;
+
+watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
+{
+ watchdogConfig = *config;
+ // The pico watchdogs accept a maximum value of 0x7fffff
+ if ( config->timeout_ms < 0x1 && config->timeout_ms > 0x7FFFFF ) {
+ return WATCHDOG_STATUS_INVALID_ARGUMENT;
+ }
+
+ watchdog_enable(config->timeout_ms, true);
+
+ return WATCHDOG_STATUS_OK;
+}
+
+void hal_watchdog_kick(void)
+{
+ watchdog_update();
+}
+
+watchdog_status_t hal_watchdog_stop(void)
+{
+ hw_clear_bits(&watchdog_hw->ctrl, WATCHDOG_CTRL_ENABLE_BITS);
+ return WATCHDOG_STATUS_OK;
+}
+
+uint32_t hal_watchdog_get_reload_value(void)
+{
+ uint32_t load_value = watchdogConfig.timeout_ms * 1000 * 2;
+ if (load_value > 0xffffffu) {
+ load_value = 0xffffffu;
+ }
+ return load_value;
+}
+
+watchdog_features_t hal_watchdog_get_platform_features(void)
+{
+ watchdog_features_t features;
+
+ features.max_timeout = 0x7FFFFF;
+ features.update_config = true;
+ features.disable_watchdog = true;
+ return features;
+
+}
+
+#endif // DEVICE_WATCHDOG
diff --git a/targets/TARGET_RASPBERRYPI/mbed_rtx.h b/targets/TARGET_RASPBERRYPI/mbed_rtx.h
new file mode 100644
index 00000000000..f43fa2e32d7
--- /dev/null
+++ b/targets/TARGET_RASPBERRYPI/mbed_rtx.h
@@ -0,0 +1,27 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2016 ARM Limited
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MBED_MBED_RTX_H
+#define MBED_MBED_RTX_H
+
+#if defined(TARGET_RPI2040)
+
+/* TODO */
+
+#endif
+
+#endif // MBED_MBED_RTX_H
diff --git a/targets/targets.json b/targets/targets.json
index aea99cac03c..9de38502376 100644
--- a/targets/targets.json
+++ b/targets/targets.json
@@ -7987,6 +7987,62 @@
"inherits": ["AMA3B1KK"],
"components_add": ["lis2dh12", "hm01b0"]
},
+ "RP2040": {
+ "inherits": ["Target"],
+ "components_add": ["FLASHIAP"],
+ "core": "Cortex-M0+",
+ "supported_toolchains": ["GCC_ARM"],
+ "extra_labels": [
+ "RASPBERRYPI",
+ "memmap_default"
+ ],
+ "release_versions": [
+ "5"
+ ],
+ "overrides": {
+ "xip-enable": true
+ },
+ "device_has": [
+ "ANALOGIN",
+ "FLASH",
+ "I2C",
+ "I2CSLAVE",
+ "INTERRUPTIN",
+ "PORT_IN",
+ "PORT_OUT",
+ "PWMOUT",
+ "SERIAL",
+ "SERIAL_FC",
+ "SPI",
+ "USTICKER",
+ "WATCHDOG",
+ "USBDEVICE",
+ "RESET_REASON"
+ ]
+ },
+ "NANO_RP2040_CONNECT": {
+ "inherits": ["RP2040"],
+ "macros_add": [
+ "PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1",
+ "PICO_NO_BINARY_INFO=1",
+ "MBED_MPU_CUSTOM",
+ "PICO_TIME_DEFAULT_ALARM_POOL_DISABLED",
+ "PICO_ON_DEVICE=1",
+ "PICO_FLASH_SIZE_BYTES=16*1024*1024",
+ "PICO_UART_ENABLE_CRLF_SUPPORT=0"
+ ]
+ },
+ "RASPBERRY_PI_PICO": {
+ "inherits": ["RP2040"],
+ "macros_add": [
+ "PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1",
+ "PICO_NO_BINARY_INFO=1",
+ "MBED_MPU_CUSTOM",
+ "PICO_TIME_DEFAULT_ALARM_POOL_DISABLED",
+ "PICO_ON_DEVICE=1",
+ "PICO_UART_ENABLE_CRLF_SUPPORT=0"
+ ]
+ },
"__build_tools_metadata__": {
"version": "1",
"public": false