SDK 1.3.0 release

See release notes for details

Co-authored-by: Brian Cooke <bdscooke@gmail.com>
Co-authored-by: Luke Wren <wren6991@gmail.com>
Co-authored-by: Uri Shaked <uri@urishaked.com>
Co-authored-by: Zapta <zapta@users.noreply.github.com>
Co-authored-by: Andrew Scheller <andrew.scheller@raspberrypi.com>
Co-authored-by: Liam Fraser <liam@raspberrypi.com>
Co-authored-by: Gabriel Wang <embedded_zhuoran@Hotmail.com>
Co-authored-by: Matias Silva <matita.martins@gmail.com>
Co-authored-by: dp111 <19616418+dp111@users.noreply.github.com>
Co-authored-by: Leonardo La Rocca <46094699+leoli51@users.noreply.github.com>
Co-authored-by: Mahyar Koshkouei <mk@deltabeard.com>
Co-authored-by: Brian Starkey <stark3y@gmail.com>
Co-authored-by: Philip Howard <github@gadgetoid.com>
Co-authored-by: Mike Causer <mcauser@gmail.com>
Co-authored-by: Martino Facchin <m.facchin@arduino.cc>
Co-authored-by: ZodiusInfuser <christopher.parrott2@gmail.com>
Co-authored-by: Manuel Wick <manuel@matronix.de>
Co-authored-by: Matias Silva <git@matiasilva.com>
Co-authored-by: Robert Pafford <19439938+rjp5th@users.noreply.github.com>
Co-authored-by: Alasdair Allan <alasdair@raspberrypi.com>
Co-authored-by: Engineer_Will <646689853@qq.com>
Co-authored-by: Garatronic <31109090+garatronic@users.noreply.github.com>
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..e361777
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,4 @@
+_Instructions: (please delete)_
+ - _please do not submit against `master`, use `develop` instead_
+ - _please make sure there is an associated issue for your PR, and reference it via "Fixes #num" in the description_
+ - _please enter a detailed description_
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c270649..0ab4c31 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,8 +33,6 @@
     add_subdirectory(tools)
     add_subdirectory(src)
 
-    add_compile_options(-Winline)
-
     # allow customization
     add_sub_list_dirs(PICO_SDK_POST_LIST_DIRS)
     add_sub_list_files(PICO_SDK_POST_LIST_FILES)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..dc69b26
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,25 @@
+# Contributing to Raspberry Pi Pico C/C++ SDK
+
+## How to Report a Bug
+
+We use GitHub to host code, track [issues](https://github.com/raspberrypi/pico-sdk/issues) and feature requests, and to accept [pull requests](https://github.com/raspberrypi/pico-sdk/pulls). If you find think you have found a bug in the SDK please report it by [opening a new issue](https://github.com/raspberrypi/pico-sdk/issues/new). Please include as much detail as possible, and ideally some code to reproduce the problem.
+
+## How to Contribute Code
+
+In order to contribute new or updated code, you must first create a GitHub account and fork the original repository to your own account. You can make changes, save them in your repository, then [make a pull request](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) against this repository. The pull request will appear [in the repository](https://github.com/raspberrypi/pico-sdk/pulls) where it can be assessed by the maintainers, and if appropriate, merged with the official repository.
+
+**NOTE:** Development takes place on the `develop` branch in this repository. Please open your https://github.com/raspberrypi/pico-sdk/pulls[pull request] (PR) against the [`develop`](https://github.com/raspberrypi/pico-sdk/tree/develop) branch, pull requests against the `master` branch will automatically CI fail checks and will not be accepted. You will be asked to rebase your PR against `develop` and if you do not do so, your PR will be closed.
+
+While we are happy to take contributions, big or small, changes in the SDK may have knock-on effects in other places so it is possible that apparently benign pull requests that make seemingly small changes could be refused. 
+
+### Code Style
+
+If you are contributing new or updated code please match the existing code style, particularly:
+
+* Use 4 spaces for indentation rather than tabs.
+* Braces are required for everything except single line `if` statements.
+* Opening braces should not be placed on a new line.
+
+### Licensing 
+
+Code in this repository is lisensed under the [BSD-3 License](LICENSE.TXT). By contributing content to this repository you are agreeing to place your contributions under this licence.
diff --git a/docs/DoxygenLayout.xml b/docs/DoxygenLayout.xml
index e0fd396..6ba5dfc 100644
--- a/docs/DoxygenLayout.xml
+++ b/docs/DoxygenLayout.xml
@@ -15,9 +15,9 @@
       <tab type="user" url="https://rptl.io/pico-faq" visible="yes" title="Raspberry Pi Pico FAQ" intro=""/>
     </tab>
     <tab type="usergroup" url="@ref weblinks_page" visible="yes" title="Web" intro="useful weblinks">
-      <tab type="user" url="https://www.raspberrypi.org/" visible="yes" title="Raspberry Pi Site" intro=""/>
+      <tab type="user" url="https://www.raspberrypi.com/" visible="yes" title="Raspberry Pi Site" intro=""/>
       <tab type="user" url="https://rptl.io/rp2040-get-started" visible="yes" title="Raspberry Pi Pico Page" intro=""/>
-      <tab type="user" url="https://www.raspberrypi.org/forums" visible="yes" title="Raspberry Pi Forums" intro=""/>
+      <tab type="user" url="https://forums.raspberrypi.com/" visible="yes" title="Raspberry Pi Forums" intro=""/>
       <tab type="user" url="https://github.com/raspberrypi/pico-sdk" visible="yes" title="Raspberry Pi Pico SDK on GitHub" intro=""/>
       <tab type="user" url="https://github.com/raspberrypi/pico-examples" visible="yes" title="Pico Examples on GitHub" intro=""/>
       <tab type="user" url="https://github.com/raspberrypi/pico-extras" visible="yes" title="Pico Extras on GitHub" intro=""/>
diff --git a/docs/header.html b/docs/header.html
index da3cd81..32bb7eb 100644
--- a/docs/header.html
+++ b/docs/header.html
@@ -54,7 +54,7 @@
 
 		<div class="navigation-footer">
 			<img src="logo-mobile.svg" alt="Raspberry Pi">
-			<a href="https://www.raspberrypi.org/" target="_blank">By Raspberry Pi (Trading) Ltd</a>
+			<a href="https://www.raspberrypi.com/" target="_blank">By Raspberry Pi (Trading) Ltd</a>
 		</div>
 <!-- 		<div class="search">
 			<form>
diff --git a/docs/weblinks_page.md b/docs/weblinks_page.md
index d4b0e9c..e579362 100644
--- a/docs/weblinks_page.md
+++ b/docs/weblinks_page.md
@@ -14,9 +14,9 @@
 
 At Raspberry Pi we have a very community-based attitude to help. We run a very popular and busy forum where you can ask questions about any aspect of the Raspberry Pi ecosystem, including the Raspberry Pi Pico.
 
-You can find our forums at the [following link](https://www.raspberrypi.org/forums).
+You can find our forums at the [following link](https://forums.raspberrypi.com/).
 
-For the main Raspberry Pi website, [see here](https://www.raspberrypi.org)
+For the main Raspberry Pi website, [see here](https://www.raspberrypi.com)
 
 For the Raspberry Pi Pico page, [see here](https://rptl.io/rp2040-get-started)
 
diff --git a/lib/tinyusb b/lib/tinyusb
index d49938d..4bfab30 160000
--- a/lib/tinyusb
+++ b/lib/tinyusb
@@ -1 +1 @@
-Subproject commit d49938d0f5052bce70e55c652b657c0a6a7e84fe
+Subproject commit 4bfab30c02279a0530e1a56f4a7c539f2d35a293
diff --git a/pico_sdk_version.cmake b/pico_sdk_version.cmake
index a2d8444..1605f56 100644
--- a/pico_sdk_version.cmake
+++ b/pico_sdk_version.cmake
@@ -3,12 +3,13 @@
 set(PICO_SDK_VERSION_MAJOR 1)
 # PICO_BUILD_DEFINE: PICO_SDK_VERSION_MINOR, SDK minor version number, type=int, group=pico_base
 # PICO_CONFIG: PICO_SDK_VERSION_MINOR, SDK minor version number, type=int, group=pico_base
-set(PICO_SDK_VERSION_MINOR 2)
+set(PICO_SDK_VERSION_MINOR 3)
 # PICO_BUILD_DEFINE: PICO_SDK_VERSION_REVISION, SDK version revision, type=int, group=pico_base
 # PICO_CONFIG: PICO_SDK_VERSION_REVISION, SDK version revision, type=int, group=pico_base
 set(PICO_SDK_VERSION_REVISION 0)
 # PICO_BUILD_DEFINE: PICO_SDK_VERSION_PRE_RELEASE_ID, optional SDK pre-release version identifier, type=string, group=pico_base
 # PICO_CONFIG: PICO_SDK_VERSION_PRE_RELEASE_ID, optional SDK pre-release version identifier, type=string, group=pico_base
+#set(PICO_SDK_VERSION_PRE_RELEASE_ID develop)
 
 # PICO_BUILD_DEFINE: PICO_SDK_VERSION_STRING, SDK version, type=string, group=pico_base
 # PICO_CONFIG: PICO_SDK_VERSION_STRING, SDK version, type=string, group=pico_base
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 59f2933..f800c2f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -36,9 +36,9 @@
 function(pico_add_map_output TARGET)
     get_target_property(target_type ${TARGET} TYPE)
     if ("EXECUTABLE" STREQUAL "${target_type}")
-        target_link_options(${TARGET} PRIVATE "LINKER:-Map=$<TARGET_PROPERTY:NAME>${CMAKE_EXECUTABLE_SUFFIX}.map")
+        target_link_options(${TARGET} PRIVATE "LINKER:-Map=$<IF:$<BOOL:$<TARGET_PROPERTY:OUTPUT_NAME>>,$<TARGET_PROPERTY:OUTPUT_NAME>,$<TARGET_PROPERTY:NAME>>${CMAKE_EXECUTABLE_SUFFIX}.map")
     else ()
-        target_link_options(${TARGET} INTERFACE "LINKER:-Map=$<TARGET_PROPERTY:NAME>${CMAKE_EXECUTABLE_SUFFIX}.map")
+        target_link_options(${TARGET} INTERFACE "LINKER:-Map=$<IF:$<BOOL:$<TARGET_PROPERTY:OUTPUT_NAME>>,$<TARGET_PROPERTY:OUTPUT_NAME>,$<TARGET_PROPERTY:NAME>>${CMAKE_EXECUTABLE_SUFFIX}.map")
     endif ()
 endfunction()
 
diff --git a/src/board_setup.cmake b/src/board_setup.cmake
index 86b80f9..405d784 100644
--- a/src/board_setup.cmake
+++ b/src/board_setup.cmake
@@ -1,4 +1,4 @@
-# PICO_CMAKE_CONFIG: PICO_BOARD, The board name being built for. This is overridable from the user environment, type=string, default=rp2040, group=build
+# PICO_CMAKE_CONFIG: PICO_BOARD, The board name being built for. This is overridable from the user environment, type=string, default=pico, group=build
 if (DEFINED ENV{PICO_BOARD})
     set(PICO_BOARD $ENV{PICO_BOARD})
     message("Using PICO_BOARD from environment ('${PICO_BOARD}')")
diff --git a/src/boards/include/boards/adafruit_feather_rp2040.h b/src/boards/include/boards/adafruit_feather_rp2040.h
index 5049f6b..2da8e70 100644
--- a/src/boards/include/boards/adafruit_feather_rp2040.h
+++ b/src/boards/include/boards/adafruit_feather_rp2040.h
@@ -44,7 +44,7 @@
 
 //------------- I2C -------------//
 #ifndef PICO_DEFAULT_I2C
-#define PICO_DEFAULT_I2C 0
+#define PICO_DEFAULT_I2C 1
 #endif
 
 #ifndef PICO_DEFAULT_I2C_SDA_PIN
@@ -86,12 +86,8 @@
 #endif
 
 // All boards have B1 RP2040
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/adafruit_itsybitsy_rp2040.h b/src/boards/include/boards/adafruit_itsybitsy_rp2040.h
index 26cde1d..f9d27e9 100644
--- a/src/boards/include/boards/adafruit_itsybitsy_rp2040.h
+++ b/src/boards/include/boards/adafruit_itsybitsy_rp2040.h
@@ -89,12 +89,8 @@
 #endif
 
 // All boards have B1 RP2040
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/adafruit_qtpy_rp2040.h b/src/boards/include/boards/adafruit_qtpy_rp2040.h
index 299249d..24184c2 100644
--- a/src/boards/include/boards/adafruit_qtpy_rp2040.h
+++ b/src/boards/include/boards/adafruit_qtpy_rp2040.h
@@ -88,12 +88,8 @@
 #endif
 
 // All boards have B1 RP2040
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/adafruit_trinkey_qt2040.h b/src/boards/include/boards/adafruit_trinkey_qt2040.h
new file mode 100644
index 0000000..f9b49df
--- /dev/null
+++ b/src/boards/include/boards/adafruit_trinkey_qt2040.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+//       SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_ADAFRUIT_TRINKEY_QT2040_H
+#define _BOARDS_ADAFRUIT_TRINKEY_QT2040_H
+
+// For board detection
+#define ADAFRUIT_TRINKEY_QT2040
+
+// On some samples, the xosc can take longer to stabilize than is usual
+#ifndef PICO_XOSC_STARTUP_DELAY_MULTIPLIER
+#define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64
+#endif
+
+//------------- UART -------------//
+// no PICO_DEFAULT_UART
+// no PICO_DEFAULT_UART_TX_PIN
+// no PICO_DEFAULT_UART_RX_PIN
+
+//------------- LED -------------//
+// No normal LED
+// #define PICO_DEFAULT_LED_PIN 13
+
+#ifndef PICO_DEFAULT_WS2812_PIN
+#define PICO_DEFAULT_WS2812_PIN 27
+#endif
+
+//------------- I2C -------------//
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 0
+#endif
+
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 16
+#endif
+
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 17
+#endif
+
+//------------- SPI -------------//
+// no PICO_DEFAULT_SPI
+// no PICO_DEFAULT_SPI_SCK_PIN
+// no PICO_DEFAULT_SPI_TX_PIN
+// no PICO_DEFAULT_SPI_RX_PIN
+// no PICO_DEFAULT_SPI_CSN_PIN
+
+//------------- FLASH -------------//
+
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (8 * 1024 * 1024)
+#endif
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/arduino_nano_rp2040_connect.h b/src/boards/include/boards/arduino_nano_rp2040_connect.h
index 9725cb7..39c6564 100644
--- a/src/boards/include/boards/arduino_nano_rp2040_connect.h
+++ b/src/boards/include/boards/arduino_nano_rp2040_connect.h
@@ -66,7 +66,7 @@
 
 //------------- FLASH -------------//
 
-#define PICO_BOOT_STAGE2_CHOOSE_AT25SF128A 1
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
 
 #ifndef PICO_FLASH_SPI_CLKDIV
 #define PICO_FLASH_SPI_CLKDIV 2
@@ -77,12 +77,8 @@
 #endif
 
 // All boards have B1 RP2040
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/melopero_shake_rp2040.h b/src/boards/include/boards/melopero_shake_rp2040.h
new file mode 100644
index 0000000..d07ca61
--- /dev/null
+++ b/src/boards/include/boards/melopero_shake_rp2040.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+//       SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_MELOPERO_SHAKE_RP2040_H
+#define _BOARDS_MELOPERO_SHAKE_RP2040_H
+
+// For board detection
+#define MELOPERO_SHAKE_RP2040
+
+//------------- UART -------------//
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 1
+#endif
+
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 8
+#endif
+
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 9
+#endif
+
+//------------- LED -------------//
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN 13
+#endif
+
+#ifndef PICO_DEFAULT_WS2812_PIN
+#define PICO_DEFAULT_WS2812_PIN 16
+#endif
+
+//------------- I2C -------------//
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 1
+#endif
+
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 2
+#endif
+
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 3
+#endif
+
+//------------- SPI -------------//
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 0
+#endif
+
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 19
+#endif
+
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 20
+#endif
+
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 18
+#endif
+
+#ifndef PICO_DEFAULT_SPI_CSN_PIN
+#define PICO_DEFAULT_SPI_CSN_PIN 1
+#endif
+
+//------------- FLASH -------------//
+
+
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (16 * 1024 * 1024)
+#endif
+
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/pico.h b/src/boards/include/boards/pico.h
index 313d085..9e7f537 100644
--- a/src/boards/include/boards/pico.h
+++ b/src/boards/include/boards/pico.h
@@ -77,12 +77,8 @@
 // Drive high to force power supply into PWM mode (lower ripple on 3V3 at light loads)
 #define PICO_SMPS_MODE_PIN 23
 
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 1
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 1
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 1
 #endif
 
 #endif
diff --git a/src/boards/include/boards/pimoroni_interstate75.h b/src/boards/include/boards/pimoroni_interstate75.h
new file mode 100644
index 0000000..e2621b0
--- /dev/null
+++ b/src/boards/include/boards/pimoroni_interstate75.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+//       SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_PIMORONI_INTERSTATE75_H
+#define _BOARDS_PIMORONI_INTERSTATE75_H
+
+// For board detection
+#define PIMORONI_INTERSTATE75
+
+// --- BOARD SPECIFIC ---
+#ifndef INTERSTATE75_R0_PIN
+#define INTERSTATE75_R0_PIN 0
+#endif
+
+#ifndef INTERSTATE75_G0_PIN
+#define INTERSTATE75_G0_PIN 1
+#endif
+
+#ifndef INTERSTATE75_B0_PIN
+#define INTERSTATE75_B0_PIN 2
+#endif
+
+#ifndef INTERSTATE75_R1_PIN
+#define INTERSTATE75_R1_PIN 3
+#endif
+
+#ifndef INTERSTATE75_G1_PIN
+#define INTERSTATE75_G1_PIN 4
+#endif
+
+#ifndef INTERSTATE75_B1_PIN
+#define INTERSTATE75_B1_PIN 5
+#endif
+
+#ifndef INTERSTATE75_ROW_A_PIN
+#define INTERSTATE75_ROW_A_PIN 6
+#endif
+
+#ifndef INTERSTATE75_ROW_B_PIN
+#define INTERSTATE75_ROW_B_PIN 7
+#endif
+
+#ifndef INTERSTATE75_ROW_C_PIN
+#define INTERSTATE75_ROW_C_PIN 8
+#endif
+
+#ifndef INTERSTATE75_ROW_D_PIN
+#define INTERSTATE75_ROW_D_PIN 9
+#endif
+
+#ifndef INTERSTATE75_ROW_E_PIN
+#define INTERSTATE75_ROW_E_PIN 10
+#endif
+
+#ifndef INTERSTATE75_CLK_PIN
+#define INTERSTATE75_CLK_PIN 11
+#endif
+
+#ifndef INTERSTATE75_LAT_PIN
+#define INTERSTATE75_LAT_PIN 12
+#endif
+
+#ifndef INTERSTATE75_OE_PIN
+#define INTERSTATE75_OE_PIN 13
+#endif
+
+#ifndef INTERSTATE75_SW_A_PIN
+#define INTERSTATE75_SW_A_PIN 14
+#endif
+
+#ifndef INTERSTATE75_LED_R_PIN
+#define INTERSTATE75_LED_R_PIN 16
+#endif
+
+#ifndef INTERSTATE75_LED_G_PIN
+#define INTERSTATE75_LED_G_PIN 17
+#endif
+
+#ifndef INTERSTATE75_LED_B_PIN
+#define INTERSTATE75_LED_B_PIN 18
+#endif
+
+#ifndef INTERSTATE75_I2C
+#define INTERSTATE75_I2C 0
+#endif
+
+#ifndef INTERSTATE75_INT_PIN
+#define INTERSTATE75_INT_PIN 19
+#endif
+
+#ifndef INTERSTATE75_SDA_PIN
+#define INTERSTATE75_SDA_PIN 20
+#endif
+
+#ifndef INTERSTATE75_SCL_PIN
+#define INTERSTATE75_SCL_PIN 21
+#endif
+
+#ifndef INTERSTATE75_USER_SW_PIN
+#define INTERSTATE75_USER_SW_PIN 23
+#endif
+
+#ifndef INTERSTATE75_A0_PIN
+#define INTERSTATE75_A0_PIN 26
+#endif
+
+#ifndef INTERSTATE75_A1_PIN
+#define INTERSTATE75_A1_PIN 27
+#endif
+
+#ifndef INTERSTATE75_A2_PIN
+#define INTERSTATE75_A2_PIN 28
+#endif
+
+#ifndef INTERSTATE75_NUM_ADC_PINS
+#define INTERSTATE75_NUM_ADC_PINS 3
+#endif
+
+#ifndef INTERSTATE75_CURRENT_SENSE_PIN
+#define INTERSTATE75_CURRENT_SENSE_PIN 29
+#endif
+
+// --- UART ---
+// no PICO_DEFAULT_UART
+// no PICO_DEFAULT_UART_TX_PIN
+// no PICO_DEFAULT_UART_RX_PIN
+
+// --- LED ---
+// Included so basic examples will work, and set it to the green LED
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN INTERSTATE75_LED_G_PIN
+#endif
+// no PICO_DEFAULT_WS2812_PIN
+
+#ifndef PICO_DEFAULT_LED_PIN_INVERTED
+#define PICO_DEFAULT_LED_PIN_INVERTED 1
+#endif
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C INTERSTATE75_I2C
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN INTERSTATE75_SDA_PIN
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN INTERSTATE75_SCL_PIN
+#endif
+
+// --- SPI ---
+// no PICO_DEFAULT_SPI
+// no PICO_DEFAULT_SPI_SCK_PIN
+// no PICO_DEFAULT_SPI_TX_PIN
+// no PICO_DEFAULT_SPI_RX_PIN
+// no PICO_DEFAULT_SPI_CSN_PIN
+
+// --- FLASH ---
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024)
+#endif
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/pimoroni_keybow2040.h b/src/boards/include/boards/pimoroni_keybow2040.h
index 8cd6c1b..43772e8 100644
--- a/src/boards/include/boards/pimoroni_keybow2040.h
+++ b/src/boards/include/boards/pimoroni_keybow2040.h
@@ -147,12 +147,8 @@
 #endif
 
 // All boards have B1 RP2040
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/pimoroni_pga2040.h b/src/boards/include/boards/pimoroni_pga2040.h
index 90340fa..980f168 100644
--- a/src/boards/include/boards/pimoroni_pga2040.h
+++ b/src/boards/include/boards/pimoroni_pga2040.h
@@ -72,12 +72,8 @@
 #endif
 
 // All boards have B1 RP2040
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/pimoroni_picolipo_16mb.h b/src/boards/include/boards/pimoroni_picolipo_16mb.h
index a0310fb..338977b 100644
--- a/src/boards/include/boards/pimoroni_picolipo_16mb.h
+++ b/src/boards/include/boards/pimoroni_picolipo_16mb.h
@@ -85,12 +85,8 @@
 #endif
 
 // All boards have B1 RP2040
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/pimoroni_picolipo_4mb.h b/src/boards/include/boards/pimoroni_picolipo_4mb.h
index 9374f41..871ed83 100644
--- a/src/boards/include/boards/pimoroni_picolipo_4mb.h
+++ b/src/boards/include/boards/pimoroni_picolipo_4mb.h
@@ -85,12 +85,8 @@
 #endif
 
 // All boards have B1 RP2040
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/pimoroni_picosystem.h b/src/boards/include/boards/pimoroni_picosystem.h
index 34eb643..1e7c80e 100644
--- a/src/boards/include/boards/pimoroni_picosystem.h
+++ b/src/boards/include/boards/pimoroni_picosystem.h
@@ -156,12 +156,8 @@
 #endif
 
 // All boards have B1 RP2040
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/pimoroni_plasma2040.h b/src/boards/include/boards/pimoroni_plasma2040.h
new file mode 100644
index 0000000..226aaf5
--- /dev/null
+++ b/src/boards/include/boards/pimoroni_plasma2040.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+//       SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_PIMORONI_PLASMA2040_H
+#define _BOARDS_PIMORONI_PLASMA2040_H
+
+// For board detection
+#define PIMORONI_PLASMA2040
+
+// --- BOARD SPECIFIC ---
+#ifndef PLASMA2040_SW_A_PIN
+#define PLASMA2040_SW_A_PIN 12
+#endif
+
+#ifndef PLASMA2040_SW_B_PIN
+#define PLASMA2040_SW_B_PIN 13
+#endif
+
+#ifndef PLASMA2040_CLK_PIN
+#define PLASMA2040_CLK_PIN 14
+#endif
+
+#ifndef PLASMA2040_DATA_PIN
+#define PLASMA2040_DATA_PIN 15
+#endif
+
+#ifndef PLASMA2040_LED_R_PIN
+#define PLASMA2040_LED_R_PIN 16
+#endif
+
+#ifndef PLASMA2040_LED_G_PIN
+#define PLASMA2040_LED_G_PIN 17
+#endif
+
+#ifndef PLASMA2040_LED_B_PIN
+#define PLASMA2040_LED_B_PIN 18
+#endif
+
+#ifndef PLASMA2040_I2C
+#define PLASMA2040_I2C 0
+#endif
+
+#ifndef PLASMA2040_INT_PIN
+#define PLASMA2040_INT_PIN 19
+#endif
+
+#ifndef PLASMA2040_SDA_PIN
+#define PLASMA2040_SDA_PIN 20
+#endif
+
+#ifndef PLASMA2040_SCL_PIN
+#define PLASMA2040_SCL_PIN 21
+#endif
+
+#ifndef PLASMA2040_USER_SW_PIN
+#define PLASMA2040_USER_SW_PIN 23
+#endif
+
+#ifndef PLASMA2040_A0_PIN
+#define PLASMA2040_A0_PIN 26
+#endif
+
+#ifndef PLASMA2040_A1_PIN
+#define PLASMA2040_A1_PIN 27
+#endif
+
+#ifndef PLASMA2040_A2_PIN
+#define PLASMA2040_A2_PIN 28
+#endif
+
+#ifndef PLASMA2040_NUM_ADC_PINS
+#define PLASMA2040_NUM_ADC_PINS 3
+#endif
+
+#ifndef PLASMA2040_CURRENT_SENSE_PIN
+#define PLASMA2040_CURRENT_SENSE_PIN 29
+#endif
+
+// --- UART ---
+// no PICO_DEFAULT_UART
+// no PICO_DEFAULT_UART_TX_PIN
+// no PICO_DEFAULT_UART_RX_PIN
+
+// --- LED ---
+// Included so basic examples will work, and set it to the green LED
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN PLASMA2040_LED_G_PIN
+#endif
+// no PICO_DEFAULT_WS2812_PIN
+
+#ifndef PICO_DEFAULT_LED_PIN_INVERTED
+#define PICO_DEFAULT_LED_PIN_INVERTED 1
+#endif
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C PLASMA2040_I2C
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN PLASMA2040_SDA_PIN
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN PLASMA2040_SCL_PIN
+#endif
+
+// --- SPI ---
+// no PICO_DEFAULT_SPI
+// no PICO_DEFAULT_SPI_SCK_PIN
+// no PICO_DEFAULT_SPI_TX_PIN
+// no PICO_DEFAULT_SPI_RX_PIN
+// no PICO_DEFAULT_SPI_CSN_PIN
+
+// --- FLASH ---
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024)
+#endif
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/pimoroni_tiny2040.h b/src/boards/include/boards/pimoroni_tiny2040.h
index 81605b3..51d17f6 100644
--- a/src/boards/include/boards/pimoroni_tiny2040.h
+++ b/src/boards/include/boards/pimoroni_tiny2040.h
@@ -120,12 +120,8 @@
 #endif
 
 // All boards have B1 RP2040
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/pybstick26_rp2040.h b/src/boards/include/boards/pybstick26_rp2040.h
new file mode 100644
index 0000000..8a9ca41
--- /dev/null
+++ b/src/boards/include/boards/pybstick26_rp2040.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+//       SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+#ifndef _BOARDS_PYBSTICK26_RP2040_H
+#define _BOARDS_PYBSTICK26_RP2040_H
+
+// For board detection
+#define PYBSTICK26_RP2040
+
+// --- UART ---
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0
+#endif
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 0
+#endif
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 1
+#endif
+
+// --- LED ---
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN 23
+#endif
+// no PICO_DEFAULT_WS2812_PIN
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 1 
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 6
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 7 
+#endif
+
+// --- SPI ---
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 1
+#endif
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 10
+#endif
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 11
+#endif
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 8
+#endif
+#ifndef PICO_DEFAULT_SPI_CSN_PIN
+#define PICO_DEFAULT_SPI_CSN_PIN 9
+#endif
+
+// --- FLASH ---
+
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2 
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (1 * 1024 * 1024)
+#endif
+
+// Drive high to force power supply into PWM mode (lower ripple on 3V3 at light loads)
+// Linear regulator on Pybstick26
+//#define PICO_SMPS_MODE_PIN 23
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED 
+#define PICO_RP2040_B0_SUPPORTED  0
+#endif
+
+#endif
+// of #define _BOARDS_PYBSTICK26_RP2040_H
diff --git a/src/boards/include/boards/sparkfun_micromod.h b/src/boards/include/boards/sparkfun_micromod.h
index e6ef44f..0c6e568 100644
--- a/src/boards/include/boards/sparkfun_micromod.h
+++ b/src/boards/include/boards/sparkfun_micromod.h
@@ -79,12 +79,8 @@
 
 // All boards have B1 RP2040
 
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/sparkfun_promicro.h b/src/boards/include/boards/sparkfun_promicro.h
index 82e96cf..45bb4a2 100644
--- a/src/boards/include/boards/sparkfun_promicro.h
+++ b/src/boards/include/boards/sparkfun_promicro.h
@@ -79,12 +79,8 @@
 
 // All boards have B1 RP2040
 
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/sparkfun_thingplus.h b/src/boards/include/boards/sparkfun_thingplus.h
index b2e4932..d1e69d5 100644
--- a/src/boards/include/boards/sparkfun_thingplus.h
+++ b/src/boards/include/boards/sparkfun_thingplus.h
@@ -85,12 +85,8 @@
 
 // All boards have B1 RP2040
 
-#ifndef PICO_FLOAT_SUPPORT_ROM_V1
-#define PICO_FLOAT_SUPPORT_ROM_V1 0
-#endif
-
-#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
-#define PICO_DOUBLE_SUPPORT_ROM_V1 0
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 0
 #endif
 
 #endif
diff --git a/src/boards/include/boards/waveshare_rp2040_lcd_0.96.h b/src/boards/include/boards/waveshare_rp2040_lcd_0.96.h
new file mode 100644
index 0000000..8c59c5c
--- /dev/null
+++ b/src/boards/include/boards/waveshare_rp2040_lcd_0.96.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+//       SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+
+#ifndef _BOARDS_WAVESHARE_RP2040_LCD_0_96_H
+#define _BOARDS_WAVESHARE_RP2040_LCD_0_96_H
+
+// For board detection
+#define WAVESHARE_RP2040_LCD_0_96
+
+// --- UART ---
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0
+#endif
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 0
+#endif
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 1
+#endif
+
+// no PICO_DEFAULT_WS2812_PIN
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 0
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 4
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 5
+#endif
+
+// --- SPI ---
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 0
+#endif
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 18
+#endif
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 19
+#endif
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 16
+#endif
+#ifndef PICO_DEFAULT_SPI_CSN_PIN
+#define PICO_DEFAULT_SPI_CSN_PIN 17
+#endif
+
+// --- LCD ---
+#ifndef WAVESHARE_RP2040_LCD_SPI
+#define WAVESHARE_RP2040_LCD_SPI 1
+#endif
+#ifndef WAVESHARE_RP2040_LCD_DC_PIN
+#define WAVESHARE_RP2040_LCD_DC_PIN 8
+#endif
+#ifndef WAVESHARE_RP2040_LCD_CS_PIN
+#define WAVESHARE_RP2040_LCD_CS_PIN 9
+#endif
+#ifndef WAVESHARE_RP2040_LCD_SCLK_PIN
+#define WAVESHARE_RP2040_LCD_SCLK_PIN 10
+#endif
+#ifndef WAVESHARE_RP2040_LCD_TX_PIN
+#define WAVESHARE_RP2040_LCD_TX_PIN 11
+#endif
+#ifndef WAVESHARE_RP2040_LCD_RST_PIN
+#define WAVESHARE_RP2040_LCD_RST_PIN 12
+#endif
+#ifndef WAVESHARE_RP2040_LCD_BL_PIN
+#define WAVESHARE_RP2040_LCD_BL_PIN 25
+#endif
+
+// --- FLASH ---
+
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024)
+#endif
+
+// Drive high to force power supply into PWM mode (lower ripple on 3V3 at light loads)
+#define PICO_SMPS_MODE_PIN 23
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED 
+#define PICO_RP2040_B0_SUPPORTED  0
+#endif
+
+#endif
+
diff --git a/src/boards/include/boards/waveshare_rp2040_plus_16mb.h b/src/boards/include/boards/waveshare_rp2040_plus_16mb.h
new file mode 100644
index 0000000..6f5e144
--- /dev/null
+++ b/src/boards/include/boards/waveshare_rp2040_plus_16mb.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+//       SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+
+#ifndef _BOARDS_WAVESHARE_RP2040_PLUS_16MB_H
+#define _BOARDS_WAVESHARE_RP2040_PLUS_16MB_H
+
+// For board detection
+#define WAVESHARE_RP2040_PLUS_16MB
+
+// --- UART ---
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0
+#endif
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 0
+#endif
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 1
+#endif
+
+// --- LED ---
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN 25
+#endif
+// no PICO_DEFAULT_WS2812_PIN
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 1
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 6
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 7
+#endif
+
+// --- SPI ---
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 0
+#endif
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 18
+#endif
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 19
+#endif
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 16
+#endif
+#ifndef PICO_DEFAULT_SPI_CSN_PIN
+#define PICO_DEFAULT_SPI_CSN_PIN 17
+#endif
+
+// --- FLASH ---
+
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (16 * 1024 * 1024)
+#endif
+
+// Drive high to force power supply into PWM mode (lower ripple on 3V3 at light loads)
+#define PICO_SMPS_MODE_PIN 23
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED 
+#define PICO_RP2040_B0_SUPPORTED  0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/waveshare_rp2040_plus_4mb.h b/src/boards/include/boards/waveshare_rp2040_plus_4mb.h
new file mode 100644
index 0000000..d8dd8f6
--- /dev/null
+++ b/src/boards/include/boards/waveshare_rp2040_plus_4mb.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+//       SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+
+#ifndef _BOARDS_WAVESHARE_RP2040_PLUS_4MB_H
+#define _BOARDS_WAVESHARE_RP2040_PLUS_4MB_H
+
+// For board detection
+#define WAVESHARE_RP2040_PLUS_4MB
+
+// --- UART ---
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0
+#endif
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 0
+#endif
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 1
+#endif
+
+// --- LED ---
+#ifndef PICO_DEFAULT_LED_PIN
+#define PICO_DEFAULT_LED_PIN 25
+#endif
+// no PICO_DEFAULT_WS2812_PIN
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 1
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 6
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 7
+#endif
+
+// --- SPI ---
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 0
+#endif
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 18
+#endif
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 19
+#endif
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 16
+#endif
+#ifndef PICO_DEFAULT_SPI_CSN_PIN
+#define PICO_DEFAULT_SPI_CSN_PIN 17
+#endif
+
+// --- FLASH ---
+
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (4 * 1024 * 1024)
+#endif
+
+// Drive high to force power supply into PWM mode (lower ripple on 3V3 at light loads)
+#define PICO_SMPS_MODE_PIN 23
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED 
+#define PICO_RP2040_B0_SUPPORTED  0
+#endif
+
+#endif
diff --git a/src/boards/include/boards/waveshare_rp2040_zero.h b/src/boards/include/boards/waveshare_rp2040_zero.h
new file mode 100644
index 0000000..281b4dc
--- /dev/null
+++ b/src/boards/include/boards/waveshare_rp2040_zero.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+// -----------------------------------------------------
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+//       SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
+// -----------------------------------------------------
+
+
+#ifndef _BOARDS_WAVESHARE_RP2040_ZERO_H
+#define _BOARDS_WAVESHARE_RP2040_ZERO_H
+
+// For board detection
+#define WAVESHARE_RP2040_ZERO
+
+// --- UART ---
+#ifndef PICO_DEFAULT_UART
+#define PICO_DEFAULT_UART 0
+#endif
+#ifndef PICO_DEFAULT_UART_TX_PIN
+#define PICO_DEFAULT_UART_TX_PIN 0
+#endif
+#ifndef PICO_DEFAULT_UART_RX_PIN
+#define PICO_DEFAULT_UART_RX_PIN 1
+#endif
+
+// --- WS2812 ---
+#ifndef PICO_DEFAULT_WS2812_PIN
+#define PICO_DEFAULT_WS2812_PIN 16
+#endif
+
+// --- I2C ---
+#ifndef PICO_DEFAULT_I2C
+#define PICO_DEFAULT_I2C 1
+#endif
+#ifndef PICO_DEFAULT_I2C_SDA_PIN
+#define PICO_DEFAULT_I2C_SDA_PIN 6
+#endif
+#ifndef PICO_DEFAULT_I2C_SCL_PIN
+#define PICO_DEFAULT_I2C_SCL_PIN 7
+#endif
+
+// --- SPI ---
+#ifndef PICO_DEFAULT_SPI
+#define PICO_DEFAULT_SPI 1
+#endif
+#ifndef PICO_DEFAULT_SPI_SCK_PIN
+#define PICO_DEFAULT_SPI_SCK_PIN 10
+#endif
+#ifndef PICO_DEFAULT_SPI_TX_PIN
+#define PICO_DEFAULT_SPI_TX_PIN 11
+#endif
+#ifndef PICO_DEFAULT_SPI_RX_PIN
+#define PICO_DEFAULT_SPI_RX_PIN 12
+#endif
+#ifndef PICO_DEFAULT_SPI_CSN_PIN
+#define PICO_DEFAULT_SPI_CSN_PIN 13
+#endif
+
+// --- FLASH ---
+#define PICO_BOOT_STAGE2_CHOOSE_W25Q080 1
+
+#ifndef PICO_FLASH_SPI_CLKDIV
+#define PICO_FLASH_SPI_CLKDIV 2
+#endif
+
+#ifndef PICO_FLASH_SIZE_BYTES
+#define PICO_FLASH_SIZE_BYTES (2 * 1024 * 1024)
+#endif
+
+// All boards have B1 RP2040
+#ifndef PICO_RP2040_B0_SUPPORTED 
+#define PICO_RP2040_B0_SUPPORTED  0
+#endif
+
+#endif
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 9948db0..38cf238 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -1,6 +1,7 @@
 pico_add_subdirectory(boot_picoboot)
 pico_add_subdirectory(boot_uf2)
 pico_add_subdirectory(pico_base)
+pico_add_subdirectory(pico_usb_reset_interface)
 
 # PICO_CMAKE_CONFIG: PICO_BARE_METAL, Flag to exclude anything except base headers from the build, type=bool, default=0, group=build
 if (NOT PICO_BARE_METAL)
diff --git a/src/common/pico_base/include/pico.h b/src/common/pico_base/include/pico.h
index c7537b1..1b73651 100644
--- a/src/common/pico_base/include/pico.h
+++ b/src/common/pico_base/include/pico.h
@@ -8,9 +8,12 @@
 #define PICO_H_
 
 /** \file pico.h
-*  \defgroup pico_base pico_base
-*
-* Core types and macros for the Raspberry Pi Pico SDK. This header is intended to be included by all source code
+ *  \defgroup pico_base pico_base
+ *
+ * Core types and macros for the Raspberry Pi Pico SDK. This header is intended to be included by all source code
+ * as it includes configuration headers and overrides in the correct order
+ *
+ * This header may be included by assembly code
 */
 
 #include "pico/types.h"
diff --git a/src/common/pico_base/include/pico/config.h b/src/common/pico_base/include/pico/config.h
index 20f32cb..8d69269 100644
--- a/src/common/pico_base/include/pico/config.h
+++ b/src/common/pico_base/include/pico/config.h
@@ -8,7 +8,7 @@
 #define PICO_CONFIG_H_
 
 // -----------------------------------------------------
-// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLER SO
+// NOTE: THIS HEADER IS ALSO INCLUDED BY ASSEMBLY CODE SO
 //       SHOULD ONLY CONSIST OF PREPROCESSOR DIRECTIVES
 //       OR USE #ifndef __ASSEMBLER__ guards
 // -------------
diff --git a/src/common/pico_base/include/pico/error.h b/src/common/pico_base/include/pico/error.h
index 722a696..fadb45e 100644
--- a/src/common/pico_base/include/pico/error.h
+++ b/src/common/pico_base/include/pico/error.h
@@ -7,6 +7,8 @@
 #ifndef _PICO_ERROR_H
 #define _PICO_ERROR_H
 
+#ifndef __ASSEMBLER__
+
 /*!
  * Common return codes from pico_sdk methods that return a status
  */
@@ -18,4 +20,6 @@
     PICO_ERROR_NO_DATA = -3,
 };
 
+#endif // !__ASSEMBLER__
+
 #endif
\ No newline at end of file
diff --git a/src/common/pico_base/include/pico/types.h b/src/common/pico_base/include/pico/types.h
index 6b8e66f..8e1627c 100644
--- a/src/common/pico_base/include/pico/types.h
+++ b/src/common/pico_base/include/pico/types.h
@@ -7,6 +7,8 @@
 #ifndef _PICO_TYPES_H
 #define _PICO_TYPES_H
 
+#ifndef __ASSEMBLER__
+
 #include "pico/assert.h"
 
 #include <stdint.h>
@@ -89,3 +91,4 @@
 #define bool_to_bit(x) ((uint)!!(x))
 
 #endif
+#endif
diff --git a/src/common/pico_sync/include/pico/lock_core.h b/src/common/pico_sync/include/pico/lock_core.h
index fc676cc..bf8bee7 100644
--- a/src/common/pico_sync/include/pico/lock_core.h
+++ b/src/common/pico_sync/include/pico/lock_core.h
@@ -93,6 +93,13 @@
  * By default this returns the calling core number, but may be overridden (e.g. to return an RTOS task id)
  */
 #define lock_get_caller_owner_id() ((lock_owner_id_t)get_core_num())
+#ifndef lock_is_owner_id_valid
+#define lock_is_owner_id_valid(id) ((id)>=0)
+#endif
+#endif
+
+#ifndef lock_is_owner_id_valid
+#define lock_is_owner_id_valid(id) ((id) != LOCK_INVALID_OWNER_ID)
 #endif
 
 #ifndef lock_internal_spin_unlock_with_wait
diff --git a/src/common/pico_sync/include/pico/mutex.h b/src/common/pico_sync/include/pico/mutex.h
index 22dd19d..e834dc5 100644
--- a/src/common/pico_sync/include/pico/mutex.h
+++ b/src/common/pico_sync/include/pico/mutex.h
@@ -19,25 +19,51 @@
  * \brief Mutex API for non IRQ mutual exclusion between cores
  *
  * Mutexes are application level locks usually used protecting data structures that might be used by
- * multiple cores. Unlike critical sections, the mutex protected code is not necessarily
- * required/expected to complete quickly, as no other sytemwide locks are held on account of a locked mutex.
+ * multiple threads of execution. Unlike critical sections, the mutex protected code is not necessarily
+ * required/expected to complete quickly, as no other sytem wide locks are held on account of an acquired mutex.
  *
- * Because they are not re-entrant on the same core, blocking on a mutex should never be done in an IRQ
- * handler. It is valid to call \ref mutex_try_enter from within an IRQ handler, if the operation
- * that would be conducted under lock can be skipped if the mutex is locked (at least by the same core).
+ * When acquired, the mutex has an owner (see \ref lock_get_caller_owner_id) which with the plain SDK is just
+ * the acquiring core, but in an RTOS it could be a task, or an IRQ handler context.
+ *
+ * Two variants of mutex are provided; \ref mutex_t (and associated mutex_ functions) is a regular mutex that cannot
+ * be acquired recursively by the same owner (a deadlock will occur if you try). \ref recursive_mutex_t
+ * (and associated recursive_mutex_ functions) is a recursive mutex that can be recursively obtained by
+ * the same caller, at the expense of some more overhead when acquiring and releasing.
+ *
+ * It is generally a bad idea to call blocking mutex_ or recursive_mutex_ functions from within an IRQ handler.
+ * It is valid to call \ref mutex_try_enter or \ref recursive_mutex_try_enter from within an IRQ handler, if the operation
+ * that would be conducted under lock can be skipped if the mutex is locked (at least by the same owner).
+ *
+ * NOTE: For backwards compatibility with version 1.2.0 of the SDK, if the define
+ * PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY is set to 1, then the the regular mutex_ functions
+ * may also be used for recursive mutexes. This flag will be removed in a future version of the SDK.
  *
  * See \ref critical_section.h for protecting access between multiple cores AND IRQ handlers
  */
+
+/*! \brief recursive mutex instance
+ * \ingroup mutex
+ */
+typedef struct __packed_aligned  {
+    lock_core_t core;
+    lock_owner_id_t owner;      //! owner id LOCK_INVALID_OWNER_ID for unowned
+    uint8_t enter_count;        //! ownership count
+#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
+    bool recursive;
+#endif
+} recursive_mutex_t;
+
+/*! \brief regular (non recursive) mutex instance
+ * \ingroup mutex
+ */
+#if !PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
 typedef struct __packed_aligned mutex {
     lock_core_t core;
     lock_owner_id_t owner;      //! owner id LOCK_INVALID_OWNER_ID for unowned
-    uint8_t recursion_state;    //! 0 means non recursive (owner or unowned)
-                                //! 1 is a maxed out recursive lock
-                                //! 2-254 is an owned lock
-                                //! 255 is an un-owned lock
 } mutex_t;
-
-#define MAX_RECURSION_STATE ((uint8_t)255)
+#else
+typedef recursive_mutex_t mutex_t; // they are one and the same when backwards compatible with SDK1.2.0
+#endif
 
 /*! \brief  Initialise a mutex structure
  *  \ingroup mutex
@@ -51,74 +77,140 @@
  *
  * A recursive mutex may be entered in a nested fashion by the same owner
  *
- * \param mtx Pointer to mutex structure
+ * \param mtx Pointer to recursive mutex structure
  */
-void recursive_mutex_init(mutex_t *mtx);
+void recursive_mutex_init(recursive_mutex_t *mtx);
 
 /*! \brief  Take ownership of a mutex
  *  \ingroup mutex
  *
- * This function will block until the calling core can claim ownership of the mutex.
- * On return the caller core owns the mutex
+ * This function will block until the caller can be granted ownership of the mutex.
+ * On return the caller owns the mutex
  *
  * \param mtx Pointer to mutex structure
  */
 void mutex_enter_blocking(mutex_t *mtx);
 
+/*! \brief  Take ownership of a recursive mutex
+ *  \ingroup mutex
+ *
+ * This function will block until the caller can be granted ownership of the mutex.
+ * On return the caller owns the mutex
+ *
+ * \param mtx Pointer to recursive mutex structure
+ */
+void recursive_mutex_enter_blocking(recursive_mutex_t *mtx);
+
 /*! \brief Attempt to take ownership of a mutex
  *  \ingroup mutex
  *
- * If the mutex wasn't owned, this will claim the mutex and return true.
+ * If the mutex wasn't owned, this will claim the mutex for the caller and return true.
  * Otherwise (if the mutex was already owned) this will return false and the
- * calling core will *NOT* own the mutex.
+ * caller will NOT own the mutex.
  *
  * \param mtx Pointer to mutex structure
- * \param owner_out If mutex was already owned, and this pointer is non-zero, it will be filled in with the core number of the current owner of the mutex
+ * \param owner_out If mutex was already owned, and this pointer is non-zero, it will be filled in with the owner id of the current owner of the mutex
+ * \return true if mutex now owned, false otherwise
  */
 bool mutex_try_enter(mutex_t *mtx, uint32_t *owner_out);
 
-/*! \brief Wait for mutex with timeout
+/*! \brief Attempt to take ownership of a recursive mutex
  *  \ingroup mutex
  *
- * Wait for up to the specific time to take ownership of the mutex. If the calling
- * core can take ownership of the mutex before the timeout expires, then true will be returned
- * and the calling core will own the mutex, otherwise false will be returned and the calling
- * core will *NOT* own the mutex.
+ * If the mutex wasn't owned or was owned by the caller, this will claim the mutex and return true.
+ * Otherwise (if the mutex was already owned by another owner) this will return false and the
+ * caller will NOT own the mutex.
  *
- * \param mtx Pointer to mutex structure
- * \param timeout_ms The timeout in milliseconds.
- * \return true if mutex now owned, false if timeout occurred before mutex became available
+ * \param mtx Pointer to recursive mutex structure
+ * \param owner_out If mutex was already owned by another owner, and this pointer is non-zero,
+ *                  it will be filled in with the owner id of the current owner of the mutex
+ * \return true if the recursive mutex (now) owned, false otherwise
  */
-bool mutex_enter_timeout_ms(mutex_t *mtx, uint32_t timeout_ms);
+bool recursive_mutex_try_enter(recursive_mutex_t *mtx, uint32_t *owner_out);
 
 /*! \brief Wait for mutex with timeout
  *  \ingroup mutex
  *
- * Wait for up to the specific time to take ownership of the mutex. If the calling
- * core can take ownership of the mutex before the timeout expires, then true will be returned
- * and the calling core will own the mutex, otherwise false will be returned and the calling
- * core will *NOT* own the mutex.
+ * Wait for up to the specific time to take ownership of the mutex. If the caller
+ * can be granted ownership of the mutex before the timeout expires, then true will be returned
+ * and the caller will own the mutex, otherwise false will be returned and the caller will NOT own the mutex.
+ *
+ * \param mtx Pointer to mutex structure
+ * \param timeout_ms The timeout in milliseconds.
+ * \return true if mutex now owned, false if timeout occurred before ownership could be granted
+ */
+bool mutex_enter_timeout_ms(mutex_t *mtx, uint32_t timeout_ms);
+
+/*! \brief Wait for recursive mutex with timeout
+ *  \ingroup mutex
+ *
+ * Wait for up to the specific time to take ownership of the recursive mutex. If the caller
+ * already has ownership of the mutex or can be granted ownership of the mutex before the timeout expires,
+ * then true will be returned and the caller will own the mutex, otherwise false will be returned and the caller
+ * will NOT own the mutex.
+ *
+ * \param mtx Pointer to recursive mutex structure
+ * \param timeout_ms The timeout in milliseconds.
+ * \return true if the recursive mutex (now) owned, false if timeout occurred before ownership could be granted
+ */
+bool recursive_mutex_enter_timeout_ms(recursive_mutex_t *mtx, uint32_t timeout_ms);
+
+/*! \brief Wait for mutex with timeout
+ *  \ingroup mutex
+ *
+ * Wait for up to the specific time to take ownership of the mutex. If the caller
+ * can be granted ownership of the mutex before the timeout expires, then true will be returned
+ * and the caller will own the mutex, otherwise false will be returned and the caller
+ * will NOT own the mutex.
  *
  * \param mtx Pointer to mutex structure
  * \param timeout_us The timeout in microseconds.
- * \return true if mutex now owned, false if timeout occurred before mutex became available
+ * \return true if mutex now owned, false if timeout occurred before ownership could be granted
  */
 bool mutex_enter_timeout_us(mutex_t *mtx, uint32_t timeout_us);
 
+/*! \brief Wait for recursive mutex with timeout
+ *  \ingroup mutex
+ *
+ * Wait for up to the specific time to take ownership of the recursive mutex. If the caller
+ * already has ownership of the mutex or can be granted ownership of the mutex before the timeout expires,
+ * then true will be returned and the caller will own the mutex, otherwise false will be returned and the caller
+ * will NOT own the mutex.
+ *
+ * \param mtx Pointer to mutex structure
+ * \param timeout_us The timeout in microseconds.
+ * \return true if the recursive mutex (now) owned, false if timeout occurred before ownership could be granted
+ */
+bool recursive_mutex_enter_timeout_us(recursive_mutex_t *mtx, uint32_t timeout_us);
+
 /*! \brief Wait for mutex until a specific time
  *  \ingroup mutex
  *
- * Wait until the specific time to take ownership of the mutex. If the calling
- * core can take ownership of the mutex before the timeout expires, then true will be returned
- * and the calling core will own the mutex, otherwise false will be returned and the calling
- * core will *NOT* own the mutex.
+ * Wait until the specific time to take ownership of the mutex. If the caller
+ * can be granted ownership of the mutex before the timeout expires, then true will be returned
+ * and the caller will own the mutex, otherwise false will be returned and the caller
+ * will NOT own the mutex.
  *
  * \param mtx Pointer to mutex structure
- * \param until The time after which to return if the core cannot take ownership of the mutex
- * \return true if mutex now owned, false if timeout occurred before mutex became available
+ * \param until The time after which to return if the caller cannot be granted ownership of the mutex
+ * \return true if mutex now owned, false if timeout occurred before ownership could be granted
  */
 bool mutex_enter_block_until(mutex_t *mtx, absolute_time_t until);
 
+/*! \brief Wait for mutex until a specific time
+ *  \ingroup mutex
+ *
+ * Wait until the specific time to take ownership of the mutex. If the caller
+ * already has ownership of the mutex or can be granted ownership of the mutex before the timeout expires,
+ * then true will be returned and the caller will own the mutex, otherwise false will be returned and the caller
+ * will NOT own the mutex.
+ *
+ * \param mtx Pointer to recursive mutex structure
+ * \param until The time after which to return if the caller cannot be granted ownership of the mutex
+ * \return true if the recursive mutex (now) owned, false if timeout occurred before ownership could be granted
+ */
+bool recursive_mutex_enter_block_until(recursive_mutex_t *mtx, absolute_time_t until);
+
 /*! \brief  Release ownership of a mutex
  *  \ingroup mutex
  *
@@ -126,13 +218,30 @@
  */
 void mutex_exit(mutex_t *mtx);
 
-/*! \brief Test for mutex initialised state
+/*! \brief  Release ownership of a recursive mutex
+ *  \ingroup mutex
+ *
+ * \param mtx Pointer to recursive mutex structure
+ */
+void recursive_mutex_exit(recursive_mutex_t *mtx);
+
+/*! \brief Test for mutex initialized state
  *  \ingroup mutex
  *
  * \param mtx Pointer to mutex structure
- * \return true if the mutex is initialised, false otherwise
+ * \return true if the mutex is initialized, false otherwise
  */
-static inline bool mutex_is_initialzed(mutex_t *mtx) {
+static inline bool mutex_is_initialized(mutex_t *mtx) {
+    return mtx->core.spin_lock != 0;
+}
+
+/*! \brief Test for recursive mutex initialized state
+ *  \ingroup mutex
+ *
+ * \param mtx Pointer to recursive mutex structure
+ * \return true if the recursive mutex is initialized, false otherwise
+ */
+static inline bool recursive_mutex_is_initialized(recursive_mutex_t *mtx) {
     return mtx->core.spin_lock != 0;
 }
 
@@ -165,22 +274,22 @@
  * A recursive mutex defined as follows:
  *
  * ```c
- * auto_init_recursive_mutex(my_mutex);
+ * auto_init_recursive_mutex(my_recursive_mutex);
  * ```
  *
  * Is equivalent to doing
  *
  * ```c
- * static mutex_t my_mutex;
+ * static recursive_mutex_t my_recursive_mutex;
  *
  * void my_init_function() {
- *    recursive_mutex_init(&my_mutex);
+ *    recursive_mutex_init(&my_recursive_mutex);
  * }
  * ```
  *
  * But the initialization of the mutex is performed automatically during runtime initialization
  */
-#define auto_init_recursive_mutex(name) static __attribute__((section(".mutex_array"))) mutex_t name = { .recursion_state = MAX_RECURSION_STATE }
+#define auto_init_recursive_mutex(name) static __attribute__((section(".mutex_array"))) recursive_mutex_t name = { .core.spin_lock = (spin_lock_t *)1 /* marker for runtime_init */ }
 
 #ifdef __cplusplus
 }
diff --git a/src/common/pico_sync/mutex.c b/src/common/pico_sync/mutex.c
index 45ede4d..3ea81c7 100644
--- a/src/common/pico_sync/mutex.c
+++ b/src/common/pico_sync/mutex.c
@@ -7,53 +7,87 @@
 #include "pico/mutex.h"
 #include "pico/time.h"
 
-static void mutex_init_internal(mutex_t *mtx, uint8_t recursion_state) {
+void mutex_init(mutex_t *mtx) {
     lock_init(&mtx->core, next_striped_spin_lock_num());
     mtx->owner = LOCK_INVALID_OWNER_ID;
-    mtx->recursion_state = recursion_state;
+#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
+    mtx->recursive = false;
+#endif
     __mem_fence_release();
 }
 
-void mutex_init(mutex_t *mtx) {
-    mutex_init_internal(mtx, 0);
-}
-
-void recursive_mutex_init(mutex_t *mtx) {
-    mutex_init_internal(mtx, MAX_RECURSION_STATE);
+void recursive_mutex_init(recursive_mutex_t *mtx) {
+    lock_init(&mtx->core, next_striped_spin_lock_num());
+    mtx->owner = LOCK_INVALID_OWNER_ID;
+    mtx->enter_count = 0;
+#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
+    mtx->recursive = true;
+#endif
+    __mem_fence_release();
 }
 
 void __time_critical_func(mutex_enter_blocking)(mutex_t *mtx) {
-    assert(mtx->core.spin_lock);
+#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
+    if (mtx->recursive) {
+        recursive_mutex_enter_blocking(mtx);
+        return;
+    }
+#endif
+    lock_owner_id_t caller = lock_get_caller_owner_id();
     do {
         uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
-        lock_owner_id_t caller = lock_get_caller_owner_id();
-        if (mtx->owner == LOCK_INVALID_OWNER_ID) {
+        if (!lock_is_owner_id_valid(mtx->owner)) {
             mtx->owner = caller;
-            if (mtx->recursion_state) {
-                assert(mtx->recursion_state == MAX_RECURSION_STATE);
-                mtx->recursion_state--;
-            }
-        } else if (mtx->owner == caller && mtx->recursion_state > 1) {
-            mtx->recursion_state--;
+            spin_unlock(mtx->core.spin_lock, save);
+            break;
+        }
+        lock_internal_spin_unlock_with_wait(&mtx->core, save);
+    } while (true);
+}
+
+void __time_critical_func(recursive_mutex_enter_blocking)(recursive_mutex_t *mtx) {
+    lock_owner_id_t caller = lock_get_caller_owner_id();
+    do {
+        uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
+        if (mtx->owner == caller || !lock_is_owner_id_valid(mtx->owner)) {
+            mtx->owner = caller;
+            uint __unused total = ++mtx->enter_count;
+            spin_unlock(mtx->core.spin_lock, save);
+            assert(total); // check for overflow
+            return;
         } else {
             lock_internal_spin_unlock_with_wait(&mtx->core, save);
-            // spin lock already unlocked, so loop again
-            continue;
         }
-        spin_unlock(mtx->core.spin_lock, save);
-        break;
     } while (true);
 }
 
 bool __time_critical_func(mutex_try_enter)(mutex_t *mtx, uint32_t *owner_out) {
+#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
+    if (mtx->recursive) {
+        return recursive_mutex_try_enter(mtx, owner_out);
+    }
+#endif
     bool entered;
     uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
-    lock_owner_id_t caller = lock_get_caller_owner_id();
-    if (mtx->owner == LOCK_INVALID_OWNER_ID) {
+    if (!lock_is_owner_id_valid(mtx->owner)) {
         mtx->owner = lock_get_caller_owner_id();
         entered = true;
-    } else if (mtx->owner == caller && mtx->recursion_state > 1) {
-        mtx->recursion_state--;
+    } else {
+        if (owner_out) *owner_out = (uint32_t) mtx->owner;
+        entered = false;
+    }
+    spin_unlock(mtx->core.spin_lock, save);
+    return entered;
+}
+
+bool __time_critical_func(recursive_mutex_try_enter)(recursive_mutex_t *mtx, uint32_t *owner_out) {
+    bool entered;
+    lock_owner_id_t caller = lock_get_caller_owner_id();
+    uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
+    if (!lock_is_owner_id_valid(mtx->owner) || mtx->owner == caller) {
+        mtx->owner = caller;
+        uint __unused total = ++mtx->enter_count;
+        assert(total); // check for overflow
         entered = true;
     } else {
         if (owner_out) *owner_out = (uint32_t) mtx->owner;
@@ -67,47 +101,84 @@
     return mutex_enter_block_until(mtx, make_timeout_time_ms(timeout_ms));
 }
 
+bool __time_critical_func(recursive_mutex_enter_timeout_ms)(recursive_mutex_t *mtx, uint32_t timeout_ms) {
+    return recursive_mutex_enter_block_until(mtx, make_timeout_time_ms(timeout_ms));
+}
+
 bool __time_critical_func(mutex_enter_timeout_us)(mutex_t *mtx, uint32_t timeout_us) {
     return mutex_enter_block_until(mtx, make_timeout_time_us(timeout_us));
 }
 
+bool __time_critical_func(recursive_mutex_enter_timeout_us)(recursive_mutex_t *mtx, uint32_t timeout_us) {
+    return recursive_mutex_enter_block_until(mtx, make_timeout_time_us(timeout_us));
+}
+
 bool __time_critical_func(mutex_enter_block_until)(mutex_t *mtx, absolute_time_t until) {
+#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
+    if (mtx->recursive) {
+        return recursive_mutex_enter_block_until(mtx, until);
+    }
+#endif
     assert(mtx->core.spin_lock);
+    lock_owner_id_t caller = lock_get_caller_owner_id();
     do {
         uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
-        lock_owner_id_t caller = lock_get_caller_owner_id();
-        if (mtx->owner == LOCK_INVALID_OWNER_ID) {
+        if (!lock_is_owner_id_valid(mtx->owner)) {
             mtx->owner = caller;
-        } else if (mtx->owner == caller && mtx->recursion_state > 1) {
-            mtx->recursion_state--;
+            spin_unlock(mtx->core.spin_lock, save);
+            return true;
         } else {
             if (lock_internal_spin_unlock_with_best_effort_wait_or_timeout(&mtx->core, save, until)) {
                 // timed out
                 return false;
-            } else {
-                // not timed out; spin lock already unlocked, so loop again
-                continue;
             }
+            // not timed out; spin lock already unlocked, so loop again
         }
-        spin_unlock(mtx->core.spin_lock, save);
-        return true;
+    } while (true);
+}
+
+bool __time_critical_func(recursive_mutex_enter_block_until)(recursive_mutex_t *mtx, absolute_time_t until) {
+    assert(mtx->core.spin_lock);
+    lock_owner_id_t caller = lock_get_caller_owner_id();
+    do {
+        uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
+        if (!lock_is_owner_id_valid(mtx->owner) || mtx->owner == caller) {
+            mtx->owner = caller;
+            uint __unused total = ++mtx->enter_count;
+            spin_unlock(mtx->core.spin_lock, save);
+            assert(total); // check for overflow
+            return true;
+        } else {
+            if (lock_internal_spin_unlock_with_best_effort_wait_or_timeout(&mtx->core, save, until)) {
+                // timed out
+                return false;
+            }
+            // not timed out; spin lock already unlocked, so loop again
+        }
     } while (true);
 }
 
 void __time_critical_func(mutex_exit)(mutex_t *mtx) {
+#if PICO_MUTEX_ENABLE_SDK120_COMPATIBILITY
+    if (mtx->recursive) {
+        recursive_mutex_exit(mtx);
+        return;
+    }
+#endif
     uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
-    assert(mtx->owner != LOCK_INVALID_OWNER_ID);
-    if (!mtx->recursion_state) {
+    assert(lock_is_owner_id_valid(mtx->owner));
+    mtx->owner = LOCK_INVALID_OWNER_ID;
+    lock_internal_spin_unlock_with_notify(&mtx->core, save);
+}
+
+void __time_critical_func(recursive_mutex_exit)(recursive_mutex_t *mtx) {
+    uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
+    assert(lock_is_owner_id_valid(mtx->owner));
+    assert(mtx->enter_count);
+    if (!--mtx->enter_count) {
         mtx->owner = LOCK_INVALID_OWNER_ID;
         lock_internal_spin_unlock_with_notify(&mtx->core, save);
     } else {
-        mtx->recursion_state++;
-        assert(mtx->recursion_state);
-        if (mtx->recursion_state == MAX_RECURSION_STATE) {
-            mtx->owner = LOCK_INVALID_OWNER_ID;
-            lock_internal_spin_unlock_with_notify(&mtx->core, save);
-        } else {
-            spin_unlock(mtx->core.spin_lock, save);
-        }
+        spin_unlock(mtx->core.spin_lock, save);
     }
 }
\ No newline at end of file
diff --git a/src/common/pico_time/include/pico/time.h b/src/common/pico_time/include/pico/time.h
index 1c34732..c00b7a8 100644
--- a/src/common/pico_time/include/pico/time.h
+++ b/src/common/pico_time/include/pico/time.h
@@ -416,9 +416,12 @@
  * @param time the timestamp when (after which) the callback should fire
  * @param callback the callback function
  * @param user_data user data to pass to the callback function
- * @param fire_if_past if true, this method will call the callback itself before returning 0 if the timestamp happens before or during this method call
- * @return >0 the alarm id
- * @return 0 the target timestamp was during or before this method call (whether the callback was called depends on fire_if_past)
+ * @param fire_if_past if true, and the alarm time falls before or during this call before the alarm can be set,
+ *                     then the callback should be called during (by) this function instead 
+ * @return >0 the alarm id for an active (at the time of return) alarm
+ * @return 0 if the alarm time passed before or during the call AND there is no active alarm to return the id of.
+ *           The latter can either happen because fire_if_past was false (i.e. no timer was ever created),
+ *           or if the callback <i>was</i> called during this method but the callback cancelled itself by returning 0
  * @return -1 if there were no alarm slots available
  */
 alarm_id_t alarm_pool_add_alarm_at(alarm_pool_t *pool, absolute_time_t time, alarm_callback_t callback, void *user_data, bool fire_if_past);
@@ -438,9 +441,12 @@
  * @param us the delay (from now) in microseconds when (after which) the callback should fire
  * @param callback the callback function
  * @param user_data user data to pass to the callback function
- * @param fire_if_past if true, this method will call the callback itself before returning 0 if the timestamp happens before or during this method call
+ * @param fire_if_past if true, and the alarm time falls during this call before the alarm can be set,
+ *                     then the callback should be called during (by) this function instead 
  * @return >0 the alarm id
- * @return 0 the target timestamp was during or before this method call (whether the callback was called depends on fire_if_past)
+ * @return 0 if the alarm time passed before or during the call AND there is no active alarm to return the id of.
+ *           The latter can either happen because fire_if_past was false (i.e. no timer was ever created),
+ *           or if the callback <i>was</i> called during this method but the callback cancelled itself by returning 0
  * @return -1 if there were no alarm slots available
  */
 static inline alarm_id_t alarm_pool_add_alarm_in_us(alarm_pool_t *pool, uint64_t us, alarm_callback_t callback, void *user_data, bool fire_if_past) {
@@ -462,9 +468,12 @@
  * @param ms the delay (from now) in milliseconds when (after which) the callback should fire
  * @param callback the callback function
  * @param user_data user data to pass to the callback function
- * @param fire_if_past if true, this method will call the callback itself before returning 0 if the timestamp happens before or during this method call
+ * @param fire_if_past if true, and the alarm time falls before or during this call before the alarm can be set,
+ *                     then the callback should be called during (by) this function instead 
  * @return >0 the alarm id
- * @return 0 the target timestamp was during or before this method call (whether the callback was called depends on fire_if_past)
+ * @return 0 if the alarm time passed before or during the call AND there is no active alarm to return the id of.
+ *           The latter can either happen because fire_if_past was false (i.e. no timer was ever created),
+ *           or if the callback <i>was</i> called during this method but the callback cancelled itself by returning 0
  * @return -1 if there were no alarm slots available
  */
 static inline alarm_id_t alarm_pool_add_alarm_in_ms(alarm_pool_t *pool, uint32_t ms, alarm_callback_t callback, void *user_data, bool fire_if_past) {
@@ -496,9 +505,12 @@
  * @param time the timestamp when (after which) the callback should fire
  * @param callback the callback function
  * @param user_data user data to pass to the callback function
- * @param fire_if_past if true, this method will call the callback itself before returning 0 if the timestamp happens before or during this method call
+ * @param fire_if_past if true, and the alarm time falls before or during this call before the alarm can be set,
+ *                     then the callback should be called during (by) this function instead 
  * @return >0 the alarm id
- * @return 0 the target timestamp was during or before this method call (whether the callback was called depends on fire_if_past)
+ * @return 0 if the alarm time passed before or during the call AND there is no active alarm to return the id of.
+ *           The latter can either happen because fire_if_past was false (i.e. no timer was ever created),
+ *           or if the callback <i>was</i> called during this method but the callback cancelled itself by returning 0
  * @return -1 if there were no alarm slots available
  */
 static inline alarm_id_t add_alarm_at(absolute_time_t time, alarm_callback_t callback, void *user_data, bool fire_if_past) {
@@ -519,9 +531,12 @@
  * @param us the delay (from now) in microseconds when (after which) the callback should fire
  * @param callback the callback function
  * @param user_data user data to pass to the callback function
- * @param fire_if_past if true, this method will call the callback itself before returning 0 if the timestamp happens before or during this method call
+ * @param fire_if_past if true, and the alarm time falls during this call before the alarm can be set,
+ *                     then the callback should be called during (by) this function instead 
  * @return >0 the alarm id
- * @return 0 the target timestamp was during or before this method call (whether the callback was called depends on fire_if_past)
+ * @return 0 if the alarm time passed before or during the call AND there is no active alarm to return the id of.
+ *           The latter can either happen because fire_if_past was false (i.e. no timer was ever created),
+ *           or if the callback <i>was</i> called during this method but the callback cancelled itself by returning 0
  * @return -1 if there were no alarm slots available
  */
 static inline alarm_id_t add_alarm_in_us(uint64_t us, alarm_callback_t callback, void *user_data, bool fire_if_past) {
@@ -542,9 +557,12 @@
  * @param ms the delay (from now) in milliseconds when (after which) the callback should fire
  * @param callback the callback function
  * @param user_data user data to pass to the callback function
- * @param fire_if_past if true, this method will call the callback itself before returning 0 if the timestamp happens before or during this method call
+ * @param fire_if_past if true, and the alarm time falls during this call before the alarm can be set,
+ *                     then the callback should be called during (by) this function instead 
  * @return >0 the alarm id
- * @return 0 the target timestamp was during or before this method call (whether the callback was called depends on fire_if_past)
+ * @return 0 if the alarm time passed before or during the call AND there is no active alarm to return the id of.
+ *           The latter can either happen because fire_if_past was false (i.e. no timer was ever created),
+ *           or if the callback <i>was</i> called during this method but the callback cancelled itself by returning 0
  * @return -1 if there were no alarm slots available
  */
 static inline alarm_id_t add_alarm_in_ms(uint32_t ms, alarm_callback_t callback, void *user_data, bool fire_if_past) {
diff --git a/src/common/pico_time/time.c b/src/common/pico_time/time.c
index f965ab8..3a585f6 100644
--- a/src/common/pico_time/time.c
+++ b/src/common/pico_time/time.c
@@ -219,18 +219,26 @@
     do {
         uint8_t id_high = 0;
         uint32_t save = spin_lock_blocking(pool->lock);
+
         pheap_node_id_t id = add_alarm_under_lock(pool, time, callback, user_data, 0, false, &missed);
         if (id) id_high = *get_entry_id_high(pool, id);
 
         spin_unlock(pool->lock, save);
 
         if (!id) {
+            // no space in pheap to allocate an alarm
             return -1;
         }
 
+        // note that if missed was true, then the id was never added to the pheap (because we
+        // passed false for create_if_past arg above)
         public_id = missed ? 0 : make_public_id(id_high, id);
         if (missed && fire_if_past) {
+            // ... so if fire_if_past == true we call the callback
             int64_t repeat = callback(public_id, user_data);
+            // if not repeated we have no id to return so set public_id to 0,
+            // otherwise we need to repeat, but will assign a new id next time
+            // todo arguably this does mean that the id passed to the first callback may differ from subsequent calls
             if (!repeat) {
                 public_id = 0;
                 break;
@@ -240,6 +248,10 @@
                 time = delayed_by_us(get_absolute_time(), (uint64_t)repeat);
             }
         } else {
+            // either:
+            // a) missed == false && public_id is > 0
+            // b) missed == true && fire_if_past == false && public_id = 0
+            // but we are done in either case
             break;
         }
     } while (true);
@@ -279,7 +291,7 @@
 #if PICO_ON_DEVICE
     printf("%lld (hi %02x)", to_us_since_boot(get_entry(pool, id)->target), *get_entry_id_high(pool, id));
 #else
-    printf(PRIu64, to_us_since_boot(get_entry(pool, id)->target));
+    printf("%"PRIu64, to_us_since_boot(get_entry(pool, id)->target));
 #endif
 }
 
@@ -302,7 +314,9 @@
     out->user_data = user_data;
     out->alarm_id = alarm_pool_add_alarm_at(pool, make_timeout_time_us((uint64_t)(delay_us >= 0 ? delay_us : -delay_us)),
                                             repeating_timer_callback, out, true);
-    return out->alarm_id > 0;
+    // note that if out->alarm_id is 0, then the callback was called during the above call (fire_if_past == true)
+    // and then the callback removed itself.
+    return out->alarm_id >= 0;
 }
 
 bool cancel_repeating_timer(repeating_timer_t *timer) {
diff --git a/src/common/pico_usb_reset_interface/CMakeLists.txt b/src/common/pico_usb_reset_interface/CMakeLists.txt
new file mode 100644
index 0000000..369375c
--- /dev/null
+++ b/src/common/pico_usb_reset_interface/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_library(pico_usb_reset_interface_headers INTERFACE)
+target_include_directories(pico_usb_reset_interface_headers INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
diff --git a/src/common/pico_usb_reset_interface/include/pico/usb_reset_interface.h b/src/common/pico_usb_reset_interface/include/pico/usb_reset_interface.h
new file mode 100644
index 0000000..153acf8
--- /dev/null
+++ b/src/common/pico_usb_reset_interface/include/pico/usb_reset_interface.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _PICO_USB_RESET_INTERFACE_H
+#define _PICO_USB_RESET_INTERFACE_H
+
+/** \file usb_reset_interface.h
+ *  \defgroup pico_usb_reset_interface pico_usb_reset_interface
+ *
+ * Definition for the reset interface that may be exposed by the pico_stdio_usb library
+ */
+
+// VENDOR sub-class for the reset interface
+#define RESET_INTERFACE_SUBCLASS 0x00
+// VENDOR protocol for the reset interface
+#define RESET_INTERFACE_PROTOCOL 0x01
+
+// CONTROL requests:
+
+// reset to BOOTSEL
+#define RESET_REQUEST_BOOTSEL 0x01
+// regular flash boot
+#define RESET_REQUEST_FLASH 0x02
+
+#endif
\ No newline at end of file
diff --git a/src/common/pico_util/include/pico/util/datetime.h b/src/common/pico_util/include/pico/util/datetime.h
index 61b5c7e..bb32835 100644
--- a/src/common/pico_util/include/pico/util/datetime.h
+++ b/src/common/pico_util/include/pico/util/datetime.h
@@ -9,6 +9,10 @@
 
 #include "pico.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /** \file datetime.h
  * \defgroup util_datetime datetime
  * \brief Date/Time formatting
@@ -24,4 +28,7 @@
  */
 void datetime_to_str(char *buf, uint buf_size, const datetime_t *t);
 
+#ifdef __cplusplus
+}
+#endif
 #endif
diff --git a/src/host/hardware_gpio/include/hardware/gpio.h b/src/host/hardware_gpio/include/hardware/gpio.h
index 223c472..b2b83a1 100644
--- a/src/host/hardware_gpio/include/hardware/gpio.h
+++ b/src/host/hardware_gpio/include/hardware/gpio.h
@@ -152,7 +152,9 @@
 void gpio_set_dir(uint gpio, bool out);
 
 // debugging
+#ifndef PICO_DEBUG_PIN_BASE
 #define PICO_DEBUG_PIN_BASE 19u
+#endif
 
 // note these two macros may only be used once per compilation unit
 #define CU_REGISTER_DEBUG_PINS(p, ...)
diff --git a/src/host/hardware_timer/timer.c b/src/host/hardware_timer/timer.c
index 1bab845..30f6a20 100644
--- a/src/host/hardware_timer/timer.c
+++ b/src/host/hardware_timer/timer.c
@@ -65,12 +65,12 @@
     const int chunk = 1u<<30u;
     uint64_t target_us = to_us_since_boot(target);
     uint64_t time_us = time_us_64();
-    while (target_us - time_us >= chunk) {
+    while ((int64_t)(target_us - time_us) >= chunk) {
         busy_wait_us_32(chunk);
         time_us = time_us_64();
     }
-    if (target_us != time_us) {
-        busy_wait_us_32(target_us - chunk);
+    if (target_us > time_us) {
+        busy_wait_us_32(target_us - time_us);
     }
 #endif
 }
diff --git a/src/host/pico_platform/include/pico/platform.h b/src/host/pico_platform/include/pico/platform.h
index 499bdf6..27e5c08 100644
--- a/src/host/pico_platform/include/pico/platform.h
+++ b/src/host/pico_platform/include/pico/platform.h
@@ -20,15 +20,21 @@
 extern "C" {
 #endif
 
-#define __not_in_flash(grup)
+#define __not_in_flash(group)
 #define __not_in_flash_func(func) func
 #define __no_inline_not_in_flash_func(func)
 #define __in_flash(group)
 #define __scratch_x(group)
 #define __scratch_y(group)
 
-#define __packed_aligned
+#ifndef _MSC_VER
+#define __packed __attribute__((packed))
+#define __packed_aligned __packed __attribute((aligned))
+#else
+// MSVC requires #pragma pack which isn't compatible with a single attribute style define
 #define __packed
+#define __packed_aligned
+#endif
 
 #define __time_critical_func(x) x
 #define __after_data(group)
diff --git a/src/host/pico_stdio/include/pico/stdio.h b/src/host/pico_stdio/include/pico/stdio.h
index 5431853..de0bde1 100644
--- a/src/host/pico_stdio/include/pico/stdio.h
+++ b/src/host/pico_stdio/include/pico/stdio.h
@@ -16,6 +16,9 @@
 static inline void stdio_init_all() { stdio_uart_init(); }
 static inline void stdio_filter_driver(stdio_driver_t *driver) {}
 static inline void stdio_set_translate_crlf(stdio_driver_t *driver, bool enabled) {}
+static inline bool stdio_usb_connected(void) { return true; }
 int getchar_timeout_us(uint32_t timeout_us);
+#define puts_raw puts
+#define putchar_raw putchar
 
 #endif
diff --git a/src/rp2040/hardware_regs/include/hardware/platform_defs.h b/src/rp2040/hardware_regs/include/hardware/platform_defs.h
index 437594c..08c7159 100644
--- a/src/rp2040/hardware_regs/include/hardware/platform_defs.h
+++ b/src/rp2040/hardware_regs/include/hardware/platform_defs.h
@@ -7,7 +7,7 @@
 #ifndef _HARDWARE_PLATFORM_DEFS_H
 #define _HARDWARE_PLATFORM_DEFS_H
 
-// This header is included from C and assembler - only define macros
+// This header is included from C and assembler - intended mostly for #defines; guard other stuff with #ifdef __ASSEMBLER__
 
 #ifndef _u
 #ifdef __ASSEMBLER__
@@ -19,6 +19,7 @@
 
 #define NUM_CORES _u(2)
 #define NUM_DMA_CHANNELS _u(12)
+#define NUM_DMA_TIMERS _u(4)
 #define NUM_IRQS _u(32)
 #define NUM_PIOS _u(2)
 #define NUM_PIO_STATE_MACHINES _u(4)
@@ -27,28 +28,17 @@
 #define NUM_UARTS _u(2)
 #define NUM_I2CS _u(2)
 #define NUM_SPIS _u(2)
-
+#define NUM_TIMERS _u(4)
 #define NUM_ADC_CHANNELS _u(5)
 
 #define NUM_BANK0_GPIOS _u(30)
+#define NUM_QSPI_GPIOS _u(6)
 
 #define PIO_INSTRUCTION_COUNT _u(32)
 
+// PICO_CONFIG: XOSC_MHZ, The crystal oscillator frequency in Mhz, type=int, default=12, advanced=true, group=hardware_base
+#ifndef XOSC_MHZ
 #define XOSC_MHZ _u(12)
-
-// PICO_CONFIG: PICO_STACK_SIZE, Stack Size, min=0x100, default=0x800, advanced=true, group=pico_standard_link
-#ifndef PICO_STACK_SIZE
-#define PICO_STACK_SIZE _u(0x800)
-#endif
-
-// PICO_CONFIG: PICO_HEAP_SIZE, Heap size to reserve, min=0x100, default=0x800, advanced=true, group=pico_standard_link
-#ifndef PICO_HEAP_SIZE
-#define PICO_HEAP_SIZE _u(0x800)
-#endif
-
-// PICO_CONFIG: PICO_NO_RAM_VECTOR_TABLE, Enable/disable the RAM vector table, type=bool, default=0, advanced=true, group=pico_runtime
-#ifndef PICO_NO_RAM_VECTOR_TABLE
-#define PICO_NO_RAM_VECTOR_TABLE 0
 #endif
 
 #endif
diff --git a/src/rp2040/hardware_regs/include/hardware/regs/dma.h b/src/rp2040/hardware_regs/include/hardware/regs/dma.h
index 49938ba..042c3c1 100644
--- a/src/rp2040/hardware_regs/include/hardware/regs/dma.h
+++ b/src/rp2040/hardware_regs/include/hardware/regs/dma.h
@@ -294,7 +294,7 @@
 #define DMA_CH0_AL1_CTRL_RESET  "-"
 #define DMA_CH0_AL1_CTRL_MSB    _u(31)
 #define DMA_CH0_AL1_CTRL_LSB    _u(0)
-#define DMA_CH0_AL1_CTRL_ACCESS "RO"
+#define DMA_CH0_AL1_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH0_AL1_READ_ADDR
 // Description : Alias for channel 0 READ_ADDR register
@@ -303,7 +303,7 @@
 #define DMA_CH0_AL1_READ_ADDR_RESET  "-"
 #define DMA_CH0_AL1_READ_ADDR_MSB    _u(31)
 #define DMA_CH0_AL1_READ_ADDR_LSB    _u(0)
-#define DMA_CH0_AL1_READ_ADDR_ACCESS "RO"
+#define DMA_CH0_AL1_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH0_AL1_WRITE_ADDR
 // Description : Alias for channel 0 WRITE_ADDR register
@@ -312,7 +312,7 @@
 #define DMA_CH0_AL1_WRITE_ADDR_RESET  "-"
 #define DMA_CH0_AL1_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH0_AL1_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH0_AL1_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH0_AL1_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH0_AL1_TRANS_COUNT_TRIG
 // Description : Alias for channel 0 TRANS_COUNT register
@@ -323,7 +323,7 @@
 #define DMA_CH0_AL1_TRANS_COUNT_TRIG_RESET  "-"
 #define DMA_CH0_AL1_TRANS_COUNT_TRIG_MSB    _u(31)
 #define DMA_CH0_AL1_TRANS_COUNT_TRIG_LSB    _u(0)
-#define DMA_CH0_AL1_TRANS_COUNT_TRIG_ACCESS "RO"
+#define DMA_CH0_AL1_TRANS_COUNT_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH0_AL2_CTRL
 // Description : Alias for channel 0 CTRL register
@@ -332,7 +332,7 @@
 #define DMA_CH0_AL2_CTRL_RESET  "-"
 #define DMA_CH0_AL2_CTRL_MSB    _u(31)
 #define DMA_CH0_AL2_CTRL_LSB    _u(0)
-#define DMA_CH0_AL2_CTRL_ACCESS "RO"
+#define DMA_CH0_AL2_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH0_AL2_TRANS_COUNT
 // Description : Alias for channel 0 TRANS_COUNT register
@@ -341,7 +341,7 @@
 #define DMA_CH0_AL2_TRANS_COUNT_RESET  "-"
 #define DMA_CH0_AL2_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH0_AL2_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH0_AL2_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH0_AL2_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH0_AL2_READ_ADDR
 // Description : Alias for channel 0 READ_ADDR register
@@ -350,7 +350,7 @@
 #define DMA_CH0_AL2_READ_ADDR_RESET  "-"
 #define DMA_CH0_AL2_READ_ADDR_MSB    _u(31)
 #define DMA_CH0_AL2_READ_ADDR_LSB    _u(0)
-#define DMA_CH0_AL2_READ_ADDR_ACCESS "RO"
+#define DMA_CH0_AL2_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH0_AL2_WRITE_ADDR_TRIG
 // Description : Alias for channel 0 WRITE_ADDR register
@@ -361,7 +361,7 @@
 #define DMA_CH0_AL2_WRITE_ADDR_TRIG_RESET  "-"
 #define DMA_CH0_AL2_WRITE_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH0_AL2_WRITE_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH0_AL2_WRITE_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH0_AL2_WRITE_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH0_AL3_CTRL
 // Description : Alias for channel 0 CTRL register
@@ -370,7 +370,7 @@
 #define DMA_CH0_AL3_CTRL_RESET  "-"
 #define DMA_CH0_AL3_CTRL_MSB    _u(31)
 #define DMA_CH0_AL3_CTRL_LSB    _u(0)
-#define DMA_CH0_AL3_CTRL_ACCESS "RO"
+#define DMA_CH0_AL3_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH0_AL3_WRITE_ADDR
 // Description : Alias for channel 0 WRITE_ADDR register
@@ -379,7 +379,7 @@
 #define DMA_CH0_AL3_WRITE_ADDR_RESET  "-"
 #define DMA_CH0_AL3_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH0_AL3_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH0_AL3_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH0_AL3_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH0_AL3_TRANS_COUNT
 // Description : Alias for channel 0 TRANS_COUNT register
@@ -388,7 +388,7 @@
 #define DMA_CH0_AL3_TRANS_COUNT_RESET  "-"
 #define DMA_CH0_AL3_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH0_AL3_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH0_AL3_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH0_AL3_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH0_AL3_READ_ADDR_TRIG
 // Description : Alias for channel 0 READ_ADDR register
@@ -399,7 +399,7 @@
 #define DMA_CH0_AL3_READ_ADDR_TRIG_RESET  "-"
 #define DMA_CH0_AL3_READ_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH0_AL3_READ_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH0_AL3_READ_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH0_AL3_READ_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH1_READ_ADDR
 // Description : DMA Channel 1 Read Address pointer
@@ -683,7 +683,7 @@
 #define DMA_CH1_AL1_CTRL_RESET  "-"
 #define DMA_CH1_AL1_CTRL_MSB    _u(31)
 #define DMA_CH1_AL1_CTRL_LSB    _u(0)
-#define DMA_CH1_AL1_CTRL_ACCESS "RO"
+#define DMA_CH1_AL1_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH1_AL1_READ_ADDR
 // Description : Alias for channel 1 READ_ADDR register
@@ -692,7 +692,7 @@
 #define DMA_CH1_AL1_READ_ADDR_RESET  "-"
 #define DMA_CH1_AL1_READ_ADDR_MSB    _u(31)
 #define DMA_CH1_AL1_READ_ADDR_LSB    _u(0)
-#define DMA_CH1_AL1_READ_ADDR_ACCESS "RO"
+#define DMA_CH1_AL1_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH1_AL1_WRITE_ADDR
 // Description : Alias for channel 1 WRITE_ADDR register
@@ -701,7 +701,7 @@
 #define DMA_CH1_AL1_WRITE_ADDR_RESET  "-"
 #define DMA_CH1_AL1_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH1_AL1_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH1_AL1_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH1_AL1_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH1_AL1_TRANS_COUNT_TRIG
 // Description : Alias for channel 1 TRANS_COUNT register
@@ -712,7 +712,7 @@
 #define DMA_CH1_AL1_TRANS_COUNT_TRIG_RESET  "-"
 #define DMA_CH1_AL1_TRANS_COUNT_TRIG_MSB    _u(31)
 #define DMA_CH1_AL1_TRANS_COUNT_TRIG_LSB    _u(0)
-#define DMA_CH1_AL1_TRANS_COUNT_TRIG_ACCESS "RO"
+#define DMA_CH1_AL1_TRANS_COUNT_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH1_AL2_CTRL
 // Description : Alias for channel 1 CTRL register
@@ -721,7 +721,7 @@
 #define DMA_CH1_AL2_CTRL_RESET  "-"
 #define DMA_CH1_AL2_CTRL_MSB    _u(31)
 #define DMA_CH1_AL2_CTRL_LSB    _u(0)
-#define DMA_CH1_AL2_CTRL_ACCESS "RO"
+#define DMA_CH1_AL2_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH1_AL2_TRANS_COUNT
 // Description : Alias for channel 1 TRANS_COUNT register
@@ -730,7 +730,7 @@
 #define DMA_CH1_AL2_TRANS_COUNT_RESET  "-"
 #define DMA_CH1_AL2_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH1_AL2_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH1_AL2_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH1_AL2_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH1_AL2_READ_ADDR
 // Description : Alias for channel 1 READ_ADDR register
@@ -739,7 +739,7 @@
 #define DMA_CH1_AL2_READ_ADDR_RESET  "-"
 #define DMA_CH1_AL2_READ_ADDR_MSB    _u(31)
 #define DMA_CH1_AL2_READ_ADDR_LSB    _u(0)
-#define DMA_CH1_AL2_READ_ADDR_ACCESS "RO"
+#define DMA_CH1_AL2_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH1_AL2_WRITE_ADDR_TRIG
 // Description : Alias for channel 1 WRITE_ADDR register
@@ -750,7 +750,7 @@
 #define DMA_CH1_AL2_WRITE_ADDR_TRIG_RESET  "-"
 #define DMA_CH1_AL2_WRITE_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH1_AL2_WRITE_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH1_AL2_WRITE_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH1_AL2_WRITE_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH1_AL3_CTRL
 // Description : Alias for channel 1 CTRL register
@@ -759,7 +759,7 @@
 #define DMA_CH1_AL3_CTRL_RESET  "-"
 #define DMA_CH1_AL3_CTRL_MSB    _u(31)
 #define DMA_CH1_AL3_CTRL_LSB    _u(0)
-#define DMA_CH1_AL3_CTRL_ACCESS "RO"
+#define DMA_CH1_AL3_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH1_AL3_WRITE_ADDR
 // Description : Alias for channel 1 WRITE_ADDR register
@@ -768,7 +768,7 @@
 #define DMA_CH1_AL3_WRITE_ADDR_RESET  "-"
 #define DMA_CH1_AL3_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH1_AL3_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH1_AL3_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH1_AL3_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH1_AL3_TRANS_COUNT
 // Description : Alias for channel 1 TRANS_COUNT register
@@ -777,7 +777,7 @@
 #define DMA_CH1_AL3_TRANS_COUNT_RESET  "-"
 #define DMA_CH1_AL3_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH1_AL3_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH1_AL3_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH1_AL3_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH1_AL3_READ_ADDR_TRIG
 // Description : Alias for channel 1 READ_ADDR register
@@ -788,7 +788,7 @@
 #define DMA_CH1_AL3_READ_ADDR_TRIG_RESET  "-"
 #define DMA_CH1_AL3_READ_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH1_AL3_READ_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH1_AL3_READ_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH1_AL3_READ_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH2_READ_ADDR
 // Description : DMA Channel 2 Read Address pointer
@@ -1072,7 +1072,7 @@
 #define DMA_CH2_AL1_CTRL_RESET  "-"
 #define DMA_CH2_AL1_CTRL_MSB    _u(31)
 #define DMA_CH2_AL1_CTRL_LSB    _u(0)
-#define DMA_CH2_AL1_CTRL_ACCESS "RO"
+#define DMA_CH2_AL1_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH2_AL1_READ_ADDR
 // Description : Alias for channel 2 READ_ADDR register
@@ -1081,7 +1081,7 @@
 #define DMA_CH2_AL1_READ_ADDR_RESET  "-"
 #define DMA_CH2_AL1_READ_ADDR_MSB    _u(31)
 #define DMA_CH2_AL1_READ_ADDR_LSB    _u(0)
-#define DMA_CH2_AL1_READ_ADDR_ACCESS "RO"
+#define DMA_CH2_AL1_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH2_AL1_WRITE_ADDR
 // Description : Alias for channel 2 WRITE_ADDR register
@@ -1090,7 +1090,7 @@
 #define DMA_CH2_AL1_WRITE_ADDR_RESET  "-"
 #define DMA_CH2_AL1_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH2_AL1_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH2_AL1_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH2_AL1_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH2_AL1_TRANS_COUNT_TRIG
 // Description : Alias for channel 2 TRANS_COUNT register
@@ -1101,7 +1101,7 @@
 #define DMA_CH2_AL1_TRANS_COUNT_TRIG_RESET  "-"
 #define DMA_CH2_AL1_TRANS_COUNT_TRIG_MSB    _u(31)
 #define DMA_CH2_AL1_TRANS_COUNT_TRIG_LSB    _u(0)
-#define DMA_CH2_AL1_TRANS_COUNT_TRIG_ACCESS "RO"
+#define DMA_CH2_AL1_TRANS_COUNT_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH2_AL2_CTRL
 // Description : Alias for channel 2 CTRL register
@@ -1110,7 +1110,7 @@
 #define DMA_CH2_AL2_CTRL_RESET  "-"
 #define DMA_CH2_AL2_CTRL_MSB    _u(31)
 #define DMA_CH2_AL2_CTRL_LSB    _u(0)
-#define DMA_CH2_AL2_CTRL_ACCESS "RO"
+#define DMA_CH2_AL2_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH2_AL2_TRANS_COUNT
 // Description : Alias for channel 2 TRANS_COUNT register
@@ -1119,7 +1119,7 @@
 #define DMA_CH2_AL2_TRANS_COUNT_RESET  "-"
 #define DMA_CH2_AL2_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH2_AL2_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH2_AL2_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH2_AL2_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH2_AL2_READ_ADDR
 // Description : Alias for channel 2 READ_ADDR register
@@ -1128,7 +1128,7 @@
 #define DMA_CH2_AL2_READ_ADDR_RESET  "-"
 #define DMA_CH2_AL2_READ_ADDR_MSB    _u(31)
 #define DMA_CH2_AL2_READ_ADDR_LSB    _u(0)
-#define DMA_CH2_AL2_READ_ADDR_ACCESS "RO"
+#define DMA_CH2_AL2_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH2_AL2_WRITE_ADDR_TRIG
 // Description : Alias for channel 2 WRITE_ADDR register
@@ -1139,7 +1139,7 @@
 #define DMA_CH2_AL2_WRITE_ADDR_TRIG_RESET  "-"
 #define DMA_CH2_AL2_WRITE_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH2_AL2_WRITE_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH2_AL2_WRITE_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH2_AL2_WRITE_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH2_AL3_CTRL
 // Description : Alias for channel 2 CTRL register
@@ -1148,7 +1148,7 @@
 #define DMA_CH2_AL3_CTRL_RESET  "-"
 #define DMA_CH2_AL3_CTRL_MSB    _u(31)
 #define DMA_CH2_AL3_CTRL_LSB    _u(0)
-#define DMA_CH2_AL3_CTRL_ACCESS "RO"
+#define DMA_CH2_AL3_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH2_AL3_WRITE_ADDR
 // Description : Alias for channel 2 WRITE_ADDR register
@@ -1157,7 +1157,7 @@
 #define DMA_CH2_AL3_WRITE_ADDR_RESET  "-"
 #define DMA_CH2_AL3_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH2_AL3_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH2_AL3_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH2_AL3_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH2_AL3_TRANS_COUNT
 // Description : Alias for channel 2 TRANS_COUNT register
@@ -1166,7 +1166,7 @@
 #define DMA_CH2_AL3_TRANS_COUNT_RESET  "-"
 #define DMA_CH2_AL3_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH2_AL3_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH2_AL3_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH2_AL3_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH2_AL3_READ_ADDR_TRIG
 // Description : Alias for channel 2 READ_ADDR register
@@ -1177,7 +1177,7 @@
 #define DMA_CH2_AL3_READ_ADDR_TRIG_RESET  "-"
 #define DMA_CH2_AL3_READ_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH2_AL3_READ_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH2_AL3_READ_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH2_AL3_READ_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH3_READ_ADDR
 // Description : DMA Channel 3 Read Address pointer
@@ -1461,7 +1461,7 @@
 #define DMA_CH3_AL1_CTRL_RESET  "-"
 #define DMA_CH3_AL1_CTRL_MSB    _u(31)
 #define DMA_CH3_AL1_CTRL_LSB    _u(0)
-#define DMA_CH3_AL1_CTRL_ACCESS "RO"
+#define DMA_CH3_AL1_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH3_AL1_READ_ADDR
 // Description : Alias for channel 3 READ_ADDR register
@@ -1470,7 +1470,7 @@
 #define DMA_CH3_AL1_READ_ADDR_RESET  "-"
 #define DMA_CH3_AL1_READ_ADDR_MSB    _u(31)
 #define DMA_CH3_AL1_READ_ADDR_LSB    _u(0)
-#define DMA_CH3_AL1_READ_ADDR_ACCESS "RO"
+#define DMA_CH3_AL1_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH3_AL1_WRITE_ADDR
 // Description : Alias for channel 3 WRITE_ADDR register
@@ -1479,7 +1479,7 @@
 #define DMA_CH3_AL1_WRITE_ADDR_RESET  "-"
 #define DMA_CH3_AL1_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH3_AL1_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH3_AL1_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH3_AL1_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH3_AL1_TRANS_COUNT_TRIG
 // Description : Alias for channel 3 TRANS_COUNT register
@@ -1490,7 +1490,7 @@
 #define DMA_CH3_AL1_TRANS_COUNT_TRIG_RESET  "-"
 #define DMA_CH3_AL1_TRANS_COUNT_TRIG_MSB    _u(31)
 #define DMA_CH3_AL1_TRANS_COUNT_TRIG_LSB    _u(0)
-#define DMA_CH3_AL1_TRANS_COUNT_TRIG_ACCESS "RO"
+#define DMA_CH3_AL1_TRANS_COUNT_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH3_AL2_CTRL
 // Description : Alias for channel 3 CTRL register
@@ -1499,7 +1499,7 @@
 #define DMA_CH3_AL2_CTRL_RESET  "-"
 #define DMA_CH3_AL2_CTRL_MSB    _u(31)
 #define DMA_CH3_AL2_CTRL_LSB    _u(0)
-#define DMA_CH3_AL2_CTRL_ACCESS "RO"
+#define DMA_CH3_AL2_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH3_AL2_TRANS_COUNT
 // Description : Alias for channel 3 TRANS_COUNT register
@@ -1508,7 +1508,7 @@
 #define DMA_CH3_AL2_TRANS_COUNT_RESET  "-"
 #define DMA_CH3_AL2_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH3_AL2_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH3_AL2_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH3_AL2_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH3_AL2_READ_ADDR
 // Description : Alias for channel 3 READ_ADDR register
@@ -1517,7 +1517,7 @@
 #define DMA_CH3_AL2_READ_ADDR_RESET  "-"
 #define DMA_CH3_AL2_READ_ADDR_MSB    _u(31)
 #define DMA_CH3_AL2_READ_ADDR_LSB    _u(0)
-#define DMA_CH3_AL2_READ_ADDR_ACCESS "RO"
+#define DMA_CH3_AL2_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH3_AL2_WRITE_ADDR_TRIG
 // Description : Alias for channel 3 WRITE_ADDR register
@@ -1528,7 +1528,7 @@
 #define DMA_CH3_AL2_WRITE_ADDR_TRIG_RESET  "-"
 #define DMA_CH3_AL2_WRITE_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH3_AL2_WRITE_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH3_AL2_WRITE_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH3_AL2_WRITE_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH3_AL3_CTRL
 // Description : Alias for channel 3 CTRL register
@@ -1537,7 +1537,7 @@
 #define DMA_CH3_AL3_CTRL_RESET  "-"
 #define DMA_CH3_AL3_CTRL_MSB    _u(31)
 #define DMA_CH3_AL3_CTRL_LSB    _u(0)
-#define DMA_CH3_AL3_CTRL_ACCESS "RO"
+#define DMA_CH3_AL3_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH3_AL3_WRITE_ADDR
 // Description : Alias for channel 3 WRITE_ADDR register
@@ -1546,7 +1546,7 @@
 #define DMA_CH3_AL3_WRITE_ADDR_RESET  "-"
 #define DMA_CH3_AL3_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH3_AL3_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH3_AL3_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH3_AL3_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH3_AL3_TRANS_COUNT
 // Description : Alias for channel 3 TRANS_COUNT register
@@ -1555,7 +1555,7 @@
 #define DMA_CH3_AL3_TRANS_COUNT_RESET  "-"
 #define DMA_CH3_AL3_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH3_AL3_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH3_AL3_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH3_AL3_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH3_AL3_READ_ADDR_TRIG
 // Description : Alias for channel 3 READ_ADDR register
@@ -1566,7 +1566,7 @@
 #define DMA_CH3_AL3_READ_ADDR_TRIG_RESET  "-"
 #define DMA_CH3_AL3_READ_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH3_AL3_READ_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH3_AL3_READ_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH3_AL3_READ_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH4_READ_ADDR
 // Description : DMA Channel 4 Read Address pointer
@@ -1850,7 +1850,7 @@
 #define DMA_CH4_AL1_CTRL_RESET  "-"
 #define DMA_CH4_AL1_CTRL_MSB    _u(31)
 #define DMA_CH4_AL1_CTRL_LSB    _u(0)
-#define DMA_CH4_AL1_CTRL_ACCESS "RO"
+#define DMA_CH4_AL1_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH4_AL1_READ_ADDR
 // Description : Alias for channel 4 READ_ADDR register
@@ -1859,7 +1859,7 @@
 #define DMA_CH4_AL1_READ_ADDR_RESET  "-"
 #define DMA_CH4_AL1_READ_ADDR_MSB    _u(31)
 #define DMA_CH4_AL1_READ_ADDR_LSB    _u(0)
-#define DMA_CH4_AL1_READ_ADDR_ACCESS "RO"
+#define DMA_CH4_AL1_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH4_AL1_WRITE_ADDR
 // Description : Alias for channel 4 WRITE_ADDR register
@@ -1868,7 +1868,7 @@
 #define DMA_CH4_AL1_WRITE_ADDR_RESET  "-"
 #define DMA_CH4_AL1_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH4_AL1_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH4_AL1_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH4_AL1_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH4_AL1_TRANS_COUNT_TRIG
 // Description : Alias for channel 4 TRANS_COUNT register
@@ -1879,7 +1879,7 @@
 #define DMA_CH4_AL1_TRANS_COUNT_TRIG_RESET  "-"
 #define DMA_CH4_AL1_TRANS_COUNT_TRIG_MSB    _u(31)
 #define DMA_CH4_AL1_TRANS_COUNT_TRIG_LSB    _u(0)
-#define DMA_CH4_AL1_TRANS_COUNT_TRIG_ACCESS "RO"
+#define DMA_CH4_AL1_TRANS_COUNT_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH4_AL2_CTRL
 // Description : Alias for channel 4 CTRL register
@@ -1888,7 +1888,7 @@
 #define DMA_CH4_AL2_CTRL_RESET  "-"
 #define DMA_CH4_AL2_CTRL_MSB    _u(31)
 #define DMA_CH4_AL2_CTRL_LSB    _u(0)
-#define DMA_CH4_AL2_CTRL_ACCESS "RO"
+#define DMA_CH4_AL2_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH4_AL2_TRANS_COUNT
 // Description : Alias for channel 4 TRANS_COUNT register
@@ -1897,7 +1897,7 @@
 #define DMA_CH4_AL2_TRANS_COUNT_RESET  "-"
 #define DMA_CH4_AL2_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH4_AL2_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH4_AL2_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH4_AL2_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH4_AL2_READ_ADDR
 // Description : Alias for channel 4 READ_ADDR register
@@ -1906,7 +1906,7 @@
 #define DMA_CH4_AL2_READ_ADDR_RESET  "-"
 #define DMA_CH4_AL2_READ_ADDR_MSB    _u(31)
 #define DMA_CH4_AL2_READ_ADDR_LSB    _u(0)
-#define DMA_CH4_AL2_READ_ADDR_ACCESS "RO"
+#define DMA_CH4_AL2_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH4_AL2_WRITE_ADDR_TRIG
 // Description : Alias for channel 4 WRITE_ADDR register
@@ -1917,7 +1917,7 @@
 #define DMA_CH4_AL2_WRITE_ADDR_TRIG_RESET  "-"
 #define DMA_CH4_AL2_WRITE_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH4_AL2_WRITE_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH4_AL2_WRITE_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH4_AL2_WRITE_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH4_AL3_CTRL
 // Description : Alias for channel 4 CTRL register
@@ -1926,7 +1926,7 @@
 #define DMA_CH4_AL3_CTRL_RESET  "-"
 #define DMA_CH4_AL3_CTRL_MSB    _u(31)
 #define DMA_CH4_AL3_CTRL_LSB    _u(0)
-#define DMA_CH4_AL3_CTRL_ACCESS "RO"
+#define DMA_CH4_AL3_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH4_AL3_WRITE_ADDR
 // Description : Alias for channel 4 WRITE_ADDR register
@@ -1935,7 +1935,7 @@
 #define DMA_CH4_AL3_WRITE_ADDR_RESET  "-"
 #define DMA_CH4_AL3_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH4_AL3_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH4_AL3_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH4_AL3_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH4_AL3_TRANS_COUNT
 // Description : Alias for channel 4 TRANS_COUNT register
@@ -1944,7 +1944,7 @@
 #define DMA_CH4_AL3_TRANS_COUNT_RESET  "-"
 #define DMA_CH4_AL3_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH4_AL3_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH4_AL3_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH4_AL3_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH4_AL3_READ_ADDR_TRIG
 // Description : Alias for channel 4 READ_ADDR register
@@ -1955,7 +1955,7 @@
 #define DMA_CH4_AL3_READ_ADDR_TRIG_RESET  "-"
 #define DMA_CH4_AL3_READ_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH4_AL3_READ_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH4_AL3_READ_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH4_AL3_READ_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH5_READ_ADDR
 // Description : DMA Channel 5 Read Address pointer
@@ -2239,7 +2239,7 @@
 #define DMA_CH5_AL1_CTRL_RESET  "-"
 #define DMA_CH5_AL1_CTRL_MSB    _u(31)
 #define DMA_CH5_AL1_CTRL_LSB    _u(0)
-#define DMA_CH5_AL1_CTRL_ACCESS "RO"
+#define DMA_CH5_AL1_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH5_AL1_READ_ADDR
 // Description : Alias for channel 5 READ_ADDR register
@@ -2248,7 +2248,7 @@
 #define DMA_CH5_AL1_READ_ADDR_RESET  "-"
 #define DMA_CH5_AL1_READ_ADDR_MSB    _u(31)
 #define DMA_CH5_AL1_READ_ADDR_LSB    _u(0)
-#define DMA_CH5_AL1_READ_ADDR_ACCESS "RO"
+#define DMA_CH5_AL1_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH5_AL1_WRITE_ADDR
 // Description : Alias for channel 5 WRITE_ADDR register
@@ -2257,7 +2257,7 @@
 #define DMA_CH5_AL1_WRITE_ADDR_RESET  "-"
 #define DMA_CH5_AL1_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH5_AL1_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH5_AL1_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH5_AL1_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH5_AL1_TRANS_COUNT_TRIG
 // Description : Alias for channel 5 TRANS_COUNT register
@@ -2268,7 +2268,7 @@
 #define DMA_CH5_AL1_TRANS_COUNT_TRIG_RESET  "-"
 #define DMA_CH5_AL1_TRANS_COUNT_TRIG_MSB    _u(31)
 #define DMA_CH5_AL1_TRANS_COUNT_TRIG_LSB    _u(0)
-#define DMA_CH5_AL1_TRANS_COUNT_TRIG_ACCESS "RO"
+#define DMA_CH5_AL1_TRANS_COUNT_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH5_AL2_CTRL
 // Description : Alias for channel 5 CTRL register
@@ -2277,7 +2277,7 @@
 #define DMA_CH5_AL2_CTRL_RESET  "-"
 #define DMA_CH5_AL2_CTRL_MSB    _u(31)
 #define DMA_CH5_AL2_CTRL_LSB    _u(0)
-#define DMA_CH5_AL2_CTRL_ACCESS "RO"
+#define DMA_CH5_AL2_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH5_AL2_TRANS_COUNT
 // Description : Alias for channel 5 TRANS_COUNT register
@@ -2286,7 +2286,7 @@
 #define DMA_CH5_AL2_TRANS_COUNT_RESET  "-"
 #define DMA_CH5_AL2_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH5_AL2_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH5_AL2_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH5_AL2_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH5_AL2_READ_ADDR
 // Description : Alias for channel 5 READ_ADDR register
@@ -2295,7 +2295,7 @@
 #define DMA_CH5_AL2_READ_ADDR_RESET  "-"
 #define DMA_CH5_AL2_READ_ADDR_MSB    _u(31)
 #define DMA_CH5_AL2_READ_ADDR_LSB    _u(0)
-#define DMA_CH5_AL2_READ_ADDR_ACCESS "RO"
+#define DMA_CH5_AL2_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH5_AL2_WRITE_ADDR_TRIG
 // Description : Alias for channel 5 WRITE_ADDR register
@@ -2306,7 +2306,7 @@
 #define DMA_CH5_AL2_WRITE_ADDR_TRIG_RESET  "-"
 #define DMA_CH5_AL2_WRITE_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH5_AL2_WRITE_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH5_AL2_WRITE_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH5_AL2_WRITE_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH5_AL3_CTRL
 // Description : Alias for channel 5 CTRL register
@@ -2315,7 +2315,7 @@
 #define DMA_CH5_AL3_CTRL_RESET  "-"
 #define DMA_CH5_AL3_CTRL_MSB    _u(31)
 #define DMA_CH5_AL3_CTRL_LSB    _u(0)
-#define DMA_CH5_AL3_CTRL_ACCESS "RO"
+#define DMA_CH5_AL3_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH5_AL3_WRITE_ADDR
 // Description : Alias for channel 5 WRITE_ADDR register
@@ -2324,7 +2324,7 @@
 #define DMA_CH5_AL3_WRITE_ADDR_RESET  "-"
 #define DMA_CH5_AL3_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH5_AL3_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH5_AL3_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH5_AL3_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH5_AL3_TRANS_COUNT
 // Description : Alias for channel 5 TRANS_COUNT register
@@ -2333,7 +2333,7 @@
 #define DMA_CH5_AL3_TRANS_COUNT_RESET  "-"
 #define DMA_CH5_AL3_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH5_AL3_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH5_AL3_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH5_AL3_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH5_AL3_READ_ADDR_TRIG
 // Description : Alias for channel 5 READ_ADDR register
@@ -2344,7 +2344,7 @@
 #define DMA_CH5_AL3_READ_ADDR_TRIG_RESET  "-"
 #define DMA_CH5_AL3_READ_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH5_AL3_READ_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH5_AL3_READ_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH5_AL3_READ_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH6_READ_ADDR
 // Description : DMA Channel 6 Read Address pointer
@@ -2628,7 +2628,7 @@
 #define DMA_CH6_AL1_CTRL_RESET  "-"
 #define DMA_CH6_AL1_CTRL_MSB    _u(31)
 #define DMA_CH6_AL1_CTRL_LSB    _u(0)
-#define DMA_CH6_AL1_CTRL_ACCESS "RO"
+#define DMA_CH6_AL1_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH6_AL1_READ_ADDR
 // Description : Alias for channel 6 READ_ADDR register
@@ -2637,7 +2637,7 @@
 #define DMA_CH6_AL1_READ_ADDR_RESET  "-"
 #define DMA_CH6_AL1_READ_ADDR_MSB    _u(31)
 #define DMA_CH6_AL1_READ_ADDR_LSB    _u(0)
-#define DMA_CH6_AL1_READ_ADDR_ACCESS "RO"
+#define DMA_CH6_AL1_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH6_AL1_WRITE_ADDR
 // Description : Alias for channel 6 WRITE_ADDR register
@@ -2646,7 +2646,7 @@
 #define DMA_CH6_AL1_WRITE_ADDR_RESET  "-"
 #define DMA_CH6_AL1_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH6_AL1_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH6_AL1_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH6_AL1_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH6_AL1_TRANS_COUNT_TRIG
 // Description : Alias for channel 6 TRANS_COUNT register
@@ -2657,7 +2657,7 @@
 #define DMA_CH6_AL1_TRANS_COUNT_TRIG_RESET  "-"
 #define DMA_CH6_AL1_TRANS_COUNT_TRIG_MSB    _u(31)
 #define DMA_CH6_AL1_TRANS_COUNT_TRIG_LSB    _u(0)
-#define DMA_CH6_AL1_TRANS_COUNT_TRIG_ACCESS "RO"
+#define DMA_CH6_AL1_TRANS_COUNT_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH6_AL2_CTRL
 // Description : Alias for channel 6 CTRL register
@@ -2666,7 +2666,7 @@
 #define DMA_CH6_AL2_CTRL_RESET  "-"
 #define DMA_CH6_AL2_CTRL_MSB    _u(31)
 #define DMA_CH6_AL2_CTRL_LSB    _u(0)
-#define DMA_CH6_AL2_CTRL_ACCESS "RO"
+#define DMA_CH6_AL2_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH6_AL2_TRANS_COUNT
 // Description : Alias for channel 6 TRANS_COUNT register
@@ -2675,7 +2675,7 @@
 #define DMA_CH6_AL2_TRANS_COUNT_RESET  "-"
 #define DMA_CH6_AL2_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH6_AL2_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH6_AL2_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH6_AL2_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH6_AL2_READ_ADDR
 // Description : Alias for channel 6 READ_ADDR register
@@ -2684,7 +2684,7 @@
 #define DMA_CH6_AL2_READ_ADDR_RESET  "-"
 #define DMA_CH6_AL2_READ_ADDR_MSB    _u(31)
 #define DMA_CH6_AL2_READ_ADDR_LSB    _u(0)
-#define DMA_CH6_AL2_READ_ADDR_ACCESS "RO"
+#define DMA_CH6_AL2_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH6_AL2_WRITE_ADDR_TRIG
 // Description : Alias for channel 6 WRITE_ADDR register
@@ -2695,7 +2695,7 @@
 #define DMA_CH6_AL2_WRITE_ADDR_TRIG_RESET  "-"
 #define DMA_CH6_AL2_WRITE_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH6_AL2_WRITE_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH6_AL2_WRITE_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH6_AL2_WRITE_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH6_AL3_CTRL
 // Description : Alias for channel 6 CTRL register
@@ -2704,7 +2704,7 @@
 #define DMA_CH6_AL3_CTRL_RESET  "-"
 #define DMA_CH6_AL3_CTRL_MSB    _u(31)
 #define DMA_CH6_AL3_CTRL_LSB    _u(0)
-#define DMA_CH6_AL3_CTRL_ACCESS "RO"
+#define DMA_CH6_AL3_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH6_AL3_WRITE_ADDR
 // Description : Alias for channel 6 WRITE_ADDR register
@@ -2713,7 +2713,7 @@
 #define DMA_CH6_AL3_WRITE_ADDR_RESET  "-"
 #define DMA_CH6_AL3_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH6_AL3_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH6_AL3_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH6_AL3_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH6_AL3_TRANS_COUNT
 // Description : Alias for channel 6 TRANS_COUNT register
@@ -2722,7 +2722,7 @@
 #define DMA_CH6_AL3_TRANS_COUNT_RESET  "-"
 #define DMA_CH6_AL3_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH6_AL3_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH6_AL3_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH6_AL3_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH6_AL3_READ_ADDR_TRIG
 // Description : Alias for channel 6 READ_ADDR register
@@ -2733,7 +2733,7 @@
 #define DMA_CH6_AL3_READ_ADDR_TRIG_RESET  "-"
 #define DMA_CH6_AL3_READ_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH6_AL3_READ_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH6_AL3_READ_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH6_AL3_READ_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH7_READ_ADDR
 // Description : DMA Channel 7 Read Address pointer
@@ -3017,7 +3017,7 @@
 #define DMA_CH7_AL1_CTRL_RESET  "-"
 #define DMA_CH7_AL1_CTRL_MSB    _u(31)
 #define DMA_CH7_AL1_CTRL_LSB    _u(0)
-#define DMA_CH7_AL1_CTRL_ACCESS "RO"
+#define DMA_CH7_AL1_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH7_AL1_READ_ADDR
 // Description : Alias for channel 7 READ_ADDR register
@@ -3026,7 +3026,7 @@
 #define DMA_CH7_AL1_READ_ADDR_RESET  "-"
 #define DMA_CH7_AL1_READ_ADDR_MSB    _u(31)
 #define DMA_CH7_AL1_READ_ADDR_LSB    _u(0)
-#define DMA_CH7_AL1_READ_ADDR_ACCESS "RO"
+#define DMA_CH7_AL1_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH7_AL1_WRITE_ADDR
 // Description : Alias for channel 7 WRITE_ADDR register
@@ -3035,7 +3035,7 @@
 #define DMA_CH7_AL1_WRITE_ADDR_RESET  "-"
 #define DMA_CH7_AL1_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH7_AL1_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH7_AL1_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH7_AL1_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH7_AL1_TRANS_COUNT_TRIG
 // Description : Alias for channel 7 TRANS_COUNT register
@@ -3046,7 +3046,7 @@
 #define DMA_CH7_AL1_TRANS_COUNT_TRIG_RESET  "-"
 #define DMA_CH7_AL1_TRANS_COUNT_TRIG_MSB    _u(31)
 #define DMA_CH7_AL1_TRANS_COUNT_TRIG_LSB    _u(0)
-#define DMA_CH7_AL1_TRANS_COUNT_TRIG_ACCESS "RO"
+#define DMA_CH7_AL1_TRANS_COUNT_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH7_AL2_CTRL
 // Description : Alias for channel 7 CTRL register
@@ -3055,7 +3055,7 @@
 #define DMA_CH7_AL2_CTRL_RESET  "-"
 #define DMA_CH7_AL2_CTRL_MSB    _u(31)
 #define DMA_CH7_AL2_CTRL_LSB    _u(0)
-#define DMA_CH7_AL2_CTRL_ACCESS "RO"
+#define DMA_CH7_AL2_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH7_AL2_TRANS_COUNT
 // Description : Alias for channel 7 TRANS_COUNT register
@@ -3064,7 +3064,7 @@
 #define DMA_CH7_AL2_TRANS_COUNT_RESET  "-"
 #define DMA_CH7_AL2_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH7_AL2_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH7_AL2_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH7_AL2_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH7_AL2_READ_ADDR
 // Description : Alias for channel 7 READ_ADDR register
@@ -3073,7 +3073,7 @@
 #define DMA_CH7_AL2_READ_ADDR_RESET  "-"
 #define DMA_CH7_AL2_READ_ADDR_MSB    _u(31)
 #define DMA_CH7_AL2_READ_ADDR_LSB    _u(0)
-#define DMA_CH7_AL2_READ_ADDR_ACCESS "RO"
+#define DMA_CH7_AL2_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH7_AL2_WRITE_ADDR_TRIG
 // Description : Alias for channel 7 WRITE_ADDR register
@@ -3084,7 +3084,7 @@
 #define DMA_CH7_AL2_WRITE_ADDR_TRIG_RESET  "-"
 #define DMA_CH7_AL2_WRITE_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH7_AL2_WRITE_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH7_AL2_WRITE_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH7_AL2_WRITE_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH7_AL3_CTRL
 // Description : Alias for channel 7 CTRL register
@@ -3093,7 +3093,7 @@
 #define DMA_CH7_AL3_CTRL_RESET  "-"
 #define DMA_CH7_AL3_CTRL_MSB    _u(31)
 #define DMA_CH7_AL3_CTRL_LSB    _u(0)
-#define DMA_CH7_AL3_CTRL_ACCESS "RO"
+#define DMA_CH7_AL3_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH7_AL3_WRITE_ADDR
 // Description : Alias for channel 7 WRITE_ADDR register
@@ -3102,7 +3102,7 @@
 #define DMA_CH7_AL3_WRITE_ADDR_RESET  "-"
 #define DMA_CH7_AL3_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH7_AL3_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH7_AL3_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH7_AL3_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH7_AL3_TRANS_COUNT
 // Description : Alias for channel 7 TRANS_COUNT register
@@ -3111,7 +3111,7 @@
 #define DMA_CH7_AL3_TRANS_COUNT_RESET  "-"
 #define DMA_CH7_AL3_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH7_AL3_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH7_AL3_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH7_AL3_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH7_AL3_READ_ADDR_TRIG
 // Description : Alias for channel 7 READ_ADDR register
@@ -3122,7 +3122,7 @@
 #define DMA_CH7_AL3_READ_ADDR_TRIG_RESET  "-"
 #define DMA_CH7_AL3_READ_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH7_AL3_READ_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH7_AL3_READ_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH7_AL3_READ_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH8_READ_ADDR
 // Description : DMA Channel 8 Read Address pointer
@@ -3406,7 +3406,7 @@
 #define DMA_CH8_AL1_CTRL_RESET  "-"
 #define DMA_CH8_AL1_CTRL_MSB    _u(31)
 #define DMA_CH8_AL1_CTRL_LSB    _u(0)
-#define DMA_CH8_AL1_CTRL_ACCESS "RO"
+#define DMA_CH8_AL1_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH8_AL1_READ_ADDR
 // Description : Alias for channel 8 READ_ADDR register
@@ -3415,7 +3415,7 @@
 #define DMA_CH8_AL1_READ_ADDR_RESET  "-"
 #define DMA_CH8_AL1_READ_ADDR_MSB    _u(31)
 #define DMA_CH8_AL1_READ_ADDR_LSB    _u(0)
-#define DMA_CH8_AL1_READ_ADDR_ACCESS "RO"
+#define DMA_CH8_AL1_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH8_AL1_WRITE_ADDR
 // Description : Alias for channel 8 WRITE_ADDR register
@@ -3424,7 +3424,7 @@
 #define DMA_CH8_AL1_WRITE_ADDR_RESET  "-"
 #define DMA_CH8_AL1_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH8_AL1_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH8_AL1_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH8_AL1_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH8_AL1_TRANS_COUNT_TRIG
 // Description : Alias for channel 8 TRANS_COUNT register
@@ -3435,7 +3435,7 @@
 #define DMA_CH8_AL1_TRANS_COUNT_TRIG_RESET  "-"
 #define DMA_CH8_AL1_TRANS_COUNT_TRIG_MSB    _u(31)
 #define DMA_CH8_AL1_TRANS_COUNT_TRIG_LSB    _u(0)
-#define DMA_CH8_AL1_TRANS_COUNT_TRIG_ACCESS "RO"
+#define DMA_CH8_AL1_TRANS_COUNT_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH8_AL2_CTRL
 // Description : Alias for channel 8 CTRL register
@@ -3444,7 +3444,7 @@
 #define DMA_CH8_AL2_CTRL_RESET  "-"
 #define DMA_CH8_AL2_CTRL_MSB    _u(31)
 #define DMA_CH8_AL2_CTRL_LSB    _u(0)
-#define DMA_CH8_AL2_CTRL_ACCESS "RO"
+#define DMA_CH8_AL2_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH8_AL2_TRANS_COUNT
 // Description : Alias for channel 8 TRANS_COUNT register
@@ -3453,7 +3453,7 @@
 #define DMA_CH8_AL2_TRANS_COUNT_RESET  "-"
 #define DMA_CH8_AL2_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH8_AL2_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH8_AL2_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH8_AL2_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH8_AL2_READ_ADDR
 // Description : Alias for channel 8 READ_ADDR register
@@ -3462,7 +3462,7 @@
 #define DMA_CH8_AL2_READ_ADDR_RESET  "-"
 #define DMA_CH8_AL2_READ_ADDR_MSB    _u(31)
 #define DMA_CH8_AL2_READ_ADDR_LSB    _u(0)
-#define DMA_CH8_AL2_READ_ADDR_ACCESS "RO"
+#define DMA_CH8_AL2_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH8_AL2_WRITE_ADDR_TRIG
 // Description : Alias for channel 8 WRITE_ADDR register
@@ -3473,7 +3473,7 @@
 #define DMA_CH8_AL2_WRITE_ADDR_TRIG_RESET  "-"
 #define DMA_CH8_AL2_WRITE_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH8_AL2_WRITE_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH8_AL2_WRITE_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH8_AL2_WRITE_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH8_AL3_CTRL
 // Description : Alias for channel 8 CTRL register
@@ -3482,7 +3482,7 @@
 #define DMA_CH8_AL3_CTRL_RESET  "-"
 #define DMA_CH8_AL3_CTRL_MSB    _u(31)
 #define DMA_CH8_AL3_CTRL_LSB    _u(0)
-#define DMA_CH8_AL3_CTRL_ACCESS "RO"
+#define DMA_CH8_AL3_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH8_AL3_WRITE_ADDR
 // Description : Alias for channel 8 WRITE_ADDR register
@@ -3491,7 +3491,7 @@
 #define DMA_CH8_AL3_WRITE_ADDR_RESET  "-"
 #define DMA_CH8_AL3_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH8_AL3_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH8_AL3_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH8_AL3_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH8_AL3_TRANS_COUNT
 // Description : Alias for channel 8 TRANS_COUNT register
@@ -3500,7 +3500,7 @@
 #define DMA_CH8_AL3_TRANS_COUNT_RESET  "-"
 #define DMA_CH8_AL3_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH8_AL3_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH8_AL3_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH8_AL3_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH8_AL3_READ_ADDR_TRIG
 // Description : Alias for channel 8 READ_ADDR register
@@ -3511,7 +3511,7 @@
 #define DMA_CH8_AL3_READ_ADDR_TRIG_RESET  "-"
 #define DMA_CH8_AL3_READ_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH8_AL3_READ_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH8_AL3_READ_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH8_AL3_READ_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH9_READ_ADDR
 // Description : DMA Channel 9 Read Address pointer
@@ -3795,7 +3795,7 @@
 #define DMA_CH9_AL1_CTRL_RESET  "-"
 #define DMA_CH9_AL1_CTRL_MSB    _u(31)
 #define DMA_CH9_AL1_CTRL_LSB    _u(0)
-#define DMA_CH9_AL1_CTRL_ACCESS "RO"
+#define DMA_CH9_AL1_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH9_AL1_READ_ADDR
 // Description : Alias for channel 9 READ_ADDR register
@@ -3804,7 +3804,7 @@
 #define DMA_CH9_AL1_READ_ADDR_RESET  "-"
 #define DMA_CH9_AL1_READ_ADDR_MSB    _u(31)
 #define DMA_CH9_AL1_READ_ADDR_LSB    _u(0)
-#define DMA_CH9_AL1_READ_ADDR_ACCESS "RO"
+#define DMA_CH9_AL1_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH9_AL1_WRITE_ADDR
 // Description : Alias for channel 9 WRITE_ADDR register
@@ -3813,7 +3813,7 @@
 #define DMA_CH9_AL1_WRITE_ADDR_RESET  "-"
 #define DMA_CH9_AL1_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH9_AL1_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH9_AL1_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH9_AL1_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH9_AL1_TRANS_COUNT_TRIG
 // Description : Alias for channel 9 TRANS_COUNT register
@@ -3824,7 +3824,7 @@
 #define DMA_CH9_AL1_TRANS_COUNT_TRIG_RESET  "-"
 #define DMA_CH9_AL1_TRANS_COUNT_TRIG_MSB    _u(31)
 #define DMA_CH9_AL1_TRANS_COUNT_TRIG_LSB    _u(0)
-#define DMA_CH9_AL1_TRANS_COUNT_TRIG_ACCESS "RO"
+#define DMA_CH9_AL1_TRANS_COUNT_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH9_AL2_CTRL
 // Description : Alias for channel 9 CTRL register
@@ -3833,7 +3833,7 @@
 #define DMA_CH9_AL2_CTRL_RESET  "-"
 #define DMA_CH9_AL2_CTRL_MSB    _u(31)
 #define DMA_CH9_AL2_CTRL_LSB    _u(0)
-#define DMA_CH9_AL2_CTRL_ACCESS "RO"
+#define DMA_CH9_AL2_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH9_AL2_TRANS_COUNT
 // Description : Alias for channel 9 TRANS_COUNT register
@@ -3842,7 +3842,7 @@
 #define DMA_CH9_AL2_TRANS_COUNT_RESET  "-"
 #define DMA_CH9_AL2_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH9_AL2_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH9_AL2_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH9_AL2_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH9_AL2_READ_ADDR
 // Description : Alias for channel 9 READ_ADDR register
@@ -3851,7 +3851,7 @@
 #define DMA_CH9_AL2_READ_ADDR_RESET  "-"
 #define DMA_CH9_AL2_READ_ADDR_MSB    _u(31)
 #define DMA_CH9_AL2_READ_ADDR_LSB    _u(0)
-#define DMA_CH9_AL2_READ_ADDR_ACCESS "RO"
+#define DMA_CH9_AL2_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH9_AL2_WRITE_ADDR_TRIG
 // Description : Alias for channel 9 WRITE_ADDR register
@@ -3862,7 +3862,7 @@
 #define DMA_CH9_AL2_WRITE_ADDR_TRIG_RESET  "-"
 #define DMA_CH9_AL2_WRITE_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH9_AL2_WRITE_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH9_AL2_WRITE_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH9_AL2_WRITE_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH9_AL3_CTRL
 // Description : Alias for channel 9 CTRL register
@@ -3871,7 +3871,7 @@
 #define DMA_CH9_AL3_CTRL_RESET  "-"
 #define DMA_CH9_AL3_CTRL_MSB    _u(31)
 #define DMA_CH9_AL3_CTRL_LSB    _u(0)
-#define DMA_CH9_AL3_CTRL_ACCESS "RO"
+#define DMA_CH9_AL3_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH9_AL3_WRITE_ADDR
 // Description : Alias for channel 9 WRITE_ADDR register
@@ -3880,7 +3880,7 @@
 #define DMA_CH9_AL3_WRITE_ADDR_RESET  "-"
 #define DMA_CH9_AL3_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH9_AL3_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH9_AL3_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH9_AL3_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH9_AL3_TRANS_COUNT
 // Description : Alias for channel 9 TRANS_COUNT register
@@ -3889,7 +3889,7 @@
 #define DMA_CH9_AL3_TRANS_COUNT_RESET  "-"
 #define DMA_CH9_AL3_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH9_AL3_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH9_AL3_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH9_AL3_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH9_AL3_READ_ADDR_TRIG
 // Description : Alias for channel 9 READ_ADDR register
@@ -3900,7 +3900,7 @@
 #define DMA_CH9_AL3_READ_ADDR_TRIG_RESET  "-"
 #define DMA_CH9_AL3_READ_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH9_AL3_READ_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH9_AL3_READ_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH9_AL3_READ_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH10_READ_ADDR
 // Description : DMA Channel 10 Read Address pointer
@@ -4184,7 +4184,7 @@
 #define DMA_CH10_AL1_CTRL_RESET  "-"
 #define DMA_CH10_AL1_CTRL_MSB    _u(31)
 #define DMA_CH10_AL1_CTRL_LSB    _u(0)
-#define DMA_CH10_AL1_CTRL_ACCESS "RO"
+#define DMA_CH10_AL1_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH10_AL1_READ_ADDR
 // Description : Alias for channel 10 READ_ADDR register
@@ -4193,7 +4193,7 @@
 #define DMA_CH10_AL1_READ_ADDR_RESET  "-"
 #define DMA_CH10_AL1_READ_ADDR_MSB    _u(31)
 #define DMA_CH10_AL1_READ_ADDR_LSB    _u(0)
-#define DMA_CH10_AL1_READ_ADDR_ACCESS "RO"
+#define DMA_CH10_AL1_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH10_AL1_WRITE_ADDR
 // Description : Alias for channel 10 WRITE_ADDR register
@@ -4202,7 +4202,7 @@
 #define DMA_CH10_AL1_WRITE_ADDR_RESET  "-"
 #define DMA_CH10_AL1_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH10_AL1_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH10_AL1_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH10_AL1_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH10_AL1_TRANS_COUNT_TRIG
 // Description : Alias for channel 10 TRANS_COUNT register
@@ -4213,7 +4213,7 @@
 #define DMA_CH10_AL1_TRANS_COUNT_TRIG_RESET  "-"
 #define DMA_CH10_AL1_TRANS_COUNT_TRIG_MSB    _u(31)
 #define DMA_CH10_AL1_TRANS_COUNT_TRIG_LSB    _u(0)
-#define DMA_CH10_AL1_TRANS_COUNT_TRIG_ACCESS "RO"
+#define DMA_CH10_AL1_TRANS_COUNT_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH10_AL2_CTRL
 // Description : Alias for channel 10 CTRL register
@@ -4222,7 +4222,7 @@
 #define DMA_CH10_AL2_CTRL_RESET  "-"
 #define DMA_CH10_AL2_CTRL_MSB    _u(31)
 #define DMA_CH10_AL2_CTRL_LSB    _u(0)
-#define DMA_CH10_AL2_CTRL_ACCESS "RO"
+#define DMA_CH10_AL2_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH10_AL2_TRANS_COUNT
 // Description : Alias for channel 10 TRANS_COUNT register
@@ -4231,7 +4231,7 @@
 #define DMA_CH10_AL2_TRANS_COUNT_RESET  "-"
 #define DMA_CH10_AL2_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH10_AL2_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH10_AL2_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH10_AL2_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH10_AL2_READ_ADDR
 // Description : Alias for channel 10 READ_ADDR register
@@ -4240,7 +4240,7 @@
 #define DMA_CH10_AL2_READ_ADDR_RESET  "-"
 #define DMA_CH10_AL2_READ_ADDR_MSB    _u(31)
 #define DMA_CH10_AL2_READ_ADDR_LSB    _u(0)
-#define DMA_CH10_AL2_READ_ADDR_ACCESS "RO"
+#define DMA_CH10_AL2_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH10_AL2_WRITE_ADDR_TRIG
 // Description : Alias for channel 10 WRITE_ADDR register
@@ -4251,7 +4251,7 @@
 #define DMA_CH10_AL2_WRITE_ADDR_TRIG_RESET  "-"
 #define DMA_CH10_AL2_WRITE_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH10_AL2_WRITE_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH10_AL2_WRITE_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH10_AL2_WRITE_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH10_AL3_CTRL
 // Description : Alias for channel 10 CTRL register
@@ -4260,7 +4260,7 @@
 #define DMA_CH10_AL3_CTRL_RESET  "-"
 #define DMA_CH10_AL3_CTRL_MSB    _u(31)
 #define DMA_CH10_AL3_CTRL_LSB    _u(0)
-#define DMA_CH10_AL3_CTRL_ACCESS "RO"
+#define DMA_CH10_AL3_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH10_AL3_WRITE_ADDR
 // Description : Alias for channel 10 WRITE_ADDR register
@@ -4269,7 +4269,7 @@
 #define DMA_CH10_AL3_WRITE_ADDR_RESET  "-"
 #define DMA_CH10_AL3_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH10_AL3_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH10_AL3_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH10_AL3_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH10_AL3_TRANS_COUNT
 // Description : Alias for channel 10 TRANS_COUNT register
@@ -4278,7 +4278,7 @@
 #define DMA_CH10_AL3_TRANS_COUNT_RESET  "-"
 #define DMA_CH10_AL3_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH10_AL3_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH10_AL3_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH10_AL3_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH10_AL3_READ_ADDR_TRIG
 // Description : Alias for channel 10 READ_ADDR register
@@ -4289,7 +4289,7 @@
 #define DMA_CH10_AL3_READ_ADDR_TRIG_RESET  "-"
 #define DMA_CH10_AL3_READ_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH10_AL3_READ_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH10_AL3_READ_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH10_AL3_READ_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH11_READ_ADDR
 // Description : DMA Channel 11 Read Address pointer
@@ -4573,7 +4573,7 @@
 #define DMA_CH11_AL1_CTRL_RESET  "-"
 #define DMA_CH11_AL1_CTRL_MSB    _u(31)
 #define DMA_CH11_AL1_CTRL_LSB    _u(0)
-#define DMA_CH11_AL1_CTRL_ACCESS "RO"
+#define DMA_CH11_AL1_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH11_AL1_READ_ADDR
 // Description : Alias for channel 11 READ_ADDR register
@@ -4582,7 +4582,7 @@
 #define DMA_CH11_AL1_READ_ADDR_RESET  "-"
 #define DMA_CH11_AL1_READ_ADDR_MSB    _u(31)
 #define DMA_CH11_AL1_READ_ADDR_LSB    _u(0)
-#define DMA_CH11_AL1_READ_ADDR_ACCESS "RO"
+#define DMA_CH11_AL1_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH11_AL1_WRITE_ADDR
 // Description : Alias for channel 11 WRITE_ADDR register
@@ -4591,7 +4591,7 @@
 #define DMA_CH11_AL1_WRITE_ADDR_RESET  "-"
 #define DMA_CH11_AL1_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH11_AL1_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH11_AL1_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH11_AL1_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH11_AL1_TRANS_COUNT_TRIG
 // Description : Alias for channel 11 TRANS_COUNT register
@@ -4602,7 +4602,7 @@
 #define DMA_CH11_AL1_TRANS_COUNT_TRIG_RESET  "-"
 #define DMA_CH11_AL1_TRANS_COUNT_TRIG_MSB    _u(31)
 #define DMA_CH11_AL1_TRANS_COUNT_TRIG_LSB    _u(0)
-#define DMA_CH11_AL1_TRANS_COUNT_TRIG_ACCESS "RO"
+#define DMA_CH11_AL1_TRANS_COUNT_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH11_AL2_CTRL
 // Description : Alias for channel 11 CTRL register
@@ -4611,7 +4611,7 @@
 #define DMA_CH11_AL2_CTRL_RESET  "-"
 #define DMA_CH11_AL2_CTRL_MSB    _u(31)
 #define DMA_CH11_AL2_CTRL_LSB    _u(0)
-#define DMA_CH11_AL2_CTRL_ACCESS "RO"
+#define DMA_CH11_AL2_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH11_AL2_TRANS_COUNT
 // Description : Alias for channel 11 TRANS_COUNT register
@@ -4620,7 +4620,7 @@
 #define DMA_CH11_AL2_TRANS_COUNT_RESET  "-"
 #define DMA_CH11_AL2_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH11_AL2_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH11_AL2_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH11_AL2_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH11_AL2_READ_ADDR
 // Description : Alias for channel 11 READ_ADDR register
@@ -4629,7 +4629,7 @@
 #define DMA_CH11_AL2_READ_ADDR_RESET  "-"
 #define DMA_CH11_AL2_READ_ADDR_MSB    _u(31)
 #define DMA_CH11_AL2_READ_ADDR_LSB    _u(0)
-#define DMA_CH11_AL2_READ_ADDR_ACCESS "RO"
+#define DMA_CH11_AL2_READ_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH11_AL2_WRITE_ADDR_TRIG
 // Description : Alias for channel 11 WRITE_ADDR register
@@ -4640,7 +4640,7 @@
 #define DMA_CH11_AL2_WRITE_ADDR_TRIG_RESET  "-"
 #define DMA_CH11_AL2_WRITE_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH11_AL2_WRITE_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH11_AL2_WRITE_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH11_AL2_WRITE_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH11_AL3_CTRL
 // Description : Alias for channel 11 CTRL register
@@ -4649,7 +4649,7 @@
 #define DMA_CH11_AL3_CTRL_RESET  "-"
 #define DMA_CH11_AL3_CTRL_MSB    _u(31)
 #define DMA_CH11_AL3_CTRL_LSB    _u(0)
-#define DMA_CH11_AL3_CTRL_ACCESS "RO"
+#define DMA_CH11_AL3_CTRL_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH11_AL3_WRITE_ADDR
 // Description : Alias for channel 11 WRITE_ADDR register
@@ -4658,7 +4658,7 @@
 #define DMA_CH11_AL3_WRITE_ADDR_RESET  "-"
 #define DMA_CH11_AL3_WRITE_ADDR_MSB    _u(31)
 #define DMA_CH11_AL3_WRITE_ADDR_LSB    _u(0)
-#define DMA_CH11_AL3_WRITE_ADDR_ACCESS "RO"
+#define DMA_CH11_AL3_WRITE_ADDR_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH11_AL3_TRANS_COUNT
 // Description : Alias for channel 11 TRANS_COUNT register
@@ -4667,7 +4667,7 @@
 #define DMA_CH11_AL3_TRANS_COUNT_RESET  "-"
 #define DMA_CH11_AL3_TRANS_COUNT_MSB    _u(31)
 #define DMA_CH11_AL3_TRANS_COUNT_LSB    _u(0)
-#define DMA_CH11_AL3_TRANS_COUNT_ACCESS "RO"
+#define DMA_CH11_AL3_TRANS_COUNT_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_CH11_AL3_READ_ADDR_TRIG
 // Description : Alias for channel 11 READ_ADDR register
@@ -4678,7 +4678,7 @@
 #define DMA_CH11_AL3_READ_ADDR_TRIG_RESET  "-"
 #define DMA_CH11_AL3_READ_ADDR_TRIG_MSB    _u(31)
 #define DMA_CH11_AL3_READ_ADDR_TRIG_LSB    _u(0)
-#define DMA_CH11_AL3_READ_ADDR_TRIG_ACCESS "RO"
+#define DMA_CH11_AL3_READ_ADDR_TRIG_ACCESS "RW"
 // =============================================================================
 // Register    : DMA_INTR
 // Description : Interrupt Status (raw)
@@ -5056,7 +5056,7 @@
 #define DMA_CH0_DBG_CTDREQ_RESET  _u(0x00000000)
 #define DMA_CH0_DBG_CTDREQ_MSB    _u(5)
 #define DMA_CH0_DBG_CTDREQ_LSB    _u(0)
-#define DMA_CH0_DBG_CTDREQ_ACCESS "RO"
+#define DMA_CH0_DBG_CTDREQ_ACCESS "WC"
 // =============================================================================
 // Register    : DMA_CH0_DBG_TCR
 // Description : Read to get channel TRANS_COUNT reload value, i.e. the length
@@ -5078,7 +5078,7 @@
 #define DMA_CH1_DBG_CTDREQ_RESET  _u(0x00000000)
 #define DMA_CH1_DBG_CTDREQ_MSB    _u(5)
 #define DMA_CH1_DBG_CTDREQ_LSB    _u(0)
-#define DMA_CH1_DBG_CTDREQ_ACCESS "RO"
+#define DMA_CH1_DBG_CTDREQ_ACCESS "WC"
 // =============================================================================
 // Register    : DMA_CH1_DBG_TCR
 // Description : Read to get channel TRANS_COUNT reload value, i.e. the length
@@ -5100,7 +5100,7 @@
 #define DMA_CH2_DBG_CTDREQ_RESET  _u(0x00000000)
 #define DMA_CH2_DBG_CTDREQ_MSB    _u(5)
 #define DMA_CH2_DBG_CTDREQ_LSB    _u(0)
-#define DMA_CH2_DBG_CTDREQ_ACCESS "RO"
+#define DMA_CH2_DBG_CTDREQ_ACCESS "WC"
 // =============================================================================
 // Register    : DMA_CH2_DBG_TCR
 // Description : Read to get channel TRANS_COUNT reload value, i.e. the length
@@ -5122,7 +5122,7 @@
 #define DMA_CH3_DBG_CTDREQ_RESET  _u(0x00000000)
 #define DMA_CH3_DBG_CTDREQ_MSB    _u(5)
 #define DMA_CH3_DBG_CTDREQ_LSB    _u(0)
-#define DMA_CH3_DBG_CTDREQ_ACCESS "RO"
+#define DMA_CH3_DBG_CTDREQ_ACCESS "WC"
 // =============================================================================
 // Register    : DMA_CH3_DBG_TCR
 // Description : Read to get channel TRANS_COUNT reload value, i.e. the length
@@ -5144,7 +5144,7 @@
 #define DMA_CH4_DBG_CTDREQ_RESET  _u(0x00000000)
 #define DMA_CH4_DBG_CTDREQ_MSB    _u(5)
 #define DMA_CH4_DBG_CTDREQ_LSB    _u(0)
-#define DMA_CH4_DBG_CTDREQ_ACCESS "RO"
+#define DMA_CH4_DBG_CTDREQ_ACCESS "WC"
 // =============================================================================
 // Register    : DMA_CH4_DBG_TCR
 // Description : Read to get channel TRANS_COUNT reload value, i.e. the length
@@ -5166,7 +5166,7 @@
 #define DMA_CH5_DBG_CTDREQ_RESET  _u(0x00000000)
 #define DMA_CH5_DBG_CTDREQ_MSB    _u(5)
 #define DMA_CH5_DBG_CTDREQ_LSB    _u(0)
-#define DMA_CH5_DBG_CTDREQ_ACCESS "RO"
+#define DMA_CH5_DBG_CTDREQ_ACCESS "WC"
 // =============================================================================
 // Register    : DMA_CH5_DBG_TCR
 // Description : Read to get channel TRANS_COUNT reload value, i.e. the length
@@ -5188,7 +5188,7 @@
 #define DMA_CH6_DBG_CTDREQ_RESET  _u(0x00000000)
 #define DMA_CH6_DBG_CTDREQ_MSB    _u(5)
 #define DMA_CH6_DBG_CTDREQ_LSB    _u(0)
-#define DMA_CH6_DBG_CTDREQ_ACCESS "RO"
+#define DMA_CH6_DBG_CTDREQ_ACCESS "WC"
 // =============================================================================
 // Register    : DMA_CH6_DBG_TCR
 // Description : Read to get channel TRANS_COUNT reload value, i.e. the length
@@ -5210,7 +5210,7 @@
 #define DMA_CH7_DBG_CTDREQ_RESET  _u(0x00000000)
 #define DMA_CH7_DBG_CTDREQ_MSB    _u(5)
 #define DMA_CH7_DBG_CTDREQ_LSB    _u(0)
-#define DMA_CH7_DBG_CTDREQ_ACCESS "RO"
+#define DMA_CH7_DBG_CTDREQ_ACCESS "WC"
 // =============================================================================
 // Register    : DMA_CH7_DBG_TCR
 // Description : Read to get channel TRANS_COUNT reload value, i.e. the length
@@ -5232,7 +5232,7 @@
 #define DMA_CH8_DBG_CTDREQ_RESET  _u(0x00000000)
 #define DMA_CH8_DBG_CTDREQ_MSB    _u(5)
 #define DMA_CH8_DBG_CTDREQ_LSB    _u(0)
-#define DMA_CH8_DBG_CTDREQ_ACCESS "RO"
+#define DMA_CH8_DBG_CTDREQ_ACCESS "WC"
 // =============================================================================
 // Register    : DMA_CH8_DBG_TCR
 // Description : Read to get channel TRANS_COUNT reload value, i.e. the length
@@ -5254,7 +5254,7 @@
 #define DMA_CH9_DBG_CTDREQ_RESET  _u(0x00000000)
 #define DMA_CH9_DBG_CTDREQ_MSB    _u(5)
 #define DMA_CH9_DBG_CTDREQ_LSB    _u(0)
-#define DMA_CH9_DBG_CTDREQ_ACCESS "RO"
+#define DMA_CH9_DBG_CTDREQ_ACCESS "WC"
 // =============================================================================
 // Register    : DMA_CH9_DBG_TCR
 // Description : Read to get channel TRANS_COUNT reload value, i.e. the length
@@ -5276,7 +5276,7 @@
 #define DMA_CH10_DBG_CTDREQ_RESET  _u(0x00000000)
 #define DMA_CH10_DBG_CTDREQ_MSB    _u(5)
 #define DMA_CH10_DBG_CTDREQ_LSB    _u(0)
-#define DMA_CH10_DBG_CTDREQ_ACCESS "RO"
+#define DMA_CH10_DBG_CTDREQ_ACCESS "WC"
 // =============================================================================
 // Register    : DMA_CH10_DBG_TCR
 // Description : Read to get channel TRANS_COUNT reload value, i.e. the length
@@ -5298,7 +5298,7 @@
 #define DMA_CH11_DBG_CTDREQ_RESET  _u(0x00000000)
 #define DMA_CH11_DBG_CTDREQ_MSB    _u(5)
 #define DMA_CH11_DBG_CTDREQ_LSB    _u(0)
-#define DMA_CH11_DBG_CTDREQ_ACCESS "RO"
+#define DMA_CH11_DBG_CTDREQ_ACCESS "WC"
 // =============================================================================
 // Register    : DMA_CH11_DBG_TCR
 // Description : Read to get channel TRANS_COUNT reload value, i.e. the length
diff --git a/src/rp2040/hardware_regs/include/hardware/regs/i2c.h b/src/rp2040/hardware_regs/include/hardware/regs/i2c.h
index 9384bed..dcddb06 100644
--- a/src/rp2040/hardware_regs/include/hardware/regs/i2c.h
+++ b/src/rp2040/hardware_regs/include/hardware/regs/i2c.h
@@ -8,6 +8,80 @@
 // Version        : 1
 // Bus type       : apb
 // Description    : DW_apb_i2c address block
+//
+//                  List of configuration constants for the Synopsys I2C
+//                  hardware (you may see references to these in I2C register
+//                  header; these are *fixed* values, set at hardware design
+//                  time):
+//
+//                  IC_ULTRA_FAST_MODE ................ 0x0
+//                  IC_UFM_TBUF_CNT_DEFAULT ........... 0x8
+//                  IC_UFM_SCL_LOW_COUNT .............. 0x0008
+//                  IC_UFM_SCL_HIGH_COUNT ............. 0x0006
+//                  IC_TX_TL .......................... 0x0
+//                  IC_TX_CMD_BLOCK ................... 0x1
+//                  IC_HAS_DMA ........................ 0x1
+//                  IC_HAS_ASYNC_FIFO ................. 0x0
+//                  IC_SMBUS_ARP ...................... 0x0
+//                  IC_FIRST_DATA_BYTE_STATUS ......... 0x1
+//                  IC_INTR_IO ........................ 0x1
+//                  IC_MASTER_MODE .................... 0x1
+//                  IC_DEFAULT_ACK_GENERAL_CALL ....... 0x1
+//                  IC_INTR_POL ....................... 0x1
+//                  IC_OPTIONAL_SAR ................... 0x0
+//                  IC_DEFAULT_TAR_SLAVE_ADDR ......... 0x055
+//                  IC_DEFAULT_SLAVE_ADDR ............. 0x055
+//                  IC_DEFAULT_HS_SPKLEN .............. 0x1
+//                  IC_FS_SCL_HIGH_COUNT .............. 0x0006
+//                  IC_HS_SCL_LOW_COUNT ............... 0x0008
+//                  IC_DEVICE_ID_VALUE ................ 0x0
+//                  IC_10BITADDR_MASTER ............... 0x0
+//                  IC_CLK_FREQ_OPTIMIZATION .......... 0x0
+//                  IC_DEFAULT_FS_SPKLEN .............. 0x7
+//                  IC_ADD_ENCODED_PARAMS ............. 0x0
+//                  IC_DEFAULT_SDA_HOLD ............... 0x000001
+//                  IC_DEFAULT_SDA_SETUP .............. 0x64
+//                  IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT . 0x0
+//                  IC_CLOCK_PERIOD ................... 100
+//                  IC_EMPTYFIFO_HOLD_MASTER_EN ....... 1
+//                  IC_RESTART_EN ..................... 0x1
+//                  IC_TX_CMD_BLOCK_DEFAULT ........... 0x0
+//                  IC_BUS_CLEAR_FEATURE .............. 0x0
+//                  IC_CAP_LOADING .................... 100
+//                  IC_FS_SCL_LOW_COUNT ............... 0x000d
+//                  APB_DATA_WIDTH .................... 32
+//                  IC_SDA_STUCK_TIMEOUT_DEFAULT ...... 0xffffffff
+//                  IC_SLV_DATA_NACK_ONLY ............. 0x1
+//                  IC_10BITADDR_SLAVE ................ 0x0
+//                  IC_CLK_TYPE ....................... 0x0
+//                  IC_SMBUS_UDID_MSB ................. 0x0
+//                  IC_SMBUS_SUSPEND_ALERT ............ 0x0
+//                  IC_HS_SCL_HIGH_COUNT .............. 0x0006
+//                  IC_SLV_RESTART_DET_EN ............. 0x1
+//                  IC_SMBUS .......................... 0x0
+//                  IC_OPTIONAL_SAR_DEFAULT ........... 0x0
+//                  IC_PERSISTANT_SLV_ADDR_DEFAULT .... 0x0
+//                  IC_USE_COUNTS ..................... 0x0
+//                  IC_RX_BUFFER_DEPTH ................ 16
+//                  IC_SCL_STUCK_TIMEOUT_DEFAULT ...... 0xffffffff
+//                  IC_RX_FULL_HLD_BUS_EN ............. 0x1
+//                  IC_SLAVE_DISABLE .................. 0x1
+//                  IC_RX_TL .......................... 0x0
+//                  IC_DEVICE_ID ...................... 0x0
+//                  IC_HC_COUNT_VALUES ................ 0x0
+//                  I2C_DYNAMIC_TAR_UPDATE ............ 0
+//                  IC_SMBUS_CLK_LOW_MEXT_DEFAULT ..... 0xffffffff
+//                  IC_SMBUS_CLK_LOW_SEXT_DEFAULT ..... 0xffffffff
+//                  IC_HS_MASTER_CODE ................. 0x1
+//                  IC_SMBUS_RST_IDLE_CNT_DEFAULT ..... 0xffff
+//                  IC_SMBUS_UDID_LSB_DEFAULT ......... 0xffffffff
+//                  IC_SS_SCL_HIGH_COUNT .............. 0x0028
+//                  IC_SS_SCL_LOW_COUNT ............... 0x002f
+//                  IC_MAX_SPEED_MODE ................. 0x2
+//                  IC_STAT_FOR_CLK_STRETCH ........... 0x0
+//                  IC_STOP_DET_IF_MASTER_ACTIVE ...... 0x0
+//                  IC_DEFAULT_UFM_SPKLEN ............. 0x1
+//                  IC_TX_BUFFER_DEPTH ................ 16
 // =============================================================================
 #ifndef HARDWARE_REGS_I2C_DEFINED
 #define HARDWARE_REGS_I2C_DEFINED
diff --git a/src/rp2040/hardware_regs/include/hardware/regs/pio.h b/src/rp2040/hardware_regs/include/hardware/regs/pio.h
index 8b4829f..b231882 100644
--- a/src/rp2040/hardware_regs/include/hardware/regs/pio.h
+++ b/src/rp2040/hardware_regs/include/hardware/regs/pio.h
@@ -378,7 +378,8 @@
 // =============================================================================
 // Register    : PIO_DBG_PADOUT
 // Description : Read to sample the pad output values PIO is currently driving
-//               to the GPIOs.
+//               to the GPIOs. On RP2040 there are 30 GPIOs, so the two most
+//               significant bits are hardwired to 0.
 #define PIO_DBG_PADOUT_OFFSET _u(0x0000003c)
 #define PIO_DBG_PADOUT_BITS   _u(0xffffffff)
 #define PIO_DBG_PADOUT_RESET  _u(0x00000000)
@@ -388,7 +389,8 @@
 // =============================================================================
 // Register    : PIO_DBG_PADOE
 // Description : Read to sample the pad output enables (direction) PIO is
-//               currently driving to the GPIOs.
+//               currently driving to the GPIOs. On RP2040 there are 30 GPIOs,
+//               so the two most significant bits are hardwired to 0.
 #define PIO_DBG_PADOE_OFFSET _u(0x00000040)
 #define PIO_DBG_PADOE_BITS   _u(0xffffffff)
 #define PIO_DBG_PADOE_RESET  _u(0x00000000)
diff --git a/src/rp2040/hardware_regs/include/hardware/regs/sio.h b/src/rp2040/hardware_regs/include/hardware/regs/sio.h
index 37ee2c1..f641533 100644
--- a/src/rp2040/hardware_regs/include/hardware/regs/sio.h
+++ b/src/rp2040/hardware_regs/include/hardware/regs/sio.h
@@ -71,7 +71,7 @@
 #define SIO_GPIO_OUT_SET_RESET  _u(0x00000000)
 #define SIO_GPIO_OUT_SET_MSB    _u(29)
 #define SIO_GPIO_OUT_SET_LSB    _u(0)
-#define SIO_GPIO_OUT_SET_ACCESS "RW"
+#define SIO_GPIO_OUT_SET_ACCESS "WO"
 // =============================================================================
 // Register    : SIO_GPIO_OUT_CLR
 // Description : GPIO output value clear
@@ -82,7 +82,7 @@
 #define SIO_GPIO_OUT_CLR_RESET  _u(0x00000000)
 #define SIO_GPIO_OUT_CLR_MSB    _u(29)
 #define SIO_GPIO_OUT_CLR_LSB    _u(0)
-#define SIO_GPIO_OUT_CLR_ACCESS "RW"
+#define SIO_GPIO_OUT_CLR_ACCESS "WO"
 // =============================================================================
 // Register    : SIO_GPIO_OUT_XOR
 // Description : GPIO output value XOR
@@ -93,7 +93,7 @@
 #define SIO_GPIO_OUT_XOR_RESET  _u(0x00000000)
 #define SIO_GPIO_OUT_XOR_MSB    _u(29)
 #define SIO_GPIO_OUT_XOR_LSB    _u(0)
-#define SIO_GPIO_OUT_XOR_ACCESS "RW"
+#define SIO_GPIO_OUT_XOR_ACCESS "WO"
 // =============================================================================
 // Register    : SIO_GPIO_OE
 // Description : GPIO output enable
@@ -119,7 +119,7 @@
 #define SIO_GPIO_OE_SET_RESET  _u(0x00000000)
 #define SIO_GPIO_OE_SET_MSB    _u(29)
 #define SIO_GPIO_OE_SET_LSB    _u(0)
-#define SIO_GPIO_OE_SET_ACCESS "RW"
+#define SIO_GPIO_OE_SET_ACCESS "WO"
 // =============================================================================
 // Register    : SIO_GPIO_OE_CLR
 // Description : GPIO output enable clear
@@ -130,7 +130,7 @@
 #define SIO_GPIO_OE_CLR_RESET  _u(0x00000000)
 #define SIO_GPIO_OE_CLR_MSB    _u(29)
 #define SIO_GPIO_OE_CLR_LSB    _u(0)
-#define SIO_GPIO_OE_CLR_ACCESS "RW"
+#define SIO_GPIO_OE_CLR_ACCESS "WO"
 // =============================================================================
 // Register    : SIO_GPIO_OE_XOR
 // Description : GPIO output enable XOR
@@ -141,7 +141,7 @@
 #define SIO_GPIO_OE_XOR_RESET  _u(0x00000000)
 #define SIO_GPIO_OE_XOR_MSB    _u(29)
 #define SIO_GPIO_OE_XOR_LSB    _u(0)
-#define SIO_GPIO_OE_XOR_ACCESS "RW"
+#define SIO_GPIO_OE_XOR_ACCESS "WO"
 // =============================================================================
 // Register    : SIO_GPIO_HI_OUT
 // Description : QSPI output value
@@ -169,7 +169,7 @@
 #define SIO_GPIO_HI_OUT_SET_RESET  _u(0x00000000)
 #define SIO_GPIO_HI_OUT_SET_MSB    _u(5)
 #define SIO_GPIO_HI_OUT_SET_LSB    _u(0)
-#define SIO_GPIO_HI_OUT_SET_ACCESS "RW"
+#define SIO_GPIO_HI_OUT_SET_ACCESS "WO"
 // =============================================================================
 // Register    : SIO_GPIO_HI_OUT_CLR
 // Description : QSPI output value clear
@@ -180,7 +180,7 @@
 #define SIO_GPIO_HI_OUT_CLR_RESET  _u(0x00000000)
 #define SIO_GPIO_HI_OUT_CLR_MSB    _u(5)
 #define SIO_GPIO_HI_OUT_CLR_LSB    _u(0)
-#define SIO_GPIO_HI_OUT_CLR_ACCESS "RW"
+#define SIO_GPIO_HI_OUT_CLR_ACCESS "WO"
 // =============================================================================
 // Register    : SIO_GPIO_HI_OUT_XOR
 // Description : QSPI output value XOR
@@ -191,7 +191,7 @@
 #define SIO_GPIO_HI_OUT_XOR_RESET  _u(0x00000000)
 #define SIO_GPIO_HI_OUT_XOR_MSB    _u(5)
 #define SIO_GPIO_HI_OUT_XOR_LSB    _u(0)
-#define SIO_GPIO_HI_OUT_XOR_ACCESS "RW"
+#define SIO_GPIO_HI_OUT_XOR_ACCESS "WO"
 // =============================================================================
 // Register    : SIO_GPIO_HI_OE
 // Description : QSPI output enable
@@ -218,7 +218,7 @@
 #define SIO_GPIO_HI_OE_SET_RESET  _u(0x00000000)
 #define SIO_GPIO_HI_OE_SET_MSB    _u(5)
 #define SIO_GPIO_HI_OE_SET_LSB    _u(0)
-#define SIO_GPIO_HI_OE_SET_ACCESS "RW"
+#define SIO_GPIO_HI_OE_SET_ACCESS "WO"
 // =============================================================================
 // Register    : SIO_GPIO_HI_OE_CLR
 // Description : QSPI output enable clear
@@ -229,7 +229,7 @@
 #define SIO_GPIO_HI_OE_CLR_RESET  _u(0x00000000)
 #define SIO_GPIO_HI_OE_CLR_MSB    _u(5)
 #define SIO_GPIO_HI_OE_CLR_LSB    _u(0)
-#define SIO_GPIO_HI_OE_CLR_ACCESS "RW"
+#define SIO_GPIO_HI_OE_CLR_ACCESS "WO"
 // =============================================================================
 // Register    : SIO_GPIO_HI_OE_XOR
 // Description : QSPI output enable XOR
@@ -240,7 +240,7 @@
 #define SIO_GPIO_HI_OE_XOR_RESET  _u(0x00000000)
 #define SIO_GPIO_HI_OE_XOR_MSB    _u(5)
 #define SIO_GPIO_HI_OE_XOR_LSB    _u(0)
-#define SIO_GPIO_HI_OE_XOR_ACCESS "RW"
+#define SIO_GPIO_HI_OE_XOR_ACCESS "WO"
 // =============================================================================
 // Register    : SIO_FIFO_ST
 // Description : Status register for inter-core FIFOs (mailboxes).
@@ -1155,7 +1155,7 @@
 #define SIO_SPINLOCK0_RESET  _u(0x00000000)
 #define SIO_SPINLOCK0_MSB    _u(31)
 #define SIO_SPINLOCK0_LSB    _u(0)
-#define SIO_SPINLOCK0_ACCESS "RO"
+#define SIO_SPINLOCK0_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK1
 // Description : Reading from a spinlock address will:
@@ -1171,7 +1171,7 @@
 #define SIO_SPINLOCK1_RESET  _u(0x00000000)
 #define SIO_SPINLOCK1_MSB    _u(31)
 #define SIO_SPINLOCK1_LSB    _u(0)
-#define SIO_SPINLOCK1_ACCESS "RO"
+#define SIO_SPINLOCK1_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK2
 // Description : Reading from a spinlock address will:
@@ -1187,7 +1187,7 @@
 #define SIO_SPINLOCK2_RESET  _u(0x00000000)
 #define SIO_SPINLOCK2_MSB    _u(31)
 #define SIO_SPINLOCK2_LSB    _u(0)
-#define SIO_SPINLOCK2_ACCESS "RO"
+#define SIO_SPINLOCK2_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK3
 // Description : Reading from a spinlock address will:
@@ -1203,7 +1203,7 @@
 #define SIO_SPINLOCK3_RESET  _u(0x00000000)
 #define SIO_SPINLOCK3_MSB    _u(31)
 #define SIO_SPINLOCK3_LSB    _u(0)
-#define SIO_SPINLOCK3_ACCESS "RO"
+#define SIO_SPINLOCK3_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK4
 // Description : Reading from a spinlock address will:
@@ -1219,7 +1219,7 @@
 #define SIO_SPINLOCK4_RESET  _u(0x00000000)
 #define SIO_SPINLOCK4_MSB    _u(31)
 #define SIO_SPINLOCK4_LSB    _u(0)
-#define SIO_SPINLOCK4_ACCESS "RO"
+#define SIO_SPINLOCK4_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK5
 // Description : Reading from a spinlock address will:
@@ -1235,7 +1235,7 @@
 #define SIO_SPINLOCK5_RESET  _u(0x00000000)
 #define SIO_SPINLOCK5_MSB    _u(31)
 #define SIO_SPINLOCK5_LSB    _u(0)
-#define SIO_SPINLOCK5_ACCESS "RO"
+#define SIO_SPINLOCK5_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK6
 // Description : Reading from a spinlock address will:
@@ -1251,7 +1251,7 @@
 #define SIO_SPINLOCK6_RESET  _u(0x00000000)
 #define SIO_SPINLOCK6_MSB    _u(31)
 #define SIO_SPINLOCK6_LSB    _u(0)
-#define SIO_SPINLOCK6_ACCESS "RO"
+#define SIO_SPINLOCK6_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK7
 // Description : Reading from a spinlock address will:
@@ -1267,7 +1267,7 @@
 #define SIO_SPINLOCK7_RESET  _u(0x00000000)
 #define SIO_SPINLOCK7_MSB    _u(31)
 #define SIO_SPINLOCK7_LSB    _u(0)
-#define SIO_SPINLOCK7_ACCESS "RO"
+#define SIO_SPINLOCK7_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK8
 // Description : Reading from a spinlock address will:
@@ -1283,7 +1283,7 @@
 #define SIO_SPINLOCK8_RESET  _u(0x00000000)
 #define SIO_SPINLOCK8_MSB    _u(31)
 #define SIO_SPINLOCK8_LSB    _u(0)
-#define SIO_SPINLOCK8_ACCESS "RO"
+#define SIO_SPINLOCK8_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK9
 // Description : Reading from a spinlock address will:
@@ -1299,7 +1299,7 @@
 #define SIO_SPINLOCK9_RESET  _u(0x00000000)
 #define SIO_SPINLOCK9_MSB    _u(31)
 #define SIO_SPINLOCK9_LSB    _u(0)
-#define SIO_SPINLOCK9_ACCESS "RO"
+#define SIO_SPINLOCK9_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK10
 // Description : Reading from a spinlock address will:
@@ -1315,7 +1315,7 @@
 #define SIO_SPINLOCK10_RESET  _u(0x00000000)
 #define SIO_SPINLOCK10_MSB    _u(31)
 #define SIO_SPINLOCK10_LSB    _u(0)
-#define SIO_SPINLOCK10_ACCESS "RO"
+#define SIO_SPINLOCK10_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK11
 // Description : Reading from a spinlock address will:
@@ -1331,7 +1331,7 @@
 #define SIO_SPINLOCK11_RESET  _u(0x00000000)
 #define SIO_SPINLOCK11_MSB    _u(31)
 #define SIO_SPINLOCK11_LSB    _u(0)
-#define SIO_SPINLOCK11_ACCESS "RO"
+#define SIO_SPINLOCK11_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK12
 // Description : Reading from a spinlock address will:
@@ -1347,7 +1347,7 @@
 #define SIO_SPINLOCK12_RESET  _u(0x00000000)
 #define SIO_SPINLOCK12_MSB    _u(31)
 #define SIO_SPINLOCK12_LSB    _u(0)
-#define SIO_SPINLOCK12_ACCESS "RO"
+#define SIO_SPINLOCK12_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK13
 // Description : Reading from a spinlock address will:
@@ -1363,7 +1363,7 @@
 #define SIO_SPINLOCK13_RESET  _u(0x00000000)
 #define SIO_SPINLOCK13_MSB    _u(31)
 #define SIO_SPINLOCK13_LSB    _u(0)
-#define SIO_SPINLOCK13_ACCESS "RO"
+#define SIO_SPINLOCK13_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK14
 // Description : Reading from a spinlock address will:
@@ -1379,7 +1379,7 @@
 #define SIO_SPINLOCK14_RESET  _u(0x00000000)
 #define SIO_SPINLOCK14_MSB    _u(31)
 #define SIO_SPINLOCK14_LSB    _u(0)
-#define SIO_SPINLOCK14_ACCESS "RO"
+#define SIO_SPINLOCK14_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK15
 // Description : Reading from a spinlock address will:
@@ -1395,7 +1395,7 @@
 #define SIO_SPINLOCK15_RESET  _u(0x00000000)
 #define SIO_SPINLOCK15_MSB    _u(31)
 #define SIO_SPINLOCK15_LSB    _u(0)
-#define SIO_SPINLOCK15_ACCESS "RO"
+#define SIO_SPINLOCK15_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK16
 // Description : Reading from a spinlock address will:
@@ -1411,7 +1411,7 @@
 #define SIO_SPINLOCK16_RESET  _u(0x00000000)
 #define SIO_SPINLOCK16_MSB    _u(31)
 #define SIO_SPINLOCK16_LSB    _u(0)
-#define SIO_SPINLOCK16_ACCESS "RO"
+#define SIO_SPINLOCK16_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK17
 // Description : Reading from a spinlock address will:
@@ -1427,7 +1427,7 @@
 #define SIO_SPINLOCK17_RESET  _u(0x00000000)
 #define SIO_SPINLOCK17_MSB    _u(31)
 #define SIO_SPINLOCK17_LSB    _u(0)
-#define SIO_SPINLOCK17_ACCESS "RO"
+#define SIO_SPINLOCK17_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK18
 // Description : Reading from a spinlock address will:
@@ -1443,7 +1443,7 @@
 #define SIO_SPINLOCK18_RESET  _u(0x00000000)
 #define SIO_SPINLOCK18_MSB    _u(31)
 #define SIO_SPINLOCK18_LSB    _u(0)
-#define SIO_SPINLOCK18_ACCESS "RO"
+#define SIO_SPINLOCK18_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK19
 // Description : Reading from a spinlock address will:
@@ -1459,7 +1459,7 @@
 #define SIO_SPINLOCK19_RESET  _u(0x00000000)
 #define SIO_SPINLOCK19_MSB    _u(31)
 #define SIO_SPINLOCK19_LSB    _u(0)
-#define SIO_SPINLOCK19_ACCESS "RO"
+#define SIO_SPINLOCK19_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK20
 // Description : Reading from a spinlock address will:
@@ -1475,7 +1475,7 @@
 #define SIO_SPINLOCK20_RESET  _u(0x00000000)
 #define SIO_SPINLOCK20_MSB    _u(31)
 #define SIO_SPINLOCK20_LSB    _u(0)
-#define SIO_SPINLOCK20_ACCESS "RO"
+#define SIO_SPINLOCK20_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK21
 // Description : Reading from a spinlock address will:
@@ -1491,7 +1491,7 @@
 #define SIO_SPINLOCK21_RESET  _u(0x00000000)
 #define SIO_SPINLOCK21_MSB    _u(31)
 #define SIO_SPINLOCK21_LSB    _u(0)
-#define SIO_SPINLOCK21_ACCESS "RO"
+#define SIO_SPINLOCK21_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK22
 // Description : Reading from a spinlock address will:
@@ -1507,7 +1507,7 @@
 #define SIO_SPINLOCK22_RESET  _u(0x00000000)
 #define SIO_SPINLOCK22_MSB    _u(31)
 #define SIO_SPINLOCK22_LSB    _u(0)
-#define SIO_SPINLOCK22_ACCESS "RO"
+#define SIO_SPINLOCK22_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK23
 // Description : Reading from a spinlock address will:
@@ -1523,7 +1523,7 @@
 #define SIO_SPINLOCK23_RESET  _u(0x00000000)
 #define SIO_SPINLOCK23_MSB    _u(31)
 #define SIO_SPINLOCK23_LSB    _u(0)
-#define SIO_SPINLOCK23_ACCESS "RO"
+#define SIO_SPINLOCK23_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK24
 // Description : Reading from a spinlock address will:
@@ -1539,7 +1539,7 @@
 #define SIO_SPINLOCK24_RESET  _u(0x00000000)
 #define SIO_SPINLOCK24_MSB    _u(31)
 #define SIO_SPINLOCK24_LSB    _u(0)
-#define SIO_SPINLOCK24_ACCESS "RO"
+#define SIO_SPINLOCK24_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK25
 // Description : Reading from a spinlock address will:
@@ -1555,7 +1555,7 @@
 #define SIO_SPINLOCK25_RESET  _u(0x00000000)
 #define SIO_SPINLOCK25_MSB    _u(31)
 #define SIO_SPINLOCK25_LSB    _u(0)
-#define SIO_SPINLOCK25_ACCESS "RO"
+#define SIO_SPINLOCK25_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK26
 // Description : Reading from a spinlock address will:
@@ -1571,7 +1571,7 @@
 #define SIO_SPINLOCK26_RESET  _u(0x00000000)
 #define SIO_SPINLOCK26_MSB    _u(31)
 #define SIO_SPINLOCK26_LSB    _u(0)
-#define SIO_SPINLOCK26_ACCESS "RO"
+#define SIO_SPINLOCK26_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK27
 // Description : Reading from a spinlock address will:
@@ -1587,7 +1587,7 @@
 #define SIO_SPINLOCK27_RESET  _u(0x00000000)
 #define SIO_SPINLOCK27_MSB    _u(31)
 #define SIO_SPINLOCK27_LSB    _u(0)
-#define SIO_SPINLOCK27_ACCESS "RO"
+#define SIO_SPINLOCK27_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK28
 // Description : Reading from a spinlock address will:
@@ -1603,7 +1603,7 @@
 #define SIO_SPINLOCK28_RESET  _u(0x00000000)
 #define SIO_SPINLOCK28_MSB    _u(31)
 #define SIO_SPINLOCK28_LSB    _u(0)
-#define SIO_SPINLOCK28_ACCESS "RO"
+#define SIO_SPINLOCK28_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK29
 // Description : Reading from a spinlock address will:
@@ -1619,7 +1619,7 @@
 #define SIO_SPINLOCK29_RESET  _u(0x00000000)
 #define SIO_SPINLOCK29_MSB    _u(31)
 #define SIO_SPINLOCK29_LSB    _u(0)
-#define SIO_SPINLOCK29_ACCESS "RO"
+#define SIO_SPINLOCK29_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK30
 // Description : Reading from a spinlock address will:
@@ -1635,7 +1635,7 @@
 #define SIO_SPINLOCK30_RESET  _u(0x00000000)
 #define SIO_SPINLOCK30_MSB    _u(31)
 #define SIO_SPINLOCK30_LSB    _u(0)
-#define SIO_SPINLOCK30_ACCESS "RO"
+#define SIO_SPINLOCK30_ACCESS "RW"
 // =============================================================================
 // Register    : SIO_SPINLOCK31
 // Description : Reading from a spinlock address will:
@@ -1651,6 +1651,6 @@
 #define SIO_SPINLOCK31_RESET  _u(0x00000000)
 #define SIO_SPINLOCK31_MSB    _u(31)
 #define SIO_SPINLOCK31_LSB    _u(0)
-#define SIO_SPINLOCK31_ACCESS "RO"
+#define SIO_SPINLOCK31_ACCESS "RW"
 // =============================================================================
 #endif // HARDWARE_REGS_SIO_DEFINED
diff --git a/src/rp2040/hardware_regs/include/hardware/regs/usb.h b/src/rp2040/hardware_regs/include/hardware/regs/usb.h
index 5461c29..552cd11 100644
--- a/src/rp2040/hardware_regs/include/hardware/regs/usb.h
+++ b/src/rp2040/hardware_regs/include/hardware/regs/usb.h
@@ -1012,7 +1012,7 @@
 #define USB_SIE_STATUS_CONNECTED_BITS   _u(0x00010000)
 #define USB_SIE_STATUS_CONNECTED_MSB    _u(16)
 #define USB_SIE_STATUS_CONNECTED_LSB    _u(16)
-#define USB_SIE_STATUS_CONNECTED_ACCESS "RO"
+#define USB_SIE_STATUS_CONNECTED_ACCESS "WC"
 // -----------------------------------------------------------------------------
 // Field       : USB_SIE_STATUS_RESUME
 // Description : Host: Device has initiated a remote resume. Device: host has
@@ -1037,7 +1037,7 @@
 #define USB_SIE_STATUS_SPEED_BITS   _u(0x00000300)
 #define USB_SIE_STATUS_SPEED_MSB    _u(9)
 #define USB_SIE_STATUS_SPEED_LSB    _u(8)
-#define USB_SIE_STATUS_SPEED_ACCESS "RO"
+#define USB_SIE_STATUS_SPEED_ACCESS "WC"
 // -----------------------------------------------------------------------------
 // Field       : USB_SIE_STATUS_SUSPENDED
 // Description : Bus in suspended state. Valid for device and host. Host and
@@ -1047,7 +1047,7 @@
 #define USB_SIE_STATUS_SUSPENDED_BITS   _u(0x00000010)
 #define USB_SIE_STATUS_SUSPENDED_MSB    _u(4)
 #define USB_SIE_STATUS_SUSPENDED_LSB    _u(4)
-#define USB_SIE_STATUS_SUSPENDED_ACCESS "RO"
+#define USB_SIE_STATUS_SUSPENDED_ACCESS "WC"
 // -----------------------------------------------------------------------------
 // Field       : USB_SIE_STATUS_LINE_STATE
 // Description : USB bus line state
@@ -2965,7 +2965,7 @@
 #define USB_INTR_BUS_RESET_ACCESS "RO"
 // -----------------------------------------------------------------------------
 // Field       : USB_INTR_VBUS_DETECT
-// Description : Source: SIE_STATUS.VBUS_DETECT
+// Description : Source: SIE_STATUS.VBUS_DETECTED
 #define USB_INTR_VBUS_DETECT_RESET  _u(0x0)
 #define USB_INTR_VBUS_DETECT_BITS   _u(0x00000800)
 #define USB_INTR_VBUS_DETECT_MSB    _u(11)
@@ -3143,7 +3143,7 @@
 #define USB_INTE_BUS_RESET_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_INTE_VBUS_DETECT
-// Description : Source: SIE_STATUS.VBUS_DETECT
+// Description : Source: SIE_STATUS.VBUS_DETECTED
 #define USB_INTE_VBUS_DETECT_RESET  _u(0x0)
 #define USB_INTE_VBUS_DETECT_BITS   _u(0x00000800)
 #define USB_INTE_VBUS_DETECT_MSB    _u(11)
@@ -3321,7 +3321,7 @@
 #define USB_INTF_BUS_RESET_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_INTF_VBUS_DETECT
-// Description : Source: SIE_STATUS.VBUS_DETECT
+// Description : Source: SIE_STATUS.VBUS_DETECTED
 #define USB_INTF_VBUS_DETECT_RESET  _u(0x0)
 #define USB_INTF_VBUS_DETECT_BITS   _u(0x00000800)
 #define USB_INTF_VBUS_DETECT_MSB    _u(11)
@@ -3499,7 +3499,7 @@
 #define USB_INTS_BUS_RESET_ACCESS "RO"
 // -----------------------------------------------------------------------------
 // Field       : USB_INTS_VBUS_DETECT
-// Description : Source: SIE_STATUS.VBUS_DETECT
+// Description : Source: SIE_STATUS.VBUS_DETECTED
 #define USB_INTS_VBUS_DETECT_RESET  _u(0x0)
 #define USB_INTS_VBUS_DETECT_BITS   _u(0x00000800)
 #define USB_INTS_VBUS_DETECT_MSB    _u(11)
diff --git a/src/rp2040/hardware_regs/include/hardware/regs/usb_device_dpram.h b/src/rp2040/hardware_regs/include/hardware/regs/usb_device_dpram.h
index 6422774..fe65ffb 100644
--- a/src/rp2040/hardware_regs/include/hardware/regs/usb_device_dpram.h
+++ b/src/rp2040/hardware_regs/include/hardware/regs/usb_device_dpram.h
@@ -2621,7 +2621,7 @@
 #define USB_DEVICE_DPRAM_EP0_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP0_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP0_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP0_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP0_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -2756,7 +2756,7 @@
 #define USB_DEVICE_DPRAM_EP0_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP0_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP0_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP0_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP0_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -2890,7 +2890,7 @@
 #define USB_DEVICE_DPRAM_EP1_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP1_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP1_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP1_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP1_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -3025,7 +3025,7 @@
 #define USB_DEVICE_DPRAM_EP1_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP1_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP1_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP1_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP1_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -3159,7 +3159,7 @@
 #define USB_DEVICE_DPRAM_EP2_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP2_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP2_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP2_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP2_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -3294,7 +3294,7 @@
 #define USB_DEVICE_DPRAM_EP2_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP2_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP2_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP2_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP2_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -3428,7 +3428,7 @@
 #define USB_DEVICE_DPRAM_EP3_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP3_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP3_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP3_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP3_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -3563,7 +3563,7 @@
 #define USB_DEVICE_DPRAM_EP3_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP3_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP3_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP3_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP3_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -3697,7 +3697,7 @@
 #define USB_DEVICE_DPRAM_EP4_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP4_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP4_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP4_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP4_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -3832,7 +3832,7 @@
 #define USB_DEVICE_DPRAM_EP4_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP4_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP4_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP4_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP4_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -3966,7 +3966,7 @@
 #define USB_DEVICE_DPRAM_EP5_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP5_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP5_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP5_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP5_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -4101,7 +4101,7 @@
 #define USB_DEVICE_DPRAM_EP5_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP5_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP5_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP5_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP5_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -4235,7 +4235,7 @@
 #define USB_DEVICE_DPRAM_EP6_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP6_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP6_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP6_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP6_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -4370,7 +4370,7 @@
 #define USB_DEVICE_DPRAM_EP6_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP6_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP6_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP6_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP6_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -4504,7 +4504,7 @@
 #define USB_DEVICE_DPRAM_EP7_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP7_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP7_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP7_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP7_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -4639,7 +4639,7 @@
 #define USB_DEVICE_DPRAM_EP7_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP7_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP7_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP7_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP7_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -4773,7 +4773,7 @@
 #define USB_DEVICE_DPRAM_EP8_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP8_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP8_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP8_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP8_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -4908,7 +4908,7 @@
 #define USB_DEVICE_DPRAM_EP8_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP8_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP8_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP8_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP8_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -5042,7 +5042,7 @@
 #define USB_DEVICE_DPRAM_EP9_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP9_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP9_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP9_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP9_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -5177,7 +5177,7 @@
 #define USB_DEVICE_DPRAM_EP9_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP9_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP9_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP9_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP9_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -5312,7 +5312,7 @@
 #define USB_DEVICE_DPRAM_EP10_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP10_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP10_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP10_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP10_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -5447,7 +5447,7 @@
 #define USB_DEVICE_DPRAM_EP10_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP10_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP10_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP10_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP10_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -5582,7 +5582,7 @@
 #define USB_DEVICE_DPRAM_EP11_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP11_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP11_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP11_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP11_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -5717,7 +5717,7 @@
 #define USB_DEVICE_DPRAM_EP11_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP11_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP11_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP11_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP11_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -5852,7 +5852,7 @@
 #define USB_DEVICE_DPRAM_EP12_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP12_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP12_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP12_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP12_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -5987,7 +5987,7 @@
 #define USB_DEVICE_DPRAM_EP12_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP12_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP12_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP12_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP12_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -6122,7 +6122,7 @@
 #define USB_DEVICE_DPRAM_EP13_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP13_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP13_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP13_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP13_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -6257,7 +6257,7 @@
 #define USB_DEVICE_DPRAM_EP13_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP13_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP13_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP13_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP13_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -6392,7 +6392,7 @@
 #define USB_DEVICE_DPRAM_EP14_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP14_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP14_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP14_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP14_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -6527,7 +6527,7 @@
 #define USB_DEVICE_DPRAM_EP14_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP14_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP14_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP14_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP14_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -6662,7 +6662,7 @@
 #define USB_DEVICE_DPRAM_EP15_IN_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP15_IN_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP15_IN_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP15_IN_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP15_IN_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
@@ -6797,7 +6797,7 @@
 #define USB_DEVICE_DPRAM_EP15_OUT_BUFFER_CONTROL_AVAILABLE_0_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : USB_DEVICE_DPRAM_EP15_OUT_BUFFER_CONTROL_LENGTH_0
-// Description : The length of the data in buffer 1.
+// Description : The length of the data in buffer 0.
 #define USB_DEVICE_DPRAM_EP15_OUT_BUFFER_CONTROL_LENGTH_0_RESET  _u(0x000)
 #define USB_DEVICE_DPRAM_EP15_OUT_BUFFER_CONTROL_LENGTH_0_BITS   _u(0x000003ff)
 #define USB_DEVICE_DPRAM_EP15_OUT_BUFFER_CONTROL_LENGTH_0_MSB    _u(9)
diff --git a/src/rp2040/hardware_regs/include/hardware/regs/xosc.h b/src/rp2040/hardware_regs/include/hardware/regs/xosc.h
index 4af78b9..ec84d3d 100644
--- a/src/rp2040/hardware_regs/include/hardware/regs/xosc.h
+++ b/src/rp2040/hardware_regs/include/hardware/regs/xosc.h
@@ -124,20 +124,21 @@
 // Description : Controls the startup delay
 #define XOSC_STARTUP_OFFSET _u(0x0000000c)
 #define XOSC_STARTUP_BITS   _u(0x00103fff)
-#define XOSC_STARTUP_RESET  _u(0x00000000)
+#define XOSC_STARTUP_RESET  _u(0x000000c4)
 // -----------------------------------------------------------------------------
 // Field       : XOSC_STARTUP_X4
 // Description : Multiplies the startup_delay by 4. This is of little value to
-//               the user given that the delay can be programmed directly
-#define XOSC_STARTUP_X4_RESET  "-"
+//               the user given that the delay can be programmed directly.
+#define XOSC_STARTUP_X4_RESET  _u(0x0)
 #define XOSC_STARTUP_X4_BITS   _u(0x00100000)
 #define XOSC_STARTUP_X4_MSB    _u(20)
 #define XOSC_STARTUP_X4_LSB    _u(20)
 #define XOSC_STARTUP_X4_ACCESS "RW"
 // -----------------------------------------------------------------------------
 // Field       : XOSC_STARTUP_DELAY
-// Description : in multiples of 256*xtal_period
-#define XOSC_STARTUP_DELAY_RESET  "-"
+// Description : in multiples of 256*xtal_period. The reset value of 0xc4
+//               corresponds to approx 50 000 cycles.
+#define XOSC_STARTUP_DELAY_RESET  _u(0x00c4)
 #define XOSC_STARTUP_DELAY_BITS   _u(0x00003fff)
 #define XOSC_STARTUP_DELAY_MSB    _u(13)
 #define XOSC_STARTUP_DELAY_LSB    _u(0)
diff --git a/src/rp2040/hardware_regs/rp2040.svd b/src/rp2040/hardware_regs/rp2040.svd
index f600d47..52da2c0 100644
--- a/src/rp2040/hardware_regs/rp2040.svd
+++ b/src/rp2040/hardware_regs/rp2040.svd
@@ -22320,18 +22320,18 @@
             <field>
               <access>read-write</access>
               <bitRange>[20:20]</bitRange>
-              <description>Multiplies the startup_delay by 4. This is of little value to the user given that the delay can be programmed directly</description>
+              <description>Multiplies the startup_delay by 4. This is of little value to the user given that the delay can be programmed directly.</description>
               <name>X4</name>
             </field>
             <field>
               <access>read-write</access>
               <bitRange>[13:0]</bitRange>
-              <description>in multiples of 256*xtal_period</description>
+              <description>in multiples of 256*xtal_period. The reset value of 0xc4 corresponds to approx 50 000 cycles.</description>
               <name>DELAY</name>
             </field>
           </fields>
           <name>STARTUP</name>
-          <resetValue>0x00000000</resetValue>
+          <resetValue>0x000000c4</resetValue>
         </register>
         <register>
           <addressOffset>0x001c</addressOffset>
@@ -24228,7 +24228,76 @@
         <usage>registers</usage>
       </addressBlock>
       <baseAddress>0x40044000</baseAddress>
-      <description>DW_apb_i2c address block</description>
+      <description>DW_apb_i2c address block\n\n
+        List of configuration constants for the Synopsys I2C hardware (you may see references to these in I2C register header; these are *fixed* values, set at hardware design time):\n\n
+        IC_ULTRA_FAST_MODE ................ 0x0\n
+        IC_UFM_TBUF_CNT_DEFAULT ........... 0x8\n
+        IC_UFM_SCL_LOW_COUNT .............. 0x0008\n
+        IC_UFM_SCL_HIGH_COUNT ............. 0x0006\n
+        IC_TX_TL .......................... 0x0\n
+        IC_TX_CMD_BLOCK ................... 0x1\n
+        IC_HAS_DMA ........................ 0x1\n
+        IC_HAS_ASYNC_FIFO ................. 0x0\n
+        IC_SMBUS_ARP ...................... 0x0\n
+        IC_FIRST_DATA_BYTE_STATUS ......... 0x1\n
+        IC_INTR_IO ........................ 0x1\n
+        IC_MASTER_MODE .................... 0x1\n
+        IC_DEFAULT_ACK_GENERAL_CALL ....... 0x1\n
+        IC_INTR_POL ....................... 0x1\n
+        IC_OPTIONAL_SAR ................... 0x0\n
+        IC_DEFAULT_TAR_SLAVE_ADDR ......... 0x055\n
+        IC_DEFAULT_SLAVE_ADDR ............. 0x055\n
+        IC_DEFAULT_HS_SPKLEN .............. 0x1\n
+        IC_FS_SCL_HIGH_COUNT .............. 0x0006\n
+        IC_HS_SCL_LOW_COUNT ............... 0x0008\n
+        IC_DEVICE_ID_VALUE ................ 0x0\n
+        IC_10BITADDR_MASTER ............... 0x0\n
+        IC_CLK_FREQ_OPTIMIZATION .......... 0x0\n
+        IC_DEFAULT_FS_SPKLEN .............. 0x7\n
+        IC_ADD_ENCODED_PARAMS ............. 0x0\n
+        IC_DEFAULT_SDA_HOLD ............... 0x000001\n
+        IC_DEFAULT_SDA_SETUP .............. 0x64\n
+        IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT . 0x0\n
+        IC_CLOCK_PERIOD ................... 100\n
+        IC_EMPTYFIFO_HOLD_MASTER_EN ....... 1\n
+        IC_RESTART_EN ..................... 0x1\n
+        IC_TX_CMD_BLOCK_DEFAULT ........... 0x0\n
+        IC_BUS_CLEAR_FEATURE .............. 0x0\n
+        IC_CAP_LOADING .................... 100\n
+        IC_FS_SCL_LOW_COUNT ............... 0x000d\n
+        APB_DATA_WIDTH .................... 32\n
+        IC_SDA_STUCK_TIMEOUT_DEFAULT ...... 0xffffffff\n
+        IC_SLV_DATA_NACK_ONLY ............. 0x1\n
+        IC_10BITADDR_SLAVE ................ 0x0\n
+        IC_CLK_TYPE ....................... 0x0\n
+        IC_SMBUS_UDID_MSB ................. 0x0\n
+        IC_SMBUS_SUSPEND_ALERT ............ 0x0\n
+        IC_HS_SCL_HIGH_COUNT .............. 0x0006\n
+        IC_SLV_RESTART_DET_EN ............. 0x1\n
+        IC_SMBUS .......................... 0x0\n
+        IC_OPTIONAL_SAR_DEFAULT ........... 0x0\n
+        IC_PERSISTANT_SLV_ADDR_DEFAULT .... 0x0\n
+        IC_USE_COUNTS ..................... 0x0\n
+        IC_RX_BUFFER_DEPTH ................ 16\n
+        IC_SCL_STUCK_TIMEOUT_DEFAULT ...... 0xffffffff\n
+        IC_RX_FULL_HLD_BUS_EN ............. 0x1\n
+        IC_SLAVE_DISABLE .................. 0x1\n
+        IC_RX_TL .......................... 0x0\n
+        IC_DEVICE_ID ...................... 0x0\n
+        IC_HC_COUNT_VALUES ................ 0x0\n
+        I2C_DYNAMIC_TAR_UPDATE ............ 0\n
+        IC_SMBUS_CLK_LOW_MEXT_DEFAULT ..... 0xffffffff\n
+        IC_SMBUS_CLK_LOW_SEXT_DEFAULT ..... 0xffffffff\n
+        IC_HS_MASTER_CODE ................. 0x1\n
+        IC_SMBUS_RST_IDLE_CNT_DEFAULT ..... 0xffff\n
+        IC_SMBUS_UDID_LSB_DEFAULT ......... 0xffffffff\n
+        IC_SS_SCL_HIGH_COUNT .............. 0x0028\n
+        IC_SS_SCL_LOW_COUNT ............... 0x002f\n
+        IC_MAX_SPEED_MODE ................. 0x2\n
+        IC_STAT_FOR_CLK_STRETCH ........... 0x0\n
+        IC_STOP_DET_IF_MASTER_ACTIVE ...... 0x0\n
+        IC_DEFAULT_UFM_SPKLEN ............. 0x1\n
+        IC_TX_BUFFER_DEPTH ................ 16</description>
       <interrupt>
         <name>I2C0_IRQ</name>
         <value>23</value>
@@ -29762,28 +29831,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0010</addressOffset>
           <description>Alias for channel 0 CTRL register</description>
           <name>CH0_AL1_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0014</addressOffset>
           <description>Alias for channel 0 READ_ADDR register</description>
           <name>CH0_AL1_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0018</addressOffset>
           <description>Alias for channel 0 WRITE_ADDR register</description>
           <name>CH0_AL1_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x001c</addressOffset>
           <description>Alias for channel 0 TRANS_COUNT register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -29792,28 +29861,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0020</addressOffset>
           <description>Alias for channel 0 CTRL register</description>
           <name>CH0_AL2_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0024</addressOffset>
           <description>Alias for channel 0 TRANS_COUNT register</description>
           <name>CH0_AL2_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0028</addressOffset>
           <description>Alias for channel 0 READ_ADDR register</description>
           <name>CH0_AL2_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x002c</addressOffset>
           <description>Alias for channel 0 WRITE_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -29822,28 +29891,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0030</addressOffset>
           <description>Alias for channel 0 CTRL register</description>
           <name>CH0_AL3_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0034</addressOffset>
           <description>Alias for channel 0 WRITE_ADDR register</description>
           <name>CH0_AL3_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0038</addressOffset>
           <description>Alias for channel 0 TRANS_COUNT register</description>
           <name>CH0_AL3_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x003c</addressOffset>
           <description>Alias for channel 0 READ_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -30047,28 +30116,28 @@
           <resetValue>0x00000800</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0050</addressOffset>
           <description>Alias for channel 1 CTRL register</description>
           <name>CH1_AL1_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0054</addressOffset>
           <description>Alias for channel 1 READ_ADDR register</description>
           <name>CH1_AL1_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0058</addressOffset>
           <description>Alias for channel 1 WRITE_ADDR register</description>
           <name>CH1_AL1_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x005c</addressOffset>
           <description>Alias for channel 1 TRANS_COUNT register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -30077,28 +30146,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0060</addressOffset>
           <description>Alias for channel 1 CTRL register</description>
           <name>CH1_AL2_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0064</addressOffset>
           <description>Alias for channel 1 TRANS_COUNT register</description>
           <name>CH1_AL2_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0068</addressOffset>
           <description>Alias for channel 1 READ_ADDR register</description>
           <name>CH1_AL2_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x006c</addressOffset>
           <description>Alias for channel 1 WRITE_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -30107,28 +30176,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0070</addressOffset>
           <description>Alias for channel 1 CTRL register</description>
           <name>CH1_AL3_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0074</addressOffset>
           <description>Alias for channel 1 WRITE_ADDR register</description>
           <name>CH1_AL3_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0078</addressOffset>
           <description>Alias for channel 1 TRANS_COUNT register</description>
           <name>CH1_AL3_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x007c</addressOffset>
           <description>Alias for channel 1 READ_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -30332,28 +30401,28 @@
           <resetValue>0x00001000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0090</addressOffset>
           <description>Alias for channel 2 CTRL register</description>
           <name>CH2_AL1_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0094</addressOffset>
           <description>Alias for channel 2 READ_ADDR register</description>
           <name>CH2_AL1_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0098</addressOffset>
           <description>Alias for channel 2 WRITE_ADDR register</description>
           <name>CH2_AL1_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x009c</addressOffset>
           <description>Alias for channel 2 TRANS_COUNT register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -30362,28 +30431,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00a0</addressOffset>
           <description>Alias for channel 2 CTRL register</description>
           <name>CH2_AL2_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00a4</addressOffset>
           <description>Alias for channel 2 TRANS_COUNT register</description>
           <name>CH2_AL2_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00a8</addressOffset>
           <description>Alias for channel 2 READ_ADDR register</description>
           <name>CH2_AL2_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00ac</addressOffset>
           <description>Alias for channel 2 WRITE_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -30392,28 +30461,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00b0</addressOffset>
           <description>Alias for channel 2 CTRL register</description>
           <name>CH2_AL3_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00b4</addressOffset>
           <description>Alias for channel 2 WRITE_ADDR register</description>
           <name>CH2_AL3_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00b8</addressOffset>
           <description>Alias for channel 2 TRANS_COUNT register</description>
           <name>CH2_AL3_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00bc</addressOffset>
           <description>Alias for channel 2 READ_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -30617,28 +30686,28 @@
           <resetValue>0x00001800</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00d0</addressOffset>
           <description>Alias for channel 3 CTRL register</description>
           <name>CH3_AL1_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00d4</addressOffset>
           <description>Alias for channel 3 READ_ADDR register</description>
           <name>CH3_AL1_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00d8</addressOffset>
           <description>Alias for channel 3 WRITE_ADDR register</description>
           <name>CH3_AL1_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00dc</addressOffset>
           <description>Alias for channel 3 TRANS_COUNT register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -30647,28 +30716,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00e0</addressOffset>
           <description>Alias for channel 3 CTRL register</description>
           <name>CH3_AL2_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00e4</addressOffset>
           <description>Alias for channel 3 TRANS_COUNT register</description>
           <name>CH3_AL2_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00e8</addressOffset>
           <description>Alias for channel 3 READ_ADDR register</description>
           <name>CH3_AL2_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00ec</addressOffset>
           <description>Alias for channel 3 WRITE_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -30677,28 +30746,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00f0</addressOffset>
           <description>Alias for channel 3 CTRL register</description>
           <name>CH3_AL3_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00f4</addressOffset>
           <description>Alias for channel 3 WRITE_ADDR register</description>
           <name>CH3_AL3_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00f8</addressOffset>
           <description>Alias for channel 3 TRANS_COUNT register</description>
           <name>CH3_AL3_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x00fc</addressOffset>
           <description>Alias for channel 3 READ_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -30902,28 +30971,28 @@
           <resetValue>0x00002000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0110</addressOffset>
           <description>Alias for channel 4 CTRL register</description>
           <name>CH4_AL1_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0114</addressOffset>
           <description>Alias for channel 4 READ_ADDR register</description>
           <name>CH4_AL1_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0118</addressOffset>
           <description>Alias for channel 4 WRITE_ADDR register</description>
           <name>CH4_AL1_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x011c</addressOffset>
           <description>Alias for channel 4 TRANS_COUNT register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -30932,28 +31001,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0120</addressOffset>
           <description>Alias for channel 4 CTRL register</description>
           <name>CH4_AL2_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0124</addressOffset>
           <description>Alias for channel 4 TRANS_COUNT register</description>
           <name>CH4_AL2_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0128</addressOffset>
           <description>Alias for channel 4 READ_ADDR register</description>
           <name>CH4_AL2_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x012c</addressOffset>
           <description>Alias for channel 4 WRITE_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -30962,28 +31031,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0130</addressOffset>
           <description>Alias for channel 4 CTRL register</description>
           <name>CH4_AL3_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0134</addressOffset>
           <description>Alias for channel 4 WRITE_ADDR register</description>
           <name>CH4_AL3_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0138</addressOffset>
           <description>Alias for channel 4 TRANS_COUNT register</description>
           <name>CH4_AL3_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x013c</addressOffset>
           <description>Alias for channel 4 READ_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -31187,28 +31256,28 @@
           <resetValue>0x00002800</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0150</addressOffset>
           <description>Alias for channel 5 CTRL register</description>
           <name>CH5_AL1_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0154</addressOffset>
           <description>Alias for channel 5 READ_ADDR register</description>
           <name>CH5_AL1_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0158</addressOffset>
           <description>Alias for channel 5 WRITE_ADDR register</description>
           <name>CH5_AL1_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x015c</addressOffset>
           <description>Alias for channel 5 TRANS_COUNT register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -31217,28 +31286,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0160</addressOffset>
           <description>Alias for channel 5 CTRL register</description>
           <name>CH5_AL2_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0164</addressOffset>
           <description>Alias for channel 5 TRANS_COUNT register</description>
           <name>CH5_AL2_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0168</addressOffset>
           <description>Alias for channel 5 READ_ADDR register</description>
           <name>CH5_AL2_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x016c</addressOffset>
           <description>Alias for channel 5 WRITE_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -31247,28 +31316,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0170</addressOffset>
           <description>Alias for channel 5 CTRL register</description>
           <name>CH5_AL3_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0174</addressOffset>
           <description>Alias for channel 5 WRITE_ADDR register</description>
           <name>CH5_AL3_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0178</addressOffset>
           <description>Alias for channel 5 TRANS_COUNT register</description>
           <name>CH5_AL3_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x017c</addressOffset>
           <description>Alias for channel 5 READ_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -31472,28 +31541,28 @@
           <resetValue>0x00003000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0190</addressOffset>
           <description>Alias for channel 6 CTRL register</description>
           <name>CH6_AL1_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0194</addressOffset>
           <description>Alias for channel 6 READ_ADDR register</description>
           <name>CH6_AL1_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0198</addressOffset>
           <description>Alias for channel 6 WRITE_ADDR register</description>
           <name>CH6_AL1_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x019c</addressOffset>
           <description>Alias for channel 6 TRANS_COUNT register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -31502,28 +31571,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01a0</addressOffset>
           <description>Alias for channel 6 CTRL register</description>
           <name>CH6_AL2_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01a4</addressOffset>
           <description>Alias for channel 6 TRANS_COUNT register</description>
           <name>CH6_AL2_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01a8</addressOffset>
           <description>Alias for channel 6 READ_ADDR register</description>
           <name>CH6_AL2_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01ac</addressOffset>
           <description>Alias for channel 6 WRITE_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -31532,28 +31601,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01b0</addressOffset>
           <description>Alias for channel 6 CTRL register</description>
           <name>CH6_AL3_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01b4</addressOffset>
           <description>Alias for channel 6 WRITE_ADDR register</description>
           <name>CH6_AL3_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01b8</addressOffset>
           <description>Alias for channel 6 TRANS_COUNT register</description>
           <name>CH6_AL3_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01bc</addressOffset>
           <description>Alias for channel 6 READ_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -31757,28 +31826,28 @@
           <resetValue>0x00003800</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01d0</addressOffset>
           <description>Alias for channel 7 CTRL register</description>
           <name>CH7_AL1_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01d4</addressOffset>
           <description>Alias for channel 7 READ_ADDR register</description>
           <name>CH7_AL1_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01d8</addressOffset>
           <description>Alias for channel 7 WRITE_ADDR register</description>
           <name>CH7_AL1_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01dc</addressOffset>
           <description>Alias for channel 7 TRANS_COUNT register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -31787,28 +31856,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01e0</addressOffset>
           <description>Alias for channel 7 CTRL register</description>
           <name>CH7_AL2_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01e4</addressOffset>
           <description>Alias for channel 7 TRANS_COUNT register</description>
           <name>CH7_AL2_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01e8</addressOffset>
           <description>Alias for channel 7 READ_ADDR register</description>
           <name>CH7_AL2_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01ec</addressOffset>
           <description>Alias for channel 7 WRITE_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -31817,28 +31886,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01f0</addressOffset>
           <description>Alias for channel 7 CTRL register</description>
           <name>CH7_AL3_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01f4</addressOffset>
           <description>Alias for channel 7 WRITE_ADDR register</description>
           <name>CH7_AL3_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01f8</addressOffset>
           <description>Alias for channel 7 TRANS_COUNT register</description>
           <name>CH7_AL3_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x01fc</addressOffset>
           <description>Alias for channel 7 READ_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -32042,28 +32111,28 @@
           <resetValue>0x00004000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0210</addressOffset>
           <description>Alias for channel 8 CTRL register</description>
           <name>CH8_AL1_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0214</addressOffset>
           <description>Alias for channel 8 READ_ADDR register</description>
           <name>CH8_AL1_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0218</addressOffset>
           <description>Alias for channel 8 WRITE_ADDR register</description>
           <name>CH8_AL1_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x021c</addressOffset>
           <description>Alias for channel 8 TRANS_COUNT register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -32072,28 +32141,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0220</addressOffset>
           <description>Alias for channel 8 CTRL register</description>
           <name>CH8_AL2_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0224</addressOffset>
           <description>Alias for channel 8 TRANS_COUNT register</description>
           <name>CH8_AL2_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0228</addressOffset>
           <description>Alias for channel 8 READ_ADDR register</description>
           <name>CH8_AL2_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x022c</addressOffset>
           <description>Alias for channel 8 WRITE_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -32102,28 +32171,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0230</addressOffset>
           <description>Alias for channel 8 CTRL register</description>
           <name>CH8_AL3_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0234</addressOffset>
           <description>Alias for channel 8 WRITE_ADDR register</description>
           <name>CH8_AL3_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0238</addressOffset>
           <description>Alias for channel 8 TRANS_COUNT register</description>
           <name>CH8_AL3_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x023c</addressOffset>
           <description>Alias for channel 8 READ_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -32327,28 +32396,28 @@
           <resetValue>0x00004800</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0250</addressOffset>
           <description>Alias for channel 9 CTRL register</description>
           <name>CH9_AL1_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0254</addressOffset>
           <description>Alias for channel 9 READ_ADDR register</description>
           <name>CH9_AL1_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0258</addressOffset>
           <description>Alias for channel 9 WRITE_ADDR register</description>
           <name>CH9_AL1_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x025c</addressOffset>
           <description>Alias for channel 9 TRANS_COUNT register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -32357,28 +32426,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0260</addressOffset>
           <description>Alias for channel 9 CTRL register</description>
           <name>CH9_AL2_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0264</addressOffset>
           <description>Alias for channel 9 TRANS_COUNT register</description>
           <name>CH9_AL2_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0268</addressOffset>
           <description>Alias for channel 9 READ_ADDR register</description>
           <name>CH9_AL2_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x026c</addressOffset>
           <description>Alias for channel 9 WRITE_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -32387,28 +32456,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0270</addressOffset>
           <description>Alias for channel 9 CTRL register</description>
           <name>CH9_AL3_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0274</addressOffset>
           <description>Alias for channel 9 WRITE_ADDR register</description>
           <name>CH9_AL3_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0278</addressOffset>
           <description>Alias for channel 9 TRANS_COUNT register</description>
           <name>CH9_AL3_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x027c</addressOffset>
           <description>Alias for channel 9 READ_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -32612,28 +32681,28 @@
           <resetValue>0x00005000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0290</addressOffset>
           <description>Alias for channel 10 CTRL register</description>
           <name>CH10_AL1_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0294</addressOffset>
           <description>Alias for channel 10 READ_ADDR register</description>
           <name>CH10_AL1_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0298</addressOffset>
           <description>Alias for channel 10 WRITE_ADDR register</description>
           <name>CH10_AL1_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x029c</addressOffset>
           <description>Alias for channel 10 TRANS_COUNT register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -32642,28 +32711,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02a0</addressOffset>
           <description>Alias for channel 10 CTRL register</description>
           <name>CH10_AL2_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02a4</addressOffset>
           <description>Alias for channel 10 TRANS_COUNT register</description>
           <name>CH10_AL2_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02a8</addressOffset>
           <description>Alias for channel 10 READ_ADDR register</description>
           <name>CH10_AL2_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02ac</addressOffset>
           <description>Alias for channel 10 WRITE_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -32672,28 +32741,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02b0</addressOffset>
           <description>Alias for channel 10 CTRL register</description>
           <name>CH10_AL3_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02b4</addressOffset>
           <description>Alias for channel 10 WRITE_ADDR register</description>
           <name>CH10_AL3_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02b8</addressOffset>
           <description>Alias for channel 10 TRANS_COUNT register</description>
           <name>CH10_AL3_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02bc</addressOffset>
           <description>Alias for channel 10 READ_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -32897,28 +32966,28 @@
           <resetValue>0x00005800</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02d0</addressOffset>
           <description>Alias for channel 11 CTRL register</description>
           <name>CH11_AL1_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02d4</addressOffset>
           <description>Alias for channel 11 READ_ADDR register</description>
           <name>CH11_AL1_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02d8</addressOffset>
           <description>Alias for channel 11 WRITE_ADDR register</description>
           <name>CH11_AL1_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02dc</addressOffset>
           <description>Alias for channel 11 TRANS_COUNT register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -32927,28 +32996,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02e0</addressOffset>
           <description>Alias for channel 11 CTRL register</description>
           <name>CH11_AL2_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02e4</addressOffset>
           <description>Alias for channel 11 TRANS_COUNT register</description>
           <name>CH11_AL2_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02e8</addressOffset>
           <description>Alias for channel 11 READ_ADDR register</description>
           <name>CH11_AL2_READ_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02ec</addressOffset>
           <description>Alias for channel 11 WRITE_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -32957,28 +33026,28 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02f0</addressOffset>
           <description>Alias for channel 11 CTRL register</description>
           <name>CH11_AL3_CTRL</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02f4</addressOffset>
           <description>Alias for channel 11 WRITE_ADDR register</description>
           <name>CH11_AL3_WRITE_ADDR</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02f8</addressOffset>
           <description>Alias for channel 11 TRANS_COUNT register</description>
           <name>CH11_AL3_TRANS_COUNT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x02fc</addressOffset>
           <description>Alias for channel 11 READ_ADDR register\n
             This is a trigger register (0xc). Writing a nonzero value will\n
@@ -33334,8 +33403,9 @@
           <description>Read: get channel DREQ counter (i.e. how many accesses the DMA expects it can perform on the peripheral without overflow/underflow. Write any value: clears the counter, and cause channel to re-initiate DREQ handshake.</description>
           <fields>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[5:0]</bitRange>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CH0_DBG_CTDREQ</name>
             </field>
           </fields>
@@ -33354,8 +33424,9 @@
           <description>Read: get channel DREQ counter (i.e. how many accesses the DMA expects it can perform on the peripheral without overflow/underflow. Write any value: clears the counter, and cause channel to re-initiate DREQ handshake.</description>
           <fields>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[5:0]</bitRange>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CH1_DBG_CTDREQ</name>
             </field>
           </fields>
@@ -33374,8 +33445,9 @@
           <description>Read: get channel DREQ counter (i.e. how many accesses the DMA expects it can perform on the peripheral without overflow/underflow. Write any value: clears the counter, and cause channel to re-initiate DREQ handshake.</description>
           <fields>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[5:0]</bitRange>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CH2_DBG_CTDREQ</name>
             </field>
           </fields>
@@ -33394,8 +33466,9 @@
           <description>Read: get channel DREQ counter (i.e. how many accesses the DMA expects it can perform on the peripheral without overflow/underflow. Write any value: clears the counter, and cause channel to re-initiate DREQ handshake.</description>
           <fields>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[5:0]</bitRange>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CH3_DBG_CTDREQ</name>
             </field>
           </fields>
@@ -33414,8 +33487,9 @@
           <description>Read: get channel DREQ counter (i.e. how many accesses the DMA expects it can perform on the peripheral without overflow/underflow. Write any value: clears the counter, and cause channel to re-initiate DREQ handshake.</description>
           <fields>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[5:0]</bitRange>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CH4_DBG_CTDREQ</name>
             </field>
           </fields>
@@ -33434,8 +33508,9 @@
           <description>Read: get channel DREQ counter (i.e. how many accesses the DMA expects it can perform on the peripheral without overflow/underflow. Write any value: clears the counter, and cause channel to re-initiate DREQ handshake.</description>
           <fields>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[5:0]</bitRange>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CH5_DBG_CTDREQ</name>
             </field>
           </fields>
@@ -33454,8 +33529,9 @@
           <description>Read: get channel DREQ counter (i.e. how many accesses the DMA expects it can perform on the peripheral without overflow/underflow. Write any value: clears the counter, and cause channel to re-initiate DREQ handshake.</description>
           <fields>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[5:0]</bitRange>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CH6_DBG_CTDREQ</name>
             </field>
           </fields>
@@ -33474,8 +33550,9 @@
           <description>Read: get channel DREQ counter (i.e. how many accesses the DMA expects it can perform on the peripheral without overflow/underflow. Write any value: clears the counter, and cause channel to re-initiate DREQ handshake.</description>
           <fields>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[5:0]</bitRange>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CH7_DBG_CTDREQ</name>
             </field>
           </fields>
@@ -33494,8 +33571,9 @@
           <description>Read: get channel DREQ counter (i.e. how many accesses the DMA expects it can perform on the peripheral without overflow/underflow. Write any value: clears the counter, and cause channel to re-initiate DREQ handshake.</description>
           <fields>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[5:0]</bitRange>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CH8_DBG_CTDREQ</name>
             </field>
           </fields>
@@ -33514,8 +33592,9 @@
           <description>Read: get channel DREQ counter (i.e. how many accesses the DMA expects it can perform on the peripheral without overflow/underflow. Write any value: clears the counter, and cause channel to re-initiate DREQ handshake.</description>
           <fields>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[5:0]</bitRange>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CH9_DBG_CTDREQ</name>
             </field>
           </fields>
@@ -33534,8 +33613,9 @@
           <description>Read: get channel DREQ counter (i.e. how many accesses the DMA expects it can perform on the peripheral without overflow/underflow. Write any value: clears the counter, and cause channel to re-initiate DREQ handshake.</description>
           <fields>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[5:0]</bitRange>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CH10_DBG_CTDREQ</name>
             </field>
           </fields>
@@ -33554,8 +33634,9 @@
           <description>Read: get channel DREQ counter (i.e. how many accesses the DMA expects it can perform on the peripheral without overflow/underflow. Write any value: clears the counter, and cause channel to re-initiate DREQ handshake.</description>
           <fields>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[5:0]</bitRange>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CH11_DBG_CTDREQ</name>
             </field>
           </fields>
@@ -35883,7 +35964,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -35989,7 +36070,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -36095,7 +36176,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -36201,7 +36282,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -36307,7 +36388,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -36413,7 +36494,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -36519,7 +36600,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -36625,7 +36706,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -36731,7 +36812,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -36837,7 +36918,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -36943,7 +37024,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -37049,7 +37130,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -37155,7 +37236,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -37261,7 +37342,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -37367,7 +37448,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -37473,7 +37554,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -37579,7 +37660,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -37685,7 +37766,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -37791,7 +37872,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -37897,7 +37978,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -38003,7 +38084,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -38109,7 +38190,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -38215,7 +38296,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -38321,7 +38402,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -38427,7 +38508,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -38533,7 +38614,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -38639,7 +38720,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -38745,7 +38826,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -38851,7 +38932,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -38957,7 +39038,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -39063,7 +39144,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -39169,7 +39250,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[9:0]</bitRange>
-              <description>The length of the data in buffer 1.</description>
+              <description>The length of the data in buffer 0.</description>
               <name>LENGTH_0</name>
             </field>
           </fields>
@@ -39992,9 +40073,10 @@
               <name>SETUP_REC</name>
             </field>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[16:16]</bitRange>
               <description>Device: connected</description>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>CONNECTED</name>
             </field>
             <field>
@@ -40011,15 +40093,17 @@
               <name>VBUS_OVER_CURR</name>
             </field>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[9:8]</bitRange>
               <description>Host: device speed. Disconnected = 00, LS = 01, FS = 10</description>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>SPEED</name>
             </field>
             <field>
-              <access>read-only</access>
+              <access>read-write</access>
               <bitRange>[4:4]</bitRange>
               <description>Bus in suspended state. Valid for device and host. Host and device will go into suspend if neither Keep Alive / SOF frames are enabled.</description>
+              <modifiedWriteValues>oneToClear</modifiedWriteValues>
               <name>SUSPENDED</name>
             </field>
             <field>
@@ -41389,7 +41473,7 @@
             <field>
               <access>read-only</access>
               <bitRange>[11:11]</bitRange>
-              <description>Source: SIE_STATUS.VBUS_DETECT</description>
+              <description>Source: SIE_STATUS.VBUS_DETECTED</description>
               <name>VBUS_DETECT</name>
             </field>
             <field>
@@ -41517,7 +41601,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[11:11]</bitRange>
-              <description>Source: SIE_STATUS.VBUS_DETECT</description>
+              <description>Source: SIE_STATUS.VBUS_DETECTED</description>
               <name>VBUS_DETECT</name>
             </field>
             <field>
@@ -41645,7 +41729,7 @@
             <field>
               <access>read-write</access>
               <bitRange>[11:11]</bitRange>
-              <description>Source: SIE_STATUS.VBUS_DETECT</description>
+              <description>Source: SIE_STATUS.VBUS_DETECTED</description>
               <name>VBUS_DETECT</name>
             </field>
             <field>
@@ -41773,7 +41857,7 @@
             <field>
               <access>read-only</access>
               <bitRange>[11:11]</bitRange>
-              <description>Source: SIE_STATUS.VBUS_DETECT</description>
+              <description>Source: SIE_STATUS.VBUS_DETECTED</description>
               <name>VBUS_DETECT</name>
             </field>
             <field>
@@ -42112,14 +42196,14 @@
         <register>
           <access>read-only</access>
           <addressOffset>0x003c</addressOffset>
-          <description>Read to sample the pad output values PIO is currently driving to the GPIOs.</description>
+          <description>Read to sample the pad output values PIO is currently driving to the GPIOs. On RP2040 there are 30 GPIOs, so the two most significant bits are hardwired to 0.</description>
           <name>DBG_PADOUT</name>
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
           <access>read-only</access>
           <addressOffset>0x0040</addressOffset>
-          <description>Read to sample the pad output enables (direction) PIO is currently driving to the GPIOs.</description>
+          <description>Read to sample the pad output enables (direction) PIO is currently driving to the GPIOs. On RP2040 there are 30 GPIOs, so the two most significant bits are hardwired to 0.</description>
           <name>DBG_PADOE</name>
           <resetValue>0x00000000</resetValue>
         </register>
@@ -42157,7 +42241,7 @@
           <description>Write-only access to instruction memory location 0</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM0</name>
             </field>
@@ -42170,7 +42254,7 @@
           <description>Write-only access to instruction memory location 1</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM1</name>
             </field>
@@ -42183,7 +42267,7 @@
           <description>Write-only access to instruction memory location 2</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM2</name>
             </field>
@@ -42196,7 +42280,7 @@
           <description>Write-only access to instruction memory location 3</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM3</name>
             </field>
@@ -42209,7 +42293,7 @@
           <description>Write-only access to instruction memory location 4</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM4</name>
             </field>
@@ -42222,7 +42306,7 @@
           <description>Write-only access to instruction memory location 5</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM5</name>
             </field>
@@ -42235,7 +42319,7 @@
           <description>Write-only access to instruction memory location 6</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM6</name>
             </field>
@@ -42248,7 +42332,7 @@
           <description>Write-only access to instruction memory location 7</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM7</name>
             </field>
@@ -42261,7 +42345,7 @@
           <description>Write-only access to instruction memory location 8</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM8</name>
             </field>
@@ -42274,7 +42358,7 @@
           <description>Write-only access to instruction memory location 9</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM9</name>
             </field>
@@ -42287,7 +42371,7 @@
           <description>Write-only access to instruction memory location 10</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM10</name>
             </field>
@@ -42300,7 +42384,7 @@
           <description>Write-only access to instruction memory location 11</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM11</name>
             </field>
@@ -42313,7 +42397,7 @@
           <description>Write-only access to instruction memory location 12</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM12</name>
             </field>
@@ -42326,7 +42410,7 @@
           <description>Write-only access to instruction memory location 13</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM13</name>
             </field>
@@ -42339,7 +42423,7 @@
           <description>Write-only access to instruction memory location 14</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM14</name>
             </field>
@@ -42352,7 +42436,7 @@
           <description>Write-only access to instruction memory location 15</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM15</name>
             </field>
@@ -42365,7 +42449,7 @@
           <description>Write-only access to instruction memory location 16</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM16</name>
             </field>
@@ -42378,7 +42462,7 @@
           <description>Write-only access to instruction memory location 17</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM17</name>
             </field>
@@ -42391,7 +42475,7 @@
           <description>Write-only access to instruction memory location 18</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM18</name>
             </field>
@@ -42404,7 +42488,7 @@
           <description>Write-only access to instruction memory location 19</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM19</name>
             </field>
@@ -42417,7 +42501,7 @@
           <description>Write-only access to instruction memory location 20</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM20</name>
             </field>
@@ -42430,7 +42514,7 @@
           <description>Write-only access to instruction memory location 21</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM21</name>
             </field>
@@ -42443,7 +42527,7 @@
           <description>Write-only access to instruction memory location 22</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM22</name>
             </field>
@@ -42456,7 +42540,7 @@
           <description>Write-only access to instruction memory location 23</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM23</name>
             </field>
@@ -42469,7 +42553,7 @@
           <description>Write-only access to instruction memory location 24</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM24</name>
             </field>
@@ -42482,7 +42566,7 @@
           <description>Write-only access to instruction memory location 25</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM25</name>
             </field>
@@ -42495,7 +42579,7 @@
           <description>Write-only access to instruction memory location 26</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM26</name>
             </field>
@@ -42508,7 +42592,7 @@
           <description>Write-only access to instruction memory location 27</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM27</name>
             </field>
@@ -42521,7 +42605,7 @@
           <description>Write-only access to instruction memory location 28</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM28</name>
             </field>
@@ -42534,7 +42618,7 @@
           <description>Write-only access to instruction memory location 29</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM29</name>
             </field>
@@ -42547,7 +42631,7 @@
           <description>Write-only access to instruction memory location 30</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM30</name>
             </field>
@@ -42560,7 +42644,7 @@
           <description>Write-only access to instruction memory location 31</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[15:0]</bitRange>
               <name>INSTR_MEM31</name>
             </field>
@@ -44142,7 +44226,7 @@
           <description>GPIO output value set</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[29:0]</bitRange>
               <description>Perform an atomic bit-set on GPIO_OUT, i.e. `GPIO_OUT |= wdata`</description>
               <name>GPIO_OUT_SET</name>
@@ -44156,7 +44240,7 @@
           <description>GPIO output value clear</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[29:0]</bitRange>
               <description>Perform an atomic bit-clear on GPIO_OUT, i.e. `GPIO_OUT &amp;= ~wdata`</description>
               <name>GPIO_OUT_CLR</name>
@@ -44170,7 +44254,7 @@
           <description>GPIO output value XOR</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[29:0]</bitRange>
               <description>Perform an atomic bitwise XOR on GPIO_OUT, i.e. `GPIO_OUT ^= wdata`</description>
               <name>GPIO_OUT_XOR</name>
@@ -44202,7 +44286,7 @@
           <description>GPIO output enable set</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[29:0]</bitRange>
               <description>Perform an atomic bit-set on GPIO_OE, i.e. `GPIO_OE |= wdata`</description>
               <name>GPIO_OE_SET</name>
@@ -44216,7 +44300,7 @@
           <description>GPIO output enable clear</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[29:0]</bitRange>
               <description>Perform an atomic bit-clear on GPIO_OE, i.e. `GPIO_OE &amp;= ~wdata`</description>
               <name>GPIO_OE_CLR</name>
@@ -44230,7 +44314,7 @@
           <description>GPIO output enable XOR</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[29:0]</bitRange>
               <description>Perform an atomic bitwise XOR on GPIO_OE, i.e. `GPIO_OE ^= wdata`</description>
               <name>GPIO_OE_XOR</name>
@@ -44262,7 +44346,7 @@
           <description>QSPI output value set</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[5:0]</bitRange>
               <description>Perform an atomic bit-set on GPIO_HI_OUT, i.e. `GPIO_HI_OUT |= wdata`</description>
               <name>GPIO_HI_OUT_SET</name>
@@ -44276,7 +44360,7 @@
           <description>QSPI output value clear</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[5:0]</bitRange>
               <description>Perform an atomic bit-clear on GPIO_HI_OUT, i.e. `GPIO_HI_OUT &amp;= ~wdata`</description>
               <name>GPIO_HI_OUT_CLR</name>
@@ -44290,7 +44374,7 @@
           <description>QSPI output value XOR</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[5:0]</bitRange>
               <description>Perform an atomic bitwise XOR on GPIO_HI_OUT, i.e. `GPIO_HI_OUT ^= wdata`</description>
               <name>GPIO_HI_OUT_XOR</name>
@@ -44322,7 +44406,7 @@
           <description>QSPI output enable set</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[5:0]</bitRange>
               <description>Perform an atomic bit-set on GPIO_HI_OE, i.e. `GPIO_HI_OE |= wdata`</description>
               <name>GPIO_HI_OE_SET</name>
@@ -44336,7 +44420,7 @@
           <description>QSPI output enable clear</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[5:0]</bitRange>
               <description>Perform an atomic bit-clear on GPIO_HI_OE, i.e. `GPIO_HI_OE &amp;= ~wdata`</description>
               <name>GPIO_HI_OE_CLR</name>
@@ -44350,7 +44434,7 @@
           <description>QSPI output enable XOR</description>
           <fields>
             <field>
-              <access>read-write</access>
+              <access>write-only</access>
               <bitRange>[5:0]</bitRange>
               <description>Perform an atomic bitwise XOR on GPIO_HI_OE, i.e. `GPIO_HI_OE ^= wdata`</description>
               <name>GPIO_HI_OE_XOR</name>
@@ -44767,7 +44851,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-write</access>
+          <access>write-only</access>
           <addressOffset>0x00bc</addressOffset>
           <description>On write, the lower 16 bits go to BASE0, upper bits to BASE1 simultaneously.\n
             Each half is sign-extended to 32 bits if that lane's SIGNED flag is set.</description>
@@ -45029,7 +45113,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-write</access>
+          <access>write-only</access>
           <addressOffset>0x00fc</addressOffset>
           <description>On write, the lower 16 bits go to BASE0, upper bits to BASE1 simultaneously.\n
             Each half is sign-extended to 32 bits if that lane's SIGNED flag is set.</description>
@@ -45037,7 +45121,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0100</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45049,7 +45133,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0104</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45061,7 +45145,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0108</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45073,7 +45157,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x010c</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45085,7 +45169,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0110</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45097,7 +45181,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0114</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45109,7 +45193,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0118</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45121,7 +45205,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x011c</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45133,7 +45217,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0120</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45145,7 +45229,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0124</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45157,7 +45241,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0128</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45169,7 +45253,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x012c</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45181,7 +45265,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0130</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45193,7 +45277,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0134</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45205,7 +45289,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0138</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45217,7 +45301,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x013c</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45229,7 +45313,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0140</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45241,7 +45325,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0144</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45253,7 +45337,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0148</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45265,7 +45349,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x014c</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45277,7 +45361,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0150</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45289,7 +45373,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0154</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45301,7 +45385,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0158</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45313,7 +45397,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x015c</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45325,7 +45409,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0160</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45337,7 +45421,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0164</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45349,7 +45433,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0168</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45361,7 +45445,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x016c</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45373,7 +45457,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0170</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45385,7 +45469,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0174</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45397,7 +45481,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x0178</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
@@ -45409,7 +45493,7 @@
           <resetValue>0x00000000</resetValue>
         </register>
         <register>
-          <access>read-only</access>
+          <access>read-write</access>
           <addressOffset>0x017c</addressOffset>
           <description>Reading from a spinlock address will:\n
             - Return 0 if lock is already locked\n
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/adc.h b/src/rp2040/hardware_structs/include/hardware/structs/adc.h
index 559b5f1..c47e9d4 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/adc.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/adc.h
@@ -1,27 +1,90 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
+
 #ifndef _HARDWARE_STRUCTS_ADC_H
 #define _HARDWARE_STRUCTS_ADC_H
 
 #include "hardware/address_mapped.h"
 #include "hardware/regs/adc.h"
 
-typedef struct {
-    io_rw_32 cs;
-    io_rw_32 result;
-    io_rw_32 fcs;
-    io_rw_32 fifo;
-    io_rw_32 div;
-    io_rw_32 intr;
-    io_rw_32 inte;
-    io_rw_32 intf;
-    io_rw_32 ints;
-} adc_hw_t;
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_adc
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/adc.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
 
-check_hw_layout(adc_hw_t, ints, ADC_INTS_OFFSET);
+typedef struct {
+    _REG_(ADC_CS_OFFSET) // ADC_CS
+    // ADC Control and Status
+    // 0x001f0000 [20:16] : RROBIN (0): Round-robin sampling
+    // 0x00007000 [14:12] : AINSEL (0): Select analog mux input
+    // 0x00000400 [10]    : ERR_STICKY (0): Some past ADC conversion encountered an error
+    // 0x00000200 [9]     : ERR (0): The most recent ADC conversion encountered an error; result is undefined or noisy
+    // 0x00000100 [8]     : READY (0): 1 if the ADC is ready to start a new conversion
+    // 0x00000008 [3]     : START_MANY (0): Continuously perform conversions whilst this bit is 1
+    // 0x00000004 [2]     : START_ONCE (0): Start a single conversion
+    // 0x00000002 [1]     : TS_EN (0): Power on temperature sensor
+    // 0x00000001 [0]     : EN (0): Power on ADC and enable its clock
+    io_rw_32 cs;
+
+    _REG_(ADC_RESULT_OFFSET) // ADC_RESULT
+    // Result of most recent ADC conversion
+    // 0x00000fff [11:0]  : RESULT (0)
+    io_ro_32 result;
+
+    _REG_(ADC_FCS_OFFSET) // ADC_FCS
+    // FIFO control and status
+    // 0x0f000000 [27:24] : THRESH (0): DREQ/IRQ asserted when level >= threshold
+    // 0x000f0000 [19:16] : LEVEL (0): The number of conversion results currently waiting in the FIFO
+    // 0x00000800 [11]    : OVER (0): 1 if the FIFO has been overflowed
+    // 0x00000400 [10]    : UNDER (0): 1 if the FIFO has been underflowed
+    // 0x00000200 [9]     : FULL (0)
+    // 0x00000100 [8]     : EMPTY (0)
+    // 0x00000008 [3]     : DREQ_EN (0): If 1: assert DMA requests when FIFO contains data
+    // 0x00000004 [2]     : ERR (0): If 1: conversion error bit appears in the FIFO alongside the result
+    // 0x00000002 [1]     : SHIFT (0): If 1: FIFO results are right-shifted to be one byte in size
+    // 0x00000001 [0]     : EN (0): If 1: write result to the FIFO after each conversion
+    io_rw_32 fcs;
+
+    _REG_(ADC_FIFO_OFFSET) // ADC_FIFO
+    // Conversion result FIFO
+    // 0x00008000 [15]    : ERR (0): 1 if this particular sample experienced a conversion error
+    // 0x00000fff [11:0]  : VAL (0)
+    io_ro_32 fifo;
+
+    _REG_(ADC_DIV_OFFSET) // ADC_DIV
+    // Clock divider
+    // 0x00ffff00 [23:8]  : INT (0): Integer part of clock divisor
+    // 0x000000ff [7:0]   : FRAC (0): Fractional part of clock divisor
+    io_rw_32 div;
+
+    _REG_(ADC_INTR_OFFSET) // ADC_INTR
+    // Raw Interrupts
+    // 0x00000001 [0]     : FIFO (0): Triggered when the sample FIFO reaches a certain level
+    io_ro_32 intr;
+
+    _REG_(ADC_INTE_OFFSET) // ADC_INTE
+    // Interrupt Enable
+    // 0x00000001 [0]     : FIFO (0): Triggered when the sample FIFO reaches a certain level
+    io_rw_32 inte;
+
+    _REG_(ADC_INTF_OFFSET) // ADC_INTF
+    // Interrupt Force
+    // 0x00000001 [0]     : FIFO (0): Triggered when the sample FIFO reaches a certain level
+    io_rw_32 intf;
+
+    _REG_(ADC_INTS_OFFSET) // ADC_INTS
+    // Interrupt status after masking & forcing
+    // 0x00000001 [0]     : FIFO (0): Triggered when the sample FIFO reaches a certain level
+    io_ro_32 ints;
+} adc_hw_t;
 
 #define adc_hw ((adc_hw_t *const)ADC_BASE)
 
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/bus_ctrl.h b/src/rp2040/hardware_structs/include/hardware/structs/bus_ctrl.h
index ce95a7c..81118a8 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/bus_ctrl.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/bus_ctrl.h
@@ -1,14 +1,25 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
+
 #ifndef _HARDWARE_STRUCTS_BUS_CTRL_H
 #define _HARDWARE_STRUCTS_BUS_CTRL_H
 
 #include "hardware/address_mapped.h"
 #include "hardware/regs/busctrl.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_busctrl
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/busctrl.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 enum bus_ctrl_perf_counter {
     arbiter_rom_perf_event_access = 19,
     arbiter_rom_perf_event_access_contested = 18,
@@ -33,15 +44,33 @@
 };
 
 typedef struct {
-    io_rw_32 priority;
-    io_ro_32 priority_ack;
-    struct {
-        io_rw_32 value;
-        io_rw_32 sel;
-    } counter[4];
-} bus_ctrl_hw_t;
+    _REG_(BUSCTRL_PERFCTR0_OFFSET) // BUSCTRL_PERFCTR0
+    // Bus fabric performance counter 0
+    // 0x00ffffff [23:0]  : PERFCTR0 (0): Busfabric saturating performance counter 0
+    io_rw_32 value;
 
-check_hw_layout(bus_ctrl_hw_t, counter[0].value, BUSCTRL_PERFCTR0_OFFSET);
+    _REG_(BUSCTRL_PERFSEL0_OFFSET) // BUSCTRL_PERFSEL0
+    // Bus fabric performance event select for PERFCTR0
+    // 0x0000001f [4:0]   : PERFSEL0 (0x1f): Select an event for PERFCTR0
+    io_rw_32 sel;
+} bus_ctrl_perf_hw_t;
+
+typedef struct {
+    _REG_(BUSCTRL_BUS_PRIORITY_OFFSET) // BUSCTRL_BUS_PRIORITY
+    // Set the priority of each master for bus arbitration
+    // 0x00001000 [12]    : DMA_W (0): 0 - low priority, 1 - high priority
+    // 0x00000100 [8]     : DMA_R (0): 0 - low priority, 1 - high priority
+    // 0x00000010 [4]     : PROC1 (0): 0 - low priority, 1 - high priority
+    // 0x00000001 [0]     : PROC0 (0): 0 - low priority, 1 - high priority
+    io_rw_32 priority;
+
+    _REG_(BUSCTRL_BUS_PRIORITY_ACK_OFFSET) // BUSCTRL_BUS_PRIORITY_ACK
+    // Bus priority acknowledge
+    // 0x00000001 [0]     : BUS_PRIORITY_ACK (0): Goes to 1 once all arbiters have registered the new global priority levels
+    io_ro_32 priority_ack;
+
+    bus_ctrl_perf_hw_t counter[4];
+} bus_ctrl_hw_t;
 
 #define bus_ctrl_hw ((bus_ctrl_hw_t *const)BUSCTRL_BASE)
 
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/clocks.h b/src/rp2040/hardware_structs/include/hardware/structs/clocks.h
index 489876d..a245dbd 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/clocks.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/clocks.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,9 +10,16 @@
 #define _HARDWARE_STRUCTS_CLOCKS_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/clocks.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_clocks
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/clocks.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 /*! \brief Enumeration identifying a hardware clock
  *  \ingroup hardware_clocks
  */
@@ -32,41 +41,286 @@
 
 /// \tag::clock_hw[]
 typedef struct {
+    _REG_(CLOCKS_CLK_GPOUT0_CTRL_OFFSET) // CLOCKS_CLK_GPOUT0_CTRL
+    // Clock control, can be changed on-the-fly (except for auxsrc)
+    // 0x00100000 [20]    : NUDGE (0): An edge on this signal shifts the phase of the output by 1 cycle of the input clock
+    // 0x00030000 [17:16] : PHASE (0): This delays the enable signal by up to 3 cycles of the input clock
+    // 0x00001000 [12]    : DC50 (0): Enables duty cycle correction for odd divisors
+    // 0x00000800 [11]    : ENABLE (0): Starts and stops the clock generator cleanly
+    // 0x00000400 [10]    : KILL (0): Asynchronously kills the clock generator
+    // 0x000001e0 [8:5]   : AUXSRC (0): Selects the auxiliary clock source, will glitch when switching
     io_rw_32 ctrl;
+
+    _REG_(CLOCKS_CLK_GPOUT0_DIV_OFFSET) // CLOCKS_CLK_GPOUT0_DIV
+    // Clock divisor, can be changed on-the-fly
+    // 0xffffff00 [31:8]  : INT (1): Integer component of the divisor, 0 -> divide by 2^16
+    // 0x000000ff [7:0]   : FRAC (0): Fractional component of the divisor
     io_rw_32 div;
-    io_rw_32 selected;
+
+    _REG_(CLOCKS_CLK_GPOUT0_SELECTED_OFFSET) // CLOCKS_CLK_GPOUT0_SELECTED
+    // Indicates which SRC is currently selected by the glitchless mux (one-hot)
+    io_ro_32 selected;
 } clock_hw_t;
 /// \end::clock_hw[]
 
 typedef struct {
-    io_rw_32 ref_khz;
-    io_rw_32 min_khz;
-    io_rw_32 max_khz;
-    io_rw_32 delay;
-    io_rw_32 interval;
-    io_rw_32 src;
+    _REG_(CLOCKS_CLK_SYS_RESUS_CTRL_OFFSET) // CLOCKS_CLK_SYS_RESUS_CTRL
+    // 0x00010000 [16]    : CLEAR (0): For clearing the resus after the fault that triggered it has been corrected
+    // 0x00001000 [12]    : FRCE (0): Force a resus, for test purposes only
+    // 0x00000100 [8]     : ENABLE (0): Enable resus
+    // 0x000000ff [7:0]   : TIMEOUT (0xff): This is expressed as a number of clk_ref cycles
+    io_rw_32 ctrl;
+
+    _REG_(CLOCKS_CLK_SYS_RESUS_STATUS_OFFSET) // CLOCKS_CLK_SYS_RESUS_STATUS
+    // 0x00000001 [0]     : RESUSSED (0): Clock has been resuscitated, correct the error then send ctrl_clear=1
     io_ro_32 status;
+} clock_resus_hw_t;
+
+typedef struct {
+    _REG_(CLOCKS_FC0_REF_KHZ_OFFSET) // CLOCKS_FC0_REF_KHZ
+    // Reference clock frequency in kHz
+    // 0x000fffff [19:0]  : FC0_REF_KHZ (0)
+    io_rw_32 ref_khz;
+
+    _REG_(CLOCKS_FC0_MIN_KHZ_OFFSET) // CLOCKS_FC0_MIN_KHZ
+    // Minimum pass frequency in kHz
+    // 0x01ffffff [24:0]  : FC0_MIN_KHZ (0)
+    io_rw_32 min_khz;
+
+    _REG_(CLOCKS_FC0_MAX_KHZ_OFFSET) // CLOCKS_FC0_MAX_KHZ
+    // Maximum pass frequency in kHz
+    // 0x01ffffff [24:0]  : FC0_MAX_KHZ (0x1ffffff)
+    io_rw_32 max_khz;
+
+    _REG_(CLOCKS_FC0_DELAY_OFFSET) // CLOCKS_FC0_DELAY
+    // Delays the start of frequency counting to allow the mux to settle
+    // 0x00000007 [2:0]   : FC0_DELAY (1)
+    io_rw_32 delay;
+
+    _REG_(CLOCKS_FC0_INTERVAL_OFFSET) // CLOCKS_FC0_INTERVAL
+    // The test interval is 0
+    // 0x0000000f [3:0]   : FC0_INTERVAL (0x8)
+    io_rw_32 interval;
+
+    _REG_(CLOCKS_FC0_SRC_OFFSET) // CLOCKS_FC0_SRC
+    // Clock sent to frequency counter, set to 0 when not required
+    // 0x000000ff [7:0]   : FC0_SRC (0)
+    io_rw_32 src;
+
+    _REG_(CLOCKS_FC0_STATUS_OFFSET) // CLOCKS_FC0_STATUS
+    // Frequency counter status
+    // 0x10000000 [28]    : DIED (0): Test clock stopped during test
+    // 0x01000000 [24]    : FAST (0): Test clock faster than expected, only valid when status_done=1
+    // 0x00100000 [20]    : SLOW (0): Test clock slower than expected, only valid when status_done=1
+    // 0x00010000 [16]    : FAIL (0): Test failed
+    // 0x00001000 [12]    : WAITING (0): Waiting for test clock to start
+    // 0x00000100 [8]     : RUNNING (0): Test running
+    // 0x00000010 [4]     : DONE (0): Test complete
+    // 0x00000001 [0]     : PASS (0): Test passed
+    io_ro_32 status;
+
+    _REG_(CLOCKS_FC0_RESULT_OFFSET) // CLOCKS_FC0_RESULT
+    // Result of frequency measurement, only valid when status_done=1
+    // 0x3fffffe0 [29:5]  : KHZ (0)
+    // 0x0000001f [4:0]   : FRAC (0)
     io_ro_32 result;
 } fc_hw_t;
 
 typedef struct {
-    clock_hw_t clk[CLK_COUNT];
-    struct {
-        io_rw_32 ctrl;
-        io_rw_32 status;
-    } resus;
+    clock_hw_t clk[CLK_COUNT]; // 10
+
+    clock_resus_hw_t resus;
+
     fc_hw_t fc0;
+
+    _REG_(CLOCKS_WAKE_EN0_OFFSET) // CLOCKS_WAKE_EN0
+    // enable clock in wake mode
+    // 0x80000000 [31]    : clk_sys_sram3 (1)
+    // 0x40000000 [30]    : clk_sys_sram2 (1)
+    // 0x20000000 [29]    : clk_sys_sram1 (1)
+    // 0x10000000 [28]    : clk_sys_sram0 (1)
+    // 0x08000000 [27]    : clk_sys_spi1 (1)
+    // 0x04000000 [26]    : clk_peri_spi1 (1)
+    // 0x02000000 [25]    : clk_sys_spi0 (1)
+    // 0x01000000 [24]    : clk_peri_spi0 (1)
+    // 0x00800000 [23]    : clk_sys_sio (1)
+    // 0x00400000 [22]    : clk_sys_rtc (1)
+    // 0x00200000 [21]    : clk_rtc_rtc (1)
+    // 0x00100000 [20]    : clk_sys_rosc (1)
+    // 0x00080000 [19]    : clk_sys_rom (1)
+    // 0x00040000 [18]    : clk_sys_resets (1)
+    // 0x00020000 [17]    : clk_sys_pwm (1)
+    // 0x00010000 [16]    : clk_sys_psm (1)
+    // 0x00008000 [15]    : clk_sys_pll_usb (1)
+    // 0x00004000 [14]    : clk_sys_pll_sys (1)
+    // 0x00002000 [13]    : clk_sys_pio1 (1)
+    // 0x00001000 [12]    : clk_sys_pio0 (1)
+    // 0x00000800 [11]    : clk_sys_pads (1)
+    // 0x00000400 [10]    : clk_sys_vreg_and_chip_reset (1)
+    // 0x00000200 [9]     : clk_sys_jtag (1)
+    // 0x00000100 [8]     : clk_sys_io (1)
+    // 0x00000080 [7]     : clk_sys_i2c1 (1)
+    // 0x00000040 [6]     : clk_sys_i2c0 (1)
+    // 0x00000020 [5]     : clk_sys_dma (1)
+    // 0x00000010 [4]     : clk_sys_busfabric (1)
+    // 0x00000008 [3]     : clk_sys_busctrl (1)
+    // 0x00000004 [2]     : clk_sys_adc (1)
+    // 0x00000002 [1]     : clk_adc_adc (1)
+    // 0x00000001 [0]     : clk_sys_clocks (1)
     io_rw_32 wake_en0;
+
+    _REG_(CLOCKS_WAKE_EN1_OFFSET) // CLOCKS_WAKE_EN1
+    // enable clock in wake mode
+    // 0x00004000 [14]    : clk_sys_xosc (1)
+    // 0x00002000 [13]    : clk_sys_xip (1)
+    // 0x00001000 [12]    : clk_sys_watchdog (1)
+    // 0x00000800 [11]    : clk_usb_usbctrl (1)
+    // 0x00000400 [10]    : clk_sys_usbctrl (1)
+    // 0x00000200 [9]     : clk_sys_uart1 (1)
+    // 0x00000100 [8]     : clk_peri_uart1 (1)
+    // 0x00000080 [7]     : clk_sys_uart0 (1)
+    // 0x00000040 [6]     : clk_peri_uart0 (1)
+    // 0x00000020 [5]     : clk_sys_timer (1)
+    // 0x00000010 [4]     : clk_sys_tbman (1)
+    // 0x00000008 [3]     : clk_sys_sysinfo (1)
+    // 0x00000004 [2]     : clk_sys_syscfg (1)
+    // 0x00000002 [1]     : clk_sys_sram5 (1)
+    // 0x00000001 [0]     : clk_sys_sram4 (1)
     io_rw_32 wake_en1;
+
+    _REG_(CLOCKS_SLEEP_EN0_OFFSET) // CLOCKS_SLEEP_EN0
+    // enable clock in sleep mode
+    // 0x80000000 [31]    : clk_sys_sram3 (1)
+    // 0x40000000 [30]    : clk_sys_sram2 (1)
+    // 0x20000000 [29]    : clk_sys_sram1 (1)
+    // 0x10000000 [28]    : clk_sys_sram0 (1)
+    // 0x08000000 [27]    : clk_sys_spi1 (1)
+    // 0x04000000 [26]    : clk_peri_spi1 (1)
+    // 0x02000000 [25]    : clk_sys_spi0 (1)
+    // 0x01000000 [24]    : clk_peri_spi0 (1)
+    // 0x00800000 [23]    : clk_sys_sio (1)
+    // 0x00400000 [22]    : clk_sys_rtc (1)
+    // 0x00200000 [21]    : clk_rtc_rtc (1)
+    // 0x00100000 [20]    : clk_sys_rosc (1)
+    // 0x00080000 [19]    : clk_sys_rom (1)
+    // 0x00040000 [18]    : clk_sys_resets (1)
+    // 0x00020000 [17]    : clk_sys_pwm (1)
+    // 0x00010000 [16]    : clk_sys_psm (1)
+    // 0x00008000 [15]    : clk_sys_pll_usb (1)
+    // 0x00004000 [14]    : clk_sys_pll_sys (1)
+    // 0x00002000 [13]    : clk_sys_pio1 (1)
+    // 0x00001000 [12]    : clk_sys_pio0 (1)
+    // 0x00000800 [11]    : clk_sys_pads (1)
+    // 0x00000400 [10]    : clk_sys_vreg_and_chip_reset (1)
+    // 0x00000200 [9]     : clk_sys_jtag (1)
+    // 0x00000100 [8]     : clk_sys_io (1)
+    // 0x00000080 [7]     : clk_sys_i2c1 (1)
+    // 0x00000040 [6]     : clk_sys_i2c0 (1)
+    // 0x00000020 [5]     : clk_sys_dma (1)
+    // 0x00000010 [4]     : clk_sys_busfabric (1)
+    // 0x00000008 [3]     : clk_sys_busctrl (1)
+    // 0x00000004 [2]     : clk_sys_adc (1)
+    // 0x00000002 [1]     : clk_adc_adc (1)
+    // 0x00000001 [0]     : clk_sys_clocks (1)
     io_rw_32 sleep_en0;
+
+    _REG_(CLOCKS_SLEEP_EN1_OFFSET) // CLOCKS_SLEEP_EN1
+    // enable clock in sleep mode
+    // 0x00004000 [14]    : clk_sys_xosc (1)
+    // 0x00002000 [13]    : clk_sys_xip (1)
+    // 0x00001000 [12]    : clk_sys_watchdog (1)
+    // 0x00000800 [11]    : clk_usb_usbctrl (1)
+    // 0x00000400 [10]    : clk_sys_usbctrl (1)
+    // 0x00000200 [9]     : clk_sys_uart1 (1)
+    // 0x00000100 [8]     : clk_peri_uart1 (1)
+    // 0x00000080 [7]     : clk_sys_uart0 (1)
+    // 0x00000040 [6]     : clk_peri_uart0 (1)
+    // 0x00000020 [5]     : clk_sys_timer (1)
+    // 0x00000010 [4]     : clk_sys_tbman (1)
+    // 0x00000008 [3]     : clk_sys_sysinfo (1)
+    // 0x00000004 [2]     : clk_sys_syscfg (1)
+    // 0x00000002 [1]     : clk_sys_sram5 (1)
+    // 0x00000001 [0]     : clk_sys_sram4 (1)
     io_rw_32 sleep_en1;
-    io_rw_32 enabled0;
-    io_rw_32 enabled1;
-    io_rw_32 intr;
+
+    _REG_(CLOCKS_ENABLED0_OFFSET) // CLOCKS_ENABLED0
+    // indicates the state of the clock enable
+    // 0x80000000 [31]    : clk_sys_sram3 (0)
+    // 0x40000000 [30]    : clk_sys_sram2 (0)
+    // 0x20000000 [29]    : clk_sys_sram1 (0)
+    // 0x10000000 [28]    : clk_sys_sram0 (0)
+    // 0x08000000 [27]    : clk_sys_spi1 (0)
+    // 0x04000000 [26]    : clk_peri_spi1 (0)
+    // 0x02000000 [25]    : clk_sys_spi0 (0)
+    // 0x01000000 [24]    : clk_peri_spi0 (0)
+    // 0x00800000 [23]    : clk_sys_sio (0)
+    // 0x00400000 [22]    : clk_sys_rtc (0)
+    // 0x00200000 [21]    : clk_rtc_rtc (0)
+    // 0x00100000 [20]    : clk_sys_rosc (0)
+    // 0x00080000 [19]    : clk_sys_rom (0)
+    // 0x00040000 [18]    : clk_sys_resets (0)
+    // 0x00020000 [17]    : clk_sys_pwm (0)
+    // 0x00010000 [16]    : clk_sys_psm (0)
+    // 0x00008000 [15]    : clk_sys_pll_usb (0)
+    // 0x00004000 [14]    : clk_sys_pll_sys (0)
+    // 0x00002000 [13]    : clk_sys_pio1 (0)
+    // 0x00001000 [12]    : clk_sys_pio0 (0)
+    // 0x00000800 [11]    : clk_sys_pads (0)
+    // 0x00000400 [10]    : clk_sys_vreg_and_chip_reset (0)
+    // 0x00000200 [9]     : clk_sys_jtag (0)
+    // 0x00000100 [8]     : clk_sys_io (0)
+    // 0x00000080 [7]     : clk_sys_i2c1 (0)
+    // 0x00000040 [6]     : clk_sys_i2c0 (0)
+    // 0x00000020 [5]     : clk_sys_dma (0)
+    // 0x00000010 [4]     : clk_sys_busfabric (0)
+    // 0x00000008 [3]     : clk_sys_busctrl (0)
+    // 0x00000004 [2]     : clk_sys_adc (0)
+    // 0x00000002 [1]     : clk_adc_adc (0)
+    // 0x00000001 [0]     : clk_sys_clocks (0)
+    io_ro_32 enabled0;
+
+    _REG_(CLOCKS_ENABLED1_OFFSET) // CLOCKS_ENABLED1
+    // indicates the state of the clock enable
+    // 0x00004000 [14]    : clk_sys_xosc (0)
+    // 0x00002000 [13]    : clk_sys_xip (0)
+    // 0x00001000 [12]    : clk_sys_watchdog (0)
+    // 0x00000800 [11]    : clk_usb_usbctrl (0)
+    // 0x00000400 [10]    : clk_sys_usbctrl (0)
+    // 0x00000200 [9]     : clk_sys_uart1 (0)
+    // 0x00000100 [8]     : clk_peri_uart1 (0)
+    // 0x00000080 [7]     : clk_sys_uart0 (0)
+    // 0x00000040 [6]     : clk_peri_uart0 (0)
+    // 0x00000020 [5]     : clk_sys_timer (0)
+    // 0x00000010 [4]     : clk_sys_tbman (0)
+    // 0x00000008 [3]     : clk_sys_sysinfo (0)
+    // 0x00000004 [2]     : clk_sys_syscfg (0)
+    // 0x00000002 [1]     : clk_sys_sram5 (0)
+    // 0x00000001 [0]     : clk_sys_sram4 (0)
+    io_ro_32 enabled1;
+
+    _REG_(CLOCKS_INTR_OFFSET) // CLOCKS_INTR
+    // Raw Interrupts
+    // 0x00000001 [0]     : CLK_SYS_RESUS (0)
+    io_ro_32 intr;
+
+    _REG_(CLOCKS_INTE_OFFSET) // CLOCKS_INTE
+    // Interrupt Enable
+    // 0x00000001 [0]     : CLK_SYS_RESUS (0)
     io_rw_32 inte;
+
+    _REG_(CLOCKS_INTF_OFFSET) // CLOCKS_INTF
+    // Interrupt Force
+    // 0x00000001 [0]     : CLK_SYS_RESUS (0)
     io_rw_32 intf;
-    io_rw_32 ints;
+
+    _REG_(CLOCKS_INTS_OFFSET) // CLOCKS_INTS
+    // Interrupt status after masking & forcing
+    // 0x00000001 [0]     : CLK_SYS_RESUS (0)
+    io_ro_32 ints;
 } clocks_hw_t;
 
 #define clocks_hw ((clocks_hw_t *const)CLOCKS_BASE)
+
+static_assert( CLK_COUNT == 10, "");
+
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/dma.h b/src/rp2040/hardware_structs/include/hardware/structs/dma.h
index 06cdf79..0d20641 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/dma.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/dma.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,51 +10,185 @@
 #define _HARDWARE_STRUCTS_DMA_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/dma.h"
 
-typedef struct {
-    io_rw_32 read_addr;
-    io_rw_32 write_addr;
-    io_rw_32 transfer_count;
-    io_rw_32 ctrl_trig;
-    io_rw_32 al1_ctrl;
-    io_rw_32 al1_read_addr;
-    io_rw_32 al1_write_addr;
-    io_rw_32 al1_transfer_count_trig;
-    io_rw_32 al2_ctrl;
-    io_rw_32 al2_transfer_count;
-    io_rw_32 al2_read_addr;
-    io_rw_32 al2_write_addr_trig;
-    io_rw_32 al3_ctrl;
-    io_rw_32 al3_write_addr;
-    io_rw_32 al3_transfer_count;
-    io_rw_32 al3_read_addr_trig;
-}  dma_channel_hw_t;
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_dma
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/dma.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
 
 typedef struct {
-    dma_channel_hw_t ch[NUM_DMA_CHANNELS];
-    uint32_t _pad0[16 * (16 - NUM_DMA_CHANNELS)];
+    _REG_(DMA_CH0_READ_ADDR_OFFSET) // DMA_CH0_READ_ADDR
+    // DMA Channel 0 Read Address pointer
+    io_rw_32 read_addr;
+
+    _REG_(DMA_CH0_WRITE_ADDR_OFFSET) // DMA_CH0_WRITE_ADDR
+    // DMA Channel 0 Write Address pointer
+    io_rw_32 write_addr;
+
+    _REG_(DMA_CH0_TRANS_COUNT_OFFSET) // DMA_CH0_TRANS_COUNT
+    // DMA Channel 0 Transfer Count
+    io_rw_32 transfer_count;
+
+    _REG_(DMA_CH0_CTRL_TRIG_OFFSET) // DMA_CH0_CTRL_TRIG
+    // DMA Channel 0 Control and Status
+    // 0x80000000 [31]    : AHB_ERROR (0): Logical OR of the READ_ERROR and WRITE_ERROR flags
+    // 0x40000000 [30]    : READ_ERROR (0): If 1, the channel received a read bus error
+    // 0x20000000 [29]    : WRITE_ERROR (0): If 1, the channel received a write bus error
+    // 0x01000000 [24]    : BUSY (0): This flag goes high when the channel starts a new transfer sequence, and low when the...
+    // 0x00800000 [23]    : SNIFF_EN (0): If 1, this channel's data transfers are visible to the sniff hardware, and each...
+    // 0x00400000 [22]    : BSWAP (0): Apply byte-swap transformation to DMA data
+    // 0x00200000 [21]    : IRQ_QUIET (0): In QUIET mode, the channel does not generate IRQs at the end of every transfer block
+    // 0x001f8000 [20:15] : TREQ_SEL (0): Select a Transfer Request signal
+    // 0x00007800 [14:11] : CHAIN_TO (0): When this channel completes, it will trigger the channel indicated by CHAIN_TO
+    // 0x00000400 [10]    : RING_SEL (0): Select whether RING_SIZE applies to read or write addresses
+    // 0x000003c0 [9:6]   : RING_SIZE (0): Size of address wrap region
+    // 0x00000020 [5]     : INCR_WRITE (0): If 1, the write address increments with each transfer
+    // 0x00000010 [4]     : INCR_READ (0): If 1, the read address increments with each transfer
+    // 0x0000000c [3:2]   : DATA_SIZE (0): Set the size of each bus transfer (byte/halfword/word)
+    // 0x00000002 [1]     : HIGH_PRIORITY (0): HIGH_PRIORITY gives a channel preferential treatment in issue scheduling: in...
+    // 0x00000001 [0]     : EN (0): DMA Channel Enable
+    io_rw_32 ctrl_trig;
+
+    _REG_(DMA_CH0_AL1_CTRL_OFFSET) // DMA_CH0_AL1_CTRL
+    // Alias for channel 0 CTRL register
+    io_rw_32 al1_ctrl;
+
+    _REG_(DMA_CH0_AL1_READ_ADDR_OFFSET) // DMA_CH0_AL1_READ_ADDR
+    // Alias for channel 0 READ_ADDR register
+    io_rw_32 al1_read_addr;
+
+    _REG_(DMA_CH0_AL1_WRITE_ADDR_OFFSET) // DMA_CH0_AL1_WRITE_ADDR
+    // Alias for channel 0 WRITE_ADDR register
+    io_rw_32 al1_write_addr;
+
+    _REG_(DMA_CH0_AL1_TRANS_COUNT_TRIG_OFFSET) // DMA_CH0_AL1_TRANS_COUNT_TRIG
+    // Alias for channel 0 TRANS_COUNT register
+    io_rw_32 al1_transfer_count_trig;
+
+    _REG_(DMA_CH0_AL2_CTRL_OFFSET) // DMA_CH0_AL2_CTRL
+    // Alias for channel 0 CTRL register
+    io_rw_32 al2_ctrl;
+
+    _REG_(DMA_CH0_AL2_TRANS_COUNT_OFFSET) // DMA_CH0_AL2_TRANS_COUNT
+    // Alias for channel 0 TRANS_COUNT register
+    io_rw_32 al2_transfer_count;
+
+    _REG_(DMA_CH0_AL2_READ_ADDR_OFFSET) // DMA_CH0_AL2_READ_ADDR
+    // Alias for channel 0 READ_ADDR register
+    io_rw_32 al2_read_addr;
+
+    _REG_(DMA_CH0_AL2_WRITE_ADDR_TRIG_OFFSET) // DMA_CH0_AL2_WRITE_ADDR_TRIG
+    // Alias for channel 0 WRITE_ADDR register
+    io_rw_32 al2_write_addr_trig;
+
+    _REG_(DMA_CH0_AL3_CTRL_OFFSET) // DMA_CH0_AL3_CTRL
+    // Alias for channel 0 CTRL register
+    io_rw_32 al3_ctrl;
+
+    _REG_(DMA_CH0_AL3_WRITE_ADDR_OFFSET) // DMA_CH0_AL3_WRITE_ADDR
+    // Alias for channel 0 WRITE_ADDR register
+    io_rw_32 al3_write_addr;
+
+    _REG_(DMA_CH0_AL3_TRANS_COUNT_OFFSET) // DMA_CH0_AL3_TRANS_COUNT
+    // Alias for channel 0 TRANS_COUNT register
+    io_rw_32 al3_transfer_count;
+
+    _REG_(DMA_CH0_AL3_READ_ADDR_TRIG_OFFSET) // DMA_CH0_AL3_READ_ADDR_TRIG
+    // Alias for channel 0 READ_ADDR register
+    io_rw_32 al3_read_addr_trig;
+} dma_channel_hw_t;
+
+typedef struct {
+    dma_channel_hw_t ch[NUM_DMA_CHANNELS]; // 12
+
+    uint32_t _pad0[64];
+
+    _REG_(DMA_INTR_OFFSET) // DMA_INTR
+    // Interrupt Status (raw)
+    // 0x0000ffff [15:0]  : INTR (0): Raw interrupt status for DMA Channels 0
     io_ro_32 intr;
+
+    _REG_(DMA_INTE0_OFFSET) // DMA_INTE0
+    // Interrupt Enables for IRQ 0
+    // 0x0000ffff [15:0]  : INTE0 (0): Set bit n to pass interrupts from channel n to DMA IRQ 0
     io_rw_32 inte0;
+
+    _REG_(DMA_INTF0_OFFSET) // DMA_INTF0
+    // Force Interrupts
+    // 0x0000ffff [15:0]  : INTF0 (0): Write 1s to force the corresponding bits in INTE0
     io_rw_32 intf0;
+
+    _REG_(DMA_INTS0_OFFSET) // DMA_INTS0
+    // Interrupt Status for IRQ 0
+    // 0x0000ffff [15:0]  : INTS0 (0): Indicates active channel interrupt requests which are currently causing IRQ 0 to be asserted
     io_rw_32 ints0;
-    uint32_t _pad1[1];
+
+    uint32_t _pad1;
+
+    _REG_(DMA_INTE1_OFFSET) // DMA_INTE1
+    // Interrupt Enables for IRQ 1
+    // 0x0000ffff [15:0]  : INTE1 (0): Set bit n to pass interrupts from channel n to DMA IRQ 1
     io_rw_32 inte1;
+
+    _REG_(DMA_INTF1_OFFSET) // DMA_INTF1
+    // Force Interrupts for IRQ 1
+    // 0x0000ffff [15:0]  : INTF1 (0): Write 1s to force the corresponding bits in INTE0
     io_rw_32 intf1;
+
+    _REG_(DMA_INTS1_OFFSET) // DMA_INTS1
+    // Interrupt Status (masked) for IRQ 1
+    // 0x0000ffff [15:0]  : INTS1 (0): Indicates active channel interrupt requests which are currently causing IRQ 1 to be asserted
     io_rw_32 ints1;
-    io_rw_32 timer[4];
-    io_wo_32 multi_channel_trigger;
+
+    _REG_(DMA_TIMER0_OFFSET) // DMA_TIMER0
+    // (Description copied from array index 0 register DMA_TIMER0 applies similarly to other array indexes)
+    //
+    // Pacing (X/Y) Fractional Timer
+    // 0xffff0000 [31:16] : X (0): Pacing Timer Dividend
+    // 0x0000ffff [15:0]  : Y (0): Pacing Timer Divisor
+    io_rw_32 timer[NUM_DMA_TIMERS]; // 4
+
+    _REG_(DMA_MULTI_CHAN_TRIGGER_OFFSET) // DMA_MULTI_CHAN_TRIGGER
+    // Trigger one or more channels simultaneously
+    // 0x0000ffff [15:0]  : MULTI_CHAN_TRIGGER (0): Each bit in this register corresponds to a DMA channel
+    io_rw_32 multi_channel_trigger;
+
+    _REG_(DMA_SNIFF_CTRL_OFFSET) // DMA_SNIFF_CTRL
+    // Sniffer Control
+    // 0x00000800 [11]    : OUT_INV (0): If set, the result appears inverted (bitwise complement) when read
+    // 0x00000400 [10]    : OUT_REV (0): If set, the result appears bit-reversed when read
+    // 0x00000200 [9]     : BSWAP (0): Locally perform a byte reverse on the sniffed data, before feeding into checksum
+    // 0x000001e0 [8:5]   : CALC (0)
+    // 0x0000001e [4:1]   : DMACH (0): DMA channel for Sniffer to observe
+    // 0x00000001 [0]     : EN (0): Enable sniffer
     io_rw_32 sniff_ctrl;
+
+    _REG_(DMA_SNIFF_DATA_OFFSET) // DMA_SNIFF_DATA
+    // Data accumulator for sniff hardware
     io_rw_32 sniff_data;
-    uint32_t _pad2[1];
+
+    uint32_t _pad2;
+
+    _REG_(DMA_FIFO_LEVELS_OFFSET) // DMA_FIFO_LEVELS
+    // Debug RAF, WAF, TDF levels
+    // 0x00ff0000 [23:16] : RAF_LVL (0): Current Read-Address-FIFO fill level
+    // 0x0000ff00 [15:8]  : WAF_LVL (0): Current Write-Address-FIFO fill level
+    // 0x000000ff [7:0]   : TDF_LVL (0): Current Transfer-Data-FIFO fill level
     io_ro_32 fifo_levels;
-    io_wo_32 abort;
+
+    _REG_(DMA_CHAN_ABORT_OFFSET) // DMA_CHAN_ABORT
+    // Abort an in-progress transfer sequence on one or more channels
+    // 0x0000ffff [15:0]  : CHAN_ABORT (0): Each bit corresponds to a channel
+    io_rw_32 abort;
 } dma_hw_t;
 
 typedef struct {
     struct dma_debug_hw_channel {
-        io_ro_32 ctrdeq;
+        io_rw_32 ctrdeq;
         io_ro_32 tcr;
         uint32_t pad[14];
     } ch[NUM_DMA_CHANNELS];
@@ -61,4 +197,7 @@
 #define dma_hw ((dma_hw_t *const)DMA_BASE)
 #define dma_debug_hw ((dma_debug_hw_t *const)(DMA_BASE + DMA_CH0_DBG_CTDREQ_OFFSET))
 
+static_assert( NUM_DMA_TIMERS == 4, "");
+static_assert( NUM_DMA_CHANNELS == 12, "");
+
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/i2c.h b/src/rp2040/hardware_structs/include/hardware/structs/i2c.h
index 1a58c50..43d6086 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/i2c.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/i2c.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,125 +12,322 @@
 #include "hardware/address_mapped.h"
 #include "hardware/regs/i2c.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_i2c
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/i2c.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(I2C_IC_CON_OFFSET) // I2C_IC_CON
+    // I2C Control Register
+    // 0x00000400 [10]    : STOP_DET_IF_MASTER_ACTIVE (0): Master issues the STOP_DET interrupt irrespective of whether...
+    // 0x00000200 [9]     : RX_FIFO_FULL_HLD_CTRL (0): This bit controls whether DW_apb_i2c should hold the bus when the Rx...
+    // 0x00000100 [8]     : TX_EMPTY_CTRL (0): This bit controls the generation of the TX_EMPTY interrupt, as described in...
+    // 0x00000080 [7]     : STOP_DET_IFADDRESSED (0): In slave mode: - 1'b1:  issues the STOP_DET interrupt only when it is...
+    // 0x00000040 [6]     : IC_SLAVE_DISABLE (1): This bit controls whether I2C has its slave disabled, which means once...
+    // 0x00000020 [5]     : IC_RESTART_EN (1): Determines whether RESTART conditions may be sent when acting as a master
+    // 0x00000010 [4]     : IC_10BITADDR_MASTER (0): Controls whether the DW_apb_i2c starts its transfers in 7- or 10-bit...
+    // 0x00000008 [3]     : IC_10BITADDR_SLAVE (0): When acting as a slave, this bit controls whether the DW_apb_i2c...
+    // 0x00000006 [2:1]   : SPEED (0x2): These bits control at which speed the DW_apb_i2c operates; its setting is relevant...
+    // 0x00000001 [0]     : MASTER_MODE (1): This bit controls whether the DW_apb_i2c master is enabled
     io_rw_32 con;
+
+    _REG_(I2C_IC_TAR_OFFSET) // I2C_IC_TAR
+    // I2C Target Address Register
+    // 0x00000800 [11]    : SPECIAL (0): This bit indicates whether software performs a Device-ID or General Call or START...
+    // 0x00000400 [10]    : GC_OR_START (0): If bit 11 (SPECIAL) is set to 1 and bit 13(Device-ID) is set to 0, then this...
+    // 0x000003ff [9:0]   : IC_TAR (0x55): This is the target address for any master transaction
     io_rw_32 tar;
+
+    _REG_(I2C_IC_SAR_OFFSET) // I2C_IC_SAR
+    // I2C Slave Address Register
+    // 0x000003ff [9:0]   : IC_SAR (0x55): The IC_SAR holds the slave address when the I2C is operating as a slave
     io_rw_32 sar;
+
     uint32_t _pad0;
+
+    _REG_(I2C_IC_DATA_CMD_OFFSET) // I2C_IC_DATA_CMD
+    // I2C Rx/Tx Data Buffer and Command Register; this is the register the CPU writes to when filling the TX FIFO and the...
+    // 0x00000800 [11]    : FIRST_DATA_BYTE (0): Indicates the first data byte received after the address phase for receive...
+    // 0x00000400 [10]    : RESTART (0): This bit controls whether a RESTART is issued before the byte is sent or received
+    // 0x00000200 [9]     : STOP (0): This bit controls whether a STOP is issued after the byte is sent or received
+    // 0x00000100 [8]     : CMD (0): This bit controls whether a read or a write is performed
+    // 0x000000ff [7:0]   : DAT (0): This register contains the data to be transmitted or received on the I2C bus
     io_rw_32 data_cmd;
+
+    _REG_(I2C_IC_SS_SCL_HCNT_OFFSET) // I2C_IC_SS_SCL_HCNT
+    // Standard Speed I2C Clock SCL High Count Register
+    // 0x0000ffff [15:0]  : IC_SS_SCL_HCNT (0x28): This register must be set before any I2C bus transaction can take place...
     io_rw_32 ss_scl_hcnt;
+
+    _REG_(I2C_IC_SS_SCL_LCNT_OFFSET) // I2C_IC_SS_SCL_LCNT
+    // Standard Speed I2C Clock SCL Low Count Register
+    // 0x0000ffff [15:0]  : IC_SS_SCL_LCNT (0x2f): This register must be set before any I2C bus transaction can take place...
     io_rw_32 ss_scl_lcnt;
+
+    _REG_(I2C_IC_FS_SCL_HCNT_OFFSET) // I2C_IC_FS_SCL_HCNT
+    // Fast Mode or Fast Mode Plus I2C Clock SCL High Count Register
+    // 0x0000ffff [15:0]  : IC_FS_SCL_HCNT (0x6): This register must be set before any I2C bus transaction can take place...
     io_rw_32 fs_scl_hcnt;
+
+    _REG_(I2C_IC_FS_SCL_LCNT_OFFSET) // I2C_IC_FS_SCL_LCNT
+    // Fast Mode or Fast Mode Plus I2C Clock SCL Low Count Register
+    // 0x0000ffff [15:0]  : IC_FS_SCL_LCNT (0xd): This register must be set before any I2C bus transaction can take place...
     io_rw_32 fs_scl_lcnt;
+
     uint32_t _pad1[2];
-    io_rw_32 intr_stat;
+
+    _REG_(I2C_IC_INTR_STAT_OFFSET) // I2C_IC_INTR_STAT
+    // I2C Interrupt Status Register
+    // 0x00001000 [12]    : R_RESTART_DET (0): See IC_RAW_INTR_STAT for a detailed description of R_RESTART_DET bit
+    // 0x00000800 [11]    : R_GEN_CALL (0): See IC_RAW_INTR_STAT for a detailed description of R_GEN_CALL bit
+    // 0x00000400 [10]    : R_START_DET (0): See IC_RAW_INTR_STAT for a detailed description of R_START_DET bit
+    // 0x00000200 [9]     : R_STOP_DET (0): See IC_RAW_INTR_STAT for a detailed description of R_STOP_DET bit
+    // 0x00000100 [8]     : R_ACTIVITY (0): See IC_RAW_INTR_STAT for a detailed description of R_ACTIVITY bit
+    // 0x00000080 [7]     : R_RX_DONE (0): See IC_RAW_INTR_STAT for a detailed description of R_RX_DONE bit
+    // 0x00000040 [6]     : R_TX_ABRT (0): See IC_RAW_INTR_STAT for a detailed description of R_TX_ABRT bit
+    // 0x00000020 [5]     : R_RD_REQ (0): See IC_RAW_INTR_STAT for a detailed description of R_RD_REQ bit
+    // 0x00000010 [4]     : R_TX_EMPTY (0): See IC_RAW_INTR_STAT for a detailed description of R_TX_EMPTY bit
+    // 0x00000008 [3]     : R_TX_OVER (0): See IC_RAW_INTR_STAT for a detailed description of R_TX_OVER bit
+    // 0x00000004 [2]     : R_RX_FULL (0): See IC_RAW_INTR_STAT for a detailed description of R_RX_FULL bit
+    // 0x00000002 [1]     : R_RX_OVER (0): See IC_RAW_INTR_STAT for a detailed description of R_RX_OVER bit
+    // 0x00000001 [0]     : R_RX_UNDER (0): See IC_RAW_INTR_STAT for a detailed description of R_RX_UNDER bit
+    io_ro_32 intr_stat;
+
+    _REG_(I2C_IC_INTR_MASK_OFFSET) // I2C_IC_INTR_MASK
+    // I2C Interrupt Mask Register
+    // 0x00001000 [12]    : M_RESTART_DET (0): This bit masks the R_RESTART_DET interrupt in IC_INTR_STAT register
+    // 0x00000800 [11]    : M_GEN_CALL (1): This bit masks the R_GEN_CALL interrupt in IC_INTR_STAT register
+    // 0x00000400 [10]    : M_START_DET (0): This bit masks the R_START_DET interrupt in IC_INTR_STAT register
+    // 0x00000200 [9]     : M_STOP_DET (0): This bit masks the R_STOP_DET interrupt in IC_INTR_STAT register
+    // 0x00000100 [8]     : M_ACTIVITY (0): This bit masks the R_ACTIVITY interrupt in IC_INTR_STAT register
+    // 0x00000080 [7]     : M_RX_DONE (1): This bit masks the R_RX_DONE interrupt in IC_INTR_STAT register
+    // 0x00000040 [6]     : M_TX_ABRT (1): This bit masks the R_TX_ABRT interrupt in IC_INTR_STAT register
+    // 0x00000020 [5]     : M_RD_REQ (1): This bit masks the R_RD_REQ interrupt in IC_INTR_STAT register
+    // 0x00000010 [4]     : M_TX_EMPTY (1): This bit masks the R_TX_EMPTY interrupt in IC_INTR_STAT register
+    // 0x00000008 [3]     : M_TX_OVER (1): This bit masks the R_TX_OVER interrupt in IC_INTR_STAT register
+    // 0x00000004 [2]     : M_RX_FULL (1): This bit masks the R_RX_FULL interrupt in IC_INTR_STAT register
+    // 0x00000002 [1]     : M_RX_OVER (1): This bit masks the R_RX_OVER interrupt in IC_INTR_STAT register
+    // 0x00000001 [0]     : M_RX_UNDER (1): This bit masks the R_RX_UNDER interrupt in IC_INTR_STAT register
     io_rw_32 intr_mask;
-    io_rw_32 raw_intr_stat;
+
+    _REG_(I2C_IC_RAW_INTR_STAT_OFFSET) // I2C_IC_RAW_INTR_STAT
+    // I2C Raw Interrupt Status Register
+    // 0x00001000 [12]    : RESTART_DET (0): Indicates whether a RESTART condition has occurred on the I2C interface when...
+    // 0x00000800 [11]    : GEN_CALL (0): Set only when a General Call address is received and it is acknowledged
+    // 0x00000400 [10]    : START_DET (0): Indicates whether a START or RESTART condition has occurred on the I2C interface...
+    // 0x00000200 [9]     : STOP_DET (0): Indicates whether a STOP condition has occurred on the I2C interface regardless...
+    // 0x00000100 [8]     : ACTIVITY (0): This bit captures DW_apb_i2c activity and stays set until it is cleared
+    // 0x00000080 [7]     : RX_DONE (0): When the DW_apb_i2c is acting as a slave-transmitter, this bit is set to 1 if the...
+    // 0x00000040 [6]     : TX_ABRT (0): This bit indicates if DW_apb_i2c, as an I2C transmitter, is unable to complete the...
+    // 0x00000020 [5]     : RD_REQ (0): This bit is set to 1 when DW_apb_i2c is acting as a slave and another I2C master is...
+    // 0x00000010 [4]     : TX_EMPTY (0): The behavior of the TX_EMPTY interrupt status differs based on the TX_EMPTY_CTRL...
+    // 0x00000008 [3]     : TX_OVER (0): Set during transmit if the transmit buffer is filled to IC_TX_BUFFER_DEPTH and the...
+    // 0x00000004 [2]     : RX_FULL (0): Set when the receive buffer reaches or goes above the RX_TL threshold in the...
+    // 0x00000002 [1]     : RX_OVER (0): Set if the receive buffer is completely filled to IC_RX_BUFFER_DEPTH and an...
+    // 0x00000001 [0]     : RX_UNDER (0): Set if the processor attempts to read the receive buffer when it is empty by...
+    io_ro_32 raw_intr_stat;
+
+    _REG_(I2C_IC_RX_TL_OFFSET) // I2C_IC_RX_TL
+    // I2C Receive FIFO Threshold Register
+    // 0x000000ff [7:0]   : RX_TL (0): Receive FIFO Threshold Level
     io_rw_32 rx_tl;
+
+    _REG_(I2C_IC_TX_TL_OFFSET) // I2C_IC_TX_TL
+    // I2C Transmit FIFO Threshold Register
+    // 0x000000ff [7:0]   : TX_TL (0): Transmit FIFO Threshold Level
     io_rw_32 tx_tl;
-    io_rw_32 clr_intr;
-    io_rw_32 clr_rx_under;
-    io_rw_32 clr_rx_over;
-    io_rw_32 clr_tx_over;
-    io_rw_32 clr_rd_req;
-    io_rw_32 clr_tx_abrt;
-    io_rw_32 clr_rx_done;
-    io_rw_32 clr_activity;
-    io_rw_32 clr_stop_det;
-    io_rw_32 clr_start_det;
-    io_rw_32 clr_gen_call;
+
+    _REG_(I2C_IC_CLR_INTR_OFFSET) // I2C_IC_CLR_INTR
+    // Clear Combined and Individual Interrupt Register
+    // 0x00000001 [0]     : CLR_INTR (0): Read this register to clear the combined interrupt, all individual interrupts,...
+    io_ro_32 clr_intr;
+
+    _REG_(I2C_IC_CLR_RX_UNDER_OFFSET) // I2C_IC_CLR_RX_UNDER
+    // Clear RX_UNDER Interrupt Register
+    // 0x00000001 [0]     : CLR_RX_UNDER (0): Read this register to clear the RX_UNDER interrupt (bit 0) of the...
+    io_ro_32 clr_rx_under;
+
+    _REG_(I2C_IC_CLR_RX_OVER_OFFSET) // I2C_IC_CLR_RX_OVER
+    // Clear RX_OVER Interrupt Register
+    // 0x00000001 [0]     : CLR_RX_OVER (0): Read this register to clear the RX_OVER interrupt (bit 1) of the...
+    io_ro_32 clr_rx_over;
+
+    _REG_(I2C_IC_CLR_TX_OVER_OFFSET) // I2C_IC_CLR_TX_OVER
+    // Clear TX_OVER Interrupt Register
+    // 0x00000001 [0]     : CLR_TX_OVER (0): Read this register to clear the TX_OVER interrupt (bit 3) of the...
+    io_ro_32 clr_tx_over;
+
+    _REG_(I2C_IC_CLR_RD_REQ_OFFSET) // I2C_IC_CLR_RD_REQ
+    // Clear RD_REQ Interrupt Register
+    // 0x00000001 [0]     : CLR_RD_REQ (0): Read this register to clear the RD_REQ interrupt (bit 5) of the...
+    io_ro_32 clr_rd_req;
+
+    _REG_(I2C_IC_CLR_TX_ABRT_OFFSET) // I2C_IC_CLR_TX_ABRT
+    // Clear TX_ABRT Interrupt Register
+    // 0x00000001 [0]     : CLR_TX_ABRT (0): Read this register to clear the TX_ABRT interrupt (bit 6) of the...
+    io_ro_32 clr_tx_abrt;
+
+    _REG_(I2C_IC_CLR_RX_DONE_OFFSET) // I2C_IC_CLR_RX_DONE
+    // Clear RX_DONE Interrupt Register
+    // 0x00000001 [0]     : CLR_RX_DONE (0): Read this register to clear the RX_DONE interrupt (bit 7) of the...
+    io_ro_32 clr_rx_done;
+
+    _REG_(I2C_IC_CLR_ACTIVITY_OFFSET) // I2C_IC_CLR_ACTIVITY
+    // Clear ACTIVITY Interrupt Register
+    // 0x00000001 [0]     : CLR_ACTIVITY (0): Reading this register clears the ACTIVITY interrupt if the I2C is not active anymore
+    io_ro_32 clr_activity;
+
+    _REG_(I2C_IC_CLR_STOP_DET_OFFSET) // I2C_IC_CLR_STOP_DET
+    // Clear STOP_DET Interrupt Register
+    // 0x00000001 [0]     : CLR_STOP_DET (0): Read this register to clear the STOP_DET interrupt (bit 9) of the...
+    io_ro_32 clr_stop_det;
+
+    _REG_(I2C_IC_CLR_START_DET_OFFSET) // I2C_IC_CLR_START_DET
+    // Clear START_DET Interrupt Register
+    // 0x00000001 [0]     : CLR_START_DET (0): Read this register to clear the START_DET interrupt (bit 10) of the...
+    io_ro_32 clr_start_det;
+
+    _REG_(I2C_IC_CLR_GEN_CALL_OFFSET) // I2C_IC_CLR_GEN_CALL
+    // Clear GEN_CALL Interrupt Register
+    // 0x00000001 [0]     : CLR_GEN_CALL (0): Read this register to clear the GEN_CALL interrupt (bit 11) of...
+    io_ro_32 clr_gen_call;
+
+    _REG_(I2C_IC_ENABLE_OFFSET) // I2C_IC_ENABLE
+    // I2C Enable Register
+    // 0x00000004 [2]     : TX_CMD_BLOCK (0): In Master mode: - 1'b1: Blocks the transmission of data on I2C bus even if Tx...
+    // 0x00000002 [1]     : ABORT (0): When set, the controller initiates the transfer abort
+    // 0x00000001 [0]     : ENABLE (0): Controls whether the DW_apb_i2c is enabled
     io_rw_32 enable;
-    io_rw_32 status;
-    io_rw_32 txflr;
-    io_rw_32 rxflr;
+
+    _REG_(I2C_IC_STATUS_OFFSET) // I2C_IC_STATUS
+    // I2C Status Register
+    // 0x00000040 [6]     : SLV_ACTIVITY (0): Slave FSM Activity Status
+    // 0x00000020 [5]     : MST_ACTIVITY (0): Master FSM Activity Status
+    // 0x00000010 [4]     : RFF (0): Receive FIFO Completely Full
+    // 0x00000008 [3]     : RFNE (0): Receive FIFO Not Empty
+    // 0x00000004 [2]     : TFE (1): Transmit FIFO Completely Empty
+    // 0x00000002 [1]     : TFNF (1): Transmit FIFO Not Full
+    // 0x00000001 [0]     : ACTIVITY (0): I2C Activity Status
+    io_ro_32 status;
+
+    _REG_(I2C_IC_TXFLR_OFFSET) // I2C_IC_TXFLR
+    // I2C Transmit FIFO Level Register This register contains the number of valid data entries in the transmit FIFO buffer
+    // 0x0000001f [4:0]   : TXFLR (0): Transmit FIFO Level
+    io_ro_32 txflr;
+
+    _REG_(I2C_IC_RXFLR_OFFSET) // I2C_IC_RXFLR
+    // I2C Receive FIFO Level Register This register contains the number of valid data entries in the receive FIFO buffer
+    // 0x0000001f [4:0]   : RXFLR (0): Receive FIFO Level
+    io_ro_32 rxflr;
+
+    _REG_(I2C_IC_SDA_HOLD_OFFSET) // I2C_IC_SDA_HOLD
+    // I2C SDA Hold Time Length Register
+    // 0x00ff0000 [23:16] : IC_SDA_RX_HOLD (0): Sets the required SDA hold time in units of ic_clk period, when DW_apb_i2c...
+    // 0x0000ffff [15:0]  : IC_SDA_TX_HOLD (1): Sets the required SDA hold time in units of ic_clk period, when DW_apb_i2c...
     io_rw_32 sda_hold;
-    io_rw_32 tx_abrt_source;
+
+    _REG_(I2C_IC_TX_ABRT_SOURCE_OFFSET) // I2C_IC_TX_ABRT_SOURCE
+    // I2C Transmit Abort Source Register
+    // 0xff800000 [31:23] : TX_FLUSH_CNT (0): This field indicates the number of Tx FIFO Data Commands which are flushed...
+    // 0x00010000 [16]    : ABRT_USER_ABRT (0): This is a master-mode-only bit
+    // 0x00008000 [15]    : ABRT_SLVRD_INTX (0): 1: When the processor side responds to a slave mode request for data to be...
+    // 0x00004000 [14]    : ABRT_SLV_ARBLOST (0): This field indicates that a Slave has lost the bus while transmitting...
+    // 0x00002000 [13]    : ABRT_SLVFLUSH_TXFIFO (0): This field specifies that the Slave has received a read command and...
+    // 0x00001000 [12]    : ARB_LOST (0): This field specifies that the Master has lost arbitration, or if...
+    // 0x00000800 [11]    : ABRT_MASTER_DIS (0): This field indicates that the User tries to initiate a Master operation...
+    // 0x00000400 [10]    : ABRT_10B_RD_NORSTRT (0): This field indicates that the restart is disabled (IC_RESTART_EN bit...
+    // 0x00000200 [9]     : ABRT_SBYTE_NORSTRT (0): To clear Bit 9, the source of the ABRT_SBYTE_NORSTRT must be fixed...
+    // 0x00000100 [8]     : ABRT_HS_NORSTRT (0): This field indicates that the restart is disabled (IC_RESTART_EN bit...
+    // 0x00000080 [7]     : ABRT_SBYTE_ACKDET (0): This field indicates that the Master has sent a START Byte and the START...
+    // 0x00000040 [6]     : ABRT_HS_ACKDET (0): This field indicates that the Master is in High Speed mode and the High...
+    // 0x00000020 [5]     : ABRT_GCALL_READ (0): This field indicates that DW_apb_i2c in the master mode has sent a General...
+    // 0x00000010 [4]     : ABRT_GCALL_NOACK (0): This field indicates that DW_apb_i2c in master mode has sent a General...
+    // 0x00000008 [3]     : ABRT_TXDATA_NOACK (0): This field indicates the master-mode only bit
+    // 0x00000004 [2]     : ABRT_10ADDR2_NOACK (0): This field indicates that the Master is in 10-bit address mode and that...
+    // 0x00000002 [1]     : ABRT_10ADDR1_NOACK (0): This field indicates that the Master is in 10-bit address mode and the...
+    // 0x00000001 [0]     : ABRT_7B_ADDR_NOACK (0): This field indicates that the Master is in 7-bit addressing mode and...
+    io_ro_32 tx_abrt_source;
+
+    _REG_(I2C_IC_SLV_DATA_NACK_ONLY_OFFSET) // I2C_IC_SLV_DATA_NACK_ONLY
+    // Generate Slave Data NACK Register
+    // 0x00000001 [0]     : NACK (0): Generate NACK
     io_rw_32 slv_data_nack_only;
+
+    _REG_(I2C_IC_DMA_CR_OFFSET) // I2C_IC_DMA_CR
+    // DMA Control Register
+    // 0x00000002 [1]     : TDMAE (0): Transmit DMA Enable
+    // 0x00000001 [0]     : RDMAE (0): Receive DMA Enable
     io_rw_32 dma_cr;
+
+    _REG_(I2C_IC_DMA_TDLR_OFFSET) // I2C_IC_DMA_TDLR
+    // DMA Transmit Data Level Register
+    // 0x0000000f [3:0]   : DMATDL (0): Transmit Data Level
     io_rw_32 dma_tdlr;
+
+    _REG_(I2C_IC_DMA_RDLR_OFFSET) // I2C_IC_DMA_RDLR
+    // I2C Receive Data Level Register
+    // 0x0000000f [3:0]   : DMARDL (0): Receive Data Level
     io_rw_32 dma_rdlr;
+
+    _REG_(I2C_IC_SDA_SETUP_OFFSET) // I2C_IC_SDA_SETUP
+    // I2C SDA Setup Register
+    // 0x000000ff [7:0]   : SDA_SETUP (0x64): SDA Setup
     io_rw_32 sda_setup;
+
+    _REG_(I2C_IC_ACK_GENERAL_CALL_OFFSET) // I2C_IC_ACK_GENERAL_CALL
+    // I2C ACK General Call Register
+    // 0x00000001 [0]     : ACK_GEN_CALL (1): ACK General Call
     io_rw_32 ack_general_call;
-    io_rw_32 enable_status;
+
+    _REG_(I2C_IC_ENABLE_STATUS_OFFSET) // I2C_IC_ENABLE_STATUS
+    // I2C Enable Status Register
+    // 0x00000004 [2]     : SLV_RX_DATA_LOST (0): Slave Received Data Lost
+    // 0x00000002 [1]     : SLV_DISABLED_WHILE_BUSY (0): Slave Disabled While Busy (Transmit, Receive)
+    // 0x00000001 [0]     : IC_EN (0): ic_en Status
+    io_ro_32 enable_status;
+
+    _REG_(I2C_IC_FS_SPKLEN_OFFSET) // I2C_IC_FS_SPKLEN
+    // I2C SS, FS or FM+ spike suppression limit
+    // 0x000000ff [7:0]   : IC_FS_SPKLEN (0x7): This register must be set before any I2C bus transaction can take place to...
     io_rw_32 fs_spklen;
+
     uint32_t _pad2;
-    io_rw_32 clr_restart_det;
+
+    _REG_(I2C_IC_CLR_RESTART_DET_OFFSET) // I2C_IC_CLR_RESTART_DET
+    // Clear RESTART_DET Interrupt Register
+    // 0x00000001 [0]     : CLR_RESTART_DET (0): Read this register to clear the RESTART_DET interrupt (bit 12) of...
+    io_ro_32 clr_restart_det;
+
+    uint32_t _pad3[18];
+
+    _REG_(I2C_IC_COMP_PARAM_1_OFFSET) // I2C_IC_COMP_PARAM_1
+    // Component Parameter Register 1
+    // 0x00ff0000 [23:16] : TX_BUFFER_DEPTH (0): TX Buffer Depth = 16
+    // 0x0000ff00 [15:8]  : RX_BUFFER_DEPTH (0): RX Buffer Depth = 16
+    // 0x00000080 [7]     : ADD_ENCODED_PARAMS (0): Encoded parameters not visible
+    // 0x00000040 [6]     : HAS_DMA (0): DMA handshaking signals are enabled
+    // 0x00000020 [5]     : INTR_IO (0): COMBINED Interrupt outputs
+    // 0x00000010 [4]     : HC_COUNT_VALUES (0): Programmable count values for each mode
+    // 0x0000000c [3:2]   : MAX_SPEED_MODE (0): MAX SPEED MODE = FAST MODE
+    // 0x00000003 [1:0]   : APB_DATA_WIDTH (0): APB data bus width is 32 bits
+    io_ro_32 comp_param_1;
+
+    _REG_(I2C_IC_COMP_VERSION_OFFSET) // I2C_IC_COMP_VERSION
+    // I2C Component Version Register
+    // 0xffffffff [31:0]  : IC_COMP_VERSION (0x3230312a)
+    io_ro_32 comp_version;
+
+    _REG_(I2C_IC_COMP_TYPE_OFFSET) // I2C_IC_COMP_TYPE
+    // I2C Component Type Register
+    // 0xffffffff [31:0]  : IC_COMP_TYPE (0x44570140): Designware Component Type number = 0x44_57_01_40
+    io_ro_32 comp_type;
 } i2c_hw_t;
 
 #define i2c0_hw ((i2c_hw_t *const)I2C0_BASE)
 #define i2c1_hw ((i2c_hw_t *const)I2C1_BASE)
 
-// List of configuration constants for the Synopsys I2C hardware (you may see
-// references to these in I2C register header; these are *fixed* values,
-// set at hardware design time):
-
-// IC_ULTRA_FAST_MODE ................ 0x0
-// IC_UFM_TBUF_CNT_DEFAULT ........... 0x8
-// IC_UFM_SCL_LOW_COUNT .............. 0x0008
-// IC_UFM_SCL_HIGH_COUNT ............. 0x0006
-// IC_TX_TL .......................... 0x0
-// IC_TX_CMD_BLOCK ................... 0x1
-// IC_HAS_DMA ........................ 0x1
-// IC_HAS_ASYNC_FIFO ................. 0x0
-// IC_SMBUS_ARP ...................... 0x0
-// IC_FIRST_DATA_BYTE_STATUS ......... 0x1
-// IC_INTR_IO ........................ 0x1
-// IC_MASTER_MODE .................... 0x1
-// IC_DEFAULT_ACK_GENERAL_CALL ....... 0x1
-// IC_INTR_POL ....................... 0x1
-// IC_OPTIONAL_SAR ................... 0x0
-// IC_DEFAULT_TAR_SLAVE_ADDR ......... 0x055
-// IC_DEFAULT_SLAVE_ADDR ............. 0x055
-// IC_DEFAULT_HS_SPKLEN .............. 0x1
-// IC_FS_SCL_HIGH_COUNT .............. 0x0006
-// IC_HS_SCL_LOW_COUNT ............... 0x0008
-// IC_DEVICE_ID_VALUE ................ 0x0
-// IC_10BITADDR_MASTER ............... 0x0
-// IC_CLK_FREQ_OPTIMIZATION .......... 0x0
-// IC_DEFAULT_FS_SPKLEN .............. 0x7
-// IC_ADD_ENCODED_PARAMS ............. 0x0
-// IC_DEFAULT_SDA_HOLD ............... 0x000001
-// IC_DEFAULT_SDA_SETUP .............. 0x64
-// IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT . 0x0
-// IC_CLOCK_PERIOD ................... 100
-// IC_EMPTYFIFO_HOLD_MASTER_EN ....... 1
-// IC_RESTART_EN ..................... 0x1
-// IC_TX_CMD_BLOCK_DEFAULT ........... 0x0
-// IC_BUS_CLEAR_FEATURE .............. 0x0
-// IC_CAP_LOADING .................... 100
-// IC_FS_SCL_LOW_COUNT ............... 0x000d
-// APB_DATA_WIDTH .................... 32
-// IC_SDA_STUCK_TIMEOUT_DEFAULT ...... 0xffffffff
-// IC_SLV_DATA_NACK_ONLY ............. 0x1
-// IC_10BITADDR_SLAVE ................ 0x0
-// IC_CLK_TYPE ....................... 0x0
-// IC_SMBUS_UDID_MSB ................. 0x0
-// IC_SMBUS_SUSPEND_ALERT ............ 0x0
-// IC_HS_SCL_HIGH_COUNT .............. 0x0006
-// IC_SLV_RESTART_DET_EN ............. 0x1
-// IC_SMBUS .......................... 0x0
-// IC_OPTIONAL_SAR_DEFAULT ........... 0x0
-// IC_PERSISTANT_SLV_ADDR_DEFAULT .... 0x0
-// IC_USE_COUNTS ..................... 0x0
-// IC_RX_BUFFER_DEPTH ................ 16
-// IC_SCL_STUCK_TIMEOUT_DEFAULT ...... 0xffffffff
-// IC_RX_FULL_HLD_BUS_EN ............. 0x1
-// IC_SLAVE_DISABLE .................. 0x1
-// IC_RX_TL .......................... 0x0
-// IC_DEVICE_ID ...................... 0x0
-// IC_HC_COUNT_VALUES ................ 0x0
-// I2C_DYNAMIC_TAR_UPDATE ............ 0
-// IC_SMBUS_CLK_LOW_MEXT_DEFAULT ..... 0xffffffff
-// IC_SMBUS_CLK_LOW_SEXT_DEFAULT ..... 0xffffffff
-// IC_HS_MASTER_CODE ................. 0x1
-// IC_SMBUS_RST_IDLE_CNT_DEFAULT ..... 0xffff
-// IC_SMBUS_UDID_LSB_DEFAULT ......... 0xffffffff
-// IC_SS_SCL_HIGH_COUNT .............. 0x0028
-// IC_SS_SCL_LOW_COUNT ............... 0x002f
-// IC_MAX_SPEED_MODE ................. 0x2
-// IC_STAT_FOR_CLK_STRETCH ........... 0x0
-// IC_STOP_DET_IF_MASTER_ACTIVE ...... 0x0
-// IC_DEFAULT_UFM_SPKLEN ............. 0x1
-// IC_TX_BUFFER_DEPTH ................ 16
-
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/interp.h b/src/rp2040/hardware_structs/include/hardware/structs/interp.h
index 6837507..e96caab 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/interp.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/interp.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,16 +10,68 @@
 #define _HARDWARE_STRUCTS_INTERP_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/sio.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_sio
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/sio.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(SIO_INTERP0_ACCUM0_OFFSET) // SIO_INTERP0_ACCUM0
+    // (Description copied from array index 0 register SIO_INTERP0_ACCUM0 applies similarly to other array indexes)
+    //
+    // Read/write access to accumulator 0
     io_rw_32 accum[2];
+
+    _REG_(SIO_INTERP0_BASE0_OFFSET) // SIO_INTERP0_BASE0
+    // (Description copied from array index 0 register SIO_INTERP0_BASE0 applies similarly to other array indexes)
+    //
+    // Read/write access to BASE0 register
     io_rw_32 base[3];
+
+    _REG_(SIO_INTERP0_POP_LANE0_OFFSET) // SIO_INTERP0_POP_LANE0
+    // (Description copied from array index 0 register SIO_INTERP0_POP_LANE0 applies similarly to other array indexes)
+    //
+    // Read LANE0 result, and simultaneously write lane results to both accumulators (POP)
     io_ro_32 pop[3];
+
+    _REG_(SIO_INTERP0_PEEK_LANE0_OFFSET) // SIO_INTERP0_PEEK_LANE0
+    // (Description copied from array index 0 register SIO_INTERP0_PEEK_LANE0 applies similarly to other array indexes)
+    //
+    // Read LANE0 result, without altering any internal state (PEEK)
     io_ro_32 peek[3];
+
+    _REG_(SIO_INTERP0_CTRL_LANE0_OFFSET) // SIO_INTERP0_CTRL_LANE0
+    // (Description copied from array index 0 register SIO_INTERP0_CTRL_LANE0 applies similarly to other array indexes)
+    //
+    // Control register for lane 0
+    // 0x02000000 [25]    : OVERF (0): Set if either OVERF0 or OVERF1 is set
+    // 0x01000000 [24]    : OVERF1 (0): Indicates if any masked-off MSBs in ACCUM1 are set
+    // 0x00800000 [23]    : OVERF0 (0): Indicates if any masked-off MSBs in ACCUM0 are set
+    // 0x00200000 [21]    : BLEND (0): Only present on INTERP0 on each core
+    // 0x00180000 [20:19] : FORCE_MSB (0): ORed into bits 29:28 of the lane result presented to the processor on the bus
+    // 0x00040000 [18]    : ADD_RAW (0): If 1, mask + shift is bypassed for LANE0 result
+    // 0x00020000 [17]    : CROSS_RESULT (0): If 1, feed the opposite lane's result into this lane's accumulator on POP
+    // 0x00010000 [16]    : CROSS_INPUT (0): If 1, feed the opposite lane's accumulator into this lane's shift + mask hardware
+    // 0x00008000 [15]    : SIGNED (0): If SIGNED is set, the shifted and masked accumulator value is sign-extended to 32 bits
+    // 0x00007c00 [14:10] : MASK_MSB (0): The most-significant bit allowed to pass by the mask (inclusive)
+    // 0x000003e0 [9:5]   : MASK_LSB (0): The least-significant bit allowed to pass by the mask (inclusive)
+    // 0x0000001f [4:0]   : SHIFT (0): Logical right-shift applied to accumulator before masking
     io_rw_32 ctrl[2];
+
+    _REG_(SIO_INTERP0_ACCUM0_ADD_OFFSET) // SIO_INTERP0_ACCUM0_ADD
+    // (Description copied from array index 0 register SIO_INTERP0_ACCUM0_ADD applies similarly to other array indexes)
+    //
+    // Values written here are atomically added to ACCUM0
+    // 0x00ffffff [23:0]  : INTERP0_ACCUM0_ADD (0)
     io_rw_32 add_raw[2];
+
+    _REG_(SIO_INTERP0_BASE_1AND0_OFFSET) // SIO_INTERP0_BASE_1AND0
+    // On write, the lower 16 bits go to BASE0, upper bits to BASE1 simultaneously
     io_wo_32 base01;
 } interp_hw_t;
 
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/iobank0.h b/src/rp2040/hardware_structs/include/hardware/structs/iobank0.h
index b19800f..aae74b2 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/iobank0.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/iobank0.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,28 +10,207 @@
 #define _HARDWARE_STRUCTS_IOBANK0_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/io_bank0.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_io_bank0
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/io_bank0.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(IO_BANK0_GPIO0_STATUS_OFFSET) // IO_BANK0_GPIO0_STATUS
+    // GPIO status
+    // 0x04000000 [26]    : IRQTOPROC (0): interrupt to processors, after override is applied
+    // 0x01000000 [24]    : IRQFROMPAD (0): interrupt from pad before override is applied
+    // 0x00080000 [19]    : INTOPERI (0): input signal to peripheral, after override is applied
+    // 0x00020000 [17]    : INFROMPAD (0): input signal from pad, before override is applied
+    // 0x00002000 [13]    : OETOPAD (0): output enable to pad after register override is applied
+    // 0x00001000 [12]    : OEFROMPERI (0): output enable from selected peripheral, before register override is applied
+    // 0x00000200 [9]     : OUTTOPAD (0): output signal to pad after register override is applied
+    // 0x00000100 [8]     : OUTFROMPERI (0): output signal from selected peripheral, before register override is applied
+    io_ro_32 status;
+
+    _REG_(IO_BANK0_GPIO0_CTRL_OFFSET) // IO_BANK0_GPIO0_CTRL
+    // GPIO control including function select and overrides
+    // 0x30000000 [29:28] : IRQOVER (0)
+    // 0x00030000 [17:16] : INOVER (0)
+    // 0x00003000 [13:12] : OEOVER (0)
+    // 0x00000300 [9:8]   : OUTOVER (0)
+    // 0x0000001f [4:0]   : FUNCSEL (0x1f): 0-31 -> selects pin function according to the gpio table
+    io_rw_32 ctrl;
+} iobank0_status_ctrl_hw_t;
+
+typedef struct {
+    _REG_(IO_BANK0_PROC0_INTE0_OFFSET) // IO_BANK0_PROC0_INTE0
+    // (Description copied from array index 0 register IO_BANK0_PROC0_INTE0 applies similarly to other array indexes)
+    //
+    // Interrupt Enable for proc0
+    // 0x80000000 [31]    : GPIO7_EDGE_HIGH (0)
+    // 0x40000000 [30]    : GPIO7_EDGE_LOW (0)
+    // 0x20000000 [29]    : GPIO7_LEVEL_HIGH (0)
+    // 0x10000000 [28]    : GPIO7_LEVEL_LOW (0)
+    // 0x08000000 [27]    : GPIO6_EDGE_HIGH (0)
+    // 0x04000000 [26]    : GPIO6_EDGE_LOW (0)
+    // 0x02000000 [25]    : GPIO6_LEVEL_HIGH (0)
+    // 0x01000000 [24]    : GPIO6_LEVEL_LOW (0)
+    // 0x00800000 [23]    : GPIO5_EDGE_HIGH (0)
+    // 0x00400000 [22]    : GPIO5_EDGE_LOW (0)
+    // 0x00200000 [21]    : GPIO5_LEVEL_HIGH (0)
+    // 0x00100000 [20]    : GPIO5_LEVEL_LOW (0)
+    // 0x00080000 [19]    : GPIO4_EDGE_HIGH (0)
+    // 0x00040000 [18]    : GPIO4_EDGE_LOW (0)
+    // 0x00020000 [17]    : GPIO4_LEVEL_HIGH (0)
+    // 0x00010000 [16]    : GPIO4_LEVEL_LOW (0)
+    // 0x00008000 [15]    : GPIO3_EDGE_HIGH (0)
+    // 0x00004000 [14]    : GPIO3_EDGE_LOW (0)
+    // 0x00002000 [13]    : GPIO3_LEVEL_HIGH (0)
+    // 0x00001000 [12]    : GPIO3_LEVEL_LOW (0)
+    // 0x00000800 [11]    : GPIO2_EDGE_HIGH (0)
+    // 0x00000400 [10]    : GPIO2_EDGE_LOW (0)
+    // 0x00000200 [9]     : GPIO2_LEVEL_HIGH (0)
+    // 0x00000100 [8]     : GPIO2_LEVEL_LOW (0)
+    // 0x00000080 [7]     : GPIO1_EDGE_HIGH (0)
+    // 0x00000040 [6]     : GPIO1_EDGE_LOW (0)
+    // 0x00000020 [5]     : GPIO1_LEVEL_HIGH (0)
+    // 0x00000010 [4]     : GPIO1_LEVEL_LOW (0)
+    // 0x00000008 [3]     : GPIO0_EDGE_HIGH (0)
+    // 0x00000004 [2]     : GPIO0_EDGE_LOW (0)
+    // 0x00000002 [1]     : GPIO0_LEVEL_HIGH (0)
+    // 0x00000001 [0]     : GPIO0_LEVEL_LOW (0)
     io_rw_32 inte[4];
+
+    _REG_(IO_BANK0_PROC0_INTF0_OFFSET) // IO_BANK0_PROC0_INTF0
+    // (Description copied from array index 0 register IO_BANK0_PROC0_INTF0 applies similarly to other array indexes)
+    //
+    // Interrupt Force for proc0
+    // 0x80000000 [31]    : GPIO7_EDGE_HIGH (0)
+    // 0x40000000 [30]    : GPIO7_EDGE_LOW (0)
+    // 0x20000000 [29]    : GPIO7_LEVEL_HIGH (0)
+    // 0x10000000 [28]    : GPIO7_LEVEL_LOW (0)
+    // 0x08000000 [27]    : GPIO6_EDGE_HIGH (0)
+    // 0x04000000 [26]    : GPIO6_EDGE_LOW (0)
+    // 0x02000000 [25]    : GPIO6_LEVEL_HIGH (0)
+    // 0x01000000 [24]    : GPIO6_LEVEL_LOW (0)
+    // 0x00800000 [23]    : GPIO5_EDGE_HIGH (0)
+    // 0x00400000 [22]    : GPIO5_EDGE_LOW (0)
+    // 0x00200000 [21]    : GPIO5_LEVEL_HIGH (0)
+    // 0x00100000 [20]    : GPIO5_LEVEL_LOW (0)
+    // 0x00080000 [19]    : GPIO4_EDGE_HIGH (0)
+    // 0x00040000 [18]    : GPIO4_EDGE_LOW (0)
+    // 0x00020000 [17]    : GPIO4_LEVEL_HIGH (0)
+    // 0x00010000 [16]    : GPIO4_LEVEL_LOW (0)
+    // 0x00008000 [15]    : GPIO3_EDGE_HIGH (0)
+    // 0x00004000 [14]    : GPIO3_EDGE_LOW (0)
+    // 0x00002000 [13]    : GPIO3_LEVEL_HIGH (0)
+    // 0x00001000 [12]    : GPIO3_LEVEL_LOW (0)
+    // 0x00000800 [11]    : GPIO2_EDGE_HIGH (0)
+    // 0x00000400 [10]    : GPIO2_EDGE_LOW (0)
+    // 0x00000200 [9]     : GPIO2_LEVEL_HIGH (0)
+    // 0x00000100 [8]     : GPIO2_LEVEL_LOW (0)
+    // 0x00000080 [7]     : GPIO1_EDGE_HIGH (0)
+    // 0x00000040 [6]     : GPIO1_EDGE_LOW (0)
+    // 0x00000020 [5]     : GPIO1_LEVEL_HIGH (0)
+    // 0x00000010 [4]     : GPIO1_LEVEL_LOW (0)
+    // 0x00000008 [3]     : GPIO0_EDGE_HIGH (0)
+    // 0x00000004 [2]     : GPIO0_EDGE_LOW (0)
+    // 0x00000002 [1]     : GPIO0_LEVEL_HIGH (0)
+    // 0x00000001 [0]     : GPIO0_LEVEL_LOW (0)
     io_rw_32 intf[4];
-    io_rw_32 ints[4];
+
+    _REG_(IO_BANK0_PROC0_INTS0_OFFSET) // IO_BANK0_PROC0_INTS0
+    // (Description copied from array index 0 register IO_BANK0_PROC0_INTS0 applies similarly to other array indexes)
+    //
+    // Interrupt status after masking & forcing for proc0
+    // 0x80000000 [31]    : GPIO7_EDGE_HIGH (0)
+    // 0x40000000 [30]    : GPIO7_EDGE_LOW (0)
+    // 0x20000000 [29]    : GPIO7_LEVEL_HIGH (0)
+    // 0x10000000 [28]    : GPIO7_LEVEL_LOW (0)
+    // 0x08000000 [27]    : GPIO6_EDGE_HIGH (0)
+    // 0x04000000 [26]    : GPIO6_EDGE_LOW (0)
+    // 0x02000000 [25]    : GPIO6_LEVEL_HIGH (0)
+    // 0x01000000 [24]    : GPIO6_LEVEL_LOW (0)
+    // 0x00800000 [23]    : GPIO5_EDGE_HIGH (0)
+    // 0x00400000 [22]    : GPIO5_EDGE_LOW (0)
+    // 0x00200000 [21]    : GPIO5_LEVEL_HIGH (0)
+    // 0x00100000 [20]    : GPIO5_LEVEL_LOW (0)
+    // 0x00080000 [19]    : GPIO4_EDGE_HIGH (0)
+    // 0x00040000 [18]    : GPIO4_EDGE_LOW (0)
+    // 0x00020000 [17]    : GPIO4_LEVEL_HIGH (0)
+    // 0x00010000 [16]    : GPIO4_LEVEL_LOW (0)
+    // 0x00008000 [15]    : GPIO3_EDGE_HIGH (0)
+    // 0x00004000 [14]    : GPIO3_EDGE_LOW (0)
+    // 0x00002000 [13]    : GPIO3_LEVEL_HIGH (0)
+    // 0x00001000 [12]    : GPIO3_LEVEL_LOW (0)
+    // 0x00000800 [11]    : GPIO2_EDGE_HIGH (0)
+    // 0x00000400 [10]    : GPIO2_EDGE_LOW (0)
+    // 0x00000200 [9]     : GPIO2_LEVEL_HIGH (0)
+    // 0x00000100 [8]     : GPIO2_LEVEL_LOW (0)
+    // 0x00000080 [7]     : GPIO1_EDGE_HIGH (0)
+    // 0x00000040 [6]     : GPIO1_EDGE_LOW (0)
+    // 0x00000020 [5]     : GPIO1_LEVEL_HIGH (0)
+    // 0x00000010 [4]     : GPIO1_LEVEL_LOW (0)
+    // 0x00000008 [3]     : GPIO0_EDGE_HIGH (0)
+    // 0x00000004 [2]     : GPIO0_EDGE_LOW (0)
+    // 0x00000002 [1]     : GPIO0_LEVEL_HIGH (0)
+    // 0x00000001 [0]     : GPIO0_LEVEL_LOW (0)
+    io_ro_32 ints[4];
 } io_irq_ctrl_hw_t;
 
 /// \tag::iobank0_hw[]
 typedef struct {
-    struct {
-        io_rw_32 status;
-        io_rw_32 ctrl;
-    } io[30];
+    iobank0_status_ctrl_hw_t io[NUM_BANK0_GPIOS]; // 30
+
+    _REG_(IO_BANK0_INTR0_OFFSET) // IO_BANK0_INTR0
+    // (Description copied from array index 0 register IO_BANK0_INTR0 applies similarly to other array indexes)
+    //
+    // Raw Interrupts
+    // 0x80000000 [31]    : GPIO7_EDGE_HIGH (0)
+    // 0x40000000 [30]    : GPIO7_EDGE_LOW (0)
+    // 0x20000000 [29]    : GPIO7_LEVEL_HIGH (0)
+    // 0x10000000 [28]    : GPIO7_LEVEL_LOW (0)
+    // 0x08000000 [27]    : GPIO6_EDGE_HIGH (0)
+    // 0x04000000 [26]    : GPIO6_EDGE_LOW (0)
+    // 0x02000000 [25]    : GPIO6_LEVEL_HIGH (0)
+    // 0x01000000 [24]    : GPIO6_LEVEL_LOW (0)
+    // 0x00800000 [23]    : GPIO5_EDGE_HIGH (0)
+    // 0x00400000 [22]    : GPIO5_EDGE_LOW (0)
+    // 0x00200000 [21]    : GPIO5_LEVEL_HIGH (0)
+    // 0x00100000 [20]    : GPIO5_LEVEL_LOW (0)
+    // 0x00080000 [19]    : GPIO4_EDGE_HIGH (0)
+    // 0x00040000 [18]    : GPIO4_EDGE_LOW (0)
+    // 0x00020000 [17]    : GPIO4_LEVEL_HIGH (0)
+    // 0x00010000 [16]    : GPIO4_LEVEL_LOW (0)
+    // 0x00008000 [15]    : GPIO3_EDGE_HIGH (0)
+    // 0x00004000 [14]    : GPIO3_EDGE_LOW (0)
+    // 0x00002000 [13]    : GPIO3_LEVEL_HIGH (0)
+    // 0x00001000 [12]    : GPIO3_LEVEL_LOW (0)
+    // 0x00000800 [11]    : GPIO2_EDGE_HIGH (0)
+    // 0x00000400 [10]    : GPIO2_EDGE_LOW (0)
+    // 0x00000200 [9]     : GPIO2_LEVEL_HIGH (0)
+    // 0x00000100 [8]     : GPIO2_LEVEL_LOW (0)
+    // 0x00000080 [7]     : GPIO1_EDGE_HIGH (0)
+    // 0x00000040 [6]     : GPIO1_EDGE_LOW (0)
+    // 0x00000020 [5]     : GPIO1_LEVEL_HIGH (0)
+    // 0x00000010 [4]     : GPIO1_LEVEL_LOW (0)
+    // 0x00000008 [3]     : GPIO0_EDGE_HIGH (0)
+    // 0x00000004 [2]     : GPIO0_EDGE_LOW (0)
+    // 0x00000002 [1]     : GPIO0_LEVEL_HIGH (0)
+    // 0x00000001 [0]     : GPIO0_LEVEL_LOW (0)
     io_rw_32 intr[4];
+
     io_irq_ctrl_hw_t proc0_irq_ctrl;
+
     io_irq_ctrl_hw_t proc1_irq_ctrl;
+
     io_irq_ctrl_hw_t dormant_wake_irq_ctrl;
 } iobank0_hw_t;
-/// \end::iobank0_hw[]
 
 #define iobank0_hw ((iobank0_hw_t *const)IO_BANK0_BASE)
+/// \end::iobank0_hw[]
+
+static_assert( NUM_BANK0_GPIOS == 30, "");
 
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/ioqspi.h b/src/rp2040/hardware_structs/include/hardware/structs/ioqspi.h
index 48d08a7..2992bfe 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/ioqspi.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/ioqspi.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,16 +10,165 @@
 #define _HARDWARE_STRUCTS_IOQSPI_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/io_qspi.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_io_qspi
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/io_qspi.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
-    struct {
-        io_rw_32 status;
-        io_rw_32 ctrl;
-    } io[6];
+    _REG_(IO_QSPI_GPIO_QSPI_SCLK_STATUS_OFFSET) // IO_QSPI_GPIO_QSPI_SCLK_STATUS
+    // GPIO status
+    // 0x04000000 [26]    : IRQTOPROC (0): interrupt to processors, after override is applied
+    // 0x01000000 [24]    : IRQFROMPAD (0): interrupt from pad before override is applied
+    // 0x00080000 [19]    : INTOPERI (0): input signal to peripheral, after override is applied
+    // 0x00020000 [17]    : INFROMPAD (0): input signal from pad, before override is applied
+    // 0x00002000 [13]    : OETOPAD (0): output enable to pad after register override is applied
+    // 0x00001000 [12]    : OEFROMPERI (0): output enable from selected peripheral, before register override is applied
+    // 0x00000200 [9]     : OUTTOPAD (0): output signal to pad after register override is applied
+    // 0x00000100 [8]     : OUTFROMPERI (0): output signal from selected peripheral, before register override is applied
+    io_ro_32 status;
+
+    _REG_(IO_QSPI_GPIO_QSPI_SCLK_CTRL_OFFSET) // IO_QSPI_GPIO_QSPI_SCLK_CTRL
+    // GPIO control including function select and overrides
+    // 0x30000000 [29:28] : IRQOVER (0)
+    // 0x00030000 [17:16] : INOVER (0)
+    // 0x00003000 [13:12] : OEOVER (0)
+    // 0x00000300 [9:8]   : OUTOVER (0)
+    // 0x0000001f [4:0]   : FUNCSEL (0x1f): 0-31 -> selects pin function according to the gpio table
+    io_rw_32 ctrl;
+} ioqspi_status_ctrl_hw_t;
+
+typedef struct {
+    _REG_(IO_QSPI_PROC0_INTE_OFFSET) // IO_QSPI_PROC0_INTE
+    // Interrupt Enable for proc0
+    // 0x00800000 [23]    : GPIO_QSPI_SD3_EDGE_HIGH (0)
+    // 0x00400000 [22]    : GPIO_QSPI_SD3_EDGE_LOW (0)
+    // 0x00200000 [21]    : GPIO_QSPI_SD3_LEVEL_HIGH (0)
+    // 0x00100000 [20]    : GPIO_QSPI_SD3_LEVEL_LOW (0)
+    // 0x00080000 [19]    : GPIO_QSPI_SD2_EDGE_HIGH (0)
+    // 0x00040000 [18]    : GPIO_QSPI_SD2_EDGE_LOW (0)
+    // 0x00020000 [17]    : GPIO_QSPI_SD2_LEVEL_HIGH (0)
+    // 0x00010000 [16]    : GPIO_QSPI_SD2_LEVEL_LOW (0)
+    // 0x00008000 [15]    : GPIO_QSPI_SD1_EDGE_HIGH (0)
+    // 0x00004000 [14]    : GPIO_QSPI_SD1_EDGE_LOW (0)
+    // 0x00002000 [13]    : GPIO_QSPI_SD1_LEVEL_HIGH (0)
+    // 0x00001000 [12]    : GPIO_QSPI_SD1_LEVEL_LOW (0)
+    // 0x00000800 [11]    : GPIO_QSPI_SD0_EDGE_HIGH (0)
+    // 0x00000400 [10]    : GPIO_QSPI_SD0_EDGE_LOW (0)
+    // 0x00000200 [9]     : GPIO_QSPI_SD0_LEVEL_HIGH (0)
+    // 0x00000100 [8]     : GPIO_QSPI_SD0_LEVEL_LOW (0)
+    // 0x00000080 [7]     : GPIO_QSPI_SS_EDGE_HIGH (0)
+    // 0x00000040 [6]     : GPIO_QSPI_SS_EDGE_LOW (0)
+    // 0x00000020 [5]     : GPIO_QSPI_SS_LEVEL_HIGH (0)
+    // 0x00000010 [4]     : GPIO_QSPI_SS_LEVEL_LOW (0)
+    // 0x00000008 [3]     : GPIO_QSPI_SCLK_EDGE_HIGH (0)
+    // 0x00000004 [2]     : GPIO_QSPI_SCLK_EDGE_LOW (0)
+    // 0x00000002 [1]     : GPIO_QSPI_SCLK_LEVEL_HIGH (0)
+    // 0x00000001 [0]     : GPIO_QSPI_SCLK_LEVEL_LOW (0)
+    io_rw_32 inte;
+
+    _REG_(IO_QSPI_PROC0_INTF_OFFSET) // IO_QSPI_PROC0_INTF
+    // Interrupt Force for proc0
+    // 0x00800000 [23]    : GPIO_QSPI_SD3_EDGE_HIGH (0)
+    // 0x00400000 [22]    : GPIO_QSPI_SD3_EDGE_LOW (0)
+    // 0x00200000 [21]    : GPIO_QSPI_SD3_LEVEL_HIGH (0)
+    // 0x00100000 [20]    : GPIO_QSPI_SD3_LEVEL_LOW (0)
+    // 0x00080000 [19]    : GPIO_QSPI_SD2_EDGE_HIGH (0)
+    // 0x00040000 [18]    : GPIO_QSPI_SD2_EDGE_LOW (0)
+    // 0x00020000 [17]    : GPIO_QSPI_SD2_LEVEL_HIGH (0)
+    // 0x00010000 [16]    : GPIO_QSPI_SD2_LEVEL_LOW (0)
+    // 0x00008000 [15]    : GPIO_QSPI_SD1_EDGE_HIGH (0)
+    // 0x00004000 [14]    : GPIO_QSPI_SD1_EDGE_LOW (0)
+    // 0x00002000 [13]    : GPIO_QSPI_SD1_LEVEL_HIGH (0)
+    // 0x00001000 [12]    : GPIO_QSPI_SD1_LEVEL_LOW (0)
+    // 0x00000800 [11]    : GPIO_QSPI_SD0_EDGE_HIGH (0)
+    // 0x00000400 [10]    : GPIO_QSPI_SD0_EDGE_LOW (0)
+    // 0x00000200 [9]     : GPIO_QSPI_SD0_LEVEL_HIGH (0)
+    // 0x00000100 [8]     : GPIO_QSPI_SD0_LEVEL_LOW (0)
+    // 0x00000080 [7]     : GPIO_QSPI_SS_EDGE_HIGH (0)
+    // 0x00000040 [6]     : GPIO_QSPI_SS_EDGE_LOW (0)
+    // 0x00000020 [5]     : GPIO_QSPI_SS_LEVEL_HIGH (0)
+    // 0x00000010 [4]     : GPIO_QSPI_SS_LEVEL_LOW (0)
+    // 0x00000008 [3]     : GPIO_QSPI_SCLK_EDGE_HIGH (0)
+    // 0x00000004 [2]     : GPIO_QSPI_SCLK_EDGE_LOW (0)
+    // 0x00000002 [1]     : GPIO_QSPI_SCLK_LEVEL_HIGH (0)
+    // 0x00000001 [0]     : GPIO_QSPI_SCLK_LEVEL_LOW (0)
+    io_rw_32 intf;
+
+    _REG_(IO_QSPI_PROC0_INTS_OFFSET) // IO_QSPI_PROC0_INTS
+    // Interrupt status after masking & forcing for proc0
+    // 0x00800000 [23]    : GPIO_QSPI_SD3_EDGE_HIGH (0)
+    // 0x00400000 [22]    : GPIO_QSPI_SD3_EDGE_LOW (0)
+    // 0x00200000 [21]    : GPIO_QSPI_SD3_LEVEL_HIGH (0)
+    // 0x00100000 [20]    : GPIO_QSPI_SD3_LEVEL_LOW (0)
+    // 0x00080000 [19]    : GPIO_QSPI_SD2_EDGE_HIGH (0)
+    // 0x00040000 [18]    : GPIO_QSPI_SD2_EDGE_LOW (0)
+    // 0x00020000 [17]    : GPIO_QSPI_SD2_LEVEL_HIGH (0)
+    // 0x00010000 [16]    : GPIO_QSPI_SD2_LEVEL_LOW (0)
+    // 0x00008000 [15]    : GPIO_QSPI_SD1_EDGE_HIGH (0)
+    // 0x00004000 [14]    : GPIO_QSPI_SD1_EDGE_LOW (0)
+    // 0x00002000 [13]    : GPIO_QSPI_SD1_LEVEL_HIGH (0)
+    // 0x00001000 [12]    : GPIO_QSPI_SD1_LEVEL_LOW (0)
+    // 0x00000800 [11]    : GPIO_QSPI_SD0_EDGE_HIGH (0)
+    // 0x00000400 [10]    : GPIO_QSPI_SD0_EDGE_LOW (0)
+    // 0x00000200 [9]     : GPIO_QSPI_SD0_LEVEL_HIGH (0)
+    // 0x00000100 [8]     : GPIO_QSPI_SD0_LEVEL_LOW (0)
+    // 0x00000080 [7]     : GPIO_QSPI_SS_EDGE_HIGH (0)
+    // 0x00000040 [6]     : GPIO_QSPI_SS_EDGE_LOW (0)
+    // 0x00000020 [5]     : GPIO_QSPI_SS_LEVEL_HIGH (0)
+    // 0x00000010 [4]     : GPIO_QSPI_SS_LEVEL_LOW (0)
+    // 0x00000008 [3]     : GPIO_QSPI_SCLK_EDGE_HIGH (0)
+    // 0x00000004 [2]     : GPIO_QSPI_SCLK_EDGE_LOW (0)
+    // 0x00000002 [1]     : GPIO_QSPI_SCLK_LEVEL_HIGH (0)
+    // 0x00000001 [0]     : GPIO_QSPI_SCLK_LEVEL_LOW (0)
+    io_ro_32 ints;
+} io_qspi_ctrl_hw_t;
+
+typedef struct {
+    ioqspi_status_ctrl_hw_t io[NUM_QSPI_GPIOS]; // 6
+
+    _REG_(IO_QSPI_INTR_OFFSET) // IO_QSPI_INTR
+    // Raw Interrupts
+    // 0x00800000 [23]    : GPIO_QSPI_SD3_EDGE_HIGH (0)
+    // 0x00400000 [22]    : GPIO_QSPI_SD3_EDGE_LOW (0)
+    // 0x00200000 [21]    : GPIO_QSPI_SD3_LEVEL_HIGH (0)
+    // 0x00100000 [20]    : GPIO_QSPI_SD3_LEVEL_LOW (0)
+    // 0x00080000 [19]    : GPIO_QSPI_SD2_EDGE_HIGH (0)
+    // 0x00040000 [18]    : GPIO_QSPI_SD2_EDGE_LOW (0)
+    // 0x00020000 [17]    : GPIO_QSPI_SD2_LEVEL_HIGH (0)
+    // 0x00010000 [16]    : GPIO_QSPI_SD2_LEVEL_LOW (0)
+    // 0x00008000 [15]    : GPIO_QSPI_SD1_EDGE_HIGH (0)
+    // 0x00004000 [14]    : GPIO_QSPI_SD1_EDGE_LOW (0)
+    // 0x00002000 [13]    : GPIO_QSPI_SD1_LEVEL_HIGH (0)
+    // 0x00001000 [12]    : GPIO_QSPI_SD1_LEVEL_LOW (0)
+    // 0x00000800 [11]    : GPIO_QSPI_SD0_EDGE_HIGH (0)
+    // 0x00000400 [10]    : GPIO_QSPI_SD0_EDGE_LOW (0)
+    // 0x00000200 [9]     : GPIO_QSPI_SD0_LEVEL_HIGH (0)
+    // 0x00000100 [8]     : GPIO_QSPI_SD0_LEVEL_LOW (0)
+    // 0x00000080 [7]     : GPIO_QSPI_SS_EDGE_HIGH (0)
+    // 0x00000040 [6]     : GPIO_QSPI_SS_EDGE_LOW (0)
+    // 0x00000020 [5]     : GPIO_QSPI_SS_LEVEL_HIGH (0)
+    // 0x00000010 [4]     : GPIO_QSPI_SS_LEVEL_LOW (0)
+    // 0x00000008 [3]     : GPIO_QSPI_SCLK_EDGE_HIGH (0)
+    // 0x00000004 [2]     : GPIO_QSPI_SCLK_EDGE_LOW (0)
+    // 0x00000002 [1]     : GPIO_QSPI_SCLK_LEVEL_HIGH (0)
+    // 0x00000001 [0]     : GPIO_QSPI_SCLK_LEVEL_LOW (0)
+    io_rw_32 intr;
+
+    io_qspi_ctrl_hw_t proc0_qspi_ctrl;
+
+    io_qspi_ctrl_hw_t proc1_qspi_ctrl;
+
+    io_qspi_ctrl_hw_t dormant_wake_qspi_ctrl;
 } ioqspi_hw_t;
 
 #define ioqspi_hw ((ioqspi_hw_t *const)IO_QSPI_BASE)
 
+static_assert( NUM_QSPI_GPIOS == 6, "");
+
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/mpu.h b/src/rp2040/hardware_structs/include/hardware/structs/mpu.h
index 34e5c39..e647220 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/mpu.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/mpu.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,11 +12,47 @@
 #include "hardware/address_mapped.h"
 #include "hardware/regs/m0plus.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_m0plus
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/m0plus.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(M0PLUS_MPU_TYPE_OFFSET) // M0PLUS_MPU_TYPE
+    // Read the MPU Type Register to determine if the processor implements an MPU, and how many regions the MPU supports
+    // 0x00ff0000 [23:16] : IREGION (0): Instruction region
+    // 0x0000ff00 [15:8]  : DREGION (0x8): Number of regions supported by the MPU
+    // 0x00000001 [0]     : SEPARATE (0): Indicates support for separate instruction and data address maps
     io_ro_32 type;
+
+    _REG_(M0PLUS_MPU_CTRL_OFFSET) // M0PLUS_MPU_CTRL
+    // Use the MPU Control Register to enable and disable the MPU, and to control whether the default memory map is enabled...
+    // 0x00000004 [2]     : PRIVDEFENA (0): Controls whether the default memory map is enabled as a background region for...
+    // 0x00000002 [1]     : HFNMIENA (0): Controls the use of the MPU for HardFaults and NMIs
+    // 0x00000001 [0]     : ENABLE (0): Enables the MPU
     io_rw_32 ctrl;
+
+    _REG_(M0PLUS_MPU_RNR_OFFSET) // M0PLUS_MPU_RNR
+    // Use the MPU Region Number Register to select the region currently accessed by MPU_RBAR and MPU_RASR
+    // 0x0000000f [3:0]   : REGION (0): Indicates the MPU region referenced by the MPU_RBAR and MPU_RASR registers
     io_rw_32 rnr;
+
+    _REG_(M0PLUS_MPU_RBAR_OFFSET) // M0PLUS_MPU_RBAR
+    // Read the MPU Region Base Address Register to determine the base address of the region identified by MPU_RNR
+    // 0xffffff00 [31:8]  : ADDR (0): Base address of the region
+    // 0x00000010 [4]     : VALID (0): On writes, indicates whether the write must update the base address of the region...
+    // 0x0000000f [3:0]   : REGION (0): On writes, specifies the number of the region whose base address to update provided...
     io_rw_32 rbar;
+
+    _REG_(M0PLUS_MPU_RASR_OFFSET) // M0PLUS_MPU_RASR
+    // Use the MPU Region Attribute and Size Register to define the size, access behaviour and memory type of the region...
+    // 0xffff0000 [31:16] : ATTRS (0): The MPU Region Attribute field
+    // 0x0000ff00 [15:8]  : SRD (0): Subregion Disable
+    // 0x0000003e [5:1]   : SIZE (0): Indicates the region size
+    // 0x00000001 [0]     : ENABLE (0): Enables the region
     io_rw_32 rasr;
 } mpu_hw_t;
 
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/pads_qspi.h b/src/rp2040/hardware_structs/include/hardware/structs/pads_qspi.h
index 451d7eb..8036cd9 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/pads_qspi.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/pads_qspi.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,14 +10,38 @@
 #define _HARDWARE_STRUCTS_PADS_QSPI_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/pads_qspi.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_pads_qspi
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/pads_qspi.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(PADS_QSPI_VOLTAGE_SELECT_OFFSET) // PADS_QSPI_VOLTAGE_SELECT
+    // Voltage select
+    // 0x00000001 [0]     : VOLTAGE_SELECT (0)
     io_rw_32 voltage_select;
-    io_rw_32 io[6];
+
+    _REG_(PADS_QSPI_GPIO_QSPI_SCLK_OFFSET) // PADS_QSPI_GPIO_QSPI_SCLK
+    // (Description copied from array index 0 register PADS_QSPI_GPIO_QSPI_SCLK applies similarly to other array indexes)
+    //
+    // Pad control register
+    // 0x00000080 [7]     : OD (0): Output disable
+    // 0x00000040 [6]     : IE (1): Input enable
+    // 0x00000030 [5:4]   : DRIVE (1): Drive strength
+    // 0x00000008 [3]     : PUE (0): Pull up enable
+    // 0x00000004 [2]     : PDE (1): Pull down enable
+    // 0x00000002 [1]     : SCHMITT (1): Enable schmitt trigger
+    // 0x00000001 [0]     : SLEWFAST (0): Slew rate control
+    io_rw_32 io[NUM_QSPI_GPIOS]; // 6
 } pads_qspi_hw_t;
 
 #define pads_qspi_hw ((pads_qspi_hw_t *const)PADS_QSPI_BASE)
 
+static_assert( NUM_QSPI_GPIOS == 6, "");
+
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/padsbank0.h b/src/rp2040/hardware_structs/include/hardware/structs/padsbank0.h
index f56dc40..2c067fa 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/padsbank0.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/padsbank0.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,14 +10,38 @@
 #define _HARDWARE_STRUCTS_PADSBANK0_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/pads_bank0.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_pads_bank0
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/pads_bank0.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(PADS_BANK0_VOLTAGE_SELECT_OFFSET) // PADS_BANK0_VOLTAGE_SELECT
+    // Voltage select
+    // 0x00000001 [0]     : VOLTAGE_SELECT (0)
     io_rw_32 voltage_select;
-    io_rw_32 io[30];
+
+    _REG_(PADS_BANK0_GPIO0_OFFSET) // PADS_BANK0_GPIO0
+    // (Description copied from array index 0 register PADS_BANK0_GPIO0 applies similarly to other array indexes)
+    //
+    // Pad control register
+    // 0x00000080 [7]     : OD (0): Output disable
+    // 0x00000040 [6]     : IE (1): Input enable
+    // 0x00000030 [5:4]   : DRIVE (1): Drive strength
+    // 0x00000008 [3]     : PUE (0): Pull up enable
+    // 0x00000004 [2]     : PDE (1): Pull down enable
+    // 0x00000002 [1]     : SCHMITT (1): Enable schmitt trigger
+    // 0x00000001 [0]     : SLEWFAST (0): Slew rate control
+    io_rw_32 io[NUM_BANK0_GPIOS]; // 30
 } padsbank0_hw_t;
 
-#define padsbank0_hw ((padsbank0_hw_t *)PADS_BANK0_BASE)
+#define padsbank0_hw ((padsbank0_hw_t *const)PADS_BANK0_BASE)
+
+static_assert( NUM_BANK0_GPIOS == 30, "");
 
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/pio.h b/src/rp2040/hardware_structs/include/hardware/structs/pio.h
index 176863b..515e4d1 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/pio.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/pio.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,41 +10,275 @@
 #define _HARDWARE_STRUCTS_PIO_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/pio.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_pio
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/pio.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
+typedef struct pio_sm_hw {
+    _REG_(PIO_SM0_CLKDIV_OFFSET) // PIO_SM0_CLKDIV
+    // Clock divisor register for state machine 0
+    // 0xffff0000 [31:16] : INT (1): Effective frequency is sysclk/(int + frac/256)
+    // 0x0000ff00 [15:8]  : FRAC (0): Fractional part of clock divisor
+    io_rw_32 clkdiv;
+
+    _REG_(PIO_SM0_EXECCTRL_OFFSET) // PIO_SM0_EXECCTRL
+    // Execution/behavioural settings for state machine 0
+    // 0x80000000 [31]    : EXEC_STALLED (0): If 1, an instruction written to SMx_INSTR is stalled, and latched by the state machine
+    // 0x40000000 [30]    : SIDE_EN (0): If 1, the MSB of the Delay/Side-set instruction field is used as side-set enable,...
+    // 0x20000000 [29]    : SIDE_PINDIR (0): If 1, side-set data is asserted to pin directions, instead of pin values
+    // 0x1f000000 [28:24] : JMP_PIN (0): The GPIO number to use as condition for JMP PIN
+    // 0x00f80000 [23:19] : OUT_EN_SEL (0): Which data bit to use for inline OUT enable
+    // 0x00040000 [18]    : INLINE_OUT_EN (0): If 1, use a bit of OUT data as an auxiliary write enable
+    // 0x00020000 [17]    : OUT_STICKY (0): Continuously assert the most recent OUT/SET to the pins
+    // 0x0001f000 [16:12] : WRAP_TOP (0x1f): After reaching this address, execution is wrapped to wrap_bottom
+    // 0x00000f80 [11:7]  : WRAP_BOTTOM (0): After reaching wrap_top, execution is wrapped to this address
+    // 0x00000010 [4]     : STATUS_SEL (0): Comparison used for the MOV x, STATUS instruction
+    // 0x0000000f [3:0]   : STATUS_N (0): Comparison level for the MOV x, STATUS instruction
+    io_rw_32 execctrl;
+
+    _REG_(PIO_SM0_SHIFTCTRL_OFFSET) // PIO_SM0_SHIFTCTRL
+    // Control behaviour of the input/output shift registers for state machine 0
+    // 0x80000000 [31]    : FJOIN_RX (0): When 1, RX FIFO steals the TX FIFO's storage, and becomes twice as deep
+    // 0x40000000 [30]    : FJOIN_TX (0): When 1, TX FIFO steals the RX FIFO's storage, and becomes twice as deep
+    // 0x3e000000 [29:25] : PULL_THRESH (0): Number of bits shifted out of OSR before autopull, or conditional pull (PULL...
+    // 0x01f00000 [24:20] : PUSH_THRESH (0): Number of bits shifted into ISR before autopush, or conditional push (PUSH...
+    // 0x00080000 [19]    : OUT_SHIFTDIR (1): 1 = shift out of output shift register to right
+    // 0x00040000 [18]    : IN_SHIFTDIR (1): 1 = shift input shift register to right (data enters from left)
+    // 0x00020000 [17]    : AUTOPULL (0): Pull automatically when the output shift register is emptied, i
+    // 0x00010000 [16]    : AUTOPUSH (0): Push automatically when the input shift register is filled, i
+    io_rw_32 shiftctrl;
+
+    _REG_(PIO_SM0_ADDR_OFFSET) // PIO_SM0_ADDR
+    // Current instruction address of state machine 0
+    // 0x0000001f [4:0]   : SM0_ADDR (0)
+    io_ro_32 addr;
+
+    _REG_(PIO_SM0_INSTR_OFFSET) // PIO_SM0_INSTR
+    // Read to see the instruction currently addressed by state machine 0's program counter
+    // 0x0000ffff [15:0]  : SM0_INSTR (0)
+    io_rw_32 instr;
+
+    _REG_(PIO_SM0_PINCTRL_OFFSET) // PIO_SM0_PINCTRL
+    // State machine pin control
+    // 0xe0000000 [31:29] : SIDESET_COUNT (0): The number of MSBs of the Delay/Side-set instruction field which are used...
+    // 0x1c000000 [28:26] : SET_COUNT (0x5): The number of pins asserted by a SET
+    // 0x03f00000 [25:20] : OUT_COUNT (0): The number of pins asserted by an OUT PINS, OUT PINDIRS or MOV PINS instruction
+    // 0x000f8000 [19:15] : IN_BASE (0): The pin which is mapped to the least-significant bit of a state machine's IN data bus
+    // 0x00007c00 [14:10] : SIDESET_BASE (0): The lowest-numbered pin that will be affected by a side-set operation
+    // 0x000003e0 [9:5]   : SET_BASE (0): The lowest-numbered pin that will be affected by a SET PINS or SET PINDIRS instruction
+    // 0x0000001f [4:0]   : OUT_BASE (0): The lowest-numbered pin that will be affected by an OUT PINS, OUT PINDIRS or MOV...
+    io_rw_32 pinctrl;
+} pio_sm_hw_t;
+
 typedef struct {
+    _REG_(PIO_CTRL_OFFSET) // PIO_CTRL
+    // PIO control register
+    // 0x00000f00 [11:8]  : CLKDIV_RESTART (0): Restart a state machine's clock divider from an initial phase of 0
+    // 0x000000f0 [7:4]   : SM_RESTART (0): Write 1 to instantly clear internal SM state which may be otherwise difficult...
+    // 0x0000000f [3:0]   : SM_ENABLE (0): Enable/disable each of the four state machines by writing 1/0 to each of these four bits
     io_rw_32 ctrl;
+
+    _REG_(PIO_FSTAT_OFFSET) // PIO_FSTAT
+    // FIFO status register
+    // 0x0f000000 [27:24] : TXEMPTY (0xf): State machine TX FIFO is empty
+    // 0x000f0000 [19:16] : TXFULL (0): State machine TX FIFO is full
+    // 0x00000f00 [11:8]  : RXEMPTY (0xf): State machine RX FIFO is empty
+    // 0x0000000f [3:0]   : RXFULL (0): State machine RX FIFO is full
     io_ro_32 fstat;
+
+    _REG_(PIO_FDEBUG_OFFSET) // PIO_FDEBUG
+    // FIFO debug register
+    // 0x0f000000 [27:24] : TXSTALL (0): State machine has stalled on empty TX FIFO during a blocking PULL, or an OUT with...
+    // 0x000f0000 [19:16] : TXOVER (0): TX FIFO overflow (i
+    // 0x00000f00 [11:8]  : RXUNDER (0): RX FIFO underflow (i
+    // 0x0000000f [3:0]   : RXSTALL (0): State machine has stalled on full RX FIFO during a blocking PUSH, or an IN with...
     io_rw_32 fdebug;
+
+    _REG_(PIO_FLEVEL_OFFSET) // PIO_FLEVEL
+    // FIFO levels
+    // 0xf0000000 [31:28] : RX3 (0)
+    // 0x0f000000 [27:24] : TX3 (0)
+    // 0x00f00000 [23:20] : RX2 (0)
+    // 0x000f0000 [19:16] : TX2 (0)
+    // 0x0000f000 [15:12] : RX1 (0)
+    // 0x00000f00 [11:8]  : TX1 (0)
+    // 0x000000f0 [7:4]   : RX0 (0)
+    // 0x0000000f [3:0]   : TX0 (0)
     io_ro_32 flevel;
-    io_wo_32 txf[NUM_PIO_STATE_MACHINES];
-    io_ro_32 rxf[NUM_PIO_STATE_MACHINES];
+
+    _REG_(PIO_TXF0_OFFSET) // PIO_TXF0
+    // (Description copied from array index 0 register PIO_TXF0 applies similarly to other array indexes)
+    //
+    // Direct write access to the TX FIFO for this state machine
+    io_wo_32 txf[NUM_PIO_STATE_MACHINES]; // 4
+
+    _REG_(PIO_RXF0_OFFSET) // PIO_RXF0
+    // (Description copied from array index 0 register PIO_RXF0 applies similarly to other array indexes)
+    //
+    // Direct read access to the RX FIFO for this state machine
+    io_ro_32 rxf[NUM_PIO_STATE_MACHINES]; // 4
+
+    _REG_(PIO_IRQ_OFFSET) // PIO_IRQ
+    // State machine IRQ flags register
+    // 0x000000ff [7:0]   : IRQ (0)
     io_rw_32 irq;
+
+    _REG_(PIO_IRQ_FORCE_OFFSET) // PIO_IRQ_FORCE
+    // Writing a 1 to each of these bits will forcibly assert the corresponding IRQ
+    // 0x000000ff [7:0]   : IRQ_FORCE (0)
     io_wo_32 irq_force;
+
+    _REG_(PIO_INPUT_SYNC_BYPASS_OFFSET) // PIO_INPUT_SYNC_BYPASS
+    // There is a 2-flipflop synchronizer on each GPIO input, which protects PIO logic from metastabilities
     io_rw_32 input_sync_bypass;
-    io_rw_32 dbg_padout;
-    io_rw_32 dbg_padoe;
-    io_rw_32 dbg_cfginfo;
-    io_wo_32 instr_mem[32];
-    struct pio_sm_hw {
-        io_rw_32 clkdiv;
-        io_rw_32 execctrl;
-        io_rw_32 shiftctrl;
-        io_ro_32 addr;
-        io_rw_32 instr;
-        io_rw_32 pinctrl;
-    } sm[NUM_PIO_STATE_MACHINES];
-    io_rw_32 intr;
+
+    _REG_(PIO_DBG_PADOUT_OFFSET) // PIO_DBG_PADOUT
+    // Read to sample the pad output values PIO is currently driving to the GPIOs
+    io_ro_32 dbg_padout;
+
+    _REG_(PIO_DBG_PADOE_OFFSET) // PIO_DBG_PADOE
+    // Read to sample the pad output enables (direction) PIO is currently driving to the GPIOs
+    io_ro_32 dbg_padoe;
+
+    _REG_(PIO_DBG_CFGINFO_OFFSET) // PIO_DBG_CFGINFO
+    // The PIO hardware has some free parameters that may vary between chip products
+    // 0x003f0000 [21:16] : IMEM_SIZE (0): The size of the instruction memory, measured in units of one instruction
+    // 0x00000f00 [11:8]  : SM_COUNT (0): The number of state machines this PIO instance is equipped with
+    // 0x0000003f [5:0]   : FIFO_DEPTH (0): The depth of the state machine TX/RX FIFOs, measured in words
+    io_ro_32 dbg_cfginfo;
+
+    _REG_(PIO_INSTR_MEM0_OFFSET) // PIO_INSTR_MEM0
+    // (Description copied from array index 0 register PIO_INSTR_MEM0 applies similarly to other array indexes)
+    //
+    // Write-only access to instruction memory location 0
+    // 0x0000ffff [15:0]  : INSTR_MEM0 (0)
+    io_wo_32 instr_mem[PIO_INSTRUCTION_COUNT]; // 32
+
+    pio_sm_hw_t sm[NUM_PIO_STATE_MACHINES]; // 4
+
+    _REG_(PIO_INTR_OFFSET) // PIO_INTR
+    // Raw Interrupts
+    // 0x00000800 [11]    : SM3 (0)
+    // 0x00000400 [10]    : SM2 (0)
+    // 0x00000200 [9]     : SM1 (0)
+    // 0x00000100 [8]     : SM0 (0)
+    // 0x00000080 [7]     : SM3_TXNFULL (0)
+    // 0x00000040 [6]     : SM2_TXNFULL (0)
+    // 0x00000020 [5]     : SM1_TXNFULL (0)
+    // 0x00000010 [4]     : SM0_TXNFULL (0)
+    // 0x00000008 [3]     : SM3_RXNEMPTY (0)
+    // 0x00000004 [2]     : SM2_RXNEMPTY (0)
+    // 0x00000002 [1]     : SM1_RXNEMPTY (0)
+    // 0x00000001 [0]     : SM0_RXNEMPTY (0)
+    io_ro_32 intr;
+
+    _REG_(PIO_IRQ0_INTE_OFFSET) // PIO_IRQ0_INTE
+    // Interrupt Enable for irq0
+    // 0x00000800 [11]    : SM3 (0)
+    // 0x00000400 [10]    : SM2 (0)
+    // 0x00000200 [9]     : SM1 (0)
+    // 0x00000100 [8]     : SM0 (0)
+    // 0x00000080 [7]     : SM3_TXNFULL (0)
+    // 0x00000040 [6]     : SM2_TXNFULL (0)
+    // 0x00000020 [5]     : SM1_TXNFULL (0)
+    // 0x00000010 [4]     : SM0_TXNFULL (0)
+    // 0x00000008 [3]     : SM3_RXNEMPTY (0)
+    // 0x00000004 [2]     : SM2_RXNEMPTY (0)
+    // 0x00000002 [1]     : SM1_RXNEMPTY (0)
+    // 0x00000001 [0]     : SM0_RXNEMPTY (0)
     io_rw_32 inte0;
+
+    _REG_(PIO_IRQ0_INTF_OFFSET) // PIO_IRQ0_INTF
+    // Interrupt Force for irq0
+    // 0x00000800 [11]    : SM3 (0)
+    // 0x00000400 [10]    : SM2 (0)
+    // 0x00000200 [9]     : SM1 (0)
+    // 0x00000100 [8]     : SM0 (0)
+    // 0x00000080 [7]     : SM3_TXNFULL (0)
+    // 0x00000040 [6]     : SM2_TXNFULL (0)
+    // 0x00000020 [5]     : SM1_TXNFULL (0)
+    // 0x00000010 [4]     : SM0_TXNFULL (0)
+    // 0x00000008 [3]     : SM3_RXNEMPTY (0)
+    // 0x00000004 [2]     : SM2_RXNEMPTY (0)
+    // 0x00000002 [1]     : SM1_RXNEMPTY (0)
+    // 0x00000001 [0]     : SM0_RXNEMPTY (0)
     io_rw_32 intf0;
+
+    _REG_(PIO_IRQ0_INTS_OFFSET) // PIO_IRQ0_INTS
+    // Interrupt status after masking & forcing for irq0
+    // 0x00000800 [11]    : SM3 (0)
+    // 0x00000400 [10]    : SM2 (0)
+    // 0x00000200 [9]     : SM1 (0)
+    // 0x00000100 [8]     : SM0 (0)
+    // 0x00000080 [7]     : SM3_TXNFULL (0)
+    // 0x00000040 [6]     : SM2_TXNFULL (0)
+    // 0x00000020 [5]     : SM1_TXNFULL (0)
+    // 0x00000010 [4]     : SM0_TXNFULL (0)
+    // 0x00000008 [3]     : SM3_RXNEMPTY (0)
+    // 0x00000004 [2]     : SM2_RXNEMPTY (0)
+    // 0x00000002 [1]     : SM1_RXNEMPTY (0)
+    // 0x00000001 [0]     : SM0_RXNEMPTY (0)
     io_ro_32 ints0;
+
+    _REG_(PIO_IRQ1_INTE_OFFSET) // PIO_IRQ1_INTE
+    // Interrupt Enable for irq1
+    // 0x00000800 [11]    : SM3 (0)
+    // 0x00000400 [10]    : SM2 (0)
+    // 0x00000200 [9]     : SM1 (0)
+    // 0x00000100 [8]     : SM0 (0)
+    // 0x00000080 [7]     : SM3_TXNFULL (0)
+    // 0x00000040 [6]     : SM2_TXNFULL (0)
+    // 0x00000020 [5]     : SM1_TXNFULL (0)
+    // 0x00000010 [4]     : SM0_TXNFULL (0)
+    // 0x00000008 [3]     : SM3_RXNEMPTY (0)
+    // 0x00000004 [2]     : SM2_RXNEMPTY (0)
+    // 0x00000002 [1]     : SM1_RXNEMPTY (0)
+    // 0x00000001 [0]     : SM0_RXNEMPTY (0)
     io_rw_32 inte1;
+
+    _REG_(PIO_IRQ1_INTF_OFFSET) // PIO_IRQ1_INTF
+    // Interrupt Force for irq1
+    // 0x00000800 [11]    : SM3 (0)
+    // 0x00000400 [10]    : SM2 (0)
+    // 0x00000200 [9]     : SM1 (0)
+    // 0x00000100 [8]     : SM0 (0)
+    // 0x00000080 [7]     : SM3_TXNFULL (0)
+    // 0x00000040 [6]     : SM2_TXNFULL (0)
+    // 0x00000020 [5]     : SM1_TXNFULL (0)
+    // 0x00000010 [4]     : SM0_TXNFULL (0)
+    // 0x00000008 [3]     : SM3_RXNEMPTY (0)
+    // 0x00000004 [2]     : SM2_RXNEMPTY (0)
+    // 0x00000002 [1]     : SM1_RXNEMPTY (0)
+    // 0x00000001 [0]     : SM0_RXNEMPTY (0)
     io_rw_32 intf1;
+
+    _REG_(PIO_IRQ1_INTS_OFFSET) // PIO_IRQ1_INTS
+    // Interrupt status after masking & forcing for irq1
+    // 0x00000800 [11]    : SM3 (0)
+    // 0x00000400 [10]    : SM2 (0)
+    // 0x00000200 [9]     : SM1 (0)
+    // 0x00000100 [8]     : SM0 (0)
+    // 0x00000080 [7]     : SM3_TXNFULL (0)
+    // 0x00000040 [6]     : SM2_TXNFULL (0)
+    // 0x00000020 [5]     : SM1_TXNFULL (0)
+    // 0x00000010 [4]     : SM0_TXNFULL (0)
+    // 0x00000008 [3]     : SM3_RXNEMPTY (0)
+    // 0x00000004 [2]     : SM2_RXNEMPTY (0)
+    // 0x00000002 [1]     : SM1_RXNEMPTY (0)
+    // 0x00000001 [0]     : SM0_RXNEMPTY (0)
     io_ro_32 ints1;
 } pio_hw_t;
 
 #define pio0_hw ((pio_hw_t *const)PIO0_BASE)
 #define pio1_hw ((pio_hw_t *const)PIO1_BASE)
 
+static_assert( NUM_PIO_STATE_MACHINES == 4, "");
+static_assert( PIO_INSTRUCTION_COUNT == 32, "");
+
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/pll.h b/src/rp2040/hardware_structs/include/hardware/structs/pll.h
index 4d5b5b7..5a506e3 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/pll.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/pll.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,11 +12,40 @@
 #include "hardware/address_mapped.h"
 #include "hardware/regs/pll.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_pll
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/pll.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 /// \tag::pll_hw[]
 typedef struct {
+    _REG_(PLL_CS_OFFSET) // PLL_CS
+    // Control and Status
+    // 0x80000000 [31]    : LOCK (0): PLL is locked
+    // 0x00000100 [8]     : BYPASS (0): Passes the reference clock to the output instead of the divided VCO
+    // 0x0000003f [5:0]   : REFDIV (1): Divides the PLL input reference clock
     io_rw_32 cs;
+
+    _REG_(PLL_PWR_OFFSET) // PLL_PWR
+    // Controls the PLL power modes
+    // 0x00000020 [5]     : VCOPD (1): PLL VCO powerdown
+    // 0x00000008 [3]     : POSTDIVPD (1): PLL post divider powerdown
+    // 0x00000004 [2]     : DSMPD (1): PLL DSM powerdown
+    // 0x00000001 [0]     : PD (1): PLL powerdown
     io_rw_32 pwr;
+
+    _REG_(PLL_FBDIV_INT_OFFSET) // PLL_FBDIV_INT
+    // Feedback divisor
+    // 0x00000fff [11:0]  : FBDIV_INT (0): see ctrl reg description for constraints
     io_rw_32 fbdiv_int;
+
+    _REG_(PLL_PRIM_OFFSET) // PLL_PRIM
+    // Controls the PLL post dividers for the primary output
+    // 0x00070000 [18:16] : POSTDIV1 (0x7): divide by 1-7
+    // 0x00007000 [14:12] : POSTDIV2 (0x7): divide by 1-7
     io_rw_32 prim;
 } pll_hw_t;
 
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/psm.h b/src/rp2040/hardware_structs/include/hardware/structs/psm.h
index cc9fb97..cdfb2e3 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/psm.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/psm.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,14 +10,100 @@
 #define _HARDWARE_STRUCTS_PSM_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/psm.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_psm
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/psm.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(PSM_FRCE_ON_OFFSET) // PSM_FRCE_ON
+    // Force block out of reset (i
+    // 0x00010000 [16]    : proc1 (0)
+    // 0x00008000 [15]    : proc0 (0)
+    // 0x00004000 [14]    : sio (0)
+    // 0x00002000 [13]    : vreg_and_chip_reset (0)
+    // 0x00001000 [12]    : xip (0)
+    // 0x00000800 [11]    : sram5 (0)
+    // 0x00000400 [10]    : sram4 (0)
+    // 0x00000200 [9]     : sram3 (0)
+    // 0x00000100 [8]     : sram2 (0)
+    // 0x00000080 [7]     : sram1 (0)
+    // 0x00000040 [6]     : sram0 (0)
+    // 0x00000020 [5]     : rom (0)
+    // 0x00000010 [4]     : busfabric (0)
+    // 0x00000008 [3]     : resets (0)
+    // 0x00000004 [2]     : clocks (0)
+    // 0x00000002 [1]     : xosc (0)
+    // 0x00000001 [0]     : rosc (0)
     io_rw_32 frce_on;
+
+    _REG_(PSM_FRCE_OFF_OFFSET) // PSM_FRCE_OFF
+    // Force into reset (i
+    // 0x00010000 [16]    : proc1 (0)
+    // 0x00008000 [15]    : proc0 (0)
+    // 0x00004000 [14]    : sio (0)
+    // 0x00002000 [13]    : vreg_and_chip_reset (0)
+    // 0x00001000 [12]    : xip (0)
+    // 0x00000800 [11]    : sram5 (0)
+    // 0x00000400 [10]    : sram4 (0)
+    // 0x00000200 [9]     : sram3 (0)
+    // 0x00000100 [8]     : sram2 (0)
+    // 0x00000080 [7]     : sram1 (0)
+    // 0x00000040 [6]     : sram0 (0)
+    // 0x00000020 [5]     : rom (0)
+    // 0x00000010 [4]     : busfabric (0)
+    // 0x00000008 [3]     : resets (0)
+    // 0x00000004 [2]     : clocks (0)
+    // 0x00000002 [1]     : xosc (0)
+    // 0x00000001 [0]     : rosc (0)
     io_rw_32 frce_off;
+
+    _REG_(PSM_WDSEL_OFFSET) // PSM_WDSEL
+    // Set to 1 if this peripheral should be reset when the watchdog fires
+    // 0x00010000 [16]    : proc1 (0)
+    // 0x00008000 [15]    : proc0 (0)
+    // 0x00004000 [14]    : sio (0)
+    // 0x00002000 [13]    : vreg_and_chip_reset (0)
+    // 0x00001000 [12]    : xip (0)
+    // 0x00000800 [11]    : sram5 (0)
+    // 0x00000400 [10]    : sram4 (0)
+    // 0x00000200 [9]     : sram3 (0)
+    // 0x00000100 [8]     : sram2 (0)
+    // 0x00000080 [7]     : sram1 (0)
+    // 0x00000040 [6]     : sram0 (0)
+    // 0x00000020 [5]     : rom (0)
+    // 0x00000010 [4]     : busfabric (0)
+    // 0x00000008 [3]     : resets (0)
+    // 0x00000004 [2]     : clocks (0)
+    // 0x00000002 [1]     : xosc (0)
+    // 0x00000001 [0]     : rosc (0)
     io_rw_32 wdsel;
-    io_rw_32 done;
+
+    _REG_(PSM_DONE_OFFSET) // PSM_DONE
+    // Indicates the peripheral's registers are ready to access
+    // 0x00010000 [16]    : proc1 (0)
+    // 0x00008000 [15]    : proc0 (0)
+    // 0x00004000 [14]    : sio (0)
+    // 0x00002000 [13]    : vreg_and_chip_reset (0)
+    // 0x00001000 [12]    : xip (0)
+    // 0x00000800 [11]    : sram5 (0)
+    // 0x00000400 [10]    : sram4 (0)
+    // 0x00000200 [9]     : sram3 (0)
+    // 0x00000100 [8]     : sram2 (0)
+    // 0x00000080 [7]     : sram1 (0)
+    // 0x00000040 [6]     : sram0 (0)
+    // 0x00000020 [5]     : rom (0)
+    // 0x00000010 [4]     : busfabric (0)
+    // 0x00000008 [3]     : resets (0)
+    // 0x00000004 [2]     : clocks (0)
+    // 0x00000002 [1]     : xosc (0)
+    // 0x00000001 [0]     : rosc (0)
+    io_ro_32 done;
 } psm_hw_t;
 
 #define psm_hw ((psm_hw_t *const)PSM_BASE)
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/pwm.h b/src/rp2040/hardware_structs/include/hardware/structs/pwm.h
index 5499561..fd9a75c 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/pwm.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/pwm.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,26 +10,117 @@
 #define _HARDWARE_STRUCTS_PWM_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/pwm.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_pwm
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/pwm.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct pwm_slice_hw {
+    _REG_(PWM_CH0_CSR_OFFSET) // PWM_CH0_CSR
+    // Control and status register
+    // 0x00000080 [7]     : PH_ADV (0): Advance the phase of the counter by 1 count, while it is running
+    // 0x00000040 [6]     : PH_RET (0): Retard the phase of the counter by 1 count, while it is running
+    // 0x00000030 [5:4]   : DIVMODE (0)
+    // 0x00000008 [3]     : B_INV (0): Invert output B
+    // 0x00000004 [2]     : A_INV (0): Invert output A
+    // 0x00000002 [1]     : PH_CORRECT (0): 1: Enable phase-correct modulation
+    // 0x00000001 [0]     : EN (0): Enable the PWM channel
     io_rw_32 csr;
+
+    _REG_(PWM_CH0_DIV_OFFSET) // PWM_CH0_DIV
+    // INT and FRAC form a fixed-point fractional number
+    // 0x00000ff0 [11:4]  : INT (1)
+    // 0x0000000f [3:0]   : FRAC (0)
     io_rw_32 div;
+
+    _REG_(PWM_CH0_CTR_OFFSET) // PWM_CH0_CTR
+    // Direct access to the PWM counter
+    // 0x0000ffff [15:0]  : CH0_CTR (0)
     io_rw_32 ctr;
+
+    _REG_(PWM_CH0_CC_OFFSET) // PWM_CH0_CC
+    // Counter compare values
+    // 0xffff0000 [31:16] : B (0)
+    // 0x0000ffff [15:0]  : A (0)
     io_rw_32 cc;
+
+    _REG_(PWM_CH0_TOP_OFFSET) // PWM_CH0_TOP
+    // Counter wrap value
+    // 0x0000ffff [15:0]  : CH0_TOP (0xffff)
     io_rw_32 top;
 } pwm_slice_hw_t;
 
 typedef struct {
-    pwm_slice_hw_t slice[NUM_PWM_SLICES];
+    pwm_slice_hw_t slice[NUM_PWM_SLICES]; // 8
+
+    _REG_(PWM_EN_OFFSET) // PWM_EN
+    // This register aliases the CSR_EN bits for all channels
+    // 0x00000080 [7]     : CH7 (0)
+    // 0x00000040 [6]     : CH6 (0)
+    // 0x00000020 [5]     : CH5 (0)
+    // 0x00000010 [4]     : CH4 (0)
+    // 0x00000008 [3]     : CH3 (0)
+    // 0x00000004 [2]     : CH2 (0)
+    // 0x00000002 [1]     : CH1 (0)
+    // 0x00000001 [0]     : CH0 (0)
     io_rw_32 en;
+
+    _REG_(PWM_INTR_OFFSET) // PWM_INTR
+    // Raw Interrupts
+    // 0x00000080 [7]     : CH7 (0)
+    // 0x00000040 [6]     : CH6 (0)
+    // 0x00000020 [5]     : CH5 (0)
+    // 0x00000010 [4]     : CH4 (0)
+    // 0x00000008 [3]     : CH3 (0)
+    // 0x00000004 [2]     : CH2 (0)
+    // 0x00000002 [1]     : CH1 (0)
+    // 0x00000001 [0]     : CH0 (0)
     io_rw_32 intr;
+
+    _REG_(PWM_INTE_OFFSET) // PWM_INTE
+    // Interrupt Enable
+    // 0x00000080 [7]     : CH7 (0)
+    // 0x00000040 [6]     : CH6 (0)
+    // 0x00000020 [5]     : CH5 (0)
+    // 0x00000010 [4]     : CH4 (0)
+    // 0x00000008 [3]     : CH3 (0)
+    // 0x00000004 [2]     : CH2 (0)
+    // 0x00000002 [1]     : CH1 (0)
+    // 0x00000001 [0]     : CH0 (0)
     io_rw_32 inte;
+
+    _REG_(PWM_INTF_OFFSET) // PWM_INTF
+    // Interrupt Force
+    // 0x00000080 [7]     : CH7 (0)
+    // 0x00000040 [6]     : CH6 (0)
+    // 0x00000020 [5]     : CH5 (0)
+    // 0x00000010 [4]     : CH4 (0)
+    // 0x00000008 [3]     : CH3 (0)
+    // 0x00000004 [2]     : CH2 (0)
+    // 0x00000002 [1]     : CH1 (0)
+    // 0x00000001 [0]     : CH0 (0)
     io_rw_32 intf;
-    io_rw_32 ints;
+
+    _REG_(PWM_INTS_OFFSET) // PWM_INTS
+    // Interrupt status after masking & forcing
+    // 0x00000080 [7]     : CH7 (0)
+    // 0x00000040 [6]     : CH6 (0)
+    // 0x00000020 [5]     : CH5 (0)
+    // 0x00000010 [4]     : CH4 (0)
+    // 0x00000008 [3]     : CH3 (0)
+    // 0x00000004 [2]     : CH2 (0)
+    // 0x00000002 [1]     : CH1 (0)
+    // 0x00000001 [0]     : CH0 (0)
+    io_ro_32 ints;
 } pwm_hw_t;
 
 #define pwm_hw ((pwm_hw_t *const)PWM_BASE)
 
+static_assert( NUM_PWM_SLICES == 8, "");
+
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/resets.h b/src/rp2040/hardware_structs/include/hardware/structs/resets.h
index a96ddeb..bc1c10c 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/resets.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/resets.h
@@ -1,19 +1,113 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
+
 #ifndef _HARDWARE_STRUCTS_RESETS_H
 #define _HARDWARE_STRUCTS_RESETS_H
 
 #include "hardware/address_mapped.h"
 #include "hardware/regs/resets.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_resets
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/resets.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 /// \tag::resets_hw[]
 typedef struct {
+    _REG_(RESETS_RESET_OFFSET) // RESETS_RESET
+    // Reset control
+    // 0x01000000 [24]    : usbctrl (1)
+    // 0x00800000 [23]    : uart1 (1)
+    // 0x00400000 [22]    : uart0 (1)
+    // 0x00200000 [21]    : timer (1)
+    // 0x00100000 [20]    : tbman (1)
+    // 0x00080000 [19]    : sysinfo (1)
+    // 0x00040000 [18]    : syscfg (1)
+    // 0x00020000 [17]    : spi1 (1)
+    // 0x00010000 [16]    : spi0 (1)
+    // 0x00008000 [15]    : rtc (1)
+    // 0x00004000 [14]    : pwm (1)
+    // 0x00002000 [13]    : pll_usb (1)
+    // 0x00001000 [12]    : pll_sys (1)
+    // 0x00000800 [11]    : pio1 (1)
+    // 0x00000400 [10]    : pio0 (1)
+    // 0x00000200 [9]     : pads_qspi (1)
+    // 0x00000100 [8]     : pads_bank0 (1)
+    // 0x00000080 [7]     : jtag (1)
+    // 0x00000040 [6]     : io_qspi (1)
+    // 0x00000020 [5]     : io_bank0 (1)
+    // 0x00000010 [4]     : i2c1 (1)
+    // 0x00000008 [3]     : i2c0 (1)
+    // 0x00000004 [2]     : dma (1)
+    // 0x00000002 [1]     : busctrl (1)
+    // 0x00000001 [0]     : adc (1)
     io_rw_32 reset;
+
+    _REG_(RESETS_WDSEL_OFFSET) // RESETS_WDSEL
+    // Watchdog select
+    // 0x01000000 [24]    : usbctrl (0)
+    // 0x00800000 [23]    : uart1 (0)
+    // 0x00400000 [22]    : uart0 (0)
+    // 0x00200000 [21]    : timer (0)
+    // 0x00100000 [20]    : tbman (0)
+    // 0x00080000 [19]    : sysinfo (0)
+    // 0x00040000 [18]    : syscfg (0)
+    // 0x00020000 [17]    : spi1 (0)
+    // 0x00010000 [16]    : spi0 (0)
+    // 0x00008000 [15]    : rtc (0)
+    // 0x00004000 [14]    : pwm (0)
+    // 0x00002000 [13]    : pll_usb (0)
+    // 0x00001000 [12]    : pll_sys (0)
+    // 0x00000800 [11]    : pio1 (0)
+    // 0x00000400 [10]    : pio0 (0)
+    // 0x00000200 [9]     : pads_qspi (0)
+    // 0x00000100 [8]     : pads_bank0 (0)
+    // 0x00000080 [7]     : jtag (0)
+    // 0x00000040 [6]     : io_qspi (0)
+    // 0x00000020 [5]     : io_bank0 (0)
+    // 0x00000010 [4]     : i2c1 (0)
+    // 0x00000008 [3]     : i2c0 (0)
+    // 0x00000004 [2]     : dma (0)
+    // 0x00000002 [1]     : busctrl (0)
+    // 0x00000001 [0]     : adc (0)
     io_rw_32 wdsel;
-    io_rw_32 reset_done;
+
+    _REG_(RESETS_RESET_DONE_OFFSET) // RESETS_RESET_DONE
+    // Reset done
+    // 0x01000000 [24]    : usbctrl (0)
+    // 0x00800000 [23]    : uart1 (0)
+    // 0x00400000 [22]    : uart0 (0)
+    // 0x00200000 [21]    : timer (0)
+    // 0x00100000 [20]    : tbman (0)
+    // 0x00080000 [19]    : sysinfo (0)
+    // 0x00040000 [18]    : syscfg (0)
+    // 0x00020000 [17]    : spi1 (0)
+    // 0x00010000 [16]    : spi0 (0)
+    // 0x00008000 [15]    : rtc (0)
+    // 0x00004000 [14]    : pwm (0)
+    // 0x00002000 [13]    : pll_usb (0)
+    // 0x00001000 [12]    : pll_sys (0)
+    // 0x00000800 [11]    : pio1 (0)
+    // 0x00000400 [10]    : pio0 (0)
+    // 0x00000200 [9]     : pads_qspi (0)
+    // 0x00000100 [8]     : pads_bank0 (0)
+    // 0x00000080 [7]     : jtag (0)
+    // 0x00000040 [6]     : io_qspi (0)
+    // 0x00000020 [5]     : io_bank0 (0)
+    // 0x00000010 [4]     : i2c1 (0)
+    // 0x00000008 [3]     : i2c0 (0)
+    // 0x00000004 [2]     : dma (0)
+    // 0x00000002 [1]     : busctrl (0)
+    // 0x00000001 [0]     : adc (0)
+    io_ro_32 reset_done;
 } resets_hw_t;
 
 #define resets_hw ((resets_hw_t *const)RESETS_BASE)
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/rosc.h b/src/rp2040/hardware_structs/include/hardware/structs/rosc.h
index 1054393..114c602 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/rosc.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/rosc.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,20 +10,75 @@
 #define _HARDWARE_STRUCTS_ROSC_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/rosc.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_rosc
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/rosc.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(ROSC_CTRL_OFFSET) // ROSC_CTRL
+    // Ring Oscillator control
+    // 0x00fff000 [23:12] : ENABLE (0): On power-up this field is initialised to ENABLE
+    // 0x00000fff [11:0]  : FREQ_RANGE (0xaa0): Controls the number of delay stages in the ROSC ring
     io_rw_32 ctrl;
+
+    _REG_(ROSC_FREQA_OFFSET) // ROSC_FREQA
+    // The FREQA & FREQB registers control the frequency by controlling the drive strength of each stage
+    // 0xffff0000 [31:16] : PASSWD (0): Set to 0x9696 to apply the settings
+    // 0x00007000 [14:12] : DS3 (0): Stage 3 drive strength
+    // 0x00000700 [10:8]  : DS2 (0): Stage 2 drive strength
+    // 0x00000070 [6:4]   : DS1 (0): Stage 1 drive strength
+    // 0x00000007 [2:0]   : DS0 (0): Stage 0 drive strength
     io_rw_32 freqa;
+
+    _REG_(ROSC_FREQB_OFFSET) // ROSC_FREQB
+    // For a detailed description see freqa register
+    // 0xffff0000 [31:16] : PASSWD (0): Set to 0x9696 to apply the settings
+    // 0x00007000 [14:12] : DS7 (0): Stage 7 drive strength
+    // 0x00000700 [10:8]  : DS6 (0): Stage 6 drive strength
+    // 0x00000070 [6:4]   : DS5 (0): Stage 5 drive strength
+    // 0x00000007 [2:0]   : DS4 (0): Stage 4 drive strength
     io_rw_32 freqb;
+
+    _REG_(ROSC_DORMANT_OFFSET) // ROSC_DORMANT
+    // Ring Oscillator pause control
     io_rw_32 dormant;
+
+    _REG_(ROSC_DIV_OFFSET) // ROSC_DIV
+    // Controls the output divider
+    // 0x00000fff [11:0]  : DIV (0): set to 0xaa0 + div where
     io_rw_32 div;
+
+    _REG_(ROSC_PHASE_OFFSET) // ROSC_PHASE
+    // Controls the phase shifted output
+    // 0x00000ff0 [11:4]  : PASSWD (0): set to 0xaa
+    // 0x00000008 [3]     : ENABLE (1): enable the phase-shifted output
+    // 0x00000004 [2]     : FLIP (0): invert the phase-shifted output
+    // 0x00000003 [1:0]   : SHIFT (0): phase shift the phase-shifted output by SHIFT input clocks
     io_rw_32 phase;
+
+    _REG_(ROSC_STATUS_OFFSET) // ROSC_STATUS
+    // Ring Oscillator Status
+    // 0x80000000 [31]    : STABLE (0): Oscillator is running and stable
+    // 0x01000000 [24]    : BADWRITE (0): An invalid value has been written to CTRL_ENABLE or CTRL_FREQ_RANGE or FREQA or...
+    // 0x00010000 [16]    : DIV_RUNNING (0): post-divider is running
+    // 0x00001000 [12]    : ENABLED (0): Oscillator is enabled but not necessarily running and stable
     io_rw_32 status;
-    io_rw_32 randombit;
+
+    _REG_(ROSC_RANDOMBIT_OFFSET) // ROSC_RANDOMBIT
+    // This just reads the state of the oscillator output so randomness is compromised if the ring oscillator is stopped or...
+    // 0x00000001 [0]     : RANDOMBIT (1)
+    io_ro_32 randombit;
+
+    _REG_(ROSC_COUNT_OFFSET) // ROSC_COUNT
+    // A down counter running at the ROSC frequency which counts to zero and stops
+    // 0x000000ff [7:0]   : COUNT (0)
     io_rw_32 count;
-    io_rw_32 dftx;
 } rosc_hw_t;
 
 #define rosc_hw ((rosc_hw_t *const)ROSC_BASE)
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/rtc.h b/src/rp2040/hardware_structs/include/hardware/structs/rtc.h
index 276bd7a..794a0e0 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/rtc.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/rtc.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,22 +10,103 @@
 #define _HARDWARE_STRUCTS_RTC_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/rtc.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_rtc
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/rtc.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(RTC_CLKDIV_M1_OFFSET) // RTC_CLKDIV_M1
+    // Divider minus 1 for the 1 second counter
+    // 0x0000ffff [15:0]  : CLKDIV_M1 (0)
     io_rw_32 clkdiv_m1;
+
+    _REG_(RTC_SETUP_0_OFFSET) // RTC_SETUP_0
+    // RTC setup register 0
+    // 0x00fff000 [23:12] : YEAR (0): Year
+    // 0x00000f00 [11:8]  : MONTH (0): Month (1
+    // 0x0000001f [4:0]   : DAY (0): Day of the month (1
     io_rw_32 setup_0;
+
+    _REG_(RTC_SETUP_1_OFFSET) // RTC_SETUP_1
+    // RTC setup register 1
+    // 0x07000000 [26:24] : DOTW (0): Day of the week: 1-Monday
+    // 0x001f0000 [20:16] : HOUR (0): Hours
+    // 0x00003f00 [13:8]  : MIN (0): Minutes
+    // 0x0000003f [5:0]   : SEC (0): Seconds
     io_rw_32 setup_1;
+
+    _REG_(RTC_CTRL_OFFSET) // RTC_CTRL
+    // RTC Control and status
+    // 0x00000100 [8]     : FORCE_NOTLEAPYEAR (0): If set, leapyear is forced off
+    // 0x00000010 [4]     : LOAD (0): Load RTC
+    // 0x00000002 [1]     : RTC_ACTIVE (0): RTC enabled (running)
+    // 0x00000001 [0]     : RTC_ENABLE (0): Enable RTC
     io_rw_32 ctrl;
+
+    _REG_(RTC_IRQ_SETUP_0_OFFSET) // RTC_IRQ_SETUP_0
+    // Interrupt setup register 0
+    // 0x20000000 [29]    : MATCH_ACTIVE (0)
+    // 0x10000000 [28]    : MATCH_ENA (0): Global match enable
+    // 0x04000000 [26]    : YEAR_ENA (0): Enable year matching
+    // 0x02000000 [25]    : MONTH_ENA (0): Enable month matching
+    // 0x01000000 [24]    : DAY_ENA (0): Enable day matching
+    // 0x00fff000 [23:12] : YEAR (0): Year
+    // 0x00000f00 [11:8]  : MONTH (0): Month (1
+    // 0x0000001f [4:0]   : DAY (0): Day of the month (1
     io_rw_32 irq_setup_0;
+
+    _REG_(RTC_IRQ_SETUP_1_OFFSET) // RTC_IRQ_SETUP_1
+    // Interrupt setup register 1
+    // 0x80000000 [31]    : DOTW_ENA (0): Enable day of the week matching
+    // 0x40000000 [30]    : HOUR_ENA (0): Enable hour matching
+    // 0x20000000 [29]    : MIN_ENA (0): Enable minute matching
+    // 0x10000000 [28]    : SEC_ENA (0): Enable second matching
+    // 0x07000000 [26:24] : DOTW (0): Day of the week
+    // 0x001f0000 [20:16] : HOUR (0): Hours
+    // 0x00003f00 [13:8]  : MIN (0): Minutes
+    // 0x0000003f [5:0]   : SEC (0): Seconds
     io_rw_32 irq_setup_1;
-    io_rw_32 rtc_1;
-    io_rw_32 rtc_0;
-    io_rw_32 intr;
+
+    _REG_(RTC_RTC_1_OFFSET) // RTC_RTC_1
+    // RTC register 1
+    // 0x00fff000 [23:12] : YEAR (0): Year
+    // 0x00000f00 [11:8]  : MONTH (0): Month (1
+    // 0x0000001f [4:0]   : DAY (0): Day of the month (1
+    io_ro_32 rtc_1;
+
+    _REG_(RTC_RTC_0_OFFSET) // RTC_RTC_0
+    // RTC register 0
+    // 0x07000000 [26:24] : DOTW (0): Day of the week
+    // 0x001f0000 [20:16] : HOUR (0): Hours
+    // 0x00003f00 [13:8]  : MIN (0): Minutes
+    // 0x0000003f [5:0]   : SEC (0): Seconds
+    io_ro_32 rtc_0;
+
+    _REG_(RTC_INTR_OFFSET) // RTC_INTR
+    // Raw Interrupts
+    // 0x00000001 [0]     : RTC (0)
+    io_ro_32 intr;
+
+    _REG_(RTC_INTE_OFFSET) // RTC_INTE
+    // Interrupt Enable
+    // 0x00000001 [0]     : RTC (0)
     io_rw_32 inte;
+
+    _REG_(RTC_INTF_OFFSET) // RTC_INTF
+    // Interrupt Force
+    // 0x00000001 [0]     : RTC (0)
     io_rw_32 intf;
-    io_rw_32 ints;
+
+    _REG_(RTC_INTS_OFFSET) // RTC_INTS
+    // Interrupt status after masking & forcing
+    // 0x00000001 [0]     : RTC (0)
+    io_ro_32 ints;
 } rtc_hw_t;
 
 #define rtc_hw ((rtc_hw_t *const)RTC_BASE)
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/scb.h b/src/rp2040/hardware_structs/include/hardware/structs/scb.h
index b48a872..42569c7 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/scb.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/scb.h
@@ -1,22 +1,67 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
+
 #ifndef _HARDWARE_STRUCTS_SCB_H
 #define _HARDWARE_STRUCTS_SCB_H
 
 #include "hardware/address_mapped.h"
 #include "hardware/regs/m0plus.h"
 
-// SCB == System Control Block
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_m0plus
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/m0plus.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(M0PLUS_CPUID_OFFSET) // M0PLUS_CPUID
+    // Read the CPU ID Base Register to determine: the ID number of the processor core, the version number of the processor...
+    // 0xff000000 [31:24] : IMPLEMENTER (0x41): Implementor code: 0x41 = ARM
+    // 0x00f00000 [23:20] : VARIANT (0): Major revision number n in the rnpm revision status:
+    // 0x000f0000 [19:16] : ARCHITECTURE (0xc): Constant that defines the architecture of the processor:
+    // 0x0000fff0 [15:4]  : PARTNO (0xc60): Number of processor within family: 0xC60 = Cortex-M0+
+    // 0x0000000f [3:0]   : REVISION (1): Minor revision number m in the rnpm revision status:
     io_ro_32 cpuid;
+
+    _REG_(M0PLUS_ICSR_OFFSET) // M0PLUS_ICSR
+    // Use the Interrupt Control State Register to set a pending Non-Maskable Interrupt (NMI), set or clear a pending...
+    // 0x80000000 [31]    : NMIPENDSET (0): Setting this bit will activate an NMI
+    // 0x10000000 [28]    : PENDSVSET (0): PendSV set-pending bit
+    // 0x08000000 [27]    : PENDSVCLR (0): PendSV clear-pending bit
+    // 0x04000000 [26]    : PENDSTSET (0): SysTick exception set-pending bit
+    // 0x02000000 [25]    : PENDSTCLR (0): SysTick exception clear-pending bit
+    // 0x00800000 [23]    : ISRPREEMPT (0): The system can only access this bit when the core is halted
+    // 0x00400000 [22]    : ISRPENDING (0): External interrupt pending flag
+    // 0x001ff000 [20:12] : VECTPENDING (0): Indicates the exception number for the highest priority pending exception: 0 =...
+    // 0x000001ff [8:0]   : VECTACTIVE (0): Active exception number field
     io_rw_32 icsr;
+
+    _REG_(M0PLUS_VTOR_OFFSET) // M0PLUS_VTOR
+    // The VTOR holds the vector table offset address
+    // 0xffffff00 [31:8]  : TBLOFF (0): Bits [31:8] of the indicate the vector table offset address
     io_rw_32 vtor;
+
+    _REG_(M0PLUS_AIRCR_OFFSET) // M0PLUS_AIRCR
+    // Use the Application Interrupt and Reset Control Register to: determine data endianness, clear all active state...
+    // 0xffff0000 [31:16] : VECTKEY (0): Register key:
+    // 0x00008000 [15]    : ENDIANESS (0): Data endianness implemented:
+    // 0x00000004 [2]     : SYSRESETREQ (0): Writing 1 to this bit causes the SYSRESETREQ signal to the outer system to be...
+    // 0x00000002 [1]     : VECTCLRACTIVE (0): Clears all active state information for fixed and configurable exceptions
     io_rw_32 aircr;
+
+    _REG_(M0PLUS_SCR_OFFSET) // M0PLUS_SCR
+    // System Control Register
+    // 0x00000010 [4]     : SEVONPEND (0): Send Event on Pending bit:
+    // 0x00000004 [2]     : SLEEPDEEP (0): Controls whether the processor uses sleep or deep sleep as its low power mode:
+    // 0x00000002 [1]     : SLEEPONEXIT (0): Indicates sleep-on-exit when returning from Handler mode to Thread mode:
     io_rw_32 scr;
-    // ...
 } armv6m_scb_t;
 
 #define scb_hw ((armv6m_scb_t *const)(PPB_BASE + M0PLUS_CPUID_OFFSET))
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/sio.h b/src/rp2040/hardware_structs/include/hardware/structs/sio.h
index bc277af..00b7e7e 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/sio.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/sio.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,51 +13,164 @@
 #include "hardware/regs/sio.h"
 #include "hardware/structs/interp.h"
 
-typedef struct {
-    io_ro_32 cpuid;
-    io_ro_32 gpio_in;
-    io_ro_32 gpio_hi_in;
-    uint32_t _pad;
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_sio
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/sio.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
 
+typedef struct {
+    _REG_(SIO_CPUID_OFFSET) // SIO_CPUID
+    // Processor core identifier
+    io_ro_32 cpuid;
+
+    _REG_(SIO_GPIO_IN_OFFSET) // SIO_GPIO_IN
+    // Input value for GPIO pins
+    // 0x3fffffff [29:0]  : GPIO_IN (0): Input value for GPIO0
+    io_ro_32 gpio_in;
+
+    _REG_(SIO_GPIO_HI_IN_OFFSET) // SIO_GPIO_HI_IN
+    // Input value for QSPI pins
+    // 0x0000003f [5:0]   : GPIO_HI_IN (0): Input value on QSPI IO in order 0
+    io_ro_32 gpio_hi_in;
+
+    uint32_t _pad0;
+
+    _REG_(SIO_GPIO_OUT_OFFSET) // SIO_GPIO_OUT
+    // GPIO output value
+    // 0x3fffffff [29:0]  : GPIO_OUT (0): Set output level (1/0 -> high/low) for GPIO0
     io_rw_32 gpio_out;
+
+    _REG_(SIO_GPIO_OUT_SET_OFFSET) // SIO_GPIO_OUT_SET
+    // GPIO output value set
+    // 0x3fffffff [29:0]  : GPIO_OUT_SET (0): Perform an atomic bit-set on GPIO_OUT, i
     io_wo_32 gpio_set;
+
+    _REG_(SIO_GPIO_OUT_CLR_OFFSET) // SIO_GPIO_OUT_CLR
+    // GPIO output value clear
+    // 0x3fffffff [29:0]  : GPIO_OUT_CLR (0): Perform an atomic bit-clear on GPIO_OUT, i
     io_wo_32 gpio_clr;
+
+    _REG_(SIO_GPIO_OUT_XOR_OFFSET) // SIO_GPIO_OUT_XOR
+    // GPIO output value XOR
+    // 0x3fffffff [29:0]  : GPIO_OUT_XOR (0): Perform an atomic bitwise XOR on GPIO_OUT, i
     io_wo_32 gpio_togl;
 
-    io_wo_32 gpio_oe;
+    _REG_(SIO_GPIO_OE_OFFSET) // SIO_GPIO_OE
+    // GPIO output enable
+    // 0x3fffffff [29:0]  : GPIO_OE (0): Set output enable (1/0 -> output/input) for GPIO0
+    io_rw_32 gpio_oe;
+
+    _REG_(SIO_GPIO_OE_SET_OFFSET) // SIO_GPIO_OE_SET
+    // GPIO output enable set
+    // 0x3fffffff [29:0]  : GPIO_OE_SET (0): Perform an atomic bit-set on GPIO_OE, i
     io_wo_32 gpio_oe_set;
+
+    _REG_(SIO_GPIO_OE_CLR_OFFSET) // SIO_GPIO_OE_CLR
+    // GPIO output enable clear
+    // 0x3fffffff [29:0]  : GPIO_OE_CLR (0): Perform an atomic bit-clear on GPIO_OE, i
     io_wo_32 gpio_oe_clr;
+
+    _REG_(SIO_GPIO_OE_XOR_OFFSET) // SIO_GPIO_OE_XOR
+    // GPIO output enable XOR
+    // 0x3fffffff [29:0]  : GPIO_OE_XOR (0): Perform an atomic bitwise XOR on GPIO_OE, i
     io_wo_32 gpio_oe_togl;
 
+    _REG_(SIO_GPIO_HI_OUT_OFFSET) // SIO_GPIO_HI_OUT
+    // QSPI output value
+    // 0x0000003f [5:0]   : GPIO_HI_OUT (0): Set output level (1/0 -> high/low) for QSPI IO0
     io_rw_32 gpio_hi_out;
+
+    _REG_(SIO_GPIO_HI_OUT_SET_OFFSET) // SIO_GPIO_HI_OUT_SET
+    // QSPI output value set
+    // 0x0000003f [5:0]   : GPIO_HI_OUT_SET (0): Perform an atomic bit-set on GPIO_HI_OUT, i
     io_wo_32 gpio_hi_set;
+
+    _REG_(SIO_GPIO_HI_OUT_CLR_OFFSET) // SIO_GPIO_HI_OUT_CLR
+    // QSPI output value clear
+    // 0x0000003f [5:0]   : GPIO_HI_OUT_CLR (0): Perform an atomic bit-clear on GPIO_HI_OUT, i
     io_wo_32 gpio_hi_clr;
+
+    _REG_(SIO_GPIO_HI_OUT_XOR_OFFSET) // SIO_GPIO_HI_OUT_XOR
+    // QSPI output value XOR
+    // 0x0000003f [5:0]   : GPIO_HI_OUT_XOR (0): Perform an atomic bitwise XOR on GPIO_HI_OUT, i
     io_wo_32 gpio_hi_togl;
 
-    io_wo_32 gpio_hi_oe;
+    _REG_(SIO_GPIO_HI_OE_OFFSET) // SIO_GPIO_HI_OE
+    // QSPI output enable
+    // 0x0000003f [5:0]   : GPIO_HI_OE (0): Set output enable (1/0 -> output/input) for QSPI IO0
+    io_rw_32 gpio_hi_oe;
+
+    _REG_(SIO_GPIO_HI_OE_SET_OFFSET) // SIO_GPIO_HI_OE_SET
+    // QSPI output enable set
+    // 0x0000003f [5:0]   : GPIO_HI_OE_SET (0): Perform an atomic bit-set on GPIO_HI_OE, i
     io_wo_32 gpio_hi_oe_set;
+
+    _REG_(SIO_GPIO_HI_OE_CLR_OFFSET) // SIO_GPIO_HI_OE_CLR
+    // QSPI output enable clear
+    // 0x0000003f [5:0]   : GPIO_HI_OE_CLR (0): Perform an atomic bit-clear on GPIO_HI_OE, i
     io_wo_32 gpio_hi_oe_clr;
+
+    _REG_(SIO_GPIO_HI_OE_XOR_OFFSET) // SIO_GPIO_HI_OE_XOR
+    // QSPI output enable XOR
+    // 0x0000003f [5:0]   : GPIO_HI_OE_XOR (0): Perform an atomic bitwise XOR on GPIO_HI_OE, i
     io_wo_32 gpio_hi_oe_togl;
 
+    _REG_(SIO_FIFO_ST_OFFSET) // SIO_FIFO_ST
+    // Status register for inter-core FIFOs (mailboxes)
+    // 0x00000008 [3]     : ROE (0): Sticky flag indicating the RX FIFO was read when empty
+    // 0x00000004 [2]     : WOF (0): Sticky flag indicating the TX FIFO was written when full
+    // 0x00000002 [1]     : RDY (1): Value is 1 if this core's TX FIFO is not full (i
+    // 0x00000001 [0]     : VLD (0): Value is 1 if this core's RX FIFO is not empty (i
     io_rw_32 fifo_st;
+
+    _REG_(SIO_FIFO_WR_OFFSET) // SIO_FIFO_WR
+    // Write access to this core's TX FIFO
     io_wo_32 fifo_wr;
+
+    _REG_(SIO_FIFO_RD_OFFSET) // SIO_FIFO_RD
+    // Read access to this core's RX FIFO
     io_ro_32 fifo_rd;
+
+    _REG_(SIO_SPINLOCK_ST_OFFSET) // SIO_SPINLOCK_ST
+    // Spinlock state
     io_ro_32 spinlock_st;
 
+    _REG_(SIO_DIV_UDIVIDEND_OFFSET) // SIO_DIV_UDIVIDEND
+    // Divider unsigned dividend
     io_rw_32 div_udividend;
+
+    _REG_(SIO_DIV_UDIVISOR_OFFSET) // SIO_DIV_UDIVISOR
+    // Divider unsigned divisor
     io_rw_32 div_udivisor;
+
+    _REG_(SIO_DIV_SDIVIDEND_OFFSET) // SIO_DIV_SDIVIDEND
+    // Divider signed dividend
     io_rw_32 div_sdividend;
+
+    _REG_(SIO_DIV_SDIVISOR_OFFSET) // SIO_DIV_SDIVISOR
+    // Divider signed divisor
     io_rw_32 div_sdivisor;
 
+    _REG_(SIO_DIV_QUOTIENT_OFFSET) // SIO_DIV_QUOTIENT
+    // Divider result quotient
     io_rw_32 div_quotient;
+
+    _REG_(SIO_DIV_REMAINDER_OFFSET) // SIO_DIV_REMAINDER
+    // Divider result remainder
     io_rw_32 div_remainder;
-    io_rw_32 div_csr;
 
-    uint32_t _pad2;
-
+    _REG_(SIO_DIV_CSR_OFFSET) // SIO_DIV_CSR
+    // Control and status register for divider
+    // 0x00000002 [1]     : DIRTY (0): Changes to 1 when any register is written, and back to 0 when QUOTIENT is read
+    // 0x00000001 [0]     : READY (1): Reads as 0 when a calculation is in progress, 1 otherwise
+    io_ro_32 div_csr;
+    uint32_t _pad1;
     interp_hw_t interp[2];
 } sio_hw_t;
 
-#define sio_hw ((sio_hw_t *)SIO_BASE)
+#define sio_hw ((sio_hw_t *const)SIO_BASE)
 
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/spi.h b/src/rp2040/hardware_structs/include/hardware/structs/spi.h
index 5b3b2ba..f7fffb8 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/spi.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/spi.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,16 +12,85 @@
 #include "hardware/address_mapped.h"
 #include "hardware/regs/spi.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_spi
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/spi.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(SPI_SSPCR0_OFFSET) // SPI_SSPCR0
+    // Control register 0, SSPCR0 on page 3-4
+    // 0x0000ff00 [15:8]  : SCR (0): Serial clock rate
+    // 0x00000080 [7]     : SPH (0): SSPCLKOUT phase, applicable to Motorola SPI frame format only
+    // 0x00000040 [6]     : SPO (0): SSPCLKOUT polarity, applicable to Motorola SPI frame format only
+    // 0x00000030 [5:4]   : FRF (0): Frame format: 00 Motorola SPI frame format
+    // 0x0000000f [3:0]   : DSS (0): Data Size Select: 0000 Reserved, undefined operation
     io_rw_32 cr0;
+
+    _REG_(SPI_SSPCR1_OFFSET) // SPI_SSPCR1
+    // Control register 1, SSPCR1 on page 3-5
+    // 0x00000008 [3]     : SOD (0): Slave-mode output disable
+    // 0x00000004 [2]     : MS (0): Master or slave mode select
+    // 0x00000002 [1]     : SSE (0): Synchronous serial port enable: 0 SSP operation disabled
+    // 0x00000001 [0]     : LBM (0): Loop back mode: 0 Normal serial port operation enabled
     io_rw_32 cr1;
+
+    _REG_(SPI_SSPDR_OFFSET) // SPI_SSPDR
+    // Data register, SSPDR on page 3-6
+    // 0x0000ffff [15:0]  : DATA (0): Transmit/Receive FIFO: Read Receive FIFO
     io_rw_32 dr;
-    io_rw_32 sr;
+
+    _REG_(SPI_SSPSR_OFFSET) // SPI_SSPSR
+    // Status register, SSPSR on page 3-7
+    // 0x00000010 [4]     : BSY (0): PrimeCell SSP busy flag, RO: 0 SSP is idle
+    // 0x00000008 [3]     : RFF (0): Receive FIFO full, RO: 0 Receive FIFO is not full
+    // 0x00000004 [2]     : RNE (0): Receive FIFO not empty, RO: 0 Receive FIFO is empty
+    // 0x00000002 [1]     : TNF (1): Transmit FIFO not full, RO: 0 Transmit FIFO is full
+    // 0x00000001 [0]     : TFE (1): Transmit FIFO empty, RO: 0 Transmit FIFO is not empty
+    io_ro_32 sr;
+
+    _REG_(SPI_SSPCPSR_OFFSET) // SPI_SSPCPSR
+    // Clock prescale register, SSPCPSR on page 3-8
+    // 0x000000ff [7:0]   : CPSDVSR (0): Clock prescale divisor
     io_rw_32 cpsr;
+
+    _REG_(SPI_SSPIMSC_OFFSET) // SPI_SSPIMSC
+    // Interrupt mask set or clear register, SSPIMSC on page 3-9
+    // 0x00000008 [3]     : TXIM (0): Transmit FIFO interrupt mask: 0 Transmit FIFO half empty or less condition interrupt is masked
+    // 0x00000004 [2]     : RXIM (0): Receive FIFO interrupt mask: 0 Receive FIFO half full or less condition interrupt is masked
+    // 0x00000002 [1]     : RTIM (0): Receive timeout interrupt mask: 0 Receive FIFO not empty and no read prior to timeout...
+    // 0x00000001 [0]     : RORIM (0): Receive overrun interrupt mask: 0 Receive FIFO written to while full condition...
     io_rw_32 imsc;
-    io_rw_32 ris;
-    io_rw_32 mis;
+
+    _REG_(SPI_SSPRIS_OFFSET) // SPI_SSPRIS
+    // Raw interrupt status register, SSPRIS on page 3-10
+    // 0x00000008 [3]     : TXRIS (1): Gives the raw interrupt state, prior to masking, of the SSPTXINTR interrupt
+    // 0x00000004 [2]     : RXRIS (0): Gives the raw interrupt state, prior to masking, of the SSPRXINTR interrupt
+    // 0x00000002 [1]     : RTRIS (0): Gives the raw interrupt state, prior to masking, of the SSPRTINTR interrupt
+    // 0x00000001 [0]     : RORRIS (0): Gives the raw interrupt state, prior to masking, of the SSPRORINTR interrupt
+    io_ro_32 ris;
+
+    _REG_(SPI_SSPMIS_OFFSET) // SPI_SSPMIS
+    // Masked interrupt status register, SSPMIS on page 3-11
+    // 0x00000008 [3]     : TXMIS (0): Gives the transmit FIFO masked interrupt state, after masking, of the SSPTXINTR interrupt
+    // 0x00000004 [2]     : RXMIS (0): Gives the receive FIFO masked interrupt state, after masking, of the SSPRXINTR interrupt
+    // 0x00000002 [1]     : RTMIS (0): Gives the receive timeout masked interrupt state, after masking, of the SSPRTINTR interrupt
+    // 0x00000001 [0]     : RORMIS (0): Gives the receive over run masked interrupt status, after masking, of the...
+    io_ro_32 mis;
+
+    _REG_(SPI_SSPICR_OFFSET) // SPI_SSPICR
+    // Interrupt clear register, SSPICR on page 3-11
+    // 0x00000002 [1]     : RTIC (0): Clears the SSPRTINTR interrupt
+    // 0x00000001 [0]     : RORIC (0): Clears the SSPRORINTR interrupt
     io_rw_32 icr;
+
+    _REG_(SPI_SSPDMACR_OFFSET) // SPI_SSPDMACR
+    // DMA control register, SSPDMACR on page 3-12
+    // 0x00000002 [1]     : TXDMAE (0): Transmit DMA Enable
+    // 0x00000001 [0]     : RXDMAE (0): Receive DMA Enable
     io_rw_32 dmacr;
 } spi_hw_t;
 
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/ssi.h b/src/rp2040/hardware_structs/include/hardware/structs/ssi.h
index 80779fe..0ab18be 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/ssi.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/ssi.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,40 +10,201 @@
 #define _HARDWARE_STRUCTS_SSI_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/ssi.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_ssi
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/ssi.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(SSI_CTRLR0_OFFSET) // SSI_CTRLR0
+    // Control register 0
+    // 0x01000000 [24]    : SSTE (0): Slave select toggle enable
+    // 0x00600000 [22:21] : SPI_FRF (0): SPI frame format
+    // 0x001f0000 [20:16] : DFS_32 (0): Data frame size in 32b transfer mode
+    // 0x0000f000 [15:12] : CFS (0): Control frame size
+    // 0x00000800 [11]    : SRL (0): Shift register loop (test mode)
+    // 0x00000400 [10]    : SLV_OE (0): Slave output enable
+    // 0x00000300 [9:8]   : TMOD (0): Transfer mode
+    // 0x00000080 [7]     : SCPOL (0): Serial clock polarity
+    // 0x00000040 [6]     : SCPH (0): Serial clock phase
+    // 0x00000030 [5:4]   : FRF (0): Frame format
+    // 0x0000000f [3:0]   : DFS (0): Data frame size
     io_rw_32 ctrlr0;
+
+    _REG_(SSI_CTRLR1_OFFSET) // SSI_CTRLR1
+    // Master Control register 1
+    // 0x0000ffff [15:0]  : NDF (0): Number of data frames
     io_rw_32 ctrlr1;
+
+    _REG_(SSI_SSIENR_OFFSET) // SSI_SSIENR
+    // SSI Enable
+    // 0x00000001 [0]     : SSI_EN (0): SSI enable
     io_rw_32 ssienr;
+
+    _REG_(SSI_MWCR_OFFSET) // SSI_MWCR
+    // Microwire Control
+    // 0x00000004 [2]     : MHS (0): Microwire handshaking
+    // 0x00000002 [1]     : MDD (0): Microwire control
+    // 0x00000001 [0]     : MWMOD (0): Microwire transfer mode
     io_rw_32 mwcr;
+
+    _REG_(SSI_SER_OFFSET) // SSI_SER
+    // Slave enable
+    // 0x00000001 [0]     : SER (0): For each bit:
     io_rw_32 ser;
+
+    _REG_(SSI_BAUDR_OFFSET) // SSI_BAUDR
+    // Baud rate
+    // 0x0000ffff [15:0]  : SCKDV (0): SSI clock divider
     io_rw_32 baudr;
+
+    _REG_(SSI_TXFTLR_OFFSET) // SSI_TXFTLR
+    // TX FIFO threshold level
+    // 0x000000ff [7:0]   : TFT (0): Transmit FIFO threshold
     io_rw_32 txftlr;
+
+    _REG_(SSI_RXFTLR_OFFSET) // SSI_RXFTLR
+    // RX FIFO threshold level
+    // 0x000000ff [7:0]   : RFT (0): Receive FIFO threshold
     io_rw_32 rxftlr;
-    io_rw_32 txflr;
-    io_rw_32 rxflr;
-    io_rw_32 sr;
+
+    _REG_(SSI_TXFLR_OFFSET) // SSI_TXFLR
+    // TX FIFO level
+    // 0x000000ff [7:0]   : TFTFL (0): Transmit FIFO level
+    io_ro_32 txflr;
+
+    _REG_(SSI_RXFLR_OFFSET) // SSI_RXFLR
+    // RX FIFO level
+    // 0x000000ff [7:0]   : RXTFL (0): Receive FIFO level
+    io_ro_32 rxflr;
+
+    _REG_(SSI_SR_OFFSET) // SSI_SR
+    // Status register
+    // 0x00000040 [6]     : DCOL (0): Data collision error
+    // 0x00000020 [5]     : TXE (0): Transmission error
+    // 0x00000010 [4]     : RFF (0): Receive FIFO full
+    // 0x00000008 [3]     : RFNE (0): Receive FIFO not empty
+    // 0x00000004 [2]     : TFE (0): Transmit FIFO empty
+    // 0x00000002 [1]     : TFNF (0): Transmit FIFO not full
+    // 0x00000001 [0]     : BUSY (0): SSI busy flag
+    io_ro_32 sr;
+
+    _REG_(SSI_IMR_OFFSET) // SSI_IMR
+    // Interrupt mask
+    // 0x00000020 [5]     : MSTIM (0): Multi-master contention interrupt mask
+    // 0x00000010 [4]     : RXFIM (0): Receive FIFO full interrupt mask
+    // 0x00000008 [3]     : RXOIM (0): Receive FIFO overflow interrupt mask
+    // 0x00000004 [2]     : RXUIM (0): Receive FIFO underflow interrupt mask
+    // 0x00000002 [1]     : TXOIM (0): Transmit FIFO overflow interrupt mask
+    // 0x00000001 [0]     : TXEIM (0): Transmit FIFO empty interrupt mask
     io_rw_32 imr;
-    io_rw_32 isr;
-    io_rw_32 risr;
-    io_rw_32 txoicr;
-    io_rw_32 rxoicr;
-    io_rw_32 rxuicr;
-    io_rw_32 msticr;
-    io_rw_32 icr;
+
+    _REG_(SSI_ISR_OFFSET) // SSI_ISR
+    // Interrupt status
+    // 0x00000020 [5]     : MSTIS (0): Multi-master contention interrupt status
+    // 0x00000010 [4]     : RXFIS (0): Receive FIFO full interrupt status
+    // 0x00000008 [3]     : RXOIS (0): Receive FIFO overflow interrupt status
+    // 0x00000004 [2]     : RXUIS (0): Receive FIFO underflow interrupt status
+    // 0x00000002 [1]     : TXOIS (0): Transmit FIFO overflow interrupt status
+    // 0x00000001 [0]     : TXEIS (0): Transmit FIFO empty interrupt status
+    io_ro_32 isr;
+
+    _REG_(SSI_RISR_OFFSET) // SSI_RISR
+    // Raw interrupt status
+    // 0x00000020 [5]     : MSTIR (0): Multi-master contention raw interrupt status
+    // 0x00000010 [4]     : RXFIR (0): Receive FIFO full raw interrupt status
+    // 0x00000008 [3]     : RXOIR (0): Receive FIFO overflow raw interrupt status
+    // 0x00000004 [2]     : RXUIR (0): Receive FIFO underflow raw interrupt status
+    // 0x00000002 [1]     : TXOIR (0): Transmit FIFO overflow raw interrupt status
+    // 0x00000001 [0]     : TXEIR (0): Transmit FIFO empty raw interrupt status
+    io_ro_32 risr;
+
+    _REG_(SSI_TXOICR_OFFSET) // SSI_TXOICR
+    // TX FIFO overflow interrupt clear
+    // 0x00000001 [0]     : TXOICR (0): Clear-on-read transmit FIFO overflow interrupt
+    io_ro_32 txoicr;
+
+    _REG_(SSI_RXOICR_OFFSET) // SSI_RXOICR
+    // RX FIFO overflow interrupt clear
+    // 0x00000001 [0]     : RXOICR (0): Clear-on-read receive FIFO overflow interrupt
+    io_ro_32 rxoicr;
+
+    _REG_(SSI_RXUICR_OFFSET) // SSI_RXUICR
+    // RX FIFO underflow interrupt clear
+    // 0x00000001 [0]     : RXUICR (0): Clear-on-read receive FIFO underflow interrupt
+    io_ro_32 rxuicr;
+
+    _REG_(SSI_MSTICR_OFFSET) // SSI_MSTICR
+    // Multi-master interrupt clear
+    // 0x00000001 [0]     : MSTICR (0): Clear-on-read multi-master contention interrupt
+    io_ro_32 msticr;
+
+    _REG_(SSI_ICR_OFFSET) // SSI_ICR
+    // Interrupt clear
+    // 0x00000001 [0]     : ICR (0): Clear-on-read all active interrupts
+    io_ro_32 icr;
+
+    _REG_(SSI_DMACR_OFFSET) // SSI_DMACR
+    // DMA control
+    // 0x00000002 [1]     : TDMAE (0): Transmit DMA enable
+    // 0x00000001 [0]     : RDMAE (0): Receive DMA enable
     io_rw_32 dmacr;
+
+    _REG_(SSI_DMATDLR_OFFSET) // SSI_DMATDLR
+    // DMA TX data level
+    // 0x000000ff [7:0]   : DMATDL (0): Transmit data watermark level
     io_rw_32 dmatdlr;
+
+    _REG_(SSI_DMARDLR_OFFSET) // SSI_DMARDLR
+    // DMA RX data level
+    // 0x000000ff [7:0]   : DMARDL (0): Receive data watermark level (DMARDLR+1)
     io_rw_32 dmardlr;
-    io_rw_32 idr;
-    io_rw_32 ssi_version_id;
+
+    _REG_(SSI_IDR_OFFSET) // SSI_IDR
+    // Identification register
+    // 0xffffffff [31:0]  : IDCODE (0x51535049): Peripheral dentification code
+    io_ro_32 idr;
+
+    _REG_(SSI_SSI_VERSION_ID_OFFSET) // SSI_SSI_VERSION_ID
+    // Version ID
+    // 0xffffffff [31:0]  : SSI_COMP_VERSION (0x3430312a): SNPS component version (format X
+    io_ro_32 ssi_version_id;
+
+    _REG_(SSI_DR0_OFFSET) // SSI_DR0
+    // Data Register 0 (of 36)
+    // 0xffffffff [31:0]  : DR (0): First data register of 36
     io_rw_32 dr0;
-    uint32_t _pad[(0xf0 - 0x60) / 4 - 1];
+
+    uint32_t _pad0[35];
+
+    _REG_(SSI_RX_SAMPLE_DLY_OFFSET) // SSI_RX_SAMPLE_DLY
+    // RX sample delay
+    // 0x000000ff [7:0]   : RSD (0): RXD sample delay (in SCLK cycles)
     io_rw_32 rx_sample_dly;
+
+    _REG_(SSI_SPI_CTRLR0_OFFSET) // SSI_SPI_CTRLR0
+    // SPI control
+    // 0xff000000 [31:24] : XIP_CMD (0x3): SPI Command to send in XIP mode (INST_L = 8-bit) or to append to Address (INST_L = 0-bit)
+    // 0x00040000 [18]    : SPI_RXDS_EN (0): Read data strobe enable
+    // 0x00020000 [17]    : INST_DDR_EN (0): Instruction DDR transfer enable
+    // 0x00010000 [16]    : SPI_DDR_EN (0): SPI DDR transfer enable
+    // 0x0000f800 [15:11] : WAIT_CYCLES (0): Wait cycles between control frame transmit and data reception (in SCLK cycles)
+    // 0x00000300 [9:8]   : INST_L (0): Instruction length (0/4/8/16b)
+    // 0x0000003c [5:2]   : ADDR_L (0): Address length (0b-60b in 4b increments)
+    // 0x00000003 [1:0]   : TRANS_TYPE (0): Address and instruction transfer format
     io_rw_32 spi_ctrlr0;
+
+    _REG_(SSI_TXD_DRIVE_EDGE_OFFSET) // SSI_TXD_DRIVE_EDGE
+    // TX drive edge
+    // 0x000000ff [7:0]   : TDE (0): TXD drive edge
     io_rw_32 txd_drive_edge;
 } ssi_hw_t;
 
 #define ssi_hw ((ssi_hw_t *const)XIP_SSI_BASE)
+
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/syscfg.h b/src/rp2040/hardware_structs/include/hardware/structs/syscfg.h
index 0bfc729..52218fb 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/syscfg.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/syscfg.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,16 +10,65 @@
 #define _HARDWARE_STRUCTS_SYSCFG_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/syscfg.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_syscfg
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/syscfg.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(SYSCFG_PROC0_NMI_MASK_OFFSET) // SYSCFG_PROC0_NMI_MASK
+    // Processor core 0 NMI source mask
     io_rw_32 proc0_nmi_mask;
+
+    _REG_(SYSCFG_PROC1_NMI_MASK_OFFSET) // SYSCFG_PROC1_NMI_MASK
+    // Processor core 1 NMI source mask
     io_rw_32 proc1_nmi_mask;
+
+    _REG_(SYSCFG_PROC_CONFIG_OFFSET) // SYSCFG_PROC_CONFIG
+    // Configuration for processors
+    // 0xf0000000 [31:28] : PROC1_DAP_INSTID (1): Configure proc1 DAP instance ID
+    // 0x0f000000 [27:24] : PROC0_DAP_INSTID (0): Configure proc0 DAP instance ID
+    // 0x00000002 [1]     : PROC1_HALTED (0): Indication that proc1 has halted
+    // 0x00000001 [0]     : PROC0_HALTED (0): Indication that proc0 has halted
     io_rw_32 proc_config;
+
+    _REG_(SYSCFG_PROC_IN_SYNC_BYPASS_OFFSET) // SYSCFG_PROC_IN_SYNC_BYPASS
+    // For each bit, if 1, bypass the input synchronizer between that GPIO
+    // 0x3fffffff [29:0]  : PROC_IN_SYNC_BYPASS (0)
     io_rw_32 proc_in_sync_bypass;
+
+    _REG_(SYSCFG_PROC_IN_SYNC_BYPASS_HI_OFFSET) // SYSCFG_PROC_IN_SYNC_BYPASS_HI
+    // For each bit, if 1, bypass the input synchronizer between that GPIO
+    // 0x0000003f [5:0]   : PROC_IN_SYNC_BYPASS_HI (0)
     io_rw_32 proc_in_sync_bypass_hi;
+
+    _REG_(SYSCFG_DBGFORCE_OFFSET) // SYSCFG_DBGFORCE
+    // Directly control the SWD debug port of either processor
+    // 0x00000080 [7]     : PROC1_ATTACH (0): Attach processor 1 debug port to syscfg controls, and disconnect it from...
+    // 0x00000040 [6]     : PROC1_SWCLK (1): Directly drive processor 1 SWCLK, if PROC1_ATTACH is set
+    // 0x00000020 [5]     : PROC1_SWDI (1): Directly drive processor 1 SWDIO input, if PROC1_ATTACH is set
+    // 0x00000010 [4]     : PROC1_SWDO (0): Observe the value of processor 1 SWDIO output
+    // 0x00000008 [3]     : PROC0_ATTACH (0): Attach processor 0 debug port to syscfg controls, and disconnect it from...
+    // 0x00000004 [2]     : PROC0_SWCLK (1): Directly drive processor 0 SWCLK, if PROC0_ATTACH is set
+    // 0x00000002 [1]     : PROC0_SWDI (1): Directly drive processor 0 SWDIO input, if PROC0_ATTACH is set
+    // 0x00000001 [0]     : PROC0_SWDO (0): Observe the value of processor 0 SWDIO output
     io_rw_32 dbgforce;
+
+    _REG_(SYSCFG_MEMPOWERDOWN_OFFSET) // SYSCFG_MEMPOWERDOWN
+    // Control power downs to memories
+    // 0x00000080 [7]     : ROM (0)
+    // 0x00000040 [6]     : USB (0)
+    // 0x00000020 [5]     : SRAM5 (0)
+    // 0x00000010 [4]     : SRAM4 (0)
+    // 0x00000008 [3]     : SRAM3 (0)
+    // 0x00000004 [2]     : SRAM2 (0)
+    // 0x00000002 [1]     : SRAM1 (0)
+    // 0x00000001 [0]     : SRAM0 (0)
     io_rw_32 mempowerdown;
 } syscfg_hw_t;
 
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/systick.h b/src/rp2040/hardware_structs/include/hardware/structs/systick.h
index 24673fb..a859fea 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/systick.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/systick.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,10 +12,38 @@
 #include "hardware/address_mapped.h"
 #include "hardware/regs/m0plus.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_m0plus
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/m0plus.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(M0PLUS_SYST_CSR_OFFSET) // M0PLUS_SYST_CSR
+    // Use the SysTick Control and Status Register to enable the SysTick features
+    // 0x00010000 [16]    : COUNTFLAG (0): Returns 1 if timer counted to 0 since last time this was read
+    // 0x00000004 [2]     : CLKSOURCE (0): SysTick clock source
+    // 0x00000002 [1]     : TICKINT (0): Enables SysTick exception request:
+    // 0x00000001 [0]     : ENABLE (0): Enable SysTick counter:
     io_rw_32 csr;
+
+    _REG_(M0PLUS_SYST_RVR_OFFSET) // M0PLUS_SYST_RVR
+    // Use the SysTick Reload Value Register to specify the start value to load into the current value register when the...
+    // 0x00ffffff [23:0]  : RELOAD (0): Value to load into the SysTick Current Value Register when the counter reaches 0
     io_rw_32 rvr;
+
+    _REG_(M0PLUS_SYST_CVR_OFFSET) // M0PLUS_SYST_CVR
+    // Use the SysTick Current Value Register to find the current value in the register
+    // 0x00ffffff [23:0]  : CURRENT (0): Reads return the current value of the SysTick counter
     io_rw_32 cvr;
+
+    _REG_(M0PLUS_SYST_CALIB_OFFSET) // M0PLUS_SYST_CALIB
+    // Use the SysTick Calibration Value Register to enable software to scale to any required speed using divide and multiply
+    // 0x80000000 [31]    : NOREF (0): If reads as 1, the Reference clock is not provided - the CLKSOURCE bit of the...
+    // 0x40000000 [30]    : SKEW (0): If reads as 1, the calibration value for 10ms is inexact (due to clock frequency)
+    // 0x00ffffff [23:0]  : TENMS (0): An optional Reload value to be used for 10ms (100Hz) timing, subject to system clock...
     io_ro_32 calib;
 } systick_hw_t;
 
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/timer.h b/src/rp2040/hardware_structs/include/hardware/structs/timer.h
index e051a06..c7c7066 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/timer.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/timer.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,28 +10,98 @@
 #define _HARDWARE_STRUCTS_TIMER_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/timer.h"
 
-#define NUM_TIMERS 4
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_timer
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/timer.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
 
 typedef struct {
+    _REG_(TIMER_TIMEHW_OFFSET) // TIMER_TIMEHW
+    // Write to bits 63:32 of time
     io_wo_32 timehw;
+
+    _REG_(TIMER_TIMELW_OFFSET) // TIMER_TIMELW
+    // Write to bits 31:0 of time
     io_wo_32 timelw;
+
+    _REG_(TIMER_TIMEHR_OFFSET) // TIMER_TIMEHR
+    // Read from bits 63:32 of time
     io_ro_32 timehr;
+
+    _REG_(TIMER_TIMELR_OFFSET) // TIMER_TIMELR
+    // Read from bits 31:0 of time
     io_ro_32 timelr;
-    io_rw_32 alarm[NUM_TIMERS];
+
+    _REG_(TIMER_ALARM0_OFFSET) // TIMER_ALARM0
+    // (Description copied from array index 0 register TIMER_ALARM0 applies similarly to other array indexes)
+    //
+    // Arm alarm 0, and configure the time it will fire
+    io_rw_32 alarm[NUM_TIMERS]; // 4
+
+    _REG_(TIMER_ARMED_OFFSET) // TIMER_ARMED
+    // Indicates the armed/disarmed status of each alarm
+    // 0x0000000f [3:0]   : ARMED (0)
     io_rw_32 armed;
+
+    _REG_(TIMER_TIMERAWH_OFFSET) // TIMER_TIMERAWH
+    // Raw read from bits 63:32 of time (no side effects)
     io_ro_32 timerawh;
+
+    _REG_(TIMER_TIMERAWL_OFFSET) // TIMER_TIMERAWL
+    // Raw read from bits 31:0 of time (no side effects)
     io_ro_32 timerawl;
+
+    _REG_(TIMER_DBGPAUSE_OFFSET) // TIMER_DBGPAUSE
+    // Set bits high to enable pause when the corresponding debug ports are active
+    // 0x00000004 [2]     : DBG1 (1): Pause when processor 1 is in debug mode
+    // 0x00000002 [1]     : DBG0 (1): Pause when processor 0 is in debug mode
     io_rw_32 dbgpause;
+
+    _REG_(TIMER_PAUSE_OFFSET) // TIMER_PAUSE
+    // Set high to pause the timer
+    // 0x00000001 [0]     : PAUSE (0)
     io_rw_32 pause;
+
+    _REG_(TIMER_INTR_OFFSET) // TIMER_INTR
+    // Raw Interrupts
+    // 0x00000008 [3]     : ALARM_3 (0)
+    // 0x00000004 [2]     : ALARM_2 (0)
+    // 0x00000002 [1]     : ALARM_1 (0)
+    // 0x00000001 [0]     : ALARM_0 (0)
     io_rw_32 intr;
+
+    _REG_(TIMER_INTE_OFFSET) // TIMER_INTE
+    // Interrupt Enable
+    // 0x00000008 [3]     : ALARM_3 (0)
+    // 0x00000004 [2]     : ALARM_2 (0)
+    // 0x00000002 [1]     : ALARM_1 (0)
+    // 0x00000001 [0]     : ALARM_0 (0)
     io_rw_32 inte;
+
+    _REG_(TIMER_INTF_OFFSET) // TIMER_INTF
+    // Interrupt Force
+    // 0x00000008 [3]     : ALARM_3 (0)
+    // 0x00000004 [2]     : ALARM_2 (0)
+    // 0x00000002 [1]     : ALARM_1 (0)
+    // 0x00000001 [0]     : ALARM_0 (0)
     io_rw_32 intf;
+
+    _REG_(TIMER_INTS_OFFSET) // TIMER_INTS
+    // Interrupt status after masking & forcing
+    // 0x00000008 [3]     : ALARM_3 (0)
+    // 0x00000004 [2]     : ALARM_2 (0)
+    // 0x00000002 [1]     : ALARM_1 (0)
+    // 0x00000001 [0]     : ALARM_0 (0)
     io_ro_32 ints;
 } timer_hw_t;
 
 #define timer_hw ((timer_hw_t *const)TIMER_BASE)
 
+static_assert( NUM_TIMERS == 4, "");
+
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/uart.h b/src/rp2040/hardware_structs/include/hardware/structs/uart.h
index 42fe8e8..09af33e 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/uart.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/uart.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,22 +12,162 @@
 #include "hardware/address_mapped.h"
 #include "hardware/regs/uart.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_uart
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/uart.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(UART_UARTDR_OFFSET) // UART_UARTDR
+    // Data Register, UARTDR
+    // 0x00000800 [11]    : OE (0): Overrun error
+    // 0x00000400 [10]    : BE (0): Break error
+    // 0x00000200 [9]     : PE (0): Parity error
+    // 0x00000100 [8]     : FE (0): Framing error
+    // 0x000000ff [7:0]   : DATA (0): Receive (read) data character
     io_rw_32 dr;
+
+    _REG_(UART_UARTRSR_OFFSET) // UART_UARTRSR
+    // Receive Status Register/Error Clear Register, UARTRSR/UARTECR
+    // 0x00000008 [3]     : OE (0): Overrun error
+    // 0x00000004 [2]     : BE (0): Break error
+    // 0x00000002 [1]     : PE (0): Parity error
+    // 0x00000001 [0]     : FE (0): Framing error
     io_rw_32 rsr;
+
     uint32_t _pad0[4];
-    io_rw_32 fr;
+
+    _REG_(UART_UARTFR_OFFSET) // UART_UARTFR
+    // Flag Register, UARTFR
+    // 0x00000100 [8]     : RI (0): Ring indicator
+    // 0x00000080 [7]     : TXFE (1): Transmit FIFO empty
+    // 0x00000040 [6]     : RXFF (0): Receive FIFO full
+    // 0x00000020 [5]     : TXFF (0): Transmit FIFO full
+    // 0x00000010 [4]     : RXFE (1): Receive FIFO empty
+    // 0x00000008 [3]     : BUSY (0): UART busy
+    // 0x00000004 [2]     : DCD (0): Data carrier detect
+    // 0x00000002 [1]     : DSR (0): Data set ready
+    // 0x00000001 [0]     : CTS (0): Clear to send
+    io_ro_32 fr;
+
     uint32_t _pad1;
+
+    _REG_(UART_UARTILPR_OFFSET) // UART_UARTILPR
+    // IrDA Low-Power Counter Register, UARTILPR
+    // 0x000000ff [7:0]   : ILPDVSR (0): 8-bit low-power divisor value
     io_rw_32 ilpr;
+
+    _REG_(UART_UARTIBRD_OFFSET) // UART_UARTIBRD
+    // Integer Baud Rate Register, UARTIBRD
+    // 0x0000ffff [15:0]  : BAUD_DIVINT (0): The integer baud rate divisor
     io_rw_32 ibrd;
+
+    _REG_(UART_UARTFBRD_OFFSET) // UART_UARTFBRD
+    // Fractional Baud Rate Register, UARTFBRD
+    // 0x0000003f [5:0]   : BAUD_DIVFRAC (0): The fractional baud rate divisor
     io_rw_32 fbrd;
+
+    _REG_(UART_UARTLCR_H_OFFSET) // UART_UARTLCR_H
+    // Line Control Register, UARTLCR_H
+    // 0x00000080 [7]     : SPS (0): Stick parity select
+    // 0x00000060 [6:5]   : WLEN (0): Word length
+    // 0x00000010 [4]     : FEN (0): Enable FIFOs: 0 = FIFOs are disabled (character mode) that is, the FIFOs become...
+    // 0x00000008 [3]     : STP2 (0): Two stop bits select
+    // 0x00000004 [2]     : EPS (0): Even parity select
+    // 0x00000002 [1]     : PEN (0): Parity enable: 0 = parity is disabled and no parity bit added to the data frame 1 =...
+    // 0x00000001 [0]     : BRK (0): Send break
     io_rw_32 lcr_h;
+
+    _REG_(UART_UARTCR_OFFSET) // UART_UARTCR
+    // Control Register, UARTCR
+    // 0x00008000 [15]    : CTSEN (0): CTS hardware flow control enable
+    // 0x00004000 [14]    : RTSEN (0): RTS hardware flow control enable
+    // 0x00002000 [13]    : OUT2 (0): This bit is the complement of the UART Out2 (nUARTOut2) modem status output
+    // 0x00001000 [12]    : OUT1 (0): This bit is the complement of the UART Out1 (nUARTOut1) modem status output
+    // 0x00000800 [11]    : RTS (0): Request to send
+    // 0x00000400 [10]    : DTR (0): Data transmit ready
+    // 0x00000200 [9]     : RXE (1): Receive enable
+    // 0x00000100 [8]     : TXE (1): Transmit enable
+    // 0x00000080 [7]     : LBE (0): Loopback enable
+    // 0x00000004 [2]     : SIRLP (0): SIR low-power IrDA mode
+    // 0x00000002 [1]     : SIREN (0): SIR enable: 0 = IrDA SIR ENDEC is disabled
+    // 0x00000001 [0]     : UARTEN (0): UART enable: 0 = UART is disabled
     io_rw_32 cr;
+
+    _REG_(UART_UARTIFLS_OFFSET) // UART_UARTIFLS
+    // Interrupt FIFO Level Select Register, UARTIFLS
+    // 0x00000038 [5:3]   : RXIFLSEL (0x2): Receive interrupt FIFO level select
+    // 0x00000007 [2:0]   : TXIFLSEL (0x2): Transmit interrupt FIFO level select
     io_rw_32 ifls;
+
+    _REG_(UART_UARTIMSC_OFFSET) // UART_UARTIMSC
+    // Interrupt Mask Set/Clear Register, UARTIMSC
+    // 0x00000400 [10]    : OEIM (0): Overrun error interrupt mask
+    // 0x00000200 [9]     : BEIM (0): Break error interrupt mask
+    // 0x00000100 [8]     : PEIM (0): Parity error interrupt mask
+    // 0x00000080 [7]     : FEIM (0): Framing error interrupt mask
+    // 0x00000040 [6]     : RTIM (0): Receive timeout interrupt mask
+    // 0x00000020 [5]     : TXIM (0): Transmit interrupt mask
+    // 0x00000010 [4]     : RXIM (0): Receive interrupt mask
+    // 0x00000008 [3]     : DSRMIM (0): nUARTDSR modem interrupt mask
+    // 0x00000004 [2]     : DCDMIM (0): nUARTDCD modem interrupt mask
+    // 0x00000002 [1]     : CTSMIM (0): nUARTCTS modem interrupt mask
+    // 0x00000001 [0]     : RIMIM (0): nUARTRI modem interrupt mask
     io_rw_32 imsc;
-    io_rw_32 ris;
-    io_rw_32 mis;
+
+    _REG_(UART_UARTRIS_OFFSET) // UART_UARTRIS
+    // Raw Interrupt Status Register, UARTRIS
+    // 0x00000400 [10]    : OERIS (0): Overrun error interrupt status
+    // 0x00000200 [9]     : BERIS (0): Break error interrupt status
+    // 0x00000100 [8]     : PERIS (0): Parity error interrupt status
+    // 0x00000080 [7]     : FERIS (0): Framing error interrupt status
+    // 0x00000040 [6]     : RTRIS (0): Receive timeout interrupt status
+    // 0x00000020 [5]     : TXRIS (0): Transmit interrupt status
+    // 0x00000010 [4]     : RXRIS (0): Receive interrupt status
+    // 0x00000008 [3]     : DSRRMIS (0): nUARTDSR modem interrupt status
+    // 0x00000004 [2]     : DCDRMIS (0): nUARTDCD modem interrupt status
+    // 0x00000002 [1]     : CTSRMIS (0): nUARTCTS modem interrupt status
+    // 0x00000001 [0]     : RIRMIS (0): nUARTRI modem interrupt status
+    io_ro_32 ris;
+
+    _REG_(UART_UARTMIS_OFFSET) // UART_UARTMIS
+    // Masked Interrupt Status Register, UARTMIS
+    // 0x00000400 [10]    : OEMIS (0): Overrun error masked interrupt status
+    // 0x00000200 [9]     : BEMIS (0): Break error masked interrupt status
+    // 0x00000100 [8]     : PEMIS (0): Parity error masked interrupt status
+    // 0x00000080 [7]     : FEMIS (0): Framing error masked interrupt status
+    // 0x00000040 [6]     : RTMIS (0): Receive timeout masked interrupt status
+    // 0x00000020 [5]     : TXMIS (0): Transmit masked interrupt status
+    // 0x00000010 [4]     : RXMIS (0): Receive masked interrupt status
+    // 0x00000008 [3]     : DSRMMIS (0): nUARTDSR modem masked interrupt status
+    // 0x00000004 [2]     : DCDMMIS (0): nUARTDCD modem masked interrupt status
+    // 0x00000002 [1]     : CTSMMIS (0): nUARTCTS modem masked interrupt status
+    // 0x00000001 [0]     : RIMMIS (0): nUARTRI modem masked interrupt status
+    io_ro_32 mis;
+
+    _REG_(UART_UARTICR_OFFSET) // UART_UARTICR
+    // Interrupt Clear Register, UARTICR
+    // 0x00000400 [10]    : OEIC (0): Overrun error interrupt clear
+    // 0x00000200 [9]     : BEIC (0): Break error interrupt clear
+    // 0x00000100 [8]     : PEIC (0): Parity error interrupt clear
+    // 0x00000080 [7]     : FEIC (0): Framing error interrupt clear
+    // 0x00000040 [6]     : RTIC (0): Receive timeout interrupt clear
+    // 0x00000020 [5]     : TXIC (0): Transmit interrupt clear
+    // 0x00000010 [4]     : RXIC (0): Receive interrupt clear
+    // 0x00000008 [3]     : DSRMIC (0): nUARTDSR modem interrupt clear
+    // 0x00000004 [2]     : DCDMIC (0): nUARTDCD modem interrupt clear
+    // 0x00000002 [1]     : CTSMIC (0): nUARTCTS modem interrupt clear
+    // 0x00000001 [0]     : RIMIC (0): nUARTRI modem interrupt clear
     io_rw_32 icr;
+
+    _REG_(UART_UARTDMACR_OFFSET) // UART_UARTDMACR
+    // DMA Control Register, UARTDMACR
+    // 0x00000004 [2]     : DMAONERR (0): DMA on error
+    // 0x00000002 [1]     : TXDMAE (0): Transmit DMA enable
+    // 0x00000001 [0]     : RXDMAE (0): Receive DMA enable
     io_rw_32 dmacr;
 } uart_hw_t;
 
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/usb.h b/src/rp2040/hardware_structs/include/hardware/structs/usb.h
index 0254e61..c9455d0 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/usb.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/usb.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,6 +12,14 @@
 #include "hardware/address_mapped.h"
 #include "hardware/regs/usb.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_usb
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/usb.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 // 0-15
 #define USB_NUM_ENDPOINTS 16
 
@@ -39,10 +49,10 @@
 #define EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER (1u << 28)
 #define EP_CTRL_INTERRUPT_ON_NAK (1u << 16)
 #define EP_CTRL_INTERRUPT_ON_STALL (1u << 17)
-#define EP_CTRL_BUFFER_TYPE_LSB 26
-#define EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB 16
+#define EP_CTRL_BUFFER_TYPE_LSB 26u
+#define EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB 16u
 
-#define USB_DPRAM_SIZE 4096
+#define USB_DPRAM_SIZE 4096u
 
 // PICO_CONFIG: USB_DPRAM_MAX, Set amount of USB RAM used by USB system, min=0, max=4096, default=4096, group=hardware_usb
 // Allow user to claim some of the USB RAM for themselves
@@ -112,38 +122,457 @@
 static_assert(offsetof(usb_host_dpram_t, epx_data) == 0x180, "");
 
 typedef struct {
+    _REG_(USB_ADDR_ENDP_OFFSET) // USB_ADDR_ENDP
+    // Device address and endpoint control
+    // 0x000f0000 [19:16] : ENDPOINT (0): Device endpoint to send data to
+    // 0x0000007f [6:0]   : ADDRESS (0): In device mode, the address that the device should respond to
     io_rw_32 dev_addr_ctrl;
-    io_rw_32 int_ep_addr_ctrl[USB_HOST_INTERRUPT_ENDPOINTS];
+
+    _REG_(USB_ADDR_ENDP1_OFFSET) // USB_ADDR_ENDP1
+    // (Description copied from array index 0 register USB_ADDR_ENDP1 applies similarly to other array indexes)
+    //
+    // Interrupt endpoint 1
+    // 0x04000000 [26]    : INTEP_PREAMBLE (0): Interrupt EP requires preamble (is a low speed device on a full speed hub)
+    // 0x02000000 [25]    : INTEP_DIR (0): Direction of the interrupt endpoint
+    // 0x000f0000 [19:16] : ENDPOINT (0): Endpoint number of the interrupt endpoint
+    // 0x0000007f [6:0]   : ADDRESS (0): Device address
+    io_rw_32 int_ep_addr_ctrl[USB_HOST_INTERRUPT_ENDPOINTS]; // 15
+
+    _REG_(USB_MAIN_CTRL_OFFSET) // USB_MAIN_CTRL
+    // Main control register
+    // 0x80000000 [31]    : SIM_TIMING (0): Reduced timings for simulation
+    // 0x00000002 [1]     : HOST_NDEVICE (0): Device mode = 0, Host mode = 1
+    // 0x00000001 [0]     : CONTROLLER_EN (0): Enable controller
     io_rw_32 main_ctrl;
-    io_rw_32 sof_rw;
+
+    _REG_(USB_SOF_WR_OFFSET) // USB_SOF_WR
+    // Set the SOF (Start of Frame) frame number in the host controller
+    // 0x000007ff [10:0]  : COUNT (0)
+    io_wo_32 sof_rw;
+
+    _REG_(USB_SOF_RD_OFFSET) // USB_SOF_RD
+    // Read the last SOF (Start of Frame) frame number seen
+    // 0x000007ff [10:0]  : COUNT (0)
     io_ro_32 sof_rd;
+
+    _REG_(USB_SIE_CTRL_OFFSET) // USB_SIE_CTRL
+    // SIE control register
+    // 0x80000000 [31]    : EP0_INT_STALL (0): Device: Set bit in EP_STATUS_STALL_NAK when EP0 sends a STALL
+    // 0x40000000 [30]    : EP0_DOUBLE_BUF (0): Device: EP0 single buffered = 0, double buffered = 1
+    // 0x20000000 [29]    : EP0_INT_1BUF (0): Device: Set bit in BUFF_STATUS for every buffer completed on EP0
+    // 0x10000000 [28]    : EP0_INT_2BUF (0): Device: Set bit in BUFF_STATUS for every 2 buffers completed on EP0
+    // 0x08000000 [27]    : EP0_INT_NAK (0): Device: Set bit in EP_STATUS_STALL_NAK when EP0 sends a NAK
+    // 0x04000000 [26]    : DIRECT_EN (0): Direct bus drive enable
+    // 0x02000000 [25]    : DIRECT_DP (0): Direct control of DP
+    // 0x01000000 [24]    : DIRECT_DM (0): Direct control of DM
+    // 0x00040000 [18]    : TRANSCEIVER_PD (0): Power down bus transceiver
+    // 0x00020000 [17]    : RPU_OPT (0): Device: Pull-up strength (0=1K2, 1=2k3)
+    // 0x00010000 [16]    : PULLUP_EN (0): Device: Enable pull up resistor
+    // 0x00008000 [15]    : PULLDOWN_EN (0): Host: Enable pull down resistors
+    // 0x00002000 [13]    : RESET_BUS (0): Host: Reset bus
+    // 0x00001000 [12]    : RESUME (0): Device: Remote wakeup
+    // 0x00000800 [11]    : VBUS_EN (0): Host: Enable VBUS
+    // 0x00000400 [10]    : KEEP_ALIVE_EN (0): Host: Enable keep alive packet (for low speed bus)
+    // 0x00000200 [9]     : SOF_EN (0): Host: Enable SOF generation (for full speed bus)
+    // 0x00000100 [8]     : SOF_SYNC (0): Host: Delay packet(s) until after SOF
+    // 0x00000040 [6]     : PREAMBLE_EN (0): Host: Preable enable for LS device on FS hub
+    // 0x00000010 [4]     : STOP_TRANS (0): Host: Stop transaction
+    // 0x00000008 [3]     : RECEIVE_DATA (0): Host: Receive transaction (IN to host)
+    // 0x00000004 [2]     : SEND_DATA (0): Host: Send transaction (OUT from host)
+    // 0x00000002 [1]     : SEND_SETUP (0): Host: Send Setup packet
+    // 0x00000001 [0]     : START_TRANS (0): Host: Start transaction
     io_rw_32 sie_ctrl;
+
+    _REG_(USB_SIE_STATUS_OFFSET) // USB_SIE_STATUS
+    // SIE status register
+    // 0x80000000 [31]    : DATA_SEQ_ERROR (0): Data Sequence Error
+    // 0x40000000 [30]    : ACK_REC (0): ACK received
+    // 0x20000000 [29]    : STALL_REC (0): Host: STALL received
+    // 0x10000000 [28]    : NAK_REC (0): Host: NAK received
+    // 0x08000000 [27]    : RX_TIMEOUT (0): RX timeout is raised by both the host and device if an ACK is not received in...
+    // 0x04000000 [26]    : RX_OVERFLOW (0): RX overflow is raised by the Serial RX engine if the incoming data is too fast
+    // 0x02000000 [25]    : BIT_STUFF_ERROR (0): Bit Stuff Error
+    // 0x01000000 [24]    : CRC_ERROR (0): CRC Error
+    // 0x00080000 [19]    : BUS_RESET (0): Device: bus reset received
+    // 0x00040000 [18]    : TRANS_COMPLETE (0): Transaction complete
+    // 0x00020000 [17]    : SETUP_REC (0): Device: Setup packet received
+    // 0x00010000 [16]    : CONNECTED (0): Device: connected
+    // 0x00000800 [11]    : RESUME (0): Host: Device has initiated a remote resume
+    // 0x00000400 [10]    : VBUS_OVER_CURR (0): VBUS over current detected
+    // 0x00000300 [9:8]   : SPEED (0): Host: device speed
+    // 0x00000010 [4]     : SUSPENDED (0): Bus in suspended state
+    // 0x0000000c [3:2]   : LINE_STATE (0): USB bus line state
+    // 0x00000001 [0]     : VBUS_DETECTED (0): Device: VBUS Detected
     io_rw_32 sie_status;
+
+    _REG_(USB_INT_EP_CTRL_OFFSET) // USB_INT_EP_CTRL
+    // interrupt endpoint control register
+    // 0x0000fffe [15:1]  : INT_EP_ACTIVE (0): Host: Enable interrupt endpoint 1 -> 15
     io_rw_32 int_ep_ctrl;
+
+    _REG_(USB_BUFF_STATUS_OFFSET) // USB_BUFF_STATUS
+    // Buffer status register
+    // 0x80000000 [31]    : EP15_OUT (0)
+    // 0x40000000 [30]    : EP15_IN (0)
+    // 0x20000000 [29]    : EP14_OUT (0)
+    // 0x10000000 [28]    : EP14_IN (0)
+    // 0x08000000 [27]    : EP13_OUT (0)
+    // 0x04000000 [26]    : EP13_IN (0)
+    // 0x02000000 [25]    : EP12_OUT (0)
+    // 0x01000000 [24]    : EP12_IN (0)
+    // 0x00800000 [23]    : EP11_OUT (0)
+    // 0x00400000 [22]    : EP11_IN (0)
+    // 0x00200000 [21]    : EP10_OUT (0)
+    // 0x00100000 [20]    : EP10_IN (0)
+    // 0x00080000 [19]    : EP9_OUT (0)
+    // 0x00040000 [18]    : EP9_IN (0)
+    // 0x00020000 [17]    : EP8_OUT (0)
+    // 0x00010000 [16]    : EP8_IN (0)
+    // 0x00008000 [15]    : EP7_OUT (0)
+    // 0x00004000 [14]    : EP7_IN (0)
+    // 0x00002000 [13]    : EP6_OUT (0)
+    // 0x00001000 [12]    : EP6_IN (0)
+    // 0x00000800 [11]    : EP5_OUT (0)
+    // 0x00000400 [10]    : EP5_IN (0)
+    // 0x00000200 [9]     : EP4_OUT (0)
+    // 0x00000100 [8]     : EP4_IN (0)
+    // 0x00000080 [7]     : EP3_OUT (0)
+    // 0x00000040 [6]     : EP3_IN (0)
+    // 0x00000020 [5]     : EP2_OUT (0)
+    // 0x00000010 [4]     : EP2_IN (0)
+    // 0x00000008 [3]     : EP1_OUT (0)
+    // 0x00000004 [2]     : EP1_IN (0)
+    // 0x00000002 [1]     : EP0_OUT (0)
+    // 0x00000001 [0]     : EP0_IN (0)
     io_rw_32 buf_status;
-    io_rw_32 buf_cpu_should_handle; // for double buff
+
+    _REG_(USB_BUFF_CPU_SHOULD_HANDLE_OFFSET) // USB_BUFF_CPU_SHOULD_HANDLE
+    // Which of the double buffers should be handled
+    // 0x80000000 [31]    : EP15_OUT (0)
+    // 0x40000000 [30]    : EP15_IN (0)
+    // 0x20000000 [29]    : EP14_OUT (0)
+    // 0x10000000 [28]    : EP14_IN (0)
+    // 0x08000000 [27]    : EP13_OUT (0)
+    // 0x04000000 [26]    : EP13_IN (0)
+    // 0x02000000 [25]    : EP12_OUT (0)
+    // 0x01000000 [24]    : EP12_IN (0)
+    // 0x00800000 [23]    : EP11_OUT (0)
+    // 0x00400000 [22]    : EP11_IN (0)
+    // 0x00200000 [21]    : EP10_OUT (0)
+    // 0x00100000 [20]    : EP10_IN (0)
+    // 0x00080000 [19]    : EP9_OUT (0)
+    // 0x00040000 [18]    : EP9_IN (0)
+    // 0x00020000 [17]    : EP8_OUT (0)
+    // 0x00010000 [16]    : EP8_IN (0)
+    // 0x00008000 [15]    : EP7_OUT (0)
+    // 0x00004000 [14]    : EP7_IN (0)
+    // 0x00002000 [13]    : EP6_OUT (0)
+    // 0x00001000 [12]    : EP6_IN (0)
+    // 0x00000800 [11]    : EP5_OUT (0)
+    // 0x00000400 [10]    : EP5_IN (0)
+    // 0x00000200 [9]     : EP4_OUT (0)
+    // 0x00000100 [8]     : EP4_IN (0)
+    // 0x00000080 [7]     : EP3_OUT (0)
+    // 0x00000040 [6]     : EP3_IN (0)
+    // 0x00000020 [5]     : EP2_OUT (0)
+    // 0x00000010 [4]     : EP2_IN (0)
+    // 0x00000008 [3]     : EP1_OUT (0)
+    // 0x00000004 [2]     : EP1_IN (0)
+    // 0x00000002 [1]     : EP0_OUT (0)
+    // 0x00000001 [0]     : EP0_IN (0)
+    io_ro_32 buf_cpu_should_handle;
+
+    _REG_(USB_EP_ABORT_OFFSET) // USB_EP_ABORT
+    // Device only: Can be set to ignore the buffer control register for this endpoint in case you would like to revoke a buffer
+    // 0x80000000 [31]    : EP15_OUT (0)
+    // 0x40000000 [30]    : EP15_IN (0)
+    // 0x20000000 [29]    : EP14_OUT (0)
+    // 0x10000000 [28]    : EP14_IN (0)
+    // 0x08000000 [27]    : EP13_OUT (0)
+    // 0x04000000 [26]    : EP13_IN (0)
+    // 0x02000000 [25]    : EP12_OUT (0)
+    // 0x01000000 [24]    : EP12_IN (0)
+    // 0x00800000 [23]    : EP11_OUT (0)
+    // 0x00400000 [22]    : EP11_IN (0)
+    // 0x00200000 [21]    : EP10_OUT (0)
+    // 0x00100000 [20]    : EP10_IN (0)
+    // 0x00080000 [19]    : EP9_OUT (0)
+    // 0x00040000 [18]    : EP9_IN (0)
+    // 0x00020000 [17]    : EP8_OUT (0)
+    // 0x00010000 [16]    : EP8_IN (0)
+    // 0x00008000 [15]    : EP7_OUT (0)
+    // 0x00004000 [14]    : EP7_IN (0)
+    // 0x00002000 [13]    : EP6_OUT (0)
+    // 0x00001000 [12]    : EP6_IN (0)
+    // 0x00000800 [11]    : EP5_OUT (0)
+    // 0x00000400 [10]    : EP5_IN (0)
+    // 0x00000200 [9]     : EP4_OUT (0)
+    // 0x00000100 [8]     : EP4_IN (0)
+    // 0x00000080 [7]     : EP3_OUT (0)
+    // 0x00000040 [6]     : EP3_IN (0)
+    // 0x00000020 [5]     : EP2_OUT (0)
+    // 0x00000010 [4]     : EP2_IN (0)
+    // 0x00000008 [3]     : EP1_OUT (0)
+    // 0x00000004 [2]     : EP1_IN (0)
+    // 0x00000002 [1]     : EP0_OUT (0)
+    // 0x00000001 [0]     : EP0_IN (0)
     io_rw_32 abort;
+
+    _REG_(USB_EP_ABORT_DONE_OFFSET) // USB_EP_ABORT_DONE
+    // Device only: Used in conjunction with `EP_ABORT`
+    // 0x80000000 [31]    : EP15_OUT (0)
+    // 0x40000000 [30]    : EP15_IN (0)
+    // 0x20000000 [29]    : EP14_OUT (0)
+    // 0x10000000 [28]    : EP14_IN (0)
+    // 0x08000000 [27]    : EP13_OUT (0)
+    // 0x04000000 [26]    : EP13_IN (0)
+    // 0x02000000 [25]    : EP12_OUT (0)
+    // 0x01000000 [24]    : EP12_IN (0)
+    // 0x00800000 [23]    : EP11_OUT (0)
+    // 0x00400000 [22]    : EP11_IN (0)
+    // 0x00200000 [21]    : EP10_OUT (0)
+    // 0x00100000 [20]    : EP10_IN (0)
+    // 0x00080000 [19]    : EP9_OUT (0)
+    // 0x00040000 [18]    : EP9_IN (0)
+    // 0x00020000 [17]    : EP8_OUT (0)
+    // 0x00010000 [16]    : EP8_IN (0)
+    // 0x00008000 [15]    : EP7_OUT (0)
+    // 0x00004000 [14]    : EP7_IN (0)
+    // 0x00002000 [13]    : EP6_OUT (0)
+    // 0x00001000 [12]    : EP6_IN (0)
+    // 0x00000800 [11]    : EP5_OUT (0)
+    // 0x00000400 [10]    : EP5_IN (0)
+    // 0x00000200 [9]     : EP4_OUT (0)
+    // 0x00000100 [8]     : EP4_IN (0)
+    // 0x00000080 [7]     : EP3_OUT (0)
+    // 0x00000040 [6]     : EP3_IN (0)
+    // 0x00000020 [5]     : EP2_OUT (0)
+    // 0x00000010 [4]     : EP2_IN (0)
+    // 0x00000008 [3]     : EP1_OUT (0)
+    // 0x00000004 [2]     : EP1_IN (0)
+    // 0x00000002 [1]     : EP0_OUT (0)
+    // 0x00000001 [0]     : EP0_IN (0)
     io_rw_32 abort_done;
+
+    _REG_(USB_EP_STALL_ARM_OFFSET) // USB_EP_STALL_ARM
+    // Device: this bit must be set in conjunction with the `STALL` bit in the buffer control register to send a STALL on EP0
+    // 0x00000002 [1]     : EP0_OUT (0)
+    // 0x00000001 [0]     : EP0_IN (0)
     io_rw_32 ep_stall_arm;
+
+    _REG_(USB_NAK_POLL_OFFSET) // USB_NAK_POLL
+    // Used by the host controller
+    // 0x03ff0000 [25:16] : DELAY_FS (0x10): NAK polling interval for a full speed device
+    // 0x000003ff [9:0]   : DELAY_LS (0x10): NAK polling interval for a low speed device
     io_rw_32 nak_poll;
+
+    _REG_(USB_EP_STATUS_STALL_NAK_OFFSET) // USB_EP_STATUS_STALL_NAK
+    // Device: bits are set when the `IRQ_ON_NAK` or `IRQ_ON_STALL` bits are set
+    // 0x80000000 [31]    : EP15_OUT (0)
+    // 0x40000000 [30]    : EP15_IN (0)
+    // 0x20000000 [29]    : EP14_OUT (0)
+    // 0x10000000 [28]    : EP14_IN (0)
+    // 0x08000000 [27]    : EP13_OUT (0)
+    // 0x04000000 [26]    : EP13_IN (0)
+    // 0x02000000 [25]    : EP12_OUT (0)
+    // 0x01000000 [24]    : EP12_IN (0)
+    // 0x00800000 [23]    : EP11_OUT (0)
+    // 0x00400000 [22]    : EP11_IN (0)
+    // 0x00200000 [21]    : EP10_OUT (0)
+    // 0x00100000 [20]    : EP10_IN (0)
+    // 0x00080000 [19]    : EP9_OUT (0)
+    // 0x00040000 [18]    : EP9_IN (0)
+    // 0x00020000 [17]    : EP8_OUT (0)
+    // 0x00010000 [16]    : EP8_IN (0)
+    // 0x00008000 [15]    : EP7_OUT (0)
+    // 0x00004000 [14]    : EP7_IN (0)
+    // 0x00002000 [13]    : EP6_OUT (0)
+    // 0x00001000 [12]    : EP6_IN (0)
+    // 0x00000800 [11]    : EP5_OUT (0)
+    // 0x00000400 [10]    : EP5_IN (0)
+    // 0x00000200 [9]     : EP4_OUT (0)
+    // 0x00000100 [8]     : EP4_IN (0)
+    // 0x00000080 [7]     : EP3_OUT (0)
+    // 0x00000040 [6]     : EP3_IN (0)
+    // 0x00000020 [5]     : EP2_OUT (0)
+    // 0x00000010 [4]     : EP2_IN (0)
+    // 0x00000008 [3]     : EP1_OUT (0)
+    // 0x00000004 [2]     : EP1_IN (0)
+    // 0x00000002 [1]     : EP0_OUT (0)
+    // 0x00000001 [0]     : EP0_IN (0)
     io_rw_32 ep_nak_stall_status;
+
+    _REG_(USB_USB_MUXING_OFFSET) // USB_USB_MUXING
+    // Where to connect the USB controller
+    // 0x00000008 [3]     : SOFTCON (0)
+    // 0x00000004 [2]     : TO_DIGITAL_PAD (0)
+    // 0x00000002 [1]     : TO_EXTPHY (0)
+    // 0x00000001 [0]     : TO_PHY (0)
     io_rw_32 muxing;
+
+    _REG_(USB_USB_PWR_OFFSET) // USB_USB_PWR
+    // Overrides for the power signals in the event that the VBUS signals are not hooked up to GPIO
+    // 0x00000020 [5]     : OVERCURR_DETECT_EN (0)
+    // 0x00000010 [4]     : OVERCURR_DETECT (0)
+    // 0x00000008 [3]     : VBUS_DETECT_OVERRIDE_EN (0)
+    // 0x00000004 [2]     : VBUS_DETECT (0)
+    // 0x00000002 [1]     : VBUS_EN_OVERRIDE_EN (0)
+    // 0x00000001 [0]     : VBUS_EN (0)
     io_rw_32 pwr;
+
+    _REG_(USB_USBPHY_DIRECT_OFFSET) // USB_USBPHY_DIRECT
+    // This register allows for direct control of the USB phy
+    // 0x00400000 [22]    : DM_OVV (0): DM over voltage
+    // 0x00200000 [21]    : DP_OVV (0): DP over voltage
+    // 0x00100000 [20]    : DM_OVCN (0): DM overcurrent
+    // 0x00080000 [19]    : DP_OVCN (0): DP overcurrent
+    // 0x00040000 [18]    : RX_DM (0): DPM pin state
+    // 0x00020000 [17]    : RX_DP (0): DPP pin state
+    // 0x00010000 [16]    : RX_DD (0): Differential RX
+    // 0x00008000 [15]    : TX_DIFFMODE (0): TX_DIFFMODE=0: Single ended mode
+    // 0x00004000 [14]    : TX_FSSLEW (0): TX_FSSLEW=0: Low speed slew rate
+    // 0x00002000 [13]    : TX_PD (0): TX power down override (if override enable is set)
+    // 0x00001000 [12]    : RX_PD (0): RX power down override (if override enable is set)
+    // 0x00000800 [11]    : TX_DM (0): Output data
+    // 0x00000400 [10]    : TX_DP (0): Output data
+    // 0x00000200 [9]     : TX_DM_OE (0): Output enable
+    // 0x00000100 [8]     : TX_DP_OE (0): Output enable
+    // 0x00000040 [6]     : DM_PULLDN_EN (0): DM pull down enable
+    // 0x00000020 [5]     : DM_PULLUP_EN (0): DM pull up enable
+    // 0x00000010 [4]     : DM_PULLUP_HISEL (0): Enable the second DM pull up resistor
+    // 0x00000004 [2]     : DP_PULLDN_EN (0): DP pull down enable
+    // 0x00000002 [1]     : DP_PULLUP_EN (0): DP pull up enable
+    // 0x00000001 [0]     : DP_PULLUP_HISEL (0): Enable the second DP pull up resistor
     io_rw_32 phy_direct;
+
+    _REG_(USB_USBPHY_DIRECT_OVERRIDE_OFFSET) // USB_USBPHY_DIRECT_OVERRIDE
+    // Override enable for each control in usbphy_direct
+    // 0x00008000 [15]    : TX_DIFFMODE_OVERRIDE_EN (0)
+    // 0x00001000 [12]    : DM_PULLUP_OVERRIDE_EN (0)
+    // 0x00000800 [11]    : TX_FSSLEW_OVERRIDE_EN (0)
+    // 0x00000400 [10]    : TX_PD_OVERRIDE_EN (0)
+    // 0x00000200 [9]     : RX_PD_OVERRIDE_EN (0)
+    // 0x00000100 [8]     : TX_DM_OVERRIDE_EN (0)
+    // 0x00000080 [7]     : TX_DP_OVERRIDE_EN (0)
+    // 0x00000040 [6]     : TX_DM_OE_OVERRIDE_EN (0)
+    // 0x00000020 [5]     : TX_DP_OE_OVERRIDE_EN (0)
+    // 0x00000010 [4]     : DM_PULLDN_EN_OVERRIDE_EN (0)
+    // 0x00000008 [3]     : DP_PULLDN_EN_OVERRIDE_EN (0)
+    // 0x00000004 [2]     : DP_PULLUP_EN_OVERRIDE_EN (0)
+    // 0x00000002 [1]     : DM_PULLUP_HISEL_OVERRIDE_EN (0)
+    // 0x00000001 [0]     : DP_PULLUP_HISEL_OVERRIDE_EN (0)
     io_rw_32 phy_direct_override;
+
+    _REG_(USB_USBPHY_TRIM_OFFSET) // USB_USBPHY_TRIM
+    // Used to adjust trim values of USB phy pull down resistors
+    // 0x00001f00 [12:8]  : DM_PULLDN_TRIM (0x1f): Value to drive to USB PHY
+    // 0x0000001f [4:0]   : DP_PULLDN_TRIM (0x1f): Value to drive to USB PHY
     io_rw_32 phy_trim;
-    io_rw_32 linestate_tuning;
-    io_rw_32 intr;
+
+    uint32_t _pad0;
+
+    _REG_(USB_INTR_OFFSET) // USB_INTR
+    // Raw Interrupts
+    // 0x00080000 [19]    : EP_STALL_NAK (0): Raised when any bit in EP_STATUS_STALL_NAK is set
+    // 0x00040000 [18]    : ABORT_DONE (0): Raised when any bit in ABORT_DONE is set
+    // 0x00020000 [17]    : DEV_SOF (0): Set every time the device receives a SOF (Start of Frame) packet
+    // 0x00010000 [16]    : SETUP_REQ (0): Device
+    // 0x00008000 [15]    : DEV_RESUME_FROM_HOST (0): Set when the device receives a resume from the host
+    // 0x00004000 [14]    : DEV_SUSPEND (0): Set when the device suspend state changes
+    // 0x00002000 [13]    : DEV_CONN_DIS (0): Set when the device connection state changes
+    // 0x00001000 [12]    : BUS_RESET (0): Source: SIE_STATUS
+    // 0x00000800 [11]    : VBUS_DETECT (0): Source: SIE_STATUS
+    // 0x00000400 [10]    : STALL (0): Source: SIE_STATUS
+    // 0x00000200 [9]     : ERROR_CRC (0): Source: SIE_STATUS
+    // 0x00000100 [8]     : ERROR_BIT_STUFF (0): Source: SIE_STATUS
+    // 0x00000080 [7]     : ERROR_RX_OVERFLOW (0): Source: SIE_STATUS
+    // 0x00000040 [6]     : ERROR_RX_TIMEOUT (0): Source: SIE_STATUS
+    // 0x00000020 [5]     : ERROR_DATA_SEQ (0): Source: SIE_STATUS
+    // 0x00000010 [4]     : BUFF_STATUS (0): Raised when any bit in BUFF_STATUS is set
+    // 0x00000008 [3]     : TRANS_COMPLETE (0): Raised every time SIE_STATUS
+    // 0x00000004 [2]     : HOST_SOF (0): Host: raised every time the host sends a SOF (Start of Frame)
+    // 0x00000002 [1]     : HOST_RESUME (0): Host: raised when a device wakes up the host
+    // 0x00000001 [0]     : HOST_CONN_DIS (0): Host: raised when a device is connected or disconnected (i
+    io_ro_32 intr;
+
+    _REG_(USB_INTE_OFFSET) // USB_INTE
+    // Interrupt Enable
+    // 0x00080000 [19]    : EP_STALL_NAK (0): Raised when any bit in EP_STATUS_STALL_NAK is set
+    // 0x00040000 [18]    : ABORT_DONE (0): Raised when any bit in ABORT_DONE is set
+    // 0x00020000 [17]    : DEV_SOF (0): Set every time the device receives a SOF (Start of Frame) packet
+    // 0x00010000 [16]    : SETUP_REQ (0): Device
+    // 0x00008000 [15]    : DEV_RESUME_FROM_HOST (0): Set when the device receives a resume from the host
+    // 0x00004000 [14]    : DEV_SUSPEND (0): Set when the device suspend state changes
+    // 0x00002000 [13]    : DEV_CONN_DIS (0): Set when the device connection state changes
+    // 0x00001000 [12]    : BUS_RESET (0): Source: SIE_STATUS
+    // 0x00000800 [11]    : VBUS_DETECT (0): Source: SIE_STATUS
+    // 0x00000400 [10]    : STALL (0): Source: SIE_STATUS
+    // 0x00000200 [9]     : ERROR_CRC (0): Source: SIE_STATUS
+    // 0x00000100 [8]     : ERROR_BIT_STUFF (0): Source: SIE_STATUS
+    // 0x00000080 [7]     : ERROR_RX_OVERFLOW (0): Source: SIE_STATUS
+    // 0x00000040 [6]     : ERROR_RX_TIMEOUT (0): Source: SIE_STATUS
+    // 0x00000020 [5]     : ERROR_DATA_SEQ (0): Source: SIE_STATUS
+    // 0x00000010 [4]     : BUFF_STATUS (0): Raised when any bit in BUFF_STATUS is set
+    // 0x00000008 [3]     : TRANS_COMPLETE (0): Raised every time SIE_STATUS
+    // 0x00000004 [2]     : HOST_SOF (0): Host: raised every time the host sends a SOF (Start of Frame)
+    // 0x00000002 [1]     : HOST_RESUME (0): Host: raised when a device wakes up the host
+    // 0x00000001 [0]     : HOST_CONN_DIS (0): Host: raised when a device is connected or disconnected (i
     io_rw_32 inte;
+
+    _REG_(USB_INTF_OFFSET) // USB_INTF
+    // Interrupt Force
+    // 0x00080000 [19]    : EP_STALL_NAK (0): Raised when any bit in EP_STATUS_STALL_NAK is set
+    // 0x00040000 [18]    : ABORT_DONE (0): Raised when any bit in ABORT_DONE is set
+    // 0x00020000 [17]    : DEV_SOF (0): Set every time the device receives a SOF (Start of Frame) packet
+    // 0x00010000 [16]    : SETUP_REQ (0): Device
+    // 0x00008000 [15]    : DEV_RESUME_FROM_HOST (0): Set when the device receives a resume from the host
+    // 0x00004000 [14]    : DEV_SUSPEND (0): Set when the device suspend state changes
+    // 0x00002000 [13]    : DEV_CONN_DIS (0): Set when the device connection state changes
+    // 0x00001000 [12]    : BUS_RESET (0): Source: SIE_STATUS
+    // 0x00000800 [11]    : VBUS_DETECT (0): Source: SIE_STATUS
+    // 0x00000400 [10]    : STALL (0): Source: SIE_STATUS
+    // 0x00000200 [9]     : ERROR_CRC (0): Source: SIE_STATUS
+    // 0x00000100 [8]     : ERROR_BIT_STUFF (0): Source: SIE_STATUS
+    // 0x00000080 [7]     : ERROR_RX_OVERFLOW (0): Source: SIE_STATUS
+    // 0x00000040 [6]     : ERROR_RX_TIMEOUT (0): Source: SIE_STATUS
+    // 0x00000020 [5]     : ERROR_DATA_SEQ (0): Source: SIE_STATUS
+    // 0x00000010 [4]     : BUFF_STATUS (0): Raised when any bit in BUFF_STATUS is set
+    // 0x00000008 [3]     : TRANS_COMPLETE (0): Raised every time SIE_STATUS
+    // 0x00000004 [2]     : HOST_SOF (0): Host: raised every time the host sends a SOF (Start of Frame)
+    // 0x00000002 [1]     : HOST_RESUME (0): Host: raised when a device wakes up the host
+    // 0x00000001 [0]     : HOST_CONN_DIS (0): Host: raised when a device is connected or disconnected (i
     io_rw_32 intf;
-    io_rw_32 ints;
+
+    _REG_(USB_INTS_OFFSET) // USB_INTS
+    // Interrupt status after masking & forcing
+    // 0x00080000 [19]    : EP_STALL_NAK (0): Raised when any bit in EP_STATUS_STALL_NAK is set
+    // 0x00040000 [18]    : ABORT_DONE (0): Raised when any bit in ABORT_DONE is set
+    // 0x00020000 [17]    : DEV_SOF (0): Set every time the device receives a SOF (Start of Frame) packet
+    // 0x00010000 [16]    : SETUP_REQ (0): Device
+    // 0x00008000 [15]    : DEV_RESUME_FROM_HOST (0): Set when the device receives a resume from the host
+    // 0x00004000 [14]    : DEV_SUSPEND (0): Set when the device suspend state changes
+    // 0x00002000 [13]    : DEV_CONN_DIS (0): Set when the device connection state changes
+    // 0x00001000 [12]    : BUS_RESET (0): Source: SIE_STATUS
+    // 0x00000800 [11]    : VBUS_DETECT (0): Source: SIE_STATUS
+    // 0x00000400 [10]    : STALL (0): Source: SIE_STATUS
+    // 0x00000200 [9]     : ERROR_CRC (0): Source: SIE_STATUS
+    // 0x00000100 [8]     : ERROR_BIT_STUFF (0): Source: SIE_STATUS
+    // 0x00000080 [7]     : ERROR_RX_OVERFLOW (0): Source: SIE_STATUS
+    // 0x00000040 [6]     : ERROR_RX_TIMEOUT (0): Source: SIE_STATUS
+    // 0x00000020 [5]     : ERROR_DATA_SEQ (0): Source: SIE_STATUS
+    // 0x00000010 [4]     : BUFF_STATUS (0): Raised when any bit in BUFF_STATUS is set
+    // 0x00000008 [3]     : TRANS_COMPLETE (0): Raised every time SIE_STATUS
+    // 0x00000004 [2]     : HOST_SOF (0): Host: raised every time the host sends a SOF (Start of Frame)
+    // 0x00000002 [1]     : HOST_RESUME (0): Host: raised when a device wakes up the host
+    // 0x00000001 [0]     : HOST_CONN_DIS (0): Host: raised when a device is connected or disconnected (i
+    io_ro_32 ints;
 } usb_hw_t;
 
-check_hw_layout(usb_hw_t, ints, USB_INTS_OFFSET);
-
-#define usb_hw ((usb_hw_t *)USBCTRL_REGS_BASE)
+#define usb_hw ((usb_hw_t *const)USBCTRL_REGS_BASE)
 
 #define usb_dpram ((usb_device_dpram_t *)USBCTRL_DPRAM_BASE)
 #define usbh_dpram ((usb_host_dpram_t *)USBCTRL_DPRAM_BASE)
 
+static_assert( USB_HOST_INTERRUPT_ENDPOINTS == 15, "");
+
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/vreg_and_chip_reset.h b/src/rp2040/hardware_structs/include/hardware/structs/vreg_and_chip_reset.h
index 9956d68..554d9e4 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/vreg_and_chip_reset.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/vreg_and_chip_reset.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,12 +10,37 @@
 #define _HARDWARE_STRUCTS_VREG_AND_CHIP_RESET_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/vreg_and_chip_reset.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_vreg_and_chip_reset
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/vreg_and_chip_reset.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(VREG_AND_CHIP_RESET_VREG_OFFSET) // VREG_AND_CHIP_RESET_VREG
+    // Voltage regulator control and status
+    // 0x00001000 [12]    : ROK (0): regulation status
+    // 0x000000f0 [7:4]   : VSEL (0xb): output voltage select
+    // 0x00000002 [1]     : HIZ (0): high impedance mode select
+    // 0x00000001 [0]     : EN (1): enable
     io_rw_32 vreg;
+
+    _REG_(VREG_AND_CHIP_RESET_BOD_OFFSET) // VREG_AND_CHIP_RESET_BOD
+    // brown-out detection control
+    // 0x000000f0 [7:4]   : VSEL (0x9): threshold select
+    // 0x00000001 [0]     : EN (1): enable
     io_rw_32 bod;
+
+    _REG_(VREG_AND_CHIP_RESET_CHIP_RESET_OFFSET) // VREG_AND_CHIP_RESET_CHIP_RESET
+    // Chip reset control and status
+    // 0x01000000 [24]    : PSM_RESTART_FLAG (0): This is set by psm_restart from the debugger
+    // 0x00100000 [20]    : HAD_PSM_RESTART (0): Last reset was from the debug port
+    // 0x00010000 [16]    : HAD_RUN (0): Last reset was from the RUN pin
+    // 0x00000100 [8]     : HAD_POR (0): Last reset was from the power-on reset or brown-out detection blocks
     io_rw_32 chip_reset;
 } vreg_and_chip_reset_hw_t;
 
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/watchdog.h b/src/rp2040/hardware_structs/include/hardware/structs/watchdog.h
index 2cf05f1..9579700 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/watchdog.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/watchdog.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,14 +10,50 @@
 #define _HARDWARE_STRUCTS_WATCHDOG_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/watchdog.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_watchdog
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/watchdog.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(WATCHDOG_CTRL_OFFSET) // WATCHDOG_CTRL
+    // Watchdog control
+    // 0x80000000 [31]    : TRIGGER (0): Trigger a watchdog reset
+    // 0x40000000 [30]    : ENABLE (0): When not enabled the watchdog timer is paused
+    // 0x04000000 [26]    : PAUSE_DBG1 (1): Pause the watchdog timer when processor 1 is in debug mode
+    // 0x02000000 [25]    : PAUSE_DBG0 (1): Pause the watchdog timer when processor 0 is in debug mode
+    // 0x01000000 [24]    : PAUSE_JTAG (1): Pause the watchdog timer when JTAG is accessing the bus fabric
+    // 0x00ffffff [23:0]  : TIME (0): Indicates the number of ticks / 2 (see errata RP2040-E1) before a watchdog reset will...
     io_rw_32 ctrl;
+
+    _REG_(WATCHDOG_LOAD_OFFSET) // WATCHDOG_LOAD
+    // Load the watchdog timer
+    // 0x00ffffff [23:0]  : LOAD (0)
     io_wo_32 load;
+
+    _REG_(WATCHDOG_REASON_OFFSET) // WATCHDOG_REASON
+    // Logs the reason for the last reset
+    // 0x00000002 [1]     : FORCE (0)
+    // 0x00000001 [0]     : TIMER (0)
     io_ro_32 reason;
+
+    _REG_(WATCHDOG_SCRATCH0_OFFSET) // WATCHDOG_SCRATCH0
+    // (Description copied from array index 0 register WATCHDOG_SCRATCH0 applies similarly to other array indexes)
+    //
+    // Scratch register
     io_rw_32 scratch[8];
+
+    _REG_(WATCHDOG_TICK_OFFSET) // WATCHDOG_TICK
+    // Controls the tick generator
+    // 0x000ff800 [19:11] : COUNT (0): Count down timer: the remaining number clk_tick cycles before the next tick is generated
+    // 0x00000400 [10]    : RUNNING (0): Is the tick generator running?
+    // 0x00000200 [9]     : ENABLE (1): start / stop tick generation
+    // 0x000001ff [8:0]   : CYCLES (0): Total number of clk_tick cycles before the next tick
     io_rw_32 tick;
 } watchdog_hw_t;
 
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/xip_ctrl.h b/src/rp2040/hardware_structs/include/hardware/structs/xip_ctrl.h
index bfa5b1c..21885e8 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/xip_ctrl.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/xip_ctrl.h
@@ -1,29 +1,72 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
+
 #ifndef _HARDWARE_STRUCTS_XIP_CTRL_H
 #define _HARDWARE_STRUCTS_XIP_CTRL_H
 
 #include "hardware/address_mapped.h"
 #include "hardware/regs/xip.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_xip
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/xip.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 typedef struct {
+    _REG_(XIP_CTRL_OFFSET) // XIP_CTRL
+    // Cache control
+    // 0x00000008 [3]     : POWER_DOWN (0): When 1, the cache memories are powered down
+    // 0x00000002 [1]     : ERR_BADWRITE (1): When 1, writes to any alias other than 0x0 (caching, allocating)
+    // 0x00000001 [0]     : EN (1): When 1, enable the cache
     io_rw_32 ctrl;
+
+    _REG_(XIP_FLUSH_OFFSET) // XIP_FLUSH
+    // Cache Flush control
+    // 0x00000001 [0]     : FLUSH (0): Write 1 to flush the cache
     io_rw_32 flush;
-    io_rw_32 stat;
+
+    _REG_(XIP_STAT_OFFSET) // XIP_STAT
+    // Cache Status
+    // 0x00000004 [2]     : FIFO_FULL (0): When 1, indicates the XIP streaming FIFO is completely full
+    // 0x00000002 [1]     : FIFO_EMPTY (1): When 1, indicates the XIP streaming FIFO is completely empty
+    // 0x00000001 [0]     : FLUSH_READY (0): Reads as 0 while a cache flush is in progress, and 1 otherwise
+    io_ro_32 stat;
+
+    _REG_(XIP_CTR_HIT_OFFSET) // XIP_CTR_HIT
+    // Cache Hit counter
     io_rw_32 ctr_hit;
+
+    _REG_(XIP_CTR_ACC_OFFSET) // XIP_CTR_ACC
+    // Cache Access counter
     io_rw_32 ctr_acc;
+
+    _REG_(XIP_STREAM_ADDR_OFFSET) // XIP_STREAM_ADDR
+    // FIFO stream address
+    // 0xfffffffc [31:2]  : STREAM_ADDR (0): The address of the next word to be streamed from flash to the streaming FIFO
     io_rw_32 stream_addr;
+
+    _REG_(XIP_STREAM_CTR_OFFSET) // XIP_STREAM_CTR
+    // FIFO stream control
+    // 0x003fffff [21:0]  : STREAM_CTR (0): Write a nonzero value to start a streaming read
     io_rw_32 stream_ctr;
-    io_rw_32 stream_fifo;
+
+    _REG_(XIP_STREAM_FIFO_OFFSET) // XIP_STREAM_FIFO
+    // FIFO stream data
+    io_ro_32 stream_fifo;
 } xip_ctrl_hw_t;
 
-#define XIP_STAT_FIFO_FULL     0x4u
-#define XIP_STAT_FIFO_EMPTY    0x2u
-#define XIP_STAT_FLUSH_RDY     0x1u
-
 #define xip_ctrl_hw ((xip_ctrl_hw_t *const)XIP_CTRL_BASE)
 
+#define XIP_STAT_FIFO_FULL XIP_STAT_FIFO_FULL_BITS
+#define XIP_STAT_FIFO_EMPTY XIP_STAT_FIFO_EMPTY_BITS
+#define XIP_STAT_FLUSH_RDY XIP_STAT_FLUSH_READY_BITS
+
 #endif
diff --git a/src/rp2040/hardware_structs/include/hardware/structs/xosc.h b/src/rp2040/hardware_structs/include/hardware/structs/xosc.h
index 698e6a2..0ff4db4 100644
--- a/src/rp2040/hardware_structs/include/hardware/structs/xosc.h
+++ b/src/rp2040/hardware_structs/include/hardware/structs/xosc.h
@@ -1,5 +1,7 @@
+// THIS HEADER FILE IS AUTOMATICALLY GENERATED -- DO NOT EDIT
+
 /*
- * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ * Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,16 +10,47 @@
 #define _HARDWARE_STRUCTS_XOSC_H
 
 #include "hardware/address_mapped.h"
-#include "hardware/platform_defs.h"
 #include "hardware/regs/xosc.h"
 
+// Reference to datasheet: https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#tab-registerlist_xosc
+//
+// The _REG_ macro is intended to help make the register navigable in your IDE (for example, using the "Go to Definition" feature)
+// _REG_(x) will link to the corresponding register in hardware/regs/xosc.h.
+//
+// Bit-field descriptions are of the form:
+// BITMASK [BITRANGE]: FIELDNAME (RESETVALUE): DESCRIPTION
+
 /// \tag::xosc_hw[]
 typedef struct {
+    _REG_(XOSC_CTRL_OFFSET) // XOSC_CTRL
+    // Crystal Oscillator Control
+    // 0x00fff000 [23:12] : ENABLE (0): On power-up this field is initialised to DISABLE and the chip runs from the ROSC
+    // 0x00000fff [11:0]  : FREQ_RANGE (0): Frequency range
     io_rw_32 ctrl;
+
+    _REG_(XOSC_STATUS_OFFSET) // XOSC_STATUS
+    // Crystal Oscillator Status
+    // 0x80000000 [31]    : STABLE (0): Oscillator is running and stable
+    // 0x01000000 [24]    : BADWRITE (0): An invalid value has been written to CTRL_ENABLE or CTRL_FREQ_RANGE or DORMANT
+    // 0x00001000 [12]    : ENABLED (0): Oscillator is enabled but not necessarily running and stable, resets to 0
+    // 0x00000003 [1:0]   : FREQ_RANGE (0): The current frequency range setting, always reads 0
     io_rw_32 status;
+
+    _REG_(XOSC_DORMANT_OFFSET) // XOSC_DORMANT
+    // Crystal Oscillator pause control
     io_rw_32 dormant;
+
+    _REG_(XOSC_STARTUP_OFFSET) // XOSC_STARTUP
+    // Controls the startup delay
+    // 0x00100000 [20]    : X4 (0): Multiplies the startup_delay by 4
+    // 0x00003fff [13:0]  : DELAY (0xc4): in multiples of 256*xtal_period
     io_rw_32 startup;
-    io_rw_32 _reserved[3];
+
+    uint32_t _pad0[3];
+
+    _REG_(XOSC_COUNT_OFFSET) // XOSC_COUNT
+    // A down counter running at the xosc frequency which counts to zero and stops
+    // 0x000000ff [7:0]   : COUNT (0)
     io_rw_32 count;
 } xosc_hw_t;
 
diff --git a/src/rp2_common.cmake b/src/rp2_common.cmake
index 7612660..c04e551 100644
--- a/src/rp2_common.cmake
+++ b/src/rp2_common.cmake
@@ -3,17 +3,17 @@
 enable_language(ASM)
 
 function(pico_add_hex_output TARGET)
-    add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_OBJCOPY} -Oihex ${TARGET}${CMAKE_EXECUTABLE_SUFFIX} ${TARGET}.hex)
+    add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${TARGET}> $<IF:$<BOOL:$<TARGET_PROPERTY:${TARGET},OUTPUT_NAME>>,$<TARGET_PROPERTY:${TARGET},OUTPUT_NAME>,$<TARGET_PROPERTY:${TARGET},NAME>>.hex)
 endfunction()
 
 function(pico_add_bin_output TARGET)
-    add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_OBJCOPY} -Obinary ${TARGET}${CMAKE_EXECUTABLE_SUFFIX} ${TARGET}.bin)
+    add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${TARGET}> $<IF:$<BOOL:$<TARGET_PROPERTY:${TARGET},OUTPUT_NAME>>,$<TARGET_PROPERTY:${TARGET},OUTPUT_NAME>,$<TARGET_PROPERTY:${TARGET},NAME>>.bin)
 endfunction()
 
 function(pico_add_dis_output TARGET)
     add_custom_command(TARGET ${TARGET} POST_BUILD
-            COMMAND ${CMAKE_OBJDUMP} -h ${TARGET}${CMAKE_EXECUTABLE_SUFFIX} >${TARGET}.dis
-            COMMAND ${CMAKE_OBJDUMP} -d ${TARGET}${CMAKE_EXECUTABLE_SUFFIX} >>${TARGET}.dis
+            COMMAND ${CMAKE_OBJDUMP} -h $<TARGET_FILE:${TARGET}> >$<IF:$<BOOL:$<TARGET_PROPERTY:${TARGET},OUTPUT_NAME>>,$<TARGET_PROPERTY:${TARGET},OUTPUT_NAME>,$<TARGET_PROPERTY:${TARGET},NAME>>.dis
+            COMMAND ${CMAKE_OBJDUMP} -d $<TARGET_FILE:${TARGET}> >>$<IF:$<BOOL:$<TARGET_PROPERTY:${TARGET},OUTPUT_NAME>>,$<TARGET_PROPERTY:${TARGET},OUTPUT_NAME>,$<TARGET_PROPERTY:${TARGET},NAME>>.dis
             )
 endfunction()
 
@@ -36,8 +36,8 @@
 
         add_custom_command(TARGET ${TARGET}_symlinked POST_BUILD
                 COMMAND rm -f "${PICO_SYMLINK_ELF_AS_FILENAME}"
-                COMMAND ln -s -r ${TARGET}${CMAKE_EXECUTABLE_SUFFIX} "${PICO_SYMLINK_ELF_AS_FILENAME}"
-                COMMENT "Symlinking from ${PICO_SYMLINK_ELF_AS_FILENAME} to ${TARGET}${CMAKE_EXECUTABLE_SUFFIX}"
+                COMMAND ln -s -r $<TARGET_FILE:${TARGET}> "${PICO_SYMLINK_ELF_AS_FILENAME}"
+                COMMENT "Symlinking from ${PICO_SYMLINK_ELF_AS_FILENAME} to ${TARGET}"
                 )
     endif ()
     # PICO_CMAKE_CONFIG: PICO_NO_UF2, Disable UF2 output, type=bool, default=0, group=build
diff --git a/src/rp2_common/CMakeLists.txt b/src/rp2_common/CMakeLists.txt
index 0277c8d..4ca55be 100644
--- a/src/rp2_common/CMakeLists.txt
+++ b/src/rp2_common/CMakeLists.txt
@@ -72,5 +72,6 @@
 set(CMAKE_EXECUTABLE_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}" PARENT_SCOPE)
 
 pico_add_doxygen(${CMAKE_CURRENT_LIST_DIR})
+pico_add_doxygen_exclude(${CMAKE_CURRENT_LIST_DIR}/cmsis)
 
 pico_promote_common_scope_vars()
\ No newline at end of file
diff --git a/src/rp2_common/boot_stage2/CMakeLists.txt b/src/rp2_common/boot_stage2/CMakeLists.txt
index 73c3e3e..a2f3960 100644
--- a/src/rp2_common/boot_stage2/CMakeLists.txt
+++ b/src/rp2_common/boot_stage2/CMakeLists.txt
@@ -4,7 +4,7 @@
 if (DEFINED ENV{PICO_DEFAULT_BOOT_STAGE2_FILE})
     set(PICO_DEFAULT_BOOT_STAGE2_FILE $ENV{PICO_DEFAULT_BOOT_STAGE2_FILE})
     message("Using PICO_DEFAULT_BOOT_STAGE2_FILE from environment ('${PICO_DEFAULT_BOOT_STAGE2_FILE}')")
-elif (PICO_DEFAULT_BOOT_STAGE2_FILE)
+elseif (PICO_DEFAULT_BOOT_STAGE2_FILE)
     # explicitly set, so cache it
     set(PICO_DEFAULT_BOOT_STAGE2_FILE "${PICO_DEFAULT_BOOT_STAGE2_FILE}" CACHE STRING "boot stage 2 source file" FORCE)
 endif()
@@ -25,6 +25,7 @@
 if (NOT EXISTS ${PICO_DEFAULT_BOOT_STAGE2_FILE})
     message(FATAL_ERROR "Specified boot stage 2 source '${PICO_DEFAULT_BOOT_STAGE2_FILE}' does not exist.")
 endif()
+pico_register_common_scope_var(PICO_DEFAULT_BOOT_STAGE2_FILE)
 
 # needed by function below
 set(PICO_BOOT_STAGE2_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "")
@@ -98,3 +99,9 @@
 
 pico_define_boot_stage2(bs2_default ${PICO_DEFAULT_BOOT_STAGE2_FILE})
 
+# Create a new boot stage 2 target using the default implementation for the current build (PICO_BOARD derived)
+function(pico_clone_default_boot_stage2 NAME)
+    pico_define_boot_stage2(${NAME} ${PICO_DEFAULT_BOOT_STAGE2_FILE})
+endfunction()
+
+pico_promote_common_scope_vars()
\ No newline at end of file
diff --git a/src/rp2_common/hardware_adc/include/hardware/adc.h b/src/rp2_common/hardware_adc/include/hardware/adc.h
index 35586a6..be82025 100644
--- a/src/rp2_common/hardware_adc/include/hardware/adc.h
+++ b/src/rp2_common/hardware_adc/include/hardware/adc.h
@@ -19,7 +19,7 @@
  * The RP2040 has an internal analogue-digital converter (ADC) with the following features:
  * - SAR ADC
  * - 500 kS/s (Using an independent 48MHz clock)
- * - 12 bit (9.5 ENOB)
+ * - 12 bit (8.7 ENOB)
  * - 5 input mux:
  *  - 4 inputs that are available on package pins shared with GPIO[29:26]
  *  - 1 input is dedicated to the internal temperature sensor
@@ -28,7 +28,7 @@
  * - DMA interface
  *
  * Although there is only one ADC you can specify the input to it using the adc_select_input() function.
- * In round robin mode (adc_rrobin()) will use that input and move to the next one after a read.
+ * In round robin mode (adc_set_round_robin()), the ADC will use that input and move to the next one after a read.
  *
  * User ADC inputs are on 0-3 (GPIO 26-29), the temperature sensor is on input 4.
  *
@@ -62,7 +62,7 @@
 /*! \brief  Initialise the gpio for use as an ADC pin
  *  \ingroup hardware_adc
  *
- * Prepare a GPIO for use with ADC, by disabling all digital functions.
+ * Prepare a GPIO for use with ADC by disabling all digital functions.
  *
  * \param gpio The GPIO number to use. Allowable GPIO numbers are 26 to 29 inclusive.
  */
@@ -167,7 +167,7 @@
 /*! \brief Setup the ADC FIFO
  *  \ingroup hardware_adc
  *
- * FIFO is 4 samples long, if a conversion is completed and the FIFO is full the result is dropped.
+ * FIFO is 4 samples long, if a conversion is completed and the FIFO is full, the result is dropped.
  *
  * \param en Enables write each conversion result to the FIFO
  * \param dreq_en Enable DMA requests when FIFO contains data
@@ -193,7 +193,7 @@
 /*! \brief Check FIFO empty state
  *  \ingroup hardware_adc
  *
- * \return Returns true if the fifo is empty
+ * \return Returns true if the FIFO is empty
  */
 static inline bool adc_fifo_is_empty(void) {
     return !!(adc_hw->fcs & ADC_FCS_EMPTY_BITS);
@@ -231,7 +231,7 @@
 /*! \brief Drain the ADC FIFO
  *  \ingroup hardware_adc
  *
- * Will wait for any conversion to complete then drain the FIFO discarding any results.
+ * Will wait for any conversion to complete then drain the FIFO, discarding any results.
  */
 static inline void adc_fifo_drain(void) {
     // Potentially there is still a conversion in progress -- wait for this to complete before draining
diff --git a/src/rp2_common/hardware_base/include/hardware/address_mapped.h b/src/rp2_common/hardware_base/include/hardware/address_mapped.h
index b58f1e5..a3b9584 100644
--- a/src/rp2_common/hardware_base/include/hardware/address_mapped.h
+++ b/src/rp2_common/hardware_base/include/hardware/address_mapped.h
@@ -55,6 +55,11 @@
 #define check_hw_layout(type, member, offset) static_assert(offsetof(type, member) == (offset), "hw offset mismatch")
 #define check_hw_size(type, size) static_assert(sizeof(type) == (size), "hw size mismatch")
 
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_ADDRESS_ALIAS, Enable/disable assertions in memory address aliasing macros, type=bool, default=0, group=hardware_base
+#ifndef PARAM_ASSERTIONS_ENABLED_ADDRESS_ALIAS
+#define PARAM_ASSERTIONS_ENABLED_ADDRESS_ALIAS 0
+#endif
+
 typedef volatile uint32_t io_rw_32;
 typedef const volatile uint32_t io_ro_32;
 typedef volatile uint32_t io_wo_32;
@@ -68,15 +73,44 @@
 typedef volatile uint8_t *const ioptr;
 typedef ioptr const const_ioptr;
 
+// A non-functional (empty) helper macro to help IDEs follow links from the autogenerated
+// hardware struct headers in hardware/structs/xxx.h to the raw register definitions
+// in hardware/regs/xxx.h. A preprocessor define such as TIMER_TIMEHW_OFFSET (a timer register offset)
+// is not generally clickable (in an IDE) if placed in a C comment, so _REG_(TIMER_TIMEHW_OFFSET) is
+// included outside of a comment instead
+#define _REG_(x)
+
+// Helper method used by hw_alias macros to optionally check input validity
+#define hw_alias_check_addr(addr) ((uintptr_t)(addr))
+// can't use the following impl as it breaks existing static declarations using hw_alias, so would be a backwards incompatibility
+//static __force_inline uint32_t hw_alias_check_addr(volatile void *addr) {
+//    uint32_t rc = (uintptr_t)addr;
+//    invalid_params_if(ADDRESS_ALIAS, rc < 0x40000000); // catch likely non HW pointer types
+//    return rc;
+//}
+
+// Helper method used by xip_alias macros to optionally check input validity
+static __force_inline uint32_t xip_alias_check_addr(const void *addr) {
+    uint32_t rc = (uintptr_t)addr;
+    valid_params_if(ADDRESS_ALIAS, rc >= XIP_MAIN_BASE && rc < XIP_NOALLOC_BASE);
+    return rc;
+}
+
 // Untyped conversion alias pointer generation macros
-#define hw_set_alias_untyped(addr) ((void *)(REG_ALIAS_SET_BITS | (uintptr_t)(addr)))
-#define hw_clear_alias_untyped(addr) ((void *)(REG_ALIAS_CLR_BITS | (uintptr_t)(addr)))
-#define hw_xor_alias_untyped(addr) ((void *)(REG_ALIAS_XOR_BITS | (uintptr_t)(addr)))
+#define hw_set_alias_untyped(addr) ((void *)(REG_ALIAS_SET_BITS | hw_alias_check_addr(addr)))
+#define hw_clear_alias_untyped(addr) ((void *)(REG_ALIAS_CLR_BITS | hw_alias_check_addr(addr)))
+#define hw_xor_alias_untyped(addr) ((void *)(REG_ALIAS_XOR_BITS | hw_alias_check_addr(addr)))
+#define xip_noalloc_alias_untyped(addr) ((void *)(XIP_NOALLOC_BASE | xip_alias_check_addr(addr)))
+#define xip_nocache_alias_untyped(addr) ((void *)(XIP_NOCACHE_BASE | xip_alias_check_addr(addr)))
+#define xip_nocache_noalloc_alias_untyped(addr) ((void *)(XIP_NOCACHE_NOALLOC_BASE | xip_alias_check_addr(addr)))
 
 // Typed conversion alias pointer generation macros
 #define hw_set_alias(p) ((typeof(p))hw_set_alias_untyped(p))
 #define hw_clear_alias(p) ((typeof(p))hw_clear_alias_untyped(p))
 #define hw_xor_alias(p) ((typeof(p))hw_xor_alias_untyped(p))
+#define xip_noalloc_alias(p) ((typeof(p))xip_noalloc_alias_untyped(p))
+#define xip_nocache_alias(p) ((typeof(p))xip_nocache_alias_untyped(p))
+#define xip_nocache_noalloc_alias(p) ((typeof(p))xip_nocache_noalloc_alias_untyped(p))
 
 /*! \brief Atomically set the specified bits to 1 in a HW register
  *  \ingroup hardware_base
diff --git a/src/rp2_common/hardware_dma/dma.c b/src/rp2_common/hardware_dma/dma.c
index 230fa16..90fde06 100644
--- a/src/rp2_common/hardware_dma/dma.c
+++ b/src/rp2_common/hardware_dma/dma.c
@@ -18,6 +18,7 @@
 
 static_assert(NUM_DMA_CHANNELS <= 16, "");
 static uint16_t _claimed;
+static uint8_t _timer_claimed;
 
 void dma_channel_claim(uint channel) {
     check_dma_channel_param(channel);
@@ -44,6 +45,25 @@
     return hw_is_claimed((uint8_t *) &_claimed, channel);
 }
 
+void dma_timer_claim(uint timer) {
+    check_dma_timer_param(timer);
+    hw_claim_or_assert(&_timer_claimed, timer, "DMA timer %d is already claimed");
+}
+
+void dma_timer_unclaim(uint timer) {
+    check_dma_timer_param(timer);
+    hw_claim_clear(&_timer_claimed, timer);
+}
+
+int dma_claim_unused_timer(bool required) {
+    return hw_claim_unused_from_range(&_timer_claimed, required, 0, NUM_DMA_TIMERS-1, "No DMA timers are available");
+}
+
+bool dma_timer_is_claimed(uint timer) {
+    check_dma_timer_param(timer);
+    return hw_is_claimed(&_timer_claimed, timer);
+}
+
 #ifndef NDEBUG
 
 void print_dma_ctrl(dma_channel_hw_t *channel) {
diff --git a/src/rp2_common/hardware_dma/include/hardware/dma.h b/src/rp2_common/hardware_dma/include/hardware/dma.h
index 526d632..7c9406f 100644
--- a/src/rp2_common/hardware_dma/include/hardware/dma.h
+++ b/src/rp2_common/hardware_dma/include/hardware/dma.h
@@ -54,6 +54,10 @@
 #endif
 }
 
+static inline void check_dma_timer_param(__unused uint timer_num) {
+    valid_params_if(DMA, timer_num < NUM_DMA_TIMERS);
+}
+
 inline static dma_channel_hw_t *dma_channel_hw_addr(uint channel) {
     check_dma_channel_param(channel);
     return &dma_hw->ch[channel];
@@ -715,6 +719,71 @@
     dma_hw->sniff_ctrl = 0;
 }
 
+/*! \brief Mark a dma timer as used
+ *  \ingroup hardware_dma
+ *
+ * Method for cooperative claiming of hardware. Will cause a panic if the timer
+ * is already claimed. Use of this method by libraries detects accidental
+ * configurations that would fail in unpredictable ways.
+ *
+ * \param timer the dma timer
+ */
+void dma_timer_claim(uint timer);
+
+/*! \brief Mark a dma timer as no longer used
+ *  \ingroup hardware_dma
+ *
+ * Method for cooperative claiming of hardware.
+ *
+ * \param timer the dma timer to release
+ */
+void dma_timer_unclaim(uint timer);
+
+/*! \brief Claim a free dma timer
+ *  \ingroup hardware_dma
+ *
+ * \param required if true the function will panic if none are available
+ * \return the dma timer number or -1 if required was false, and none were free
+ */
+int dma_claim_unused_timer(bool required);
+
+/*! \brief Determine if a dma timer is claimed
+ *  \ingroup hardware_dma
+ *
+ * \param timer the dma timer
+ * \return true if the timer is claimed, false otherwise
+ * \see dma_timer_claim
+ */
+bool dma_timer_is_claimed(uint timer);
+
+/*! \brief Set the divider for the given DMA timer
+ *  \ingroup hardware_dma
+ *
+ * The timer will run at the system_clock_freq * numerator / denominator, so this is the speed
+ * that data elements will be transferred at via a DMA channel using this timer as a DREQ
+ *
+ * \param timer the dma timer
+ * \param numerator the fraction's numerator
+ * \param denominator the fraction's denominator
+ */
+static inline void dma_timer_set_fraction(uint timer, uint16_t numerator, uint16_t denominator) {
+    check_dma_timer_param(timer);
+    dma_hw->timer[timer] = (((uint32_t)numerator) << DMA_TIMER0_X_LSB) | (((uint32_t)denominator) << DMA_TIMER0_Y_LSB);
+}
+
+/*! \brief Return the DREQ number for a given DMA timer
+ *  \ingroup hardware_dma
+ *
+ * \param timer_num DMA timer number 0-3
+ */
+static inline uint dma_get_timer_dreq(uint timer_num) {
+    static_assert(DREQ_DMA_TIMER1 == DREQ_DMA_TIMER0 + 1, "");
+    static_assert(DREQ_DMA_TIMER2 == DREQ_DMA_TIMER0 + 2, "");
+    static_assert(DREQ_DMA_TIMER3 == DREQ_DMA_TIMER0 + 3, "");
+    check_dma_timer_param(timer_num);
+    return DREQ_DMA_TIMER0 + timer_num;
+}
+
 #ifndef NDEBUG
 void print_dma_ctrl(dma_channel_hw_t *channel);
 #endif
diff --git a/src/rp2_common/hardware_exception/include/hardware/exception.h b/src/rp2_common/hardware_exception/include/hardware/exception.h
index 0b805d7..005168b 100644
--- a/src/rp2_common/hardware_exception/include/hardware/exception.h
+++ b/src/rp2_common/hardware_exception/include/hardware/exception.h
@@ -16,7 +16,7 @@
  *
  * Methods for setting processor exception handlers
  *
- * Exceptions are identified by a \ref exception_num which is a number from -15 to -1; these are the numbers relative to
+ * Exceptions are identified by a \ref exception_number which is a number from -15 to -1; these are the numbers relative to
  * the index of the first IRQ vector in the vector table. (i.e. vector table index is exception_num plus 16)
  *
  * There is one set of exception handlers per core, so the exception handlers for each core as set by these methods are independent.
@@ -85,11 +85,11 @@
  * prior to the call to exception_set_exclusive_handler(), so that exception_set_exclusive_handler()
  * may be called again in the future.
  *
- * \param num Exception number \ref exception_nums
+ * \param num Exception number \ref exception_number
  * \param original_handler The original handler returned from \ref exception_set_exclusive_handler
  * \see exception_set_exclusive_handler()
  */
-void exception_restore_handler(enum exception_number, exception_handler_t original_handler);
+void exception_restore_handler(enum exception_number num, exception_handler_t original_handler);
 
 /*! \brief Get the current exception handler for the specified exception from the currently installed vector table
  * of the execution core
diff --git a/src/rp2_common/hardware_flash/flash.c b/src/rp2_common/hardware_flash/flash.c
index dc9d833..5699302 100644
--- a/src/rp2_common/hardware_flash/flash.c
+++ b/src/rp2_common/hardware_flash/flash.c
@@ -50,7 +50,7 @@
 
 static void __no_inline_not_in_flash_func(flash_enable_xip_via_boot2)(void) {
     // Set up XIP for 03h read on bus access (slow but generic)
-    void (*flash_enter_cmd_xip)(void) = (void(*)(void))rom_func_lookup(rom_table_code('C', 'X'));
+    rom_flash_enter_cmd_xip_fn flash_enter_cmd_xip = (rom_flash_enter_cmd_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_ENTER_CMD_XIP);
     assert(flash_enter_cmd_xip);
     flash_enter_cmd_xip();
 }
@@ -66,11 +66,10 @@
 #endif
     invalid_params_if(FLASH, flash_offs & (FLASH_SECTOR_SIZE - 1));
     invalid_params_if(FLASH, count & (FLASH_SECTOR_SIZE - 1));
-    void (*connect_internal_flash)(void) = (void(*)(void))rom_func_lookup(rom_table_code('I', 'F'));
-    void (*flash_exit_xip)(void) = (void(*)(void))rom_func_lookup(rom_table_code('E', 'X'));
-    void (*flash_range_erase)(uint32_t, size_t, uint32_t, uint8_t) =
-        (void(*)(uint32_t, size_t, uint32_t, uint8_t))rom_func_lookup(rom_table_code('R', 'E'));
-    void (*flash_flush_cache)(void) = (void(*)(void))rom_func_lookup(rom_table_code('F', 'C'));
+    rom_connect_internal_flash_fn connect_internal_flash = (rom_connect_internal_flash_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH);
+    rom_flash_exit_xip_fn flash_exit_xip = (rom_flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP);
+    rom_flash_range_erase_fn flash_range_erase = (rom_flash_range_erase_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_RANGE_ERASE);
+    rom_flash_flush_cache_fn flash_flush_cache = (rom_flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE);
     assert(connect_internal_flash && flash_exit_xip && flash_range_erase && flash_flush_cache);
     flash_init_boot2_copyout();
 
@@ -90,11 +89,10 @@
 #endif
     invalid_params_if(FLASH, flash_offs & (FLASH_PAGE_SIZE - 1));
     invalid_params_if(FLASH, count & (FLASH_PAGE_SIZE - 1));
-    void (*connect_internal_flash)(void) = (void(*)(void))rom_func_lookup(rom_table_code('I', 'F'));
-    void (*flash_exit_xip)(void) = (void(*)(void))rom_func_lookup(rom_table_code('E', 'X'));
-    void (*flash_range_program)(uint32_t, const uint8_t*, size_t) =
-        (void(*)(uint32_t, const uint8_t*, size_t))rom_func_lookup(rom_table_code('R', 'P'));
-    void (*flash_flush_cache)(void) = (void(*)(void))rom_func_lookup(rom_table_code('F', 'C'));
+    rom_connect_internal_flash_fn connect_internal_flash = (rom_connect_internal_flash_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH);
+    rom_flash_exit_xip_fn flash_exit_xip = (rom_flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP);
+    rom_flash_range_program_fn flash_range_program = (rom_flash_range_program_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_RANGE_PROGRAM);
+    rom_flash_flush_cache_fn flash_flush_cache = (rom_flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE);
     assert(connect_internal_flash && flash_exit_xip && flash_range_program && flash_flush_cache);
     flash_init_boot2_copyout();
 
@@ -124,9 +122,9 @@
 }
 
 void __no_inline_not_in_flash_func(flash_do_cmd)(const uint8_t *txbuf, uint8_t *rxbuf, size_t count) {
-    void (*connect_internal_flash)(void) = (void(*)(void))rom_func_lookup(rom_table_code('I', 'F'));
-    void (*flash_exit_xip)(void) = (void(*)(void))rom_func_lookup(rom_table_code('E', 'X'));
-    void (*flash_flush_cache)(void) = (void(*)(void))rom_func_lookup(rom_table_code('F', 'C'));
+    rom_connect_internal_flash_fn connect_internal_flash = (rom_connect_internal_flash_fn)rom_func_lookup_inline(ROM_FUNC_CONNECT_INTERNAL_FLASH);
+    rom_flash_exit_xip_fn flash_exit_xip = (rom_flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP);
+    rom_flash_flush_cache_fn flash_flush_cache = (rom_flash_flush_cache_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_FLUSH_CACHE);
     assert(connect_internal_flash && flash_exit_xip && flash_flush_cache);
     flash_init_boot2_copyout();
     __compiler_memory_barrier();
diff --git a/src/rp2_common/hardware_gpio/gpio.c b/src/rp2_common/hardware_gpio/gpio.c
index 10b1502..2816b97 100644
--- a/src/rp2_common/hardware_gpio/gpio.c
+++ b/src/rp2_common/hardware_gpio/gpio.c
@@ -142,7 +142,7 @@
     io_irq_ctrl_hw_t *irq_ctrl_base = get_core_num() ?
                                            &iobank0_hw->proc1_irq_ctrl : &iobank0_hw->proc0_irq_ctrl;
     for (uint gpio = 0; gpio < NUM_BANK0_GPIOS; gpio++) {
-        io_rw_32 *status_reg = &irq_ctrl_base->ints[gpio / 8];
+        io_ro_32 *status_reg = &irq_ctrl_base->ints[gpio / 8];
         uint events = (*status_reg >> 4 * (gpio % 8)) & 0xf;
         if (events) {
             // TODO: If both cores care about this event then the second core won't get the irq?
diff --git a/src/rp2_common/hardware_gpio/include/hardware/gpio.h b/src/rp2_common/hardware_gpio/include/hardware/gpio.h
index e90be27..7037e85 100644
--- a/src/rp2_common/hardware_gpio/include/hardware/gpio.h
+++ b/src/rp2_common/hardware_gpio/include/hardware/gpio.h
@@ -178,6 +178,12 @@
  */
 void gpio_set_function(uint gpio, enum gpio_function fn);
 
+/*! \brief Determine current GPIO function
+ *  \ingroup hardware_gpio
+ *
+ * \param gpio GPIO number
+ * \return Which GPIO function is currently selected from list \ref gpio_function
+ */
 enum gpio_function gpio_get_function(uint gpio);
 
 /*! \brief Select up and down pulls on specific GPIO
@@ -401,7 +407,7 @@
 /*! \brief Initialise a GPIO for (enabled I/O and set func to GPIO_FUNC_SIO)
  *  \ingroup hardware_gpio
  *
- * Clear the output enable (i.e. set to input)
+ * Clear the output enable (i.e. set to input).
  * Clear any output value.
  *
  * \param gpio GPIO number
@@ -411,7 +417,7 @@
 /*! \brief Initialise multiple GPIOs (enabled I/O and set func to GPIO_FUNC_SIO)
  *  \ingroup hardware_gpio
  *
- * Clear the output enable (i.e. set to input)
+ * Clear the output enable (i.e. set to input).
  * Clear any output value.
  *
  * \param gpio_mask Mask with 1 bit per GPIO number to initialize
diff --git a/src/rp2_common/hardware_i2c/i2c.c b/src/rp2_common/hardware_i2c/i2c.c
index 9d2e931..95bcfea 100644
--- a/src/rp2_common/hardware_i2c/i2c.c
+++ b/src/rp2_common/hardware_i2c/i2c.c
@@ -115,16 +115,18 @@
     invalid_params_if(I2C, addr >= 0x80); // 7-bit addresses
     invalid_params_if(I2C, i2c_reserved_addr(addr));
     i2c->hw->enable = 0;
+    uint32_t ctrl_set_if_master = I2C_IC_CON_MASTER_MODE_BITS | I2C_IC_CON_IC_SLAVE_DISABLE_BITS;
+    uint32_t ctrl_set_if_slave = I2C_IC_CON_RX_FIFO_FULL_HLD_CTRL_BITS;
     if (slave) {
-        hw_clear_bits(&i2c->hw->con,
-                      I2C_IC_CON_MASTER_MODE_BITS |
-                      I2C_IC_CON_IC_SLAVE_DISABLE_BITS
+        hw_write_masked(&i2c->hw->con,
+            ctrl_set_if_slave,
+            ctrl_set_if_master | ctrl_set_if_slave
         );
         i2c->hw->sar = addr;
     } else {
-        hw_set_bits(&i2c->hw->con,
-                    I2C_IC_CON_MASTER_MODE_BITS |
-                    I2C_IC_CON_IC_SLAVE_DISABLE_BITS
+        hw_write_masked(&i2c->hw->con,
+            ctrl_set_if_master,
+            ctrl_set_if_master | ctrl_set_if_slave
         );
     }
     i2c->hw->enable = 1;
diff --git a/src/rp2_common/hardware_i2c/include/hardware/i2c.h b/src/rp2_common/hardware_i2c/include/hardware/i2c.h
index 5cce6f8..23ff8f1 100644
--- a/src/rp2_common/hardware_i2c/include/hardware/i2c.h
+++ b/src/rp2_common/hardware_i2c/include/hardware/i2c.h
@@ -10,6 +10,7 @@
 #include "pico.h"
 #include "pico/time.h"
 #include "hardware/structs/i2c.h"
+#include "hardware/regs/dreq.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
@@ -26,10 +27,12 @@
  * 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
+ * information between the devices connected to the bus. Each device is recognized by a unique 7-bit 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.
+ * clock signals to permit that transfer. The first byte in the data transfer always contains the 7-bit address and
+ * a read/write bit in the LSB position. This API takes care of toggling the read/write bit. After this, 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.
  *
@@ -154,7 +157,7 @@
  *  \ingroup hardware_i2c
  *
  * \param i2c Either \ref i2c0 or \ref i2c1
- * \param addr Address of device to write to
+ * \param addr 7-bit 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),
@@ -171,7 +174,7 @@
  *  \ingroup hardware_i2c
  *
  * \param i2c Either \ref i2c0 or \ref i2c1
- * \param addr Address of device to read from
+ * \param addr 7-bit 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),
@@ -185,7 +188,7 @@
  *  \ingroup hardware_i2c
  *
  * \param i2c Either \ref i2c0 or \ref i2c1
- * \param addr Address of device to write to
+ * \param addr 7-bit 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),
@@ -207,7 +210,7 @@
  *  \ingroup hardware_i2c
  *
  * \param i2c Either \ref i2c0 or \ref i2c1
- * \param addr Address of device to read from
+ * \param addr 7-bit 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),
@@ -226,7 +229,7 @@
  *  \ingroup hardware_i2c
  *
  * \param i2c Either \ref i2c0 or \ref i2c1
- * \param addr Address of device to write to
+ * \param addr 7-bit 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),
@@ -239,12 +242,12 @@
  *  \ingroup hardware_i2c
  *
  * \param i2c Either \ref i2c0 or \ref i2c1
- * \param addr Address of device to read from
+ * \param addr 7-bit 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.
+ * \return Number of bytes read, or PICO_ERROR_GENERIC if address not acknowledged or no device present.
  */
 int i2c_read_blocking(i2c_inst_t *i2c, uint8_t addr, uint8_t *dst, size_t len, bool nostop);
 
@@ -309,6 +312,19 @@
     }
 }
 
+/*! \brief Return the DREQ to use for pacing transfers to/from a particular I2C instance
+ *  \ingroup hardware_i2c
+ *
+ * \param i2c Either \ref i2c0 or \ref i2c1
+ * \param is_tx true for sending data to the I2C instance, false for receiving data from the I2C instance
+ */
+static inline uint i2c_get_dreq(i2c_inst_t *i2c, bool is_tx) {
+    static_assert(DREQ_I2C0_RX == DREQ_I2C0_TX + 1, "");
+    static_assert(DREQ_I2C1_RX == DREQ_I2C1_TX + 1, "");
+    static_assert(DREQ_I2C1_TX == DREQ_I2C0_TX + 2, "");
+    return DREQ_I2C0_TX + i2c_hw_index(i2c) * 2 + !is_tx;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/rp2_common/hardware_irq/include/hardware/irq.h b/src/rp2_common/hardware_irq/include/hardware/irq.h
index d82ad54..424a497 100644
--- a/src/rp2_common/hardware_irq/include/hardware/irq.h
+++ b/src/rp2_common/hardware_irq/include/hardware/irq.h
@@ -8,12 +8,12 @@
 #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
+// PICO_CONFIG: PICO_MAX_SHARED_IRQ_HANDLERS, Maximum number of shared IRQ handlers, 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
+// PICO_CONFIG: PICO_DISABLE_SHARED_IRQ_HANDLERS, Disable shared IRQ handlers, type=bool, default=0, group=hardware_irq
 #ifndef PICO_DISABLE_SHARED_IRQ_HANDLERS
 #define PICO_DISABLE_SHARED_IRQ_HANDLERS 0
 #endif
@@ -37,13 +37,13 @@
  * 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
+ * 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
+ * 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:
@@ -53,7 +53,7 @@
  *    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.
+ * be in register r0.
  *
  * \section interrupt_nums Interrupt Numbers
  *
@@ -119,7 +119,11 @@
  */
 typedef void (*irq_handler_t)(void);
 
-/*! \brief Set specified interrupts priority
+static inline void check_irq_param(__unused uint num) {
+    invalid_params_if(IRQ, num >= NUM_IRQS);
+}
+
+/*! \brief Set specified interrupt's priority
  *  \ingroup hardware_irq
  *
  * \param num Interrupt number
@@ -133,6 +137,21 @@
  */
 void irq_set_priority(uint num, uint8_t hardware_priority);
 
+/*! \brief Get specified interrupt's priority
+ *  \ingroup hardware_irq
+ *
+ * Numerically-lower values indicate a higher priority. Hardware priorities
+ * range from 0 (highest priority) to 255 (lowest priority) 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
+ *
+ * \param num Interrupt number
+ * \return the IRQ priority
+ */
+uint irq_get_priority(uint num);
+
 /*! \brief Enable or disable a specific interrupt on the executing core
  *  \ingroup hardware_irq
  *
@@ -245,7 +264,7 @@
     *((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
+/*! \brief Force an interrupt to be pending on the executing core
  *  \ingroup hardware_irq
  *
  * This should generally not be used for IRQs connected to hardware.
diff --git a/src/rp2_common/hardware_irq/irq.c b/src/rp2_common/hardware_irq/irq.c
index e47b68d..211f6d0 100644
--- a/src/rp2_common/hardware_irq/irq.c
+++ b/src/rp2_common/hardware_irq/irq.c
@@ -33,10 +33,6 @@
     spin_unlock(spin_lock_instance(PICO_SPINLOCK_ID_IRQ), save);
 }
 
-static inline void check_irq_param(__unused 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);
@@ -63,7 +59,7 @@
     *((io_rw_32 *) (PPB_BASE + M0PLUS_NVIC_ISPR_OFFSET)) = 1u << num;
 }
 
-#if PICO_MAX_SHARED_IRQ_HANDLERS
+#if !PICO_DISABLE_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, "");
 
@@ -92,11 +88,13 @@
 } 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);
 }
+#else
+#define is_shared_irq_raw_handler(h) false
+#endif
 
 irq_handler_t irq_get_vtable_handler(uint num) {
     check_irq_param(num);
@@ -133,6 +131,7 @@
 }
 
 
+#if !PICO_DISABLE_SHARED_IRQ_HANDLERS
 static uint16_t make_branch(uint16_t *from, void *to) {
     uint32_t ui_from = (uint32_t)from;
     uint32_t ui_to = (uint32_t)to;
@@ -160,37 +159,36 @@
 // 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;
+    int32_t result = 0xaaaa;
     // 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)
-        :
-        );
+         : "+l" (result), "+l" (to)
+         : "l" (from)
+         :
+         );
     return (int8_t)result;
 }
 
 static inline int8_t get_slot_index(struct irq_handler_chain_slot *slot) {
     return slot_diff(slot, irq_handler_chain_slots);
 }
+#endif
 
 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
+#if PICO_NO_RAM_VECTOR_TABLE
     panic_unsupported()
+#elif PICO_DISABLE_SHARED_IRQ_HANDLERS
+    irq_set_exclusive_handler(num, handler);
 #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);
+    hard_assert(irq_hander_chain_free_slot_head >= 0); // we must have a slot
     struct irq_handler_chain_slot *slot = &irq_handler_chain_slots[irq_hander_chain_free_slot_head];
     int8_t slot_index = irq_hander_chain_free_slot_head;
     irq_hander_chain_free_slot_head = slot->link;
@@ -261,7 +259,7 @@
     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 !PICO_DISABLE_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.
 
@@ -361,7 +359,15 @@
     *p = (*p & ~(0xffu << (8 * (num & 3u)))) | (((uint32_t) hardware_priority) << (8 * (num & 3u)));
 }
 
-#if !PICO_DISABLE_SHARED_IRQ_HANDLERS && PICO_MAX_SHARED_IRQ_HANDLERS
+uint irq_get_priority(uint num) {
+    check_irq_param(num);
+
+    // note that only 32 bit reads are supported
+    io_rw_32 *p = (io_rw_32 *)((PPB_BASE + M0PLUS_NVIC_IPR0_OFFSET) + (num & ~3u));
+    return (uint8_t)(*p >> (8 * (num & 3u)));
+}
+
+#if !PICO_DISABLE_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) {
@@ -397,8 +403,11 @@
 
 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);
+    static_assert(!(NUM_IRQS & 3), "");
+    uint32_t prio4 = (PICO_DEFAULT_IRQ_PRIORITY & 0xff) * 0x1010101u;
+    io_rw_32 * p = (io_rw_32 *)(PPB_BASE + M0PLUS_NVIC_IPR0_OFFSET);
+    for (uint i = 0; i < NUM_IRQS / 4; i++) {
+        *p++ = prio4;
     }
 #endif
 }
diff --git a/src/rp2_common/hardware_irq/irq_handler_chain.S b/src/rp2_common/hardware_irq/irq_handler_chain.S
index 6a8a4b6..7d7be7d 100644
--- a/src/rp2_common/hardware_irq/irq_handler_chain.S
+++ b/src/rp2_common/hardware_irq/irq_handler_chain.S
@@ -4,7 +4,7 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#include "hardware/platform_defs.h"
+#include "pico.h"
 #include "hardware/irq.h"
 
 #if !PICO_DISABLE_SHARED_IRQ_HANDLERS
diff --git a/src/rp2_common/hardware_pio/include/hardware/pio.h b/src/rp2_common/hardware_pio/include/hardware/pio.h
index 07d0669..d2377ac 100644
--- a/src/rp2_common/hardware_pio/include/hardware/pio.h
+++ b/src/rp2_common/hardware_pio/include/hardware/pio.h
@@ -25,7 +25,7 @@
  * 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
+ * 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
@@ -436,14 +436,19 @@
     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
+/*! \brief Return the DREQ to use for pacing transfers to/from a particular state machine FIFO
  *  \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
+ * \param is_tx true for sending data to the state machine, false for receiving data from the state machine
  */
 static inline uint pio_get_dreq(PIO pio, uint sm, bool is_tx) {
+    static_assert(DREQ_PIO0_TX1 == DREQ_PIO0_TX0 + 1, "");
+    static_assert(DREQ_PIO0_TX2 == DREQ_PIO0_TX0 + 2, "");
+    static_assert(DREQ_PIO0_TX3 == DREQ_PIO0_TX0 + 3, "");
+    static_assert(DREQ_PIO0_RX0 == DREQ_PIO0_TX0 + NUM_PIO_STATE_MACHINES, "");
+    static_assert(DREQ_PIO1_RX0 == DREQ_PIO1_TX0 + NUM_PIO_STATE_MACHINES, "");
     check_pio_param(pio);
     check_sm_param(sm);
     return sm + (is_tx ? 0 : NUM_PIO_STATE_MACHINES) + (pio == pio0 ? DREQ_PIO0_TX0 : DREQ_PIO1_TX0);
diff --git a/src/rp2_common/hardware_pio/include/hardware/pio_instructions.h b/src/rp2_common/hardware_pio/include/hardware/pio_instructions.h
index 07df65b..3662135 100644
--- a/src/rp2_common/hardware_pio/include/hardware/pio_instructions.h
+++ b/src/rp2_common/hardware_pio/include/hardware/pio_instructions.h
@@ -9,7 +9,18 @@
 
 #include "pico.h"
 
-// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS, Enable/disable assertions in the PIO instructions, type=bool, default=0, group=hardware_pio
+/** \brief PIO instruction encoding 
+ *  \defgroup pio_instructions pio_instructions
+ *  \ingroup hardware_pio
+ * 
+ * Functions for generating PIO instruction encodings programmatically. In debug builds
+ *`PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS` can be set to 1 to enable validation of encoding function
+ * parameters.
+ *
+ * For fuller descriptions of the instructions in question see the "RP2040 Datasheet"
+ */
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS, Enable/disable assertions in the PIO instructions, type=bool, default=0, group=pio_instructions
 #ifndef PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS
 #define PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS 0
 #endif
@@ -44,6 +55,12 @@
 #define _PIO_INVALID_MOV_DEST 0u
 #endif
 
+/*! \brief Enumeration of values to pass for source/destination args for instruction encoding functions
+ *  \ingroup pio_instructions
+ *
+ * \note Not all values are suitable for all functions. Validity is only checked in debug mode when
+ * `PARAM_ASSERTIONS_ENABLED_PIO_INSTRUCTIONS` is 1
+ */
 enum pio_src_dest {
     pio_pins = 0u,
     pio_x = 1u,
@@ -58,11 +75,11 @@
     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) {
+static inline 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) {
+static inline 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);
@@ -75,100 +92,388 @@
     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) {
+static inline 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) {
+/*! \brief Encode just the delay slot bits of an instruction
+ *  \ingroup pio_instructions
+ *
+ * \note This function does not return a valid instruction encoding; instead it returns an encoding of the delay
+ * slot suitable for `OR`ing with the result of an encoding function for an actual instruction. Care should be taken when
+ * combining the results of this function with the results of \ref pio_encode_sideset and \ref pio_encode_sideset_opt
+ * as they share the same bits within the instruction encoding.
+ *
+ * \param cycles the number of cycles 0-31 (or less if side set is being used)
+ * \return the delay slot bits to be ORed with an instruction encoding
+ */
+static inline uint pio_encode_delay(uint cycles) {
     // note that the maximum cycles will be smaller if sideset_bit_count > 0
     valid_params_if(PIO_INSTRUCTIONS, cycles <= 0x1f);
     return cycles << 8u;
 }
 
-inline static uint pio_encode_sideset(uint sideset_bit_count, uint value) {
+/*! \brief Encode just the side set bits of an instruction (in non optional side set mode)
+ *  \ingroup pio_instructions
+ *
+ * \note This function does not return a valid instruction encoding; instead it returns an encoding of the side set bits
+ * suitable for `OR`ing with the result of an encoding function for an actual instruction. Care should be taken when
+ * combining the results of this function with the results of \ref pio_encode_delay as they share the same bits
+ * within the instruction encoding.
+ *
+ * \param sideset_bit_count number of side set bits as would be specified via `.sideset` in pioasm
+ * \param value the value to sideset on the pins
+ * \return the side set bits to be ORed with an instruction encoding
+ */
+static inline 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 <= ((1u << sideset_bit_count) - 1));
     return value << (13u - sideset_bit_count);
 }
 
-inline static uint pio_encode_sideset_opt(uint sideset_bit_count, uint value) {
+/*! \brief Encode just the side set bits of an instruction (in optional -`opt` side set mode)
+ *  \ingroup pio_instructions
+ *
+ * \note This function does not return a valid instruction encoding; instead it returns an encoding of the side set bits
+ * suitable for `OR`ing with the result of an encoding function for an actual instruction. Care should be taken when
+ * combining the results of this function with the results of \ref pio_encode_delay as they share the same bits
+ * within the instruction encoding.
+ *
+ * \param sideset_bit_count number of side set bits as would be specified via `.sideset <n> opt` in pioasm
+ * \param value the value to sideset on the pins
+ * \return the side set bits to be ORed with an instruction encoding
+ */
+static inline uint pio_encode_sideset_opt(uint sideset_bit_count, uint value) {
     valid_params_if(PIO_INSTRUCTIONS, sideset_bit_count >= 1 && sideset_bit_count <= 4);
     valid_params_if(PIO_INSTRUCTIONS, value <= ((1u << sideset_bit_count) - 1));
     return 0x1000u | value << (12u - sideset_bit_count);
 }
 
-inline static uint pio_encode_jmp(uint addr) {
+/*! \brief Encode an unconditional JMP instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `JMP <addr>`
+ *
+ * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline 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) {
+/*! \brief Encode a conditional JMP if scratch X zero instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `JMP !X <addr>`
+ *
+ * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline uint pio_encode_jmp_not_x(uint addr) {
+    return _pio_encode_instr_and_args(pio_instr_bits_jmp, 1, addr);
+}
+
+/*! \brief Encode a conditional JMP if scratch X non-zero (and post-decrement X) instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `JMP X-- <addr>`
+ *
+ * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline uint pio_encode_jmp_x_dec(uint addr) {
+    return _pio_encode_instr_and_args(pio_instr_bits_jmp, 2, addr);
+}
+
+/*! \brief Encode a conditional JMP if scratch Y zero instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `JMP !Y <addr>`
+ *
+ * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline uint pio_encode_jmp_not_y(uint addr) {
+    return _pio_encode_instr_and_args(pio_instr_bits_jmp, 3, addr);
+}
+
+/*! \brief Encode a conditional JMP if scratch Y non-zero (and post-decrement Y) instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `JMP Y-- <addr>`
+ *
+ * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline uint pio_encode_jmp_y_dec(uint addr) {
+    return _pio_encode_instr_and_args(pio_instr_bits_jmp, 4, addr);
+}
+
+/*! \brief Encode a conditional JMP if scratch X not equal scratch Y instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `JMP X!=Y <addr>`
+ *
+ * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline uint pio_encode_jmp_x_ne_y(uint addr) {
+    return _pio_encode_instr_and_args(pio_instr_bits_jmp, 5, addr);
+}
+
+/*! \brief Encode a conditional JMP if input pin high instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `JMP PIN <addr>`
+ *
+ * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline uint pio_encode_jmp_pin(uint addr) {
+    return _pio_encode_instr_and_args(pio_instr_bits_jmp, 6, addr);
+}
+
+/*! \brief Encode a conditional JMP if output shift register not empty instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `JMP !OSRE <addr>`
+ *
+ * \param addr The target address 0-31 (an absolute address within the PIO instruction memory)
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline uint pio_encode_jmp_not_osre(uint addr) {
+    return _pio_encode_instr_and_args(pio_instr_bits_jmp, 7, addr);
+}
+
+static inline 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);
+/*! \brief Encode a WAIT for GPIO pin instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `WAIT <polarity> GPIO <gpio>`
+ *
+ * \param polarity true for `WAIT 1`, false for `WAIT 0`
+ * \param gpio The real GPIO number 0-31
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline uint pio_encode_wait_gpio(bool polarity, uint gpio) {
+    return _pio_encode_instr_and_args(pio_instr_bits_wait, 0u | (polarity ? 4u : 0u), gpio);
 }
 
-inline static uint pio_encode_wait_pin(bool polarity, uint pin) {
+/*! \brief Encode a WAIT for pin instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `WAIT <polarity> PIN <pin>`
+ *
+ * \param polarity true for `WAIT 1`, false for `WAIT 0`
+ * \param pin The pin number 0-31 relative to the executing SM's input pin mapping
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline 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) {
+/*! \brief Encode a WAIT for IRQ instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `WAIT <polarity> IRQ <irq> <relative>`
+ *
+ * \param polarity true for `WAIT 1`, false for `WAIT 0`
+ * \param relative true for a `WAIT IRQ <irq> REL`, false for regular `WAIT IRQ <irq>`
+ * \param irq the irq number 0-7
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline 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) {
+/*! \brief Encode an IN instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `IN <src>, <count>`
+ *
+ * \param src The source to take data from
+ * \param count The number of bits 1-32
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline uint pio_encode_in(enum pio_src_dest src, uint count) {
     valid_params_if(PIO_INSTRUCTIONS, !(src & _PIO_INVALID_IN_SRC));
-    return _pio_encode_instr_and_src_dest(pio_instr_bits_in, src, value);
+    return _pio_encode_instr_and_src_dest(pio_instr_bits_in, src, count);
 }
 
-inline static uint pio_encode_out(enum pio_src_dest dest, uint value) {
+/*! \brief Encode an OUT instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `OUT <src>, <count>`
+ *
+ * \param dest The destination to write data to
+ * \param count The number of bits 1-32
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline uint pio_encode_out(enum pio_src_dest dest, uint count) {
     valid_params_if(PIO_INSTRUCTIONS, !(dest & _PIO_INVALID_OUT_DEST));
-    return _pio_encode_instr_and_src_dest(pio_instr_bits_out, dest, value);
+    return _pio_encode_instr_and_src_dest(pio_instr_bits_out, dest, count);
 }
 
-inline static uint pio_encode_push(bool if_full, bool block) {
+/*! \brief Encode a PUSH instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `PUSH <if_full>, <block>`
+ *
+ * \param if_full true for `PUSH IF_FULL ...`, false for `PUSH ...`
+ * \param block true for `PUSH ... BLOCK`, false for `PUSH ...`
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline 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) {
+/*! \brief Encode a PULL instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `PULL <if_empty>, <block>`
+ *
+ * \param if_empty true for `PULL IF_EMPTY ...`, false for `PULL ...`
+ * \param block true for `PULL ... BLOCK`, false for `PULL ...`
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline 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) {
+/*! \brief Encode a MOV instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `MOV <dest>, <src>`
+ *
+ * \param dest The destination to write data to
+ * \param src The source to take data from
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline 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) {
+/*! \brief Encode a MOV instruction with bit invert
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `MOV <dest>, ~<src>`
+ *
+ * \param dest The destination to write inverted data to
+ * \param src The source to take data from
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline 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) {
+/*! \brief Encode a MOV instruction with bit reverse
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `MOV <dest>, ::<src>`
+ *
+ * \param dest The destination to write bit reversed data to
+ * \param src The source to take data from
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline 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) {
+/*! \brief Encode a IRQ SET instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `IRQ SET <irq> <relative>`
+ *
+ * \param relative true for a `IRQ SET <irq> REL`, false for regular `IRQ SET <irq>`
+ * \param irq the irq number 0-7
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline 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) {
+/*! \brief Encode a IRQ WAIT instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `IRQ WAIT <irq> <relative>`
+ *
+ * \param relative true for a `IRQ WAIT <irq> REL`, false for regular `IRQ WAIT <irq>`
+ * \param irq the irq number 0-7
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline uint pio_encode_irq_wait(bool relative, uint irq) {
+    return _pio_encode_instr_and_args(pio_instr_bits_irq, 1, _pio_encode_irq(relative, irq));
+}
+
+/*! \brief Encode a IRQ CLEAR instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `IRQ CLEAR <irq> <relative>`
+ *
+ * \param relative true for a `IRQ CLEAR <irq> REL`, false for regular `IRQ CLEAR <irq>`
+ * \param irq the irq number 0-7
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline 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) {
+/*! \brief Encode a SET instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `SET <dest>, <value>`
+ *
+ * \param dest The destination to apply the value to
+ * \param value The value 0-31
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline 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(void) {
+/*! \brief Encode a NOP instruction
+ *  \ingroup pio_instructions
+ *
+ * This is the equivalent of `NOP` which is itself encoded as `MOV y, y`
+ *
+ * \return The instruction encoding with 0 delay and no side set value
+ * \see pio_encode_delay, pio_encode_sideset, pio_encode_sideset_opt
+ */
+static inline uint pio_encode_nop(void) {
     return pio_encode_mov(pio_y, pio_y);
 }
 
diff --git a/src/rp2_common/hardware_pwm/include/hardware/pwm.h b/src/rp2_common/hardware_pwm/include/hardware/pwm.h
index ed696e7..634375e 100644
--- a/src/rp2_common/hardware_pwm/include/hardware/pwm.h
+++ b/src/rp2_common/hardware_pwm/include/hardware/pwm.h
@@ -9,6 +9,7 @@
 
 #include "pico.h"
 #include "hardware/structs/pwm.h"
+#include "hardware/regs/dreq.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -26,7 +27,7 @@
  *
  * 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
+ * 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
@@ -116,21 +117,21 @@
  * 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));
+    c->div = (uint32_t)(div * (float)(1u << PWM_CH0_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.
+ * \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;
+    c->div = div << PWM_CH0_DIV_INT_LSB;
 }
 
 /** \brief Set PWM counting mode in a PWM configuration
@@ -201,7 +202,7 @@
 /** \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,
+ * 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.
@@ -239,7 +240,7 @@
 /** \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
+ * Set the value of the PWM counter compare value, for either channel A or channel B.
  *
  * The counter compare register is double-buffered in hardware. This means
  * that, when the PWM is running, a write to the counter compare values does
@@ -263,7 +264,7 @@
 /** \brief Set PWM counter compare values
  *  \ingroup hardware_pwm
  *
- * Set the value of the PWM counter compare values, A and B
+ * Set the value of the PWM counter compare values, A and B.
  *
  * The counter compare register is double-buffered in hardware. This means
  * that, when the PWM is running, a write to the counter compare values does
@@ -284,7 +285,7 @@
  *  \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.
+ * 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).
@@ -309,7 +310,7 @@
  * Get current value of PWM counter
  *
  * \param slice_num PWM slice number
- * \return Current value of PWM counter
+ * \return Current value of the PWM counter
  */
 static inline uint16_t pwm_get_counter(uint slice_num) {
     check_slice_num_param(slice_num);
@@ -367,7 +368,7 @@
 /** \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.
+ * Set the clock divider. Counter increment will be on sysclock divided by this value, taking into account the gating.
  *
  * \param slice_num PWM slice number
  * \param integer  8 bit integer part of the clock divider
@@ -382,7 +383,7 @@
 /** \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.
+ * Set the clock divider. Counter increment will be on sysclock divided by this value, taking into account the gating.
  *
  * \param slice_num PWM slice number
  * \param divider Floating point clock divider,  1.f <= value < 256.f
@@ -441,8 +442,28 @@
 /** \brief Enable/Disable PWM
  *  \ingroup hardware_pwm
  *
+ * When a PWM is disabled, it halts its counter, and the output pins are left
+ * high or low depending on exactly when the counter is halted. When
+ * re-enabled the PWM resumes immediately from where it left off.
+ *
+ * If the PWM's output pins need to be low when halted:
+ *
+ * - The counter compare can be set to zero whilst the PWM is enabled, and
+ *   then the PWM disabled once both pins are seen to be low
+ *
+ * - The GPIO output overrides can be used to force the actual pins low
+ *
+ * - The PWM can be run for one cycle (i.e. enabled then immediately disabled)
+ *   with a TOP of 0, count of 0 and counter compare of 0, to force the pins
+ *   low when the PWM has already been halted. The same method can be used
+ *   with a counter compare value of 1 to force a pin high.
+ *
+ * Note that, when disabled, the PWM can still be advanced one count at a time
+ * by pulsing the PH_ADV bit in its CSR. The output pins transition as though
+ * the PWM were enabled.
+ *
  * \param slice_num PWM slice number
- * \param enabled true to enable the specified PWM, false to disable
+ * \param enabled true to enable the specified PWM, false to disable.
  */
 static inline void pwm_set_enabled(uint slice_num, bool enabled) {
     check_slice_num_param(slice_num);
@@ -461,7 +482,7 @@
 /*! \brief  Enable PWM instance interrupt
  *  \ingroup hardware_pwm
  *
- * Used to enable a single PWM instance interrupt
+ * Used to enable a single PWM instance interrupt.
  *
  * \param slice_num PWM block to enable/disable
  * \param enabled true to enable, false to disable
@@ -492,7 +513,7 @@
     }
 }
 
-/*! \brief  Clear single PWM channel interrupt
+/*! \brief  Clear a single PWM channel interrupt
  *  \ingroup hardware_pwm
  *
  * \param slice_num PWM slice number
@@ -519,6 +540,18 @@
     pwm_hw->intf = 1u << slice_num;
 }
 
+/*! \brief Return the DREQ to use for pacing transfers to a particular PWM slice
+ *  \ingroup hardware_pwm
+ *
+ * \param slice_num PWM slice number
+ */
+static inline uint pwm_get_dreq(uint slice_num) {
+    static_assert(DREQ_PWM_WRAP1 == DREQ_PWM_WRAP0 + 1, "");
+    static_assert(DREQ_PWM_WRAP7 == DREQ_PWM_WRAP0 + 7, "");
+    check_slice_num_param(slice_num);
+    return DREQ_PWM_WRAP0 + slice_num;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/rp2_common/hardware_spi/include/hardware/spi.h b/src/rp2_common/hardware_spi/include/hardware/spi.h
index b766f74..e8dc952 100644
--- a/src/rp2_common/hardware_spi/include/hardware/spi.h
+++ b/src/rp2_common/hardware_spi/include/hardware/spi.h
@@ -10,6 +10,7 @@
 #include "pico.h"
 #include "pico/time.h"
 #include "hardware/structs/spi.h"
+#include "hardware/regs/dreq.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
@@ -337,6 +338,19 @@
  */
 int spi_read16_blocking(spi_inst_t *spi, uint16_t repeated_tx_data, uint16_t *dst, size_t len);
 
+/*! \brief Return the DREQ to use for pacing transfers to/from a particular SPI instance
+ *  \ingroup hardware_spi
+ *
+ * \param spi SPI instance specifier, either \ref spi0 or \ref spi1
+ * \param is_tx true for sending data to the SPI instance, false for receiving data from the SPI instance
+ */
+static inline uint spi_get_dreq(spi_inst_t *spi, bool is_tx) {
+    static_assert(DREQ_SPI0_RX == DREQ_SPI0_TX + 1, "");
+    static_assert(DREQ_SPI1_RX == DREQ_SPI1_TX + 1, "");
+    static_assert(DREQ_SPI1_TX == DREQ_SPI0_TX + 2, "");
+    return DREQ_SPI0_TX + spi_get_index(spi) * 2 + !is_tx;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/rp2_common/hardware_uart/include/hardware/uart.h b/src/rp2_common/hardware_uart/include/hardware/uart.h
index 02fdd1f..bce0d2f 100644
--- a/src/rp2_common/hardware_uart/include/hardware/uart.h
+++ b/src/rp2_common/hardware_uart/include/hardware/uart.h
@@ -9,6 +9,7 @@
 
 #include "pico.h"
 #include "hardware/structs/uart.h"
+#include "hardware/regs/dreq.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
@@ -205,12 +206,17 @@
  * 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 rx_has_data If true an interrupt will be fired when the RX FIFO contains 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) {
+    // Both UARTRXINTR (RX) and UARTRTINTR (RX timeout) interrupts are
+    // required for rx_has_data. RX asserts when >=4 characters are in the RX
+    // FIFO (for RXIFLSEL=0). RT asserts when there are >=1 characters and no
+    // more have been received for 32 bit periods.
     uart_get_hw(uart)->imsc = (bool_to_bit(tx_needs_data) << UART_UARTIMSC_TXIM_LSB) |
-                              (bool_to_bit(rx_has_data) << UART_UARTIMSC_RXIM_LSB);
+                              (bool_to_bit(rx_has_data) << UART_UARTIMSC_RXIM_LSB) |
+                              (bool_to_bit(rx_has_data) << UART_UARTIMSC_RTIM_LSB);
     if (rx_has_data) {
         // Set minimum threshold
         hw_write_masked(&uart_get_hw(uart)->ifls, 0 << UART_UARTIFLS_RXIFLSEL_LSB,
@@ -321,7 +327,7 @@
 /*! \brief  Write single character to UART for transmission.
  *  \ingroup hardware_uart
  *
- * This function will block until all the character has been sent
+ * This function will block until the entire character has been sent
  *
  * \param uart UART instance. \ref uart0 or \ref uart1
  * \param c The character  to send
@@ -407,7 +413,7 @@
  */
 void uart_set_translate_crlf(uart_inst_t *uart, bool translate);
 
-/*! \brief Wait for the default UART'S TX fifo to be drained
+/*! \brief Wait for the default UART's TX FIFO to be drained
  *  \ingroup hardware_uart
  */
 static inline void uart_default_tx_wait_blocking(void) {
@@ -427,6 +433,19 @@
  */
 bool uart_is_readable_within_us(uart_inst_t *uart, uint32_t us);
 
+/*! \brief Return the DREQ to use for pacing transfers to/from a particular UART instance
+ *  \ingroup hardware_uart
+ *
+ * \param uart UART instance. \ref uart0 or \ref uart1
+ * \param is_tx true for sending data to the UART instance, false for receiving data from the UART instance
+ */
+static inline uint uart_get_dreq(uart_inst_t *uart, bool is_tx) {
+    static_assert(DREQ_UART0_RX == DREQ_UART0_TX + 1, "");
+    static_assert(DREQ_UART1_RX == DREQ_UART1_TX + 1, "");
+    static_assert(DREQ_UART1_TX == DREQ_UART0_TX + 2, "");
+    return DREQ_UART0_TX + uart_get_index(uart) * 2 + !is_tx;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/rp2_common/hardware_watchdog/include/hardware/watchdog.h b/src/rp2_common/hardware_watchdog/include/hardware/watchdog.h
index cbc43a6..747838b 100644
--- a/src/rp2_common/hardware_watchdog/include/hardware/watchdog.h
+++ b/src/rp2_common/hardware_watchdog/include/hardware/watchdog.h
@@ -8,6 +8,7 @@
 #define _HARDWARE_WATCHDOG_H
 
 #include "pico.h"
+#include "hardware/structs/watchdog.h"
 
 /** \file hardware/watchdog.h
  *  \defgroup hardware_watchdog hardware_watchdog
@@ -66,6 +67,11 @@
  *
  * By default the SDK assumes a 12MHz XOSC and sets the \ref watchdog_start_tick appropriately.
  *
+ * This method sets a marker in the watchdog scratch register 4 that is checked by \ref watchdog_enable_caused_reboot.
+ * If the device is subsequently reset via a call to watchdog_reboot (including for example by dragging a UF2
+ * onto the RPI-RP2), then this value will be cleared, and so \ref watchdog_enable_caused_reboot will
+ * return false.
+ *
  * \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
  */
@@ -75,12 +81,31 @@
  * \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
+ * @return true If the watchdog timer or a watchdog force caused the last reboot
+ * @return false If there has been no watchdog reboot since the last power on reset. A power on reset is typically caused by a power cycle or the run pin (reset button) being toggled.
  */
 bool watchdog_caused_reboot(void);
 
 /**
+ * \brief Did watchdog_enable cause the last reboot?
+ * \ingroup hardware_watchdog
+ *
+ * Perform additional checking along with \ref watchdog_caused_reboot to determine if a watchdog timeout initiated by
+ * \ref watchdog_enable caused the last reboot.
+ *
+ * This method checks for a special value in watchdog scratch register 4 placed there by \ref watchdog_enable.
+ * This would not be present if a watchdog reset is initiated by \ref watchdog_reboot or by the RP2040 bootrom
+ * (e.g. dragging a UF2 onto the RPI-RP2 drive).
+ *
+ * @return true If the watchdog timer or a watchdog force caused (see \reg watchdog_caused_reboot) the last reboot
+ *              and the watchdog reboot happened after \ref watchdog_enable was called
+ * @return false If there has been no watchdog reboot since the last power on reset, or the watchdog reboot was not caused
+ *               by a watchdog timeout after \ref watchdog_enable was called.
+ *               A power on reset is typically caused by a power cycle or the run pin (reset button) being toggled.
+ */
+bool watchdog_enable_caused_reboot(void);
+
+/**
  * @brief Returns the number of microseconds before the watchdog will reboot the chip.
  * \ingroup hardware_watchdog
  *
diff --git a/src/rp2_common/hardware_watchdog/watchdog.c b/src/rp2_common/hardware_watchdog/watchdog.c
index 36031aa..9545205 100644
--- a/src/rp2_common/hardware_watchdog/watchdog.c
+++ b/src/rp2_common/hardware_watchdog/watchdog.c
@@ -49,25 +49,28 @@
         hw_clear_bits(&watchdog_hw->ctrl, dbg_bits);
     }
 
-    if (!delay_ms) delay_ms = 50;
+    if (!delay_ms) {
+        hw_set_bits(&watchdog_hw->ctrl, WATCHDOG_CTRL_TRIGGER_BITS);
+    } else {
+        // Note, we have x2 here as the watchdog HW currently decrements twice per tick
+        load_value = delay_ms * 1000 * 2;
 
-    // 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;
 
-    if (load_value > 0xffffffu)
-        load_value = 0xffffffu;
+        watchdog_update();
 
-
-    watchdog_update();
-
-    hw_set_bits(&watchdog_hw->ctrl, WATCHDOG_CTRL_ENABLE_BITS);
+        hw_set_bits(&watchdog_hw->ctrl, WATCHDOG_CTRL_ENABLE_BITS);
+    }
 }
 // end::watchdog_enable[]
 
+#define WATCHDOG_NON_REBOOT_MAGIC 0x6ab73121
+
 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;
+    // update scratch[4] to distinguish from magic used for reboot to specific address, or 0 used to reboot
+    // into regular flash path
+    watchdog_hw->scratch[4] = WATCHDOG_NON_REBOOT_MAGIC;
     _watchdog_enable(delay_ms, pause_on_debug);
 }
 
@@ -96,4 +99,8 @@
 bool watchdog_caused_reboot(void) {
     // If any reason bits are set this is true
     return watchdog_hw->reason;
+}
+
+bool watchdog_enable_caused_reboot(void) {
+    return watchdog_hw->reason && watchdog_hw->scratch[4] == WATCHDOG_NON_REBOOT_MAGIC;
 }
\ No newline at end of file
diff --git a/src/rp2_common/hardware_xosc/xosc.c b/src/rp2_common/hardware_xosc/xosc.c
index 9a95e37..7a7055c 100644
--- a/src/rp2_common/hardware_xosc/xosc.c
+++ b/src/rp2_common/hardware_xosc/xosc.c
@@ -13,8 +13,8 @@
 #include "hardware/regs/xosc.h"
 #include "hardware/xosc.h"
 
-#if XOSC_MHZ < 1 || XOSC_MHZ > 15
-#error XOSC_MHZ must be in the range 1-15
+#if XOSC_MHZ < 1 || XOSC_MHZ > 50
+#error XOSC_MHZ must be in the range 1-50
 #endif
 
 #define STARTUP_DELAY (((((XOSC_MHZ * MHZ) / 1000) + 128) / 256) * PICO_XOSC_STARTUP_DELAY_MULTIPLIER)
diff --git a/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S b/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S
index 7c0b42c..eba839e 100644
--- a/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S
+++ b/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S
@@ -9,6 +9,8 @@
 .thumb
 
 #include "pico/asm_helper.S"
+#include "pico/bootrom.h"
+
 __pre_init __aeabi_bits_init, 00010
 
 .macro bits_section name
@@ -24,10 +26,10 @@
 .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
+    .word ROM_FUNC_POPCOUNT32
+    .word ROM_FUNC_CLZ32
+    .word ROM_FUNC_CTZ32
+    .word ROM_FUNC_REVERSE32
 aeabi_bits_funcs_end:
 
 .section .text
diff --git a/src/rp2_common/pico_bootrom/bootrom.c b/src/rp2_common/pico_bootrom/bootrom.c
index 08cdb33..af7d091 100644
--- a/src/rp2_common/pico_bootrom/bootrom.c
+++ b/src/rp2_common/pico_bootrom/bootrom.c
@@ -16,9 +16,7 @@
 #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);
+    return rom_func_lookup_inline(code);
 }
 
 void *rom_data_lookup(uint32_t code) {
diff --git a/src/rp2_common/pico_bootrom/include/pico/bootrom.h b/src/rp2_common/pico_bootrom/include/pico/bootrom.h
index 7d42926..e557893 100644
--- a/src/rp2_common/pico_bootrom/include/pico/bootrom.h
+++ b/src/rp2_common/pico_bootrom/include/pico/bootrom.h
@@ -12,8 +12,60 @@
 /** \file bootrom.h
  * \defgroup pico_bootrom pico_bootrom
  * Access to functions and data in the RP2040 bootrom
+ *
+ * This header may be included by assembly code
  */
 
+// ROM FUNCTIONS
+
+#define ROM_FUNC_POPCOUNT32             ROM_TABLE_CODE('P', '3')
+#define ROM_FUNC_REVERSE32              ROM_TABLE_CODE('R', '3')
+#define ROM_FUNC_CLZ32                  ROM_TABLE_CODE('L', '3')
+#define ROM_FUNC_CTZ32                  ROM_TABLE_CODE('T', '3')
+#define ROM_FUNC_MEMSET                 ROM_TABLE_CODE('M', 'S')
+#define ROM_FUNC_MEMSET4                ROM_TABLE_CODE('S', '4')
+#define ROM_FUNC_MEMCPY                 ROM_TABLE_CODE('M', 'C')
+#define ROM_FUNC_MEMCPY44               ROM_TABLE_CODE('C', '4')
+#define ROM_FUNC_RESET_USB_BOOT         ROM_TABLE_CODE('U', 'B')
+#define ROM_FUNC_CONNECT_INTERNAL_FLASH ROM_TABLE_CODE('I', 'F')
+#define ROM_FUNC_FLASH_EXIT_XIP         ROM_TABLE_CODE('E', 'X')
+#define ROM_FUNC_FLASH_RANGE_ERASE      ROM_TABLE_CODE('R', 'E')
+#define ROM_FUNC_FLASH_RANGE_PROGRAM    ROM_TABLE_CODE('R', 'P')
+#define ROM_FUNC_FLASH_FLUSH_CACHE      ROM_TABLE_CODE('F', 'C')
+#define ROM_FUNC_FLASH_ENTER_CMD_XIP    ROM_TABLE_CODE('C', 'X')
+
+/*! \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()
+ */
+#define ROM_TABLE_CODE(c1, c2) ((c1) | ((c2) << 8))
+
+#ifndef __ASSEMBLER__
+
+// ROM FUNCTION SIGNATURES
+
+typedef uint32_t (*rom_popcount32_fn)(uint32_t);
+typedef uint32_t (*rom_reverse32_fn)(uint32_t);
+typedef uint32_t (*rom_clz32_fn)(uint32_t);
+typedef uint32_t (*rom_ctz32_fn)(uint32_t);
+typedef uint8_t *(*rom_memset_fn)(uint8_t *, uint8_t, uint32_t);
+typedef uint32_t *(*rom_memset4_fn)(uint32_t *, uint8_t, uint32_t);
+typedef uint32_t *(*rom_memcpy_fn)(uint8_t *, const uint8_t *, uint32_t);
+typedef uint32_t *(*rom_memcpy44_fn)(uint32_t *, const uint32_t *, uint32_t);
+typedef void __attribute__((noreturn)) (*rom_reset_usb_boot_fn)(uint32_t, uint32_t);
+typedef rom_reset_usb_boot_fn reset_usb_boot_fn; // kept for backwards compatibility
+typedef void (*rom_connect_internal_flash_fn)(void);
+typedef void (*rom_flash_exit_xip_fn)(void);
+typedef void (*rom_flash_range_erase_fn)(uint32_t, size_t, uint32_t, uint8_t);
+typedef void (*rom_flash_range_program_fn)(uint32_t, const uint8_t*, size_t);
+typedef void (*rom_flash_flush_cache_fn)(void);
+typedef void (*rom_flash_enter_cmd_xip_fn)(void);
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -22,13 +74,13 @@
  * \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(uint8_t c1, uint8_t c2) {
-    return (((uint)c2) << 8u) | (uint)c1;
+    return ROM_TABLE_CODE((uint32_t) c1, (uint32_t) c2);
 }
 
 /*!
@@ -60,7 +112,24 @@
  */
 bool rom_funcs_lookup(uint32_t *table, unsigned int count);
 
-typedef void __attribute__((noreturn)) (*reset_usb_boot_fn)(uint32_t, uint32_t);
+// 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)
+
+/*!
+ * \brief Lookup a bootrom function by code. This method is forceably inlined into the caller for FLASH/RAM sensitive code usage
+ * \ingroup pico_bootrom
+ * \param code the code
+ * \return a pointer to the function, or NULL if the code does not match any bootrom function
+ */
+static __force_inline void *rom_func_lookup_inline(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);
+}
 
 /*!
  * \brief Reboot the device into BOOTSEL mode
@@ -81,7 +150,7 @@
  */
 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'));
+    rom_reset_usb_boot_fn func = (rom_reset_usb_boot_fn) rom_func_lookup(ROM_FUNC_RESET_USB_BOOT);
     func(usb_activity_gpio_pin_mask, disable_interface_mask);
 }
 
@@ -89,4 +158,5 @@
 }
 #endif
 
+#endif // !__ASSEMBLER__
 #endif
diff --git a/src/rp2_common/pico_bootsel_via_double_reset/pico_bootsel_via_double_reset.c b/src/rp2_common/pico_bootsel_via_double_reset/pico_bootsel_via_double_reset.c
index 595a2d5..d333ab2 100644
--- a/src/rp2_common/pico_bootsel_via_double_reset/pico_bootsel_via_double_reset.c
+++ b/src/rp2_common/pico_bootsel_via_double_reset/pico_bootsel_via_double_reset.c
@@ -43,8 +43,7 @@
 
 static uint32_t __uninitialized_ram(magic_location)[count_of(magic_token)];
 
-/*! \brief Check for double reset and enter BOOTSEL mode if detected
- *  \ingroup pico_bootsel_via_double_reset
+/* Check for double reset and enter BOOTSEL mode if detected
  *
  * This function is registered to run automatically before main(). The
  * algorithm is:
diff --git a/src/rp2_common/pico_divider/CMakeLists.txt b/src/rp2_common/pico_divider/CMakeLists.txt
index 813d1c1..ceed042 100644
--- a/src/rp2_common/pico_divider/CMakeLists.txt
+++ b/src/rp2_common/pico_divider/CMakeLists.txt
@@ -21,6 +21,7 @@
 
     target_link_libraries(pico_divider_hardware_explicit INTERFACE
             pico_divider_headers
+            hardware_divider
             hardware_regs
             )
 
diff --git a/src/rp2_common/pico_divider/divider.S b/src/rp2_common/pico_divider/divider.S
index ac67a5e..234c1a4 100644
--- a/src/rp2_common/pico_divider/divider.S
+++ b/src/rp2_common/pico_divider/divider.S
@@ -413,6 +413,7 @@
  lsls r3,#16
  orrs r3,r4
  str r3,[r7,#SIO_DIV_UDIVIDEND_OFFSET] @ y1=(r0<<16)+(((ui32)y)>>16);
+ str r2,[r7,#SIO_DIV_UDIVISOR_OFFSET]  @ must set divisor again, as we do not save/restore regs at all in IRQs if not dirty
  wait_div 1
  uxth r4,r0
  ldr r3,[r7,#SIO_DIV_REMAINDER_OFFSET] @ r1=y1-q1*x; 0<=r1<x
@@ -420,6 +421,7 @@
  lsls r3,#16
  orrs r3,r4
  str r3,[r7,#SIO_DIV_UDIVIDEND_OFFSET] @ y1=(r0<<16)+(((ui32)y)>>16);
+ str r2,[r7,#SIO_DIV_UDIVISOR_OFFSET]  @ must set divisor again, as we do not save/restore regs at all in IRQs if not dirty
  wait_div 3
  movs r3,#0
  lsls r4,r5,#16             @ quotient=(q0<<32)+(q1<<16)+q2
diff --git a/src/rp2_common/pico_double/double_aeabi.S b/src/rp2_common/pico_double/double_aeabi.S
index a871e43..0c59738 100644
--- a/src/rp2_common/pico_double/double_aeabi.S
+++ b/src/rp2_common/pico_double/double_aeabi.S
@@ -83,7 +83,7 @@
 
 .macro table_tail_call SF_TABLE_OFFSET
     push {r3, r4}
-#if PICO_DOUBLE_SUPPORT_ROM_V1
+#if PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
 #ifndef NDEBUG
     movs r3, #0
     mov ip, r3
@@ -99,12 +99,12 @@
     push {r3, r4}
     ldr r3, =sd_table
     ldr r3, [r3, #\SF_TABLE_OFFSET]
-#if PICO_DOUBLE_SUPPORT_ROM_V1
+#if PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
     mov ip, pc
 #endif
     str r3, [sp, #4]
     pop {r3, pc}
-#if PICO_DOUBLE_SUPPORT_ROM_V1
+#if PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
 .byte \SF_TABLE_OFFSET, 0xdf
 .word \shim
 #endif
@@ -733,7 +733,7 @@
     push {r2, r3, r4}
     movs r3, #0x13
     ldrb r3, [r3]
-#if PICO_DOUBLE_SUPPORT_ROM_V1
+#if PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
     cmp r3, #1
     bne 1f
     ldr r3, =dsincos_shim
diff --git a/src/rp2_common/pico_double/double_init_rom.c b/src/rp2_common/pico_double/double_init_rom.c
index 1a25559..af6f6a2 100644
--- a/src/rp2_common/pico_double/double_init_rom.c
+++ b/src/rp2_common/pico_double/double_init_rom.c
@@ -12,16 +12,18 @@
 // 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
+#if !(PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED)
 static __attribute__((noreturn)) void missing_double_func_shim(void) {
     panic("missing double function");
 }
 #endif
 extern void double_table_shim_on_use_helper(void);
 
+void __attribute__((weak)) *sf_clz_func;
+
 void __aeabi_double_init(void) {
     int rom_version = rp2040_rom_version();
-#if PICO_DOUBLE_SUPPORT_ROM_V1
+#if PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
     if (rom_version == 1) {
 
         // this is a little tricky.. we only want to pull in a shim if the corresponding function
@@ -63,4 +65,6 @@
         // we use the unused entry for SINCOS
         sd_table[SF_TABLE_V3_FSINCOS / 4] = (uintptr_t) double_table_shim_on_use_helper;
     }
+
+    sf_clz_func = rom_func_lookup(ROM_FUNC_CLZ32);
 }
diff --git a/src/rp2_common/pico_double/double_math.c b/src/rp2_common/pico_double/double_math.c
index c6db8c1..6c35ded 100644
--- a/src/rp2_common/pico_double/double_math.c
+++ b/src/rp2_common/pico_double/double_math.c
@@ -41,11 +41,25 @@
 #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\"")
+typedef union {
+    double d;
+    ui64 ix;
+} double_ui64;
+
+static inline double ui642double(ui64 ix) {
+    double_ui64 tmp;
+    tmp.ix = ix;
+    return tmp.d;
+}
+
+static inline ui64 double2ui64(double d) {
+    double_ui64 tmp;
+    tmp.d = d;
+    return tmp.ix;
+}
 
 static inline bool disnan(double x) {
-    ui64 ix=*(ui64*)&x;
+    ui64 ix= double2ui64(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;
 }
@@ -59,17 +73,17 @@
 #endif
 
 static inline int dgetsignexp(double x) {
-    ui64 ix=*(ui64*)&x;
+    ui64 ix=double2ui64(x);
     return (ix>>52)&0xfff;
 }
 
 static inline int dgetexp(double x) {
-    ui64 ix=*(ui64*)&x;
+    ui64 ix=double2ui64(x);
     return (ix>>52)&0x7ff;
 }
 
 static inline double dldexp(double x,int de) {
-    ui64 ix=*(ui64*)&x,iy;
+    ui64 ix=double2ui64(x),iy;
     int e;
     e=dgetexp(x);
     if(e==0||e==0x7ff) return x;
@@ -77,7 +91,7 @@
     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;
+    return ui642double(iy);
 }
 
 double WRAPPER_FUNC(ldexp)(double x, int de) {
@@ -87,9 +101,9 @@
 
 
 static inline double dcopysign(double x,double y) {
-    ui64 ix=*(ui64*)&x,iy=*(ui64*)&y;
+    ui64 ix=double2ui64(x),iy=double2ui64(y);
     ix=((ix&0x7fffffffffffffffULL)|(iy&0x8000000000000000ULL));
-    return *(double*)&ix;
+    return ui642double(ix);
 }
 
 double WRAPPER_FUNC(copysign)(double x, double y) {
@@ -104,7 +118,7 @@
 static inline int disminf(double x)  { return dgetsignexp(x)==0xfff; }
 
 static inline int disint(double x) {
-    ui64 ix=*(ui64*)&x,m;
+    ui64 ix=double2ui64(x),m;
     int e=dgetexp(x);
     if(e==0) return 1;       // 0 is an integer
     e-=0x3ff;                // remove exponent bias
@@ -117,7 +131,7 @@
 }
 
 static inline int disoddint(double x) {
-    ui64 ix=*(ui64*)&x,m;
+    ui64 ix=double2ui64(x),m;
     int e=dgetexp(x);
     e-=0x3ff;                // remove exponent bias
     if(e<0) return 0;        // |x|<1; 0 is not odd
@@ -130,24 +144,24 @@
 }
 
 static inline int disstrictneg(double x) {
-    ui64 ix=*(ui64*)&x;
+    ui64 ix=double2ui64(x);
     if(diszero(x)) return 0;
     return ix>>63;
 }
 
 static inline int disneg(double x) {
-    ui64 ix=*(ui64*)&x;
+    ui64 ix=double2ui64(x);
     return ix>>63;
 }
 
 static inline double dneg(double x) {
-    ui64 ix=*(ui64*)&x;
+    ui64 ix=double2ui64(x);
     ix^=0x8000000000000000ULL;
-    return *(double*)&ix;
+    return ui642double(ix);
 }
 
 static inline int dispo2(double x) {
-    ui64 ix=*(ui64*)&x;
+    ui64 ix=double2ui64(x);
     if(diszero(x)) return 0;
     if(disinf(x)) return 0;
     ix&=0x000fffffffffffffULL;
@@ -164,33 +178,33 @@
 
 double WRAPPER_FUNC(trunc)(double x) {
     check_nan_d1(x);
-    ui64 ix=*(ui64*)&x,m;
+    ui64 ix=double2ui64(x),m;
     int e=dgetexp(x);
     e-=0x3ff;                // remove exponent bias
     if(e<0) {                // |x|<1
         ix&=0x8000000000000000ULL;
-        return *(double*)&ix;
+        return ui642double(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<<e)-1;           // mask for bits of significance <1
     ix&=~m;
-    return *(double*)&ix;
+    return ui642double(ix);
 }
 
 double WRAPPER_FUNC(round)(double x) {
     check_nan_d1(x);
-    ui64 ix=*(ui64*)&x,m;
+    ui64 ix=double2ui64(x),m;
     int e=dgetexp(x);
     e-=0x3ff;                // remove exponent bias
     if(e<-1) {               // |x|<0.5
         ix&=0x8000000000000000ULL;
-        return *(double*)&ix;
+        return ui642double(ix);
     }
     if(e==-1) {              // 0.5<=|x|<1
         ix&=0x8000000000000000ULL;
         ix|=0x3ff0000000000000ULL;        // ±1
-        return *(double*)&ix;
+        return ui642double(ix);
     }
     e=52-e;                  // bit position in mantissa with significance 1, <=52
     if(e<=0) return x;       // |x| large, so must be an integer
@@ -198,16 +212,16 @@
     ix+=m;
     m=m+m-1;                 // mask for bits of significance <1
     ix&=~m;
-    return *(double*)&ix;
+    return ui642double(ix);
 }
 
 double WRAPPER_FUNC(floor)(double x) {
     check_nan_d1(x);
-    ui64 ix=*(ui64*)&x,m;
+    ui64 ix=double2ui64(x),m;
     int e=dgetexp(x);
     if(e==0) {               // x==0
         ix&=0x8000000000000000ULL;
-        return *(double*)&ix;
+        return ui642double(ix);
     }
     e-=0x3ff;                // remove exponent bias
     if(e<0) {                // |x|<1, not zero
@@ -219,16 +233,16 @@
     m=(1ULL<<e)-1;           // mask for bit of significance <1
     if(disneg(x)) ix+=m;     // add 1-ε to magnitude if negative
     ix&=~m;                  // truncate
-    return *(double*)&ix;
+    return ui642double(ix);
 }
 
 double WRAPPER_FUNC(ceil)(double x) {
     check_nan_d1(x);
-    ui64 ix=*(ui64*)&x,m;
+    ui64 ix=double2ui64(x),m;
     int e=dgetexp(x);
     if(e==0) {               // x==0
         ix&=0x8000000000000000ULL;
-        return *(double*)&ix;
+        return ui642double(ix);
     }
     e-=0x3ff;                 // remove exponent bias
     if(e<0) {                // |x|<1, not zero
@@ -240,7 +254,7 @@
     m=(1ULL<<e)-1;           // mask for bit of significance <1
     if(!disneg(x)) ix+=m;    // add 1-ε to magnitude if positive
     ix&=~m;                  // truncate
-    return *(double*)&ix;
+    return ui642double(ix);
 }
 
 double WRAPPER_FUNC(asin)(double x) {
@@ -549,7 +563,7 @@
 
 double WRAPPER_FUNC(fmod)(double x,double y) {
     check_nan_d2(x, y);
-    ui64 ix=*(ui64*)&x,iy=*(ui64*)&y;
+    ui64 ix=double2ui64(x),iy=double2ui64(y);
     int sx,ex,ey;
     i64 mx,my;
     DUNPACKS(ix,sx,ex,mx);
@@ -568,7 +582,7 @@
 
 double WRAPPER_FUNC(remquo)(double x,double y,int*quo) {
     check_nan_d2(x, y);
-    ui64 ix=*(ui64*)&x,iy=*(ui64*)&y;
+    ui64 ix=double2ui64(x),iy=double2ui64(y);
     int sx,sy,ex,ey,q;
     i64 mx,my;
     DUNPACKS(ix,sx,ex,mx);
@@ -609,5 +623,4 @@
 
 double WRAPPER_FUNC(remainder)(double x,double y) { check_nan_d2(x, y); return remquo(x,y,0); }
 
-_Pragma("GCC diagnostic pop") // strict-aliasing
 _Pragma("GCC diagnostic pop") // conversion
\ No newline at end of file
diff --git a/src/rp2_common/pico_double/double_v1_rom_shim.S b/src/rp2_common/pico_double/double_v1_rom_shim.S
index a8db6b7..7a14ca4 100644
--- a/src/rp2_common/pico_double/double_v1_rom_shim.S
+++ b/src/rp2_common/pico_double/double_v1_rom_shim.S
@@ -63,7 +63,7 @@
     str r0, [sp, #12]
     pop {r0-r2, pc}
 
-#if PICO_DOUBLE_SUPPORT_ROM_V1
+#if PICO_DOUBLE_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
 // 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
@@ -1218,11 +1218,6 @@
  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
 
@@ -1264,7 +1259,7 @@
  eors r1,r1,r0                 @ generate extreme fixed-point values
  pop {r15}
 
-double_section double2uint64_shim
+double_section double2uint64_shim 
  regular_func double2uint64_shim
  movs r2,#0                    @ and fall through
 regular_func double2ufix64_shim
@@ -1288,7 +1283,12 @@
  asrs r3,r1,#31
  ldr r4, =d2fix_a
  bx r4
-
+ 
+ret_dzero:
+ movs r0,#0
+ movs r1,#0
+ bx r14
+ 
 .weak d2fix_a // weak because it exists in float code too
 regular_func d2fix_a
 @ here
@@ -2181,4 +2181,4 @@
 .word 0x40000000, 0x00000000   @ log 1+2^-32 Q62
 
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c b/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c
index 9158320..e1073ca 100644
--- a/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c
+++ b/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c
@@ -22,16 +22,21 @@
 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.
+#if PICO_RP2040_B0_SUPPORTED || PICO_RP2040_B1_SUPPORTED
+    // Actually check for B0/B1 h/w
+    if (rp2040_chip_version() == 1) {
+        // 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();
+        // Wait SE0 phase will call force ls_j phase which will call finish phase
+        hw_enumeration_fix_wait_se0();
+    }
+#endif
 }
 
 static inline uint8_t hw_line_state(void) {
diff --git a/src/rp2_common/pico_float/float_aeabi.S b/src/rp2_common/pico_float/float_aeabi.S
index b901d30..db393df 100644
--- a/src/rp2_common/pico_float/float_aeabi.S
+++ b/src/rp2_common/pico_float/float_aeabi.S
@@ -80,7 +80,7 @@
 #endif
 
 .macro table_tail_call SF_TABLE_OFFSET
-#if PICO_FLOAT_SUPPORT_ROM_V1
+#if PICO_FLOAT_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
 #ifndef NDEBUG
     movs r3, #0
     mov ip, r3
@@ -94,11 +94,11 @@
 .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
+#if PICO_FLOAT_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
     mov ip, pc
 #endif
     bx r3
-#if PICO_FLOAT_SUPPORT_ROM_V1
+#if PICO_FLOAT_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
 .byte \SF_TABLE_OFFSET, 0xdf
 .word \shim
 #endif
@@ -584,13 +584,13 @@
 
 float_wrapper_section srqtf
 wrapper_func_f1 sqrtf
-#if PICO_FLOAT_SUPPORT_ROM_V1
+#if PICO_FLOAT_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
     // check for negative
     asrs r1, r0, #23
     bmi 1f
 #endif
     table_tail_call SF_TABLE_FSQRT
-#if PICO_FLOAT_SUPPORT_ROM_V1
+#if PICO_FLOAT_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
 1:
     mvns r0, r1
     cmp r0, #255
diff --git a/src/rp2_common/pico_float/float_init_rom.c b/src/rp2_common/pico_float/float_init_rom.c
index 24c74ce..646c0e9 100644
--- a/src/rp2_common/pico_float/float_init_rom.c
+++ b/src/rp2_common/pico_float/float_init_rom.c
@@ -11,9 +11,9 @@
 // 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;
+void __attribute__((weak)) *sf_clz_func;
 
-#if !PICO_FLOAT_SUPPORT_ROM_V1
+#if !(PICO_FLOAT_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED)
 static __attribute__((noreturn)) void missing_float_func_shim(void) {
     panic("");
 }
@@ -22,7 +22,7 @@
 void __aeabi_float_init(void) {
     int rom_version = rp2040_rom_version();
     void *rom_table = rom_data_lookup(rom_table_code('S', 'F'));
-#if PICO_FLOAT_SUPPORT_ROM_V1
+#if PICO_FLOAT_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
     if (rom_version == 1) {
         memcpy(&sf_table, rom_table, SF_TABLE_V1_SIZE);
         extern void float_table_shim_on_use_helper(void);
@@ -66,5 +66,5 @@
         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'));
+    sf_clz_func = rom_func_lookup(ROM_FUNC_CLZ32);
 }
diff --git a/src/rp2_common/pico_float/float_math.c b/src/rp2_common/pico_float/float_math.c
index bc7fa9a..a48a2d7 100644
--- a/src/rp2_common/pico_float/float_math.c
+++ b/src/rp2_common/pico_float/float_math.c
@@ -39,11 +39,25 @@
 #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\"")
+typedef union {
+    float f;
+    ui32 ix;
+} float_ui32;
+
+static inline float ui322float(ui32 ix) {
+    float_ui32 tmp;
+    tmp.ix = ix;
+    return tmp.f;
+}
+
+static inline ui32 float2ui32(float f) {
+    float_ui32 tmp;
+    tmp.f = f;
+    return tmp.ix;
+}
 
 static inline bool fisnan(float x) {
-    ui32 ix=*(ui32*)&x;
+    ui32 ix=float2ui32(x);
     return ix * 2 > 0xff000000u;
 }
 
@@ -56,17 +70,17 @@
 #endif
 
 static inline int fgetsignexp(float x) {
-    ui32 ix=*(ui32*)&x;
+    ui32 ix=float2ui32(x);
     return (ix>>23)&0x1ff;
 }
 
 static inline int fgetexp(float x) {
-    ui32 ix=*(ui32*)&x;
+    ui32 ix=float2ui32(x);
     return (ix>>23)&0xff;
 }
 
 static inline float fldexp(float x,int de) {
-    ui32 ix=*(ui32*)&x,iy;
+    ui32 ix=float2ui32(x),iy;
     int e;
     e=fgetexp(x);
     if(e==0||e==0xff) return x;
@@ -74,7 +88,7 @@
     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;
+    return ui322float(iy);
 }
 
 float WRAPPER_FUNC(ldexpf)(float x, int de) {
@@ -83,9 +97,9 @@
 }
 
 static inline float fcopysign(float x,float y) {
-    ui32 ix=*(ui32*)&x,iy=*(ui32*)&y;
+    ui32 ix=float2ui32(x),iy=float2ui32(y);
     ix=((ix&0x7fffffff)|(iy&0x80000000));
-    return *(float*)&ix;
+    return ui322float(ix);
 }
 
 float WRAPPER_FUNC(copysignf)(float x, float y) {
@@ -101,7 +115,7 @@
 static inline int fisminf(float x)  { return fgetsignexp(x)==0x1ff; }
 
 static inline int fisint(float x) {
-    ui32 ix=*(ui32*)&x,m;
+    ui32 ix=float2ui32(x),m;
     int e=fgetexp(x);
     if(e==0) return 1;       // 0 is an integer
     e-=0x7f;                 // remove exponent bias
@@ -114,7 +128,7 @@
 }
 
 static inline int fisoddint(float x) {
-    ui32 ix=*(ui32*)&x,m;
+    ui32 ix=float2ui32(x),m;
     int e=fgetexp(x);
     e-=0x7f;                 // remove exponent bias
     if(e<0) return 0;        // |x|<1; 0 is not odd
@@ -127,24 +141,24 @@
 }
 
 static inline int fisstrictneg(float x) {
-    ui32 ix=*(ui32*)&x;
+    ui32 ix=float2ui32(x);
     if(fiszero(x)) return 0;
     return ix>>31;
 }
 
 static inline int fisneg(float x) {
-    ui32 ix=*(ui32*)&x;
+    ui32 ix=float2ui32(x);
     return ix>>31;
 }
 
 static inline float fneg(float x) {
-    ui32 ix=*(ui32*)&x;
+    ui32 ix=float2ui32(x);
     ix^=0x80000000;
-    return *(float*)&ix;
+    return ui322float(ix);
 }
 
 static inline int fispo2(float x) {
-    ui32 ix=*(ui32*)&x;
+    ui32 ix=float2ui32(x);
     if(fiszero(x)) return 0;
     if(fisinf(x)) return 0;
     ix&=0x007fffff;
@@ -161,33 +175,33 @@
 
 float WRAPPER_FUNC(truncf)(float x) {
     check_nan_f1(x);
-    ui32 ix=*(ui32*)&x,m;
+    ui32 ix=float2ui32(x),m;
     int e=fgetexp(x);
     e-=0x7f;                 // remove exponent bias
     if(e<0) {                // |x|<1
         ix&=0x80000000;
-        return *(float*)&ix;
+        return ui322float(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<<e)-1;              // mask for bits of significance <1
     ix&=~m;
-    return *(float*)&ix;
+    return ui322float(ix);
 }
 
 float WRAPPER_FUNC(roundf)(float x) {
     check_nan_f1(x);
-    ui32 ix=*(ui32*)&x,m;
+    ui32 ix=float2ui32(x),m;
     int e=fgetexp(x);
     e-=0x7f;                 // remove exponent bias
     if(e<-1) {               // |x|<0.5
         ix&=0x80000000;
-        return *(float*)&ix;
+        return ui322float(ix);
     }
     if(e==-1) {              // 0.5<=|x|<1
         ix&=0x80000000;
         ix|=0x3f800000;        // ±1
-        return *(float*)&ix;
+        return ui322float(ix);
     }
     e=23-e;                  // bit position in mantissa with significance 1, <=23
     if(e<=0) return x;       // |x| large, so must be an integer
@@ -195,16 +209,16 @@
     ix+=m;
     m=m+m-1;                 // mask for bits of significance <1
     ix&=~m;
-    return *(float*)&ix;
+    return ui322float(ix);
 }
 
 float WRAPPER_FUNC(floorf)(float x) {
     check_nan_f1(x);
-    ui32 ix=*(ui32*)&x,m;
+    ui32 ix=float2ui32(x),m;
     int e=fgetexp(x);
     if(e==0) {       // x==0
         ix&=0x80000000;
-        return *(float*)&ix;
+        return ui322float(ix);
     }
     e-=0x7f;                 // remove exponent bias
     if(e<0) {                // |x|<1, not zero
@@ -216,16 +230,16 @@
     m=(1<<e)-1;              // mask for bit of significance <1
     if(fisneg(x)) ix+=m;     // add 1-ε to magnitude if negative
     ix&=~m;                  // truncate
-    return *(float*)&ix;
+    return ui322float(ix);
 }
 
 float WRAPPER_FUNC(ceilf)(float x) {
     check_nan_f1(x);
-    ui32 ix=*(ui32*)&x,m;
+    ui32 ix=float2ui32(x),m;
     int e=fgetexp(x);
     if(e==0) {       // x==0
         ix&=0x80000000;
-        return *(float*)&ix;
+        return ui322float(ix);
     }
     e-=0x7f;                 // remove exponent bias
     if(e<0) {                // |x|<1, not zero
@@ -237,7 +251,7 @@
     m=(1<<e)-1;              // mask for bit of significance <1
     if(!fisneg(x)) ix+=m;    // add 1-ε to magnitude if positive
     ix&=~m;                  // truncate
-    return *(float*)&ix;
+    return ui322float(ix);
 }
 
 float WRAPPER_FUNC(asinf)(float x) {
@@ -505,7 +519,7 @@
 
 float WRAPPER_FUNC(fmodf)(float x,float y) {
     check_nan_f2(x,y);
-    ui32 ix=*(ui32*)&x,iy=*(ui32*)&y;
+    ui32 ix=float2ui32(x),iy=float2ui32(y);
     int sx,ex,ey;
     i32 mx,my;
     FUNPACKS(ix,sx,ex,mx);
@@ -526,7 +540,7 @@
 
 float WRAPPER_FUNC(remquof)(float x,float y,int*quo) {
     check_nan_f2(x,y);
-    ui32 ix=*(ui32*)&x,iy=*(ui32*)&y;
+    ui32 ix=float2ui32(x),iy=float2ui32(y);
     int sx,sy,ex,ey,q;
     i32 mx,my;
     FUNPACKS(ix,sx,ex,mx);
@@ -567,5 +581,4 @@
 
 float WRAPPER_FUNC(remainderf)(float x,float y) { check_nan_f2(x,y); return remquof(x,y,0); }
 
-_Pragma("GCC diagnostic pop") // strict-aliasing
 _Pragma("GCC diagnostic pop") // conversion
\ No newline at end of file
diff --git a/src/rp2_common/pico_float/float_v1_rom_shim.S b/src/rp2_common/pico_float/float_v1_rom_shim.S
index a29925e..d7541a4 100644
--- a/src/rp2_common/pico_float/float_v1_rom_shim.S
+++ b/src/rp2_common/pico_float/float_v1_rom_shim.S
@@ -6,7 +6,7 @@
 
 #include "pico/asm_helper.S"
 
-#if PICO_FLOAT_SUPPORT_ROM_V1
+#if PICO_FLOAT_SUPPORT_ROM_V1 && PICO_RP2040_B0_SUPPORTED
 .syntax unified
 .cpu cortex-m0plus
 .thumb
diff --git a/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S b/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S
index e07a9fe..8540905 100644
--- a/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S
+++ b/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S
@@ -9,6 +9,7 @@
 .thumb
 
 #include "pico/asm_helper.S"
+#include "pico/bootrom.h"
 
 __pre_init __aeabi_mem_init, 00001
 
@@ -34,10 +35,10 @@
 
 .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')
+    .word ROM_FUNC_MEMSET
+    .word ROM_FUNC_MEMCPY
+    .word ROM_FUNC_MEMSET4
+    .word ROM_FUNC_MEMCPY44
 aeabi_mem_funcs_end:
 
 .section .text
@@ -58,20 +59,20 @@
 mem_section aeabi_memset_memcpy
 
 wrapper_func __aeabi_memset
-    // args are backwards
-    eors r0, r1
-    eors r1, r0
-    eors r0, r1
+    // 2nd/3rd args are reversed
+    eors r2, r1
+    eors r1, r2
+    eors r2, 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
+    // 2nd/3rd args are reversed
+    eors r2, r1
+    eors r1, r2
+    eors r2, r1
     ldr r3, =aeabi_mem_funcs
     ldr r3, [r3, #MEMSET4]
     bx r3
diff --git a/src/rp2_common/pico_multicore/include/pico/multicore.h b/src/rp2_common/pico_multicore/include/pico/multicore.h
index 1c91a86..6f12f41 100644
--- a/src/rp2_common/pico_multicore/include/pico/multicore.h
+++ b/src/rp2_common/pico_multicore/include/pico/multicore.h
@@ -17,7 +17,7 @@
 
 /** \file multicore.h
  *  \defgroup pico_multicore pico_multicore
- * Adds support for running code on the second processor core (core1)
+ * Adds support for running code on the second processor core (core 1)
  *
  * \subsection multicore_example Example
  * \addtogroup pico_multicore
@@ -33,95 +33,155 @@
 #endif
 #endif
 
-/*! \brief  Reset Core 1
+/*! \brief  Reset core 1
  *  \ingroup pico_multicore
  *
+ * This function can be used to reset core 1 into its initial state (ready for launching code against via \ref multicore_launch_core1 and similar methods)
+ *
+ * \note this function should only be called from core 0
  */
 void multicore_reset_core1(void);
 
 /*! \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)
+ * Wake up (a previously reset) core 1 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.
+ * core 1 must previously have been reset either as a result of a system reset or by calling \ref multicore_reset_core1
+ *
+ * core 1 will use the same vector table as core 0
+ *
+ * \param entry Function entry point
+ * \see multicore_reset_core1
  */
 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
+ * Wake up (a previously reset) core 1 and enter the given function on core 1 using the passed stack for core 1
+ *
+ * core 1 must previously have been reset either as a result of a system reset or by calling \ref multicore_reset_core1
+ *
+ * core 1 will use the same vector table as core 0
+ *
+ * \param entry Function entry point
+ * \param stack_bottom The bottom (lowest address) of the stack
+ * \param stack_size_bytes The size of the stack in bytes (must be a multiple of 4)
+ * \see multicore_reset_core1
  */
 void multicore_launch_core1_with_stack(void (*entry)(void), uint32_t *stack_bottom, size_t stack_size_bytes);
 
 /*! \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
+ * Wake up (a previously reset) core 1 and start it executing with a specific entry point, stack pointer
+ * and vector table.
  *
+ * This is a low level function that does not provide a stack guard even if USE_STACK_GUARDS is defined
+ *
+ * core 1 must previously have been reset either as a result of a system reset or by calling \ref multicore_reset_core1
+ *
+ * \param entry Function entry point
+ * \param sp Pointer to the top of the core 1 stack
+ * \param vector_table address of the vector table to use for core 1
+ * \see multicore_reset_core1
  */
 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
+ * \brief Functions for the inter-core FIFOs
  *
  * 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.
+ *
+ * \note The inter-core FIFOs are a very precious resource and are frequently used for SDK functionality (e.g. during
+ * core 1 launch or by the \ref multicore_lockout functions). Additionally they are often required for the exclusive use
+ * of an RTOS (e.g. FreeRTOS SMP). For these reasons it is suggested that you do not use the FIFO for your own purposes
+ * unless none of the above concerns apply; the majority of cases for transferring data between cores can be eqaully
+ * well handled  by using a \ref queue
  */
 
-
-/*! \brief Check the read FIFO to see if there is data waiting
+/*! \brief Check the read FIFO to see if there is data available (sent by the other core)
  *  \ingroup multicore_fifo
  *
+ * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
+ *
  * \return true if the FIFO has data in it, false otherwise
  */
 static inline bool multicore_fifo_rvalid(void) {
     return !!(sio_hw->fifo_st & SIO_FIFO_ST_VLD_BITS);
 }
 
-/*! \brief Check the write FIFO to see if it is ready for more data
+/*! \brief Check the write FIFO to see if it has space for more data
  *  \ingroup multicore_fifo
  *
+ * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
+ *
  *  @return true if the FIFO has room for more data, false otherwise
  */
 static inline bool multicore_fifo_wready(void) {
     return !!(sio_hw->fifo_st & SIO_FIFO_ST_RDY_BITS);
 }
 
-/*! \brief Push data on to the FIFO.
+/*! \brief Push data on to the write FIFO (data to the other core).
  *  \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.
  *
+ * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
+ *
  * \param data A 32 bit value to push on to the FIFO
  */
 void multicore_fifo_push_blocking(uint32_t data);
 
+/*! \brief Push data on to the write FIFO (data to the other core) with timeout.
+ *  \ingroup multicore_fifo
+ *
+ * This function will block until there is space for the data to be sent
+ * or the timeout is reached
+ *
+ * \param data A 32 bit value to push on to the FIFO
+ * \param timeout_us the timeout in microseconds
+ * \return true if the data was pushed, false if the timeout occurred before data could be pushed
+ */
 bool multicore_fifo_push_timeout_us(uint32_t data, uint64_t timeout_us);
 
-/*! \brief Pop data from the FIFO.
+/*! \brief Pop data from the read FIFO (data from the other core).
  *  \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.
+ * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
+ *
+ * \return 32 bit data from the read FIFO.
  */
 uint32_t multicore_fifo_pop_blocking(void);
 
-bool multicore_fifo_pop_timeout_us(uint64_t timeout_us, uint32_t *out);
-
-/*! \brief Flush any data in the incoming FIFO
+/*! \brief Pop data from the read FIFO (data from the other core) with timeout.
  *  \ingroup multicore_fifo
  *
+ * This function will block until there is data ready to be read or the timeout is reached
+ *
+ * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
+ *
+ * \param timeout_us the timeout in microseconds
+ * \param out the location to store the popped data if available
+ * \return true if the data was popped and a value copied into `out`, false if the timeout occurred before data could be popped
+ */
+bool multicore_fifo_pop_timeout_us(uint64_t timeout_us, uint32_t *out);
+
+/*! \brief Discard any data in the read FIFO
+ *  \ingroup multicore_fifo
+ *
+ * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
  */
 static inline void multicore_fifo_drain(void) {
     while (multicore_fifo_rvalid())
@@ -133,38 +193,117 @@
  *
  * Note that this only clears an interrupt that was caused by the ROE or WOF flags.
  * To clear the VLD flag you need to use one of the 'pop' or 'drain' functions.
+ *
+ * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
+ *
+ * \see multicore_fifo_get_status
 */
 static inline void multicore_fifo_clear_irq(void) {
     // Write any value to clear the error flags
     sio_hw->fifo_st = 0xff;
 }
 
-/*! \brief Get FIFO status
+/*! \brief Get FIFO statuses
  *  \ingroup multicore_fifo
  *
- * \return The status as a bitfield
+ * \return The statuses 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.
+ * 3 | Sticky flag indicating the RX FIFO was read when empty (ROE). This read was ignored by the FIFO.
+ * 2 | Sticky flag indicating the TX FIFO was written when full (WOF). 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)
+ *
+ * See the note in the \ref multicore_fifo section for considerations regarding use of the inter-core FIFOs
+ *
 */
 static inline uint32_t multicore_fifo_get_status(void) {
     return sio_hw->fifo_st;
 }
 
-// call this from the lockout victim thread
+/*!
+ * \defgroup multicore_lockout lockout
+ * \ingroup pico_multicore
+ * \brief Functions to enable one core to force the other core to pause execution in a known state.
+ *
+ * Sometimes it is useful to enter a critical section on both cores at once. On a single
+ * core system a critical section can trivially be entered by disabling interrupts, however on a multi-core
+ * system that is not sufficient, and unless the other core is polling in some way, then it will need to be interrupted
+ * in order to cooperatively enter a blocked state.
+ *
+ * These "lockout" functions use the inter core FIFOs to cause an interrupt on one core from the other, and manage
+ * waiting for the other core to enter the "locked out" state.
+ *
+ * The usage is that the "victim" core ... i.e the core that can be "locked out" by the other core calls
+ * \ref multicore_lockout_victim_init to hook the FIFO interrupt. Note that either or both cores may do this.
+ *
+ * \note When "locked out" the victim core is paused (it is actually executing a tight loop with code in RAM) and has interrupts disabled.
+ * This makes the lockout functions suitable for use by code that wants to write to flash (at which point no code may be executing
+ * from flash)
+ *
+ * The core which wishes to lockout the other core calls \ref multicore_lockout_start_blocking or
+ * \ref multicore_lockout_start_timeout_us to interrupt the other "victim" core and wait for it to be in a
+ * "locked out" state. Once the lockout is no longer needed it calls \ref multicore_lockout_end_blocking or
+ * \ref multicore_lockout_end_timeout_us to release the lockout and wait for confirmation.
+ *
+ * \note Because multicore lockout uses the intercore FIFOs, the FIFOs <b>cannot</b> be used for any other purpose
+ */
+
+/*! \brief Initialize the current core such that it can be a "victim" of lockout (i.e. forced to pause in a known state by the other core)
+ *  \ingroup multicore_lockout
+ *
+ * This code hooks the intercore FIFO IRQ, and the FIFO may not be used for any other purpose after this.
+ */
 void multicore_lockout_victim_init(void);
 
-// start locking out the other core (it will be
-bool multicore_lockout_start_timeout_us(uint64_t timeout_us);
+/*! \brief Request the other core to pause in a known state and wait for it to do so
+ *  \ingroup multicore_lockout
+ *
+ * The other (victim) core must have previously executed \ref multicore_lockout_victim_init()
+ *
+ * \note multicore_lockout_start_ functions are not nestable, and must be paired with a call to a corresponding
+ * \ref multicore_lockout_end_blocking
+ */
 void multicore_lockout_start_blocking(void);
 
-bool multicore_lockout_end_timeout_us(uint64_t timeout_us);
+/*! \brief Request the other core to pause in a known state and wait up to a time limit for it to do so
+ *  \ingroup multicore_lockout
+ *
+ * The other core must have previously executed \ref multicore_lockout_victim_init()
+ *
+ * \note multicore_lockout_start_ functions are not nestable, and must be paired with a call to a corresponding
+ * \ref multicore_lockout_end_blocking
+ *
+ * \param timeout_us the timeout in microseconds
+ * \return true if the other core entered the locked out state within the timeout, false otherwise
+ */
+bool multicore_lockout_start_timeout_us(uint64_t timeout_us);
+
+/*! \brief Release the other core from a locked out state amd wait for it to acknowledge
+ *  \ingroup multicore_lockout
+ *
+ * \note The other core must previously have been "locked out" by calling a `multicore_lockout_start_` function
+ * from this core
+ */
 void multicore_lockout_end_blocking(void);
 
+/*! \brief Release the other core from a locked out state amd wait up to a time limit for it to acknowledge
+ *  \ingroup multicore_lockout
+ *
+ * The other core must previously have been "locked out" by calling a `multicore_lockout_start_` function
+ * from this core
+ *
+ * \note be very careful using small timeout values, as a timeout here will leave the "lockout" functionality
+ * in a bad state. It is probably preferable to use \ref multicore_lockout_end_blocking anyway as if you have
+ * already waited for the victim core to enter the lockout state, then the victim core will be ready to exit
+ * the lockout state very quickly.
+ *
+ * \param timeout_us the timeout in microseconds
+ * \return true if the other core successfully exited locked out state within the timeout, false otherwise
+ */
+bool multicore_lockout_end_timeout_us(uint64_t timeout_us);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/rp2_common/pico_multicore/multicore.c b/src/rp2_common/pico_multicore/multicore.c
index 531e294..121b4fb 100644
--- a/src/rp2_common/pico_multicore/multicore.c
+++ b/src/rp2_common/pico_multicore/multicore.c
@@ -126,22 +126,32 @@
 }
 
 void multicore_launch_core1_raw(void (*entry)(void), uint32_t *sp, uint32_t vector_table) {
-    const uint32_t cmd_sequence[] = {0, 0, 1, (uintptr_t) vector_table, (uintptr_t) sp, (uintptr_t) entry};
-
+    // Allow for the fact that the caller may have already enabled the FIFO IRQ for their
+    // own purposes (expecting FIFO content after core 1 is launched). We must disable
+    // the IRQ during the handshake, then restore afterwards.
     bool enabled = irq_is_enabled(SIO_IRQ_PROC0);
     irq_set_enabled(SIO_IRQ_PROC0, false);
 
+    // Values to be sent in order over the FIFO from core 0 to core 1
+    //
+    // vector_table is value for VTOR register
+    // sp is initial stack pointer (SP)
+    // entry is the initial program counter (PC) (don't forget to set the thumb bit!)
+    const 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
+        // Always drain the READ FIFO (from core 1) before sending a 0
         if (!cmd) {
             multicore_fifo_drain();
-            __sev(); // core 1 may be waiting for fifo space
+            // Execute a SEV as core 1 may be waiting for FIFO space via WFE
+            __sev();
         }
         multicore_fifo_push_blocking(cmd);
         uint32_t response = multicore_fifo_pop_blocking();
-        // move to next state on correct response otherwise start over
+        // Move to next state on correct response (echo-d value) otherwise start over
         seq = cmd == response ? seq + 1 : 0;
     } while (seq < count_of(cmd_sequence));
 
@@ -176,7 +186,7 @@
 static void check_lockout_mutex_init(void) {
     // use known available lock - we only need it briefly
     uint32_t save = hw_claim_lock();
-    if (!mutex_is_initialzed(&lockout_mutex)) {
+    if (!mutex_is_initialized(&lockout_mutex)) {
         mutex_init(&lockout_mutex);
     }
     hw_claim_unlock(save);
@@ -237,7 +247,7 @@
 }
 
 static bool multicore_lockout_end_block_until(absolute_time_t until) {
-    assert(mutex_is_initialzed(&lockout_mutex));
+    assert(mutex_is_initialized(&lockout_mutex));
     if (!mutex_enter_block_until(&lockout_mutex, until)) {
         return false;
     }
diff --git a/src/rp2_common/pico_platform/include/pico/asm_helper.S b/src/rp2_common/pico_platform/include/pico/asm_helper.S
index 050e6a5..3e01c66 100644
--- a/src/rp2_common/pico_platform/include/pico/asm_helper.S
+++ b/src/rp2_common/pico_platform/include/pico/asm_helper.S
@@ -4,13 +4,7 @@
  * 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))
+#include "pico.h"
 
 // do not put align in here as it is used mid function sometimes
 .macro regular_func x
diff --git a/src/rp2_common/pico_platform/include/pico/platform.h b/src/rp2_common/pico_platform/include/pico/platform.h
index c008b95..ee1d360 100644
--- a/src/rp2_common/pico_platform/include/pico/platform.h
+++ b/src/rp2_common/pico_platform/include/pico/platform.h
@@ -7,91 +7,304 @@
 #ifndef _PICO_PLATFORM_H_
 #define _PICO_PLATFORM_H_
 
+/** \file platform.h
+ *  \defgroup pico_platform pico_platform
+ *
+ * Macros and definitions (and functions when included by non assembly code) for the RP2 family device / architecture
+ * to provide a common abstraction over low level compiler / platform specifics.
+ *
+ * This header may be included by assembly code
+ */
+
+#include "hardware/platform_defs.h"
+
+// Marker for builds targeting the RP2040
+#define PICO_RP2040 1
+
+// PICO_CONFIG: PICO_STACK_SIZE, Stack Size, min=0x100, default=0x800, advanced=true, group=pico_platform
+#ifndef PICO_STACK_SIZE
+#define PICO_STACK_SIZE _u(0x800)
+#endif
+
+// PICO_CONFIG: PICO_HEAP_SIZE, Heap size to reserve, min=0x100, default=0x800, advanced=true, group=pico_platform
+#ifndef PICO_HEAP_SIZE
+#define PICO_HEAP_SIZE _u(0x800)
+#endif
+
+// PICO_CONFIG: PICO_NO_RAM_VECTOR_TABLE, Enable/disable the RAM vector table, type=bool, default=0, advanced=true, group=pico_platform
+#ifndef PICO_NO_RAM_VECTOR_TABLE
+#define PICO_NO_RAM_VECTOR_TABLE 0
+#endif
+
+// PICO_CONFIG: PICO_RP2040_B0_SUPPORTED, Whether to include any specific software support for RP2040 B0 revision, type=bool, default=1, advanced=true, group=pico_platform
+#ifndef PICO_RP2040_B0_SUPPORTED
+#define PICO_RP2040_B0_SUPPORTED 1
+#endif
+
+// PICO_CONFIG: PICO_FLOAT_SUPPORT_ROM_V1, Include float support code for RP2040 B0 when that chip revision is supported , type=bool, default=1, advanced=true, group=pico_platform
+#ifndef PICO_FLOAT_SUPPORT_ROM_V1
+#define PICO_FLOAT_SUPPORT_ROM_V1 1
+#endif
+
+// PICO_CONFIG: PICO_DOUBLE_SUPPORT_ROM_V1, Include double support code for RP2040 B0 when that chip revision is supported , type=bool, default=1, advanced=true, group=pico_platform
+#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
+#define PICO_DOUBLE_SUPPORT_ROM_V1 1
+#endif
+
+
+// PICO_CONFIG: PICO_RP2040_B1_SUPPORTED, Whether to include any specific software support for RP2040 B1 revision, type=bool, default=1, advanced=true, group=pico_platform
+#ifndef PICO_RP2040_B1_SUPPORTED
+#define PICO_RP2040_B1_SUPPORTED 1
+#endif
+
+// PICO_CONFIG: PICO_RP2040_B2_SUPPORTED, Whether to include any specific software support for RP2040 B2 revision, type=bool, default=1, advanced=true, group=pico_platform
+#ifndef PICO_RP2040_B2_SUPPORTED
+#define PICO_RP2040_B2_SUPPORTED 1
+#endif
+
+// --- remainder of file is not included by assembly code ---
+
+#ifndef __ASSEMBLER__
+
 #include <sys/cdefs.h>
 #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
-*/
-
+/*! \brief Marker for an interrupt handler
+ *  \ingroup pico_platform
+ * For example an IRQ handler function called my_interrupt_handler:
+ *
+ *     void __isr my_interrupt_handler(void) {
+ */
 #define __isr
 
-// Section naming macros
+/*! \brief Section attribute macro for placement in RAM after the `.data` section
+ *  \ingroup pico_platform
+ *
+ * For example a 400 element `uint32_t` array placed after the .data section
+ *
+ *     uint32_t __after_data("my_group_name") a_big_array[400];
+ *
+ * The section attribute is `.after_data.<group>`
+ *
+ * \param group a string suffix to use in the section name to distinguish groups that can be linker
+ *              garbage-collected independently
+ */
 #define __after_data(group) __attribute__((section(".after_data." group)))
+
+/*! \brief Section attribute macro for placement not in flash (i.e in RAM)
+ *  \ingroup pico_platform
+ *
+ * For example a 3 element `uint32_t` array placed in RAM (even though it is `static const`)
+ *
+ *     static const uint32_t __not_in_flash("my_group_name") an_array[3];
+ *
+ * The section attribute is `.time_critical.<group>`
+ *
+ * \param group a string suffix to use in the section name to distinguish groups that can be linker
+ *              garbage-collected independently
+ */
 #define __not_in_flash(group) __attribute__((section(".time_critical." group)))
+
+/*! \brief Section attribute macro for placement in the SRAM bank 4 (known as "scratch X")
+ *  \ingroup pico_platform
+ *
+ * Scratch X is commonly used for critical data and functions accessed only by one core (when only
+ * one core is accessing the RAM bank, there is no opportunity for stalls)
+ *
+ * For example a `uint32_t` variable placed in "scratch X"
+ *
+ *     uint32_t __scratch_x("my_group_name") foo = 23;
+ *
+ * The section attribute is `.scratch_x.<group>`
+ *
+ * \param group a string suffix to use in the section name to distinguish groups that can be linker
+ *              garbage-collected independently
+ */
 #define __scratch_x(group) __attribute__((section(".scratch_x." group)))
+
+/*! \brief Section attribute macro for placement in the SRAM bank 5 (known as "scratch Y")
+ *  \ingroup pico_platform
+ *
+ * Scratch Y is commonly used for critical data and functions accessed only by one core (when only
+ * one core is accessing the RAM bank, there is no opportunity for stalls)
+ *
+ * For example a `uint32_t` variable placed in "scratch Y"
+ *
+ *     uint32_t __scratch_y("my_group_name") foo = 23;
+ *
+ * The section attribute is `.scratch_y.<group>`
+ *
+ * \param group a string suffix to use in the section name to distinguish groups that can be linker
+ *              garbage-collected independently
+ */
 #define __scratch_y(group) __attribute__((section(".scratch_y." group)))
+
+/*! \brief Section attribute macro for data that is to be left uninitialized
+ *  \ingroup pico_platform
+ *
+ * Data marked this way will retain its value across a reset (normally uninitialized data - in the .bss
+ * section) is initialized to zero during runtime initialization
+ *
+ * For example a `uint32_t` foo that will retain its value if the program is restarted by reset.
+ *
+ *     uint32_t __uninitialized_ram("my_group_name") foo;
+ *
+ * The section attribute is `.uninitialized_ram.<group>`
+ *
+ * \param group a string suffix to use in the section name to distinguish groups that can be linker
+ *              garbage-collected independently
+ */
 #define __uninitialized_ram(group) __attribute__((section(".uninitialized_ram." #group))) group
-// For use with PICO_COPY_TO_RAM:
+
+/*! \brief Section attribute macro for placement in flash even in a COPY_TO_RAM binary
+ *  \ingroup pico_platform
+ *
+ * For example a `uint32_t` variable explicitly placed in flash (it will hard fault if you attempt to write it!)
+ *
+ *     uint32_t __in_flash("my_group_name") foo = 23;
+ *
+ * The section attribute is `.flashdata.<group>`
+ *
+ * \param group a string suffix to use in the section name to distinguish groups that can be linker
+ *              garbage-collected independently
+ */
 #define __in_flash(group) __attribute__((section(".flashdata" group)))
 
-/**
+/*! \brief Indicates a function should not be stored in flash
+ *  \ingroup pico_platform
+ *
  * Decorates a function name, such that the function will execute from RAM (assuming it is not inlined
  * into a flash function by the compiler)
+ *
+ * For example a function called my_func taking an int parameter:
+ *
+ *     void __not_in_flash_func(my_func)(int some_arg) {
+ *
+ * The function is placed in the `.time_critical.<func_name>` linker section
+ *
+ * \see __no_inline_not_in_flash_func
  */
 #define __not_in_flash_func(func_name) __not_in_flash(__STRING(func_name)) func_name
-/**
- * Historical synonym for __not_in_flash_func()
+
+/*! \brief Indicates a function is time/latency critical and should not run from flash
+ *  \ingroup pico_platform
+ *
+ * Decorates a function name, such that the function will execute from RAM (assuming it is not inlined
+ * into a flash function by the compiler) to avoid possible flash latency. Currently this macro is identical
+ * in implementation to `__not_in_flash_func`, however the semantics are distinct and a `__time_critical_func`
+ * may in the future be treated more specially to reduce the overhead when calling such function from a flash
+ * function.
+ *
+ * For example a function called my_func taking an int parameter:
+ *
+ *     void __time_critical(my_func)(int some_arg) {
+ *
+ * The function is placed in the `.time_critical.<func_name>` linker section
+ *
+ * \see __not_in_flash_func
  */
 #define __time_critical_func(func_name) __not_in_flash_func(func_name)
 
-/**
+/*! \brief Indicate a function should not be stored in flash and should not be inlined
+ *  \ingroup pico_platform
+ *
  * Decorates a function name, such that the function will execute from RAM, explicitly marking it as
  * noinline to prevent it being inlined into a flash function by the compiler
+ *
+ * For example a function called my_func taking an int parameter:
+ *
+ *     void __no_inline_not_in_flash_func(my_func)(int some_arg) {
+ *
+ * The function is placed in the `.time_critical.<func_name>` linker section
  */
 #define __no_inline_not_in_flash_func(func_name) __noinline __not_in_flash_func(func_name)
 
 #define __packed_aligned __packed __aligned(4)
 
-#if defined(__GNUC__) && __GNUC__ < 7
+/*! \brief Attribute to force inlining of a function regardless of optimization level
+ *  \ingroup pico_platform
+ *
+ *  For example my_function here will always be inlined:
+ *
+ *      int __force_inline my_function(int x) {
+ *
+ */
+#if defined(__GNUC__) && __GNUC__ <= 7
 #define __force_inline inline __always_inline
 #else
 #define __force_inline __always_inline
 #endif
+
+/*! \brief Macro to determine the number of elements in an array
+ *  \ingroup pico_platform
+ */
 #ifndef count_of
 #define count_of(a) (sizeof(a)/sizeof((a)[0]))
 #endif
 
+/*! \brief Macro to return the maximum of two comparable values
+ *  \ingroup pico_platform
+ */
 #ifndef MAX
 #define MAX(a, b) ((a)>(b)?(a):(b))
 #endif
 
+/*! \brief Macro to return the minimum of two comparable values
+ *  \ingroup pico_platform
+ */
 #ifndef MIN
 #define MIN(a, b) ((b)>(a)?(a):(b))
 #endif
 
-/**
- * Execute a breakpoint instruction
+/*! \brief Execute a breakpoint instruction
+ *  \ingroup pico_platform
  */
 static inline void __breakpoint(void) {
     __asm__("bkpt #0");
 }
 
-/**
- * Ensure that the compiler does not move memory access across this method call
+/*! \brief Ensure that the compiler does not move memory access across this method call
+ *  \ingroup pico_platform
+ *
+ *  For example in the following code:
+ *
+ *      *some_memory_location = var_a;
+ *      __compiler_memory_barrier();
+ *      uint32_t var_b = *some_other_memory_location
+ *
+ * The compiler will not move the load from `some_other_memory_location` above the memory barrier (which it otherwise
+ * might - even above the memory store!)
  */
 __force_inline static void __compiler_memory_barrier(void) {
     __asm__ volatile ("" : : : "memory");
 }
 
-// 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
+/*! \brief Macro for converting memory addresses to 32 bit addresses suitable for DMA
+ *  \ingroup pico_platform
+ *
+ *  This is just a cast to `uintptr_t` on the RP2040, however you may want to use this when developing code
+ *  that also runs in "host" mode. If the host mode is 64 bit and you are embedding data pointers
+ *  in other data (e.g. DMA chaining), then there is a need in "host" mode to convert a 64 bit native
+ *  pointer to a 32 bit value for storage, which can be done using this macro.
+ */
 #define host_safe_hw_ptr(x) ((uintptr_t)(x))
+#define native_safe_hw_ptr(x) host_safe_hw_ptr(x)
 
-/**
- * Panic (see panic()) with the message "Unsupported".
+
+/*! \brief Panics with the message "Unsupported"
+ *  \ingroup pico_platform
+ *  \see panic
  */
 void __attribute__((noreturn)) panic_unsupported(void);
 
-/**
- * Panic with a message. An attempt is made to output the message to all registered STDOUT drivers
+/*! \brief Displays a panic message and halts execution
+ *  \ingroup pico_platform
+ *
+ * An attempt is made to output the message to all registered STDOUT drivers
  * after which this method executes a BKPT instruction.
  *
  * @param fmt format string (printf-like)
@@ -110,36 +323,34 @@
 bool running_on_fpga(void);
 #endif
 
-/**
- * @return the RP2040 chip revision number
+/*! \brief Returns the RP2040 chip revision number
+ *  \ingroup pico_platform
+ * @return the RP2040 chip revision number (1 for B0/B1, 2 for B2)
  */
 uint8_t rp2040_chip_version(void);
 
-/**
- * @return the RP2040 rom version number
+/*! \brief Returns the RP2040 rom version number
+ *  \ingroup pico_platform
+ * @return the RP2040 rom version number (1 for RP2040-B0, 2 for RP2040-B1, 3 for RP2040-B2)
  */
 static inline uint8_t rp2040_rom_version(void) {
     return *(uint8_t*)0x13;
 }
 
-/**
- * Empty function intended to be called by any tight hardware polling loop. using this ubiquitously
+/*! \brief No-op function for the body of tight loops
+ *  \ingroup pico_platform
+ *
+ * Np-op function intended to be called by any tight hardware polling loop. Using this ubiquitously
  * makes it much easier to find tight loops, but also in the future \#ifdef-ed support for lockup
  * debugging might be added
  */
-static inline void tight_loop_contents(void) {}
+static __force_inline void tight_loop_contents(void) {}
 
-/**
- * Helper macro for making chain DMA code portable to PICO_PLATFORM=host. The problem here is
- * that embedded pointers in the data are only 32 bit, which is a problem if the host
- * system is 64 bit. This macro is zero cost on the actual device, but in host mode
- * it provides a 64->32 bit 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;
- * i.e. this is a 1 cycle operation.
+/*! \brief Multiply two integers using an assembly `MUL` instruction
+ *  \ingroup pico_platform
+ *
+ * This multiplies a by b using multiply instruction using the ARM mul instruction regardless of values (the compiler
+ * might otherwise choose to perform shifts/adds), i.e. this is a 1 cycle operation.
  *
  * \param a the first operand
  * \param b the second operand
@@ -150,10 +361,14 @@
     return a;
 }
 
-/**
- * Efficiently Multiplies value a by possibly constant value b.
+/*! \brief multiply two integer values using the fastest method possible
+ *  \ingroup pico_platform
+ *
+ * Efficiently multiplies 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
- * which is often a slow combination of shifts and adds
+ * which is often a slow combination of shifts and adds. If b is a power of 2 then a single shift is of course preferable
+ * and will be used
  *
  * \param a the first operand
  * \param b the second operand
@@ -163,18 +378,34 @@
 (__builtin_popcount(b) >= 2 ? __mul_instruction(a,b) : (a)*(b)), \
 (a)*(b))
 
-#define WRAPPER_FUNC(x) __wrap_ ## x
-#define REAL_FUNC(x) __real_ ## x
-
+/*! \brief Utility macro to assert two types are equivalent.
+ *  \ingroup pico_platform
+ *
+ *  This macro can be useful in other macros along with `typeof` to assert that two parameters are of equivalent type
+ *  (or that a single parameter is of an expected type)
+ */
 #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));
 
-/**
- * Get the current exception level on this core
+/*! \brief Get the current exception level on this core
+ *  \ingroup pico_platform
+ *
  * \return the exception number if the CPU is handling an exception, or 0 otherwise
  */
 uint __get_current_exception(void);
 
+#define WRAPPER_FUNC(x) __wrap_ ## x
+#define REAL_FUNC(x) __real_ ## x
+
 #ifdef __cplusplus
 }
 #endif
+
+#else // __ASSEMBLER__
+
+#define WRAPPER_FUNC_NAME(x) __wrap_##x
+#define SECTION_NAME(x) .text.##x
+#define RAM_SECTION_NAME(x) .time_critical.##x
+
+#endif // !__ASSEMBLER__
+
 #endif
diff --git a/src/rp2_common/pico_runtime/runtime.c b/src/rp2_common/pico_runtime/runtime.c
index 6628934..575e23e 100644
--- a/src/rp2_common/pico_runtime/runtime.c
+++ b/src/rp2_common/pico_runtime/runtime.c
@@ -20,16 +20,18 @@
 
 #include "pico/mutex.h"
 #include "pico/time.h"
+
+#if LIB_PICO_PRINTF_PICO
 #include "pico/printf.h"
+#else
+#define weak_raw_printf printf
+#define weak_raw_vprintf vprintf
+#endif
 
 #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];
@@ -113,15 +115,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;
+    // this is an array of either mutex_t or recursive_mutex_t (i.e. not necessarily the same size)
+    // however each starts with a lock_core_t, and the spin_lock is initialized to address 1 for a recursive
+    // spinlock and 0 for a regular one.
 
-    // the first function pointer, not the address of it.
-    for (mutex_t *m = &__mutex_array_start; m < &__mutex_array_end; m++) {
-        if (m->recursion_state) {
-            recursive_mutex_init(m);
+    static_assert(!(sizeof(mutex_t)&3), "");
+    static_assert(!(sizeof(recursive_mutex_t)&3), "");
+    static_assert(!offsetof(mutex_t, core), "");
+    static_assert(!offsetof(recursive_mutex_t, core), "");
+    extern lock_core_t __mutex_array_start;
+    extern lock_core_t __mutex_array_end;
+
+    for (lock_core_t *l = &__mutex_array_start; l < &__mutex_array_end; ) {
+        if (l->spin_lock) {
+            assert(1 == (uintptr_t)l->spin_lock); // indicator for a recursive mutex
+            recursive_mutex_t *rm = (recursive_mutex_t *)l;
+            recursive_mutex_init(rm);
+            l = &rm[1].core; // next
         } else {
+            mutex_t *m = (mutex_t *)l;
             mutex_init(m);
+            l = &m[1].core; // next
         }
     }
 
@@ -230,7 +244,7 @@
 // Use a forwarding method here as it is a little simpler than renaming the symbol as it is used from assembler
 void __attribute__((naked, noreturn)) __printflike(1, 0) panic(__unused const char *fmt, ...) {
     // if you get an undefined reference here, you didn't define your PICO_PANIC_FUNCTION!
-    asm (
+    __asm (
             "push {lr}\n"
 #if !PICO_PANIC_FUNCTION_EMPTY
             "bl " __XSTRING(PICO_PANIC_FUNCTION) "\n"
diff --git a/src/rp2_common/pico_standard_link/CMakeLists.txt b/src/rp2_common/pico_standard_link/CMakeLists.txt
index 78de372..a730540 100644
--- a/src/rp2_common/pico_standard_link/CMakeLists.txt
+++ b/src/rp2_common/pico_standard_link/CMakeLists.txt
@@ -79,6 +79,10 @@
     # boot_stage2 will be linked if PICO_NO_FLASH would be defined to 0
     target_link_libraries(pico_standard_link INTERFACE $<$<NOT:$<IF:$<STREQUAL:$<TARGET_PROPERTY:PICO_TARGET_BINARY_TYPE>,no_flash>,1,$<AND:$<BOOL:${PICO_NO_FLASH}>,$<STREQUAL:,$<TARGET_PROPERTY:PICO_TARGET_BINARY_TYPE>>>>>:$<IF:$<BOOL:$<TARGET_PROPERTY:PICO_TARGET_BOOT_STAGE2>>,$<TARGET_PROPERTY:PICO_TARGET_BOOT_STAGE2>,bs2_default>_library>)
 
+    # PICO_CMAKE_CONFIG: PICO_USE_DEFAULT_MAX_PAGE_SIZE, Don't shrink linker max page to 4096, type=bool, default=0, advanced=true, group=pico_standard_link
+    if (NOT PICO_USE_DEFAULT_MAX_PAGE_SIZE)
+        target_link_options(pico_standard_link INTERFACE "LINKER:-z,max-page-size=4096")
+    endif()
     # done in compiler now
     #target_link_options(pico_standard_link INTERFACE "LINKER:--build-id=none")
 
diff --git a/src/rp2_common/pico_standard_link/crt0.S b/src/rp2_common/pico_standard_link/crt0.S
index 4134f0b..f57ddfd 100644
--- a/src/rp2_common/pico_standard_link/crt0.S
+++ b/src/rp2_common/pico_standard_link/crt0.S
@@ -4,12 +4,11 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include "pico.h"
 #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"
-#include "pico/config.h"
 
 #ifdef NDEBUG
 #ifndef COLLAPSE_IRQS
diff --git a/src/rp2_common/pico_stdio/include/pico/stdio.h b/src/rp2_common/pico_stdio/include/pico/stdio.h
index 9f01ae9..e44c01d 100644
--- a/src/rp2_common/pico_stdio/include/pico/stdio.h
+++ b/src/rp2_common/pico_stdio/include/pico/stdio.h
@@ -49,6 +49,9 @@
  * 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 libraries in the binary.
  *
+ * When stdio_usb is configured, this method can be optionally made to block, waiting for a connection
+ * via the variables specified in \ref stdio_usb_init (i.e. \ref PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS)
+ *
  * \see stdio_uart, stdio_usb, stdio_semihosting
  */
 void stdio_init_all(void);
@@ -74,7 +77,7 @@
 /*! \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
+ * \note this method should always be called on an initialized driver and is not re-entrant
  * \param driver the driver
  * \param enabled true to add, false to remove
  */
@@ -100,6 +103,16 @@
  */
 void stdio_set_translate_crlf(stdio_driver_t *driver, bool translate);
 
+/*! \brief putchar variant that skips any CR/LF conversion if enabled
+ * \ingroup pico_stdio
+ */
+int putchar_raw(int c);
+
+/*! \brief puts variant that skips any CR/LF conversion if enabled
+ * \ingroup pico_stdio
+ */
+int puts_raw(const char *s);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/rp2_common/pico_stdio/stdio.c b/src/rp2_common/pico_stdio/stdio.c
index 4f520ca..b457b8a 100644
--- a/src/rp2_common/pico_stdio/stdio.c
+++ b/src/rp2_common/pico_stdio/stdio.c
@@ -10,7 +10,9 @@
 
 #include "pico.h"
 #include "pico/mutex.h"
+#if LIB_PICO_PRINTF_PICO
 #include "pico/printf.h"
+#endif
 #include "pico/stdio.h"
 #include "pico/stdio/driver.h"
 #include "pico/time.h"
@@ -53,12 +55,15 @@
 }
 
 #else
-static bool print_serialize_begin(void) {
+static bool stdout_serialize_begin(void) {
     return true;
 }
-static void print_serialize_end(void) {
+static void stdout_serialize_end(void) {
 }
 #endif
+static void stdio_out_chars_no_crlf(stdio_driver_t *driver, const char *s, int len) {
+    driver->out_chars(s, len);
+}
 
 static void stdio_out_chars_crlf(stdio_driver_t *driver, const char *s, int len) {
 #if PICO_STDIO_ENABLE_CRLF_SUPPORT
@@ -89,7 +94,7 @@
 #endif
 }
 
-static bool stdio_put_string(const char *s, int len, bool newline) {
+static bool stdio_put_string(const char *s, int len, bool newline, bool no_cr) {
     bool serialized = stdout_serialize_begin();
     if (!serialized) {
 #if PICO_STDIO_IGNORE_NESTED_STDOUT
@@ -97,13 +102,14 @@
 #endif
     }
     if (len == -1) len = (int)strlen(s);
+    void (*out_func)(stdio_driver_t *, const char *, int) = no_cr ? stdio_out_chars_no_crlf : stdio_out_chars_crlf;
     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);
+        out_func(driver, s, len);
         if (newline) {
             const char c = '\n';
-            stdio_out_chars_crlf(driver, &c, 1);
+            out_func(driver, &c, 1);
         }
     }
     if (serialized) {
@@ -134,13 +140,26 @@
 
 int WRAPPER_FUNC(putchar)(int c) {
     char cc = (char)c;
-    stdio_put_string(&cc, 1, false);
+    stdio_put_string(&cc, 1, false, false);
     return c;
 }
 
 int WRAPPER_FUNC(puts)(const char *s) {
     int len = (int)strlen(s);
-    stdio_put_string(s, len, true);
+    stdio_put_string(s, len, true, false);
+    stdio_flush();
+    return len;
+}
+
+int putchar_raw(int c) {
+    char cc = (char)c;
+    stdio_put_string(&cc, 1, false, true);
+    return c;
+}
+
+int puts_raw(const char *s) {
+    int len = (int)strlen(s);
+    stdio_put_string(s, len, true, true);
     stdio_flush();
     return len;
 }
@@ -154,7 +173,7 @@
 
 int _write(int handle, char *buffer, int length) {
     if (handle == 1) {
-        stdio_put_string(buffer, length, false);
+        stdio_put_string(buffer, length, false, false);
         return length;
     }
     return -1;
@@ -243,7 +262,7 @@
     return ret;
 }
 
-void stdio_init_all() {
+void stdio_init_all(void) {
     // todo add explicit custom, or registered although you can call stdio_enable_driver explicitly anyway
     // These are well known ones
 #if LIB_PICO_STDIO_UART
diff --git a/src/rp2_common/pico_stdio_semihosting/stdio_semihosting.c b/src/rp2_common/pico_stdio_semihosting/stdio_semihosting.c
index 8936770..4eb673f 100644
--- a/src/rp2_common/pico_stdio_semihosting/stdio_semihosting.c
+++ b/src/rp2_common/pico_stdio_semihosting/stdio_semihosting.c
@@ -18,7 +18,7 @@
 //    );
 //}
 
-static void __attribute__((naked)) semihosting_putc(char c) {
+static void __attribute__((naked)) semihosting_putc(__unused const char *c) {
     __asm (
 
     "mov r1, r0\n"
@@ -30,8 +30,8 @@
 
 
 static void stdio_semihosting_out_chars(const char *buf, int length) {
-    for (uint i = 0; i <length; i++) {
-        semihosting_putc(buf[i]);
+    for (int i = 0; i < length; i++) {
+        semihosting_putc(&buf[i]);
     }
 }
 
diff --git a/src/rp2_common/pico_stdio_usb/CMakeLists.txt b/src/rp2_common/pico_stdio_usb/CMakeLists.txt
index 2e33f5a..b6abadd 100644
--- a/src/rp2_common/pico_stdio_usb/CMakeLists.txt
+++ b/src/rp2_common/pico_stdio_usb/CMakeLists.txt
@@ -14,5 +14,6 @@
         pico_stdio
         pico_time
         pico_unique_id
+        pico_usb_reset_interface_headers
     )
 endif()
diff --git a/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb.h b/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb.h
index 6a1effa..2aeb647 100644
--- a/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb.h
+++ b/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb.h
@@ -54,6 +54,16 @@
 #define PICO_STDIO_USB_RESET_MAGIC_BAUD_RATE 1200
 #endif
 
+// PICO_CONFIG: PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS, Maximum number of milliseconds to wait during initialization for a CDC connection from the host (negative means indefinite) during initialization, default=0, group=pico_stdio_usb
+#ifndef PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS
+#define PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS 0
+#endif
+
+// PICO_CONFIG: PICO_STDIO_USB_POST_CONNECT_WAIT_DELAY_MS, Number of extra milliseconds to wait when using PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS after a host CDC connection is detected (some host terminals seem to sometimes lose transmissions sent right after connection), default=50, group=pico_stdio_usb
+#ifndef PICO_STDIO_USB_POST_CONNECT_WAIT_DELAY_MS
+#define PICO_STDIO_USB_POST_CONNECT_WAIT_DELAY_MS 50
+#endif
+
 // PICO_CONFIG: PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED, Optionally define a pin to use as bootloader activity LED when BOOTSEL mode is entered via USB (either VIA_BAUD_RATE or VIA_VENDOR_INTERFACE), type=int, min=0, max=29, group=pico_stdio_usb
 
 // PICO_CONFIG: PICO_STDIO_USB_RESET_BOOTSEL_FIXED_ACTIVITY_LED, Whether the pin specified by PICO_STDIO_USB_RESET_BOOTSEL_ACTIVITY_LED is fixed or can be modified by picotool over the VENDOR USB interface, type=bool, default=0, group=pico_stdio_usb
@@ -94,10 +104,22 @@
 extern stdio_driver_t stdio_usb;
 
 /*! \brief Explicitly initialize USB stdio and add it to the current set of stdin drivers
- *  \ingroup pico_stdio_uart
+ *  \ingroup pico_stdio_usb
+ *
+ *  \ref PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS can be set to cause this method to wait for a CDC connection
+ *  from the host before returning, which is useful if you don't want any initial stdout output to be discarded
+ *  before the connection is established.
+ *
+ *  \return true if the USB CDC was initialized, false if an error occurred
  */
 bool stdio_usb_init(void);
 
+/*! \brief Check if there is an active stdio CDC connection to a host
+ *  \ingroup pico_stdio_usb
+ *
+ *  \return true if stdio is connected over CDC
+ */
+bool stdio_usb_connected(void);
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb/reset_interface.h b/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb/reset_interface.h
index c8e248d..e0cca10 100644
--- a/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb/reset_interface.h
+++ b/src/rp2_common/pico_stdio_usb/include/pico/stdio_usb/reset_interface.h
@@ -7,17 +7,7 @@
 #ifndef _PICO_STDIO_USB_RESET_INTERFACE_H
 #define _PICO_STDIO_USB_RESET_INTERFACE_H
 
-// We use VENDOR, 0, 0 for PICOBOOT, so lets use VENDOR, 0, 1 for RESET
+// definitions have been moved here
+#include "pico/usb_reset_interface.h"
 
-// VENDOR sub-class for the reset interface
-#define RESET_INTERFACE_SUBCLASS 0x00
-// VENDOR protocol for the reset interface
-#define RESET_INTERFACE_PROTOCOL 0x01
-
-// CONTROL requests:
-
-// reset to BOOTSEL
-#define RESET_REQUEST_BOOTSEL 0x01
-// regular flash boot
-#define RESET_REQUEST_FLASH 0x02
 #endif
\ No newline at end of file
diff --git a/src/rp2_common/pico_stdio_usb/reset_interface.c b/src/rp2_common/pico_stdio_usb/reset_interface.c
index 2f2e72b..06dce86 100644
--- a/src/rp2_common/pico_stdio_usb/reset_interface.c
+++ b/src/rp2_common/pico_stdio_usb/reset_interface.c
@@ -38,7 +38,7 @@
 }
 
 // Support for parameterized reset via vendor interface control request
-static bool resetd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) {
+static bool resetd_control_xfer_cb(uint8_t __unused rhport, uint8_t stage, tusb_control_request_t const * request) {
     // nothing to do with DATA & ACK stage
     if (stage != CONTROL_STAGE_SETUP) return true;
 
diff --git a/src/rp2_common/pico_stdio_usb/stdio_usb.c b/src/rp2_common/pico_stdio_usb/stdio_usb.c
index 2cca2c2..913d606 100644
--- a/src/rp2_common/pico_stdio_usb/stdio_usb.c
+++ b/src/rp2_common/pico_stdio_usb/stdio_usb.c
@@ -41,10 +41,10 @@
     if (tud_cdc_connected()) {
         for (int i = 0; i < length;) {
             int n = length - i;
-            int avail = tud_cdc_write_available();
+            int avail = (int) tud_cdc_write_available();
             if (n > avail) n = avail;
             if (n) {
-                int n2 = tud_cdc_write(buf + i, n);
+                int n2 = (int) tud_cdc_write(buf + i, (uint32_t)n);
                 tud_task();
                 tud_cdc_write_flush();
                 i += n2;
@@ -73,7 +73,7 @@
     }
     int rc = PICO_ERROR_NO_DATA;
     if (tud_cdc_connected() && tud_cdc_available()) {
-        int count = tud_cdc_read(buf, length);
+        int count = (int) tud_cdc_read(buf, (uint32_t) length);
         rc =  count ? count : PICO_ERROR_NO_DATA;
     }
     mutex_exit(&stdio_usb_mutex);
@@ -103,9 +103,29 @@
     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);
+#if PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS
+#if PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS > 0
+        absolute_time_t until = make_timeout_time_ms(PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS);
+#else
+        absolute_time_t until = at_the_end_of_time;
+#endif
+        do {
+            if (stdio_usb_connected()) {
+#if PICO_STDIO_USB_POST_CONNECT_WAIT_DELAY_MS != 0
+                sleep_ms(PICO_STDIO_USB_POST_CONNECT_WAIT_DELAY_MS);
+#endif
+                break;
+            }
+            sleep_ms(10);
+        } while (!time_reached(until));
+#endif
     }
     return rc;
 }
+
+bool stdio_usb_connected(void) {
+    return tud_cdc_connected();
+}
 #else
 #include "pico/stdio_usb.h"
 #warning stdio USB was configured, but is being disabled as TinyUSB is explicitly linked
diff --git a/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c b/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c
index d06d700..b3cfed0 100644
--- a/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c
+++ b/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c
@@ -143,7 +143,7 @@
     }
 
     // first byte is length (including header), second byte is string type
-    desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * len + 2);
+    desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * len + 2));
 
     return desc_str;
 }
diff --git a/src/rp2_common/pico_unique_id/include/pico/unique_id.h b/src/rp2_common/pico_unique_id/include/pico/unique_id.h
index 31b09ed..4132a60 100644
--- a/src/rp2_common/pico_unique_id/include/pico/unique_id.h
+++ b/src/rp2_common/pico_unique_id/include/pico/unique_id.h
@@ -7,6 +7,8 @@
 #ifndef _PICO_UNIQUE_ID_H_
 #define _PICO_UNIQUE_ID_H_
 
+#include "pico.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/src/rp2_common/tinyusb/CMakeLists.txt b/src/rp2_common/tinyusb/CMakeLists.txt
index c4d238d..80a6e78 100644
--- a/src/rp2_common/tinyusb/CMakeLists.txt
+++ b/src/rp2_common/tinyusb/CMakeLists.txt
@@ -15,12 +15,13 @@
 endif()
 
 if (EXISTS ${PICO_TINYUSB_PATH}/${TINYUSB_TEST_PATH})
-    message("TinyUSB available at ${PICO_TINYUSB_PATH}/${TINYUSB_TEST_PATH}; adding USB support.")
+    message("TinyUSB available at ${PICO_TINYUSB_PATH}/${TINYUSB_TEST_PATH}; enabling build support for USB.")
 
     pico_register_common_scope_var(PICO_TINYUSB_PATH)
 
     set(BOARD pico_sdk)
-    include(${PICO_TINYUSB_PATH}/hw/bsp/rp2040/family.cmake)
+    set(FAMILY rp2040)
+    include(${PICO_TINYUSB_PATH}/hw/bsp/family_support.cmake)
 
     add_library(tinyusb_common INTERFACE)
     target_link_libraries(tinyusb_common INTERFACE tinyusb_common_base)
diff --git a/test/kitchen_sink/CMakeLists.txt b/test/kitchen_sink/CMakeLists.txt
index 68d7a61..024d42c 100644
--- a/test/kitchen_sink/CMakeLists.txt
+++ b/test/kitchen_sink/CMakeLists.txt
@@ -97,7 +97,13 @@
 pico_add_extra_outputs(kitchen_sink)
 
 add_executable(kitchen_sink_extra_stdio)
-target_link_libraries(kitchen_sink_extra_stdio kitchen_sink_libs) # no kitchen_sink_options as TinyUSB has warnings
+if (COMMAND suppress_tinyusb_warnings)
+    # Explicitly suppress warnings in TinyUSB files which have them (this has to be done
+    # from the project that uses them per CMake "feature"). Note the function comes from
+    # TinyUSB itself, so we have to guard against TinyUSB not being present with the above if
+    suppress_tinyusb_warnings()
+endif()
+target_link_libraries(kitchen_sink_extra_stdio kitchen_sink_libs kitchen_sink_options)
 pico_add_extra_outputs(kitchen_sink_extra_stdio)
 pico_enable_stdio_usb(kitchen_sink_extra_stdio 1)
 pico_enable_stdio_semihosting(kitchen_sink_extra_stdio 1)
@@ -111,3 +117,4 @@
 pico_set_binary_type(kitchen_sink_no_flash no_flash)
 target_link_libraries(kitchen_sink_no_flash kitchen_sink_libs kitchen_sink_options)
 pico_add_extra_outputs(kitchen_sink_no_flash)
+
diff --git a/test/kitchen_sink/kitchen_sink.c b/test/kitchen_sink/kitchen_sink.c
index e607b80..57d4ef7 100644
--- a/test/kitchen_sink/kitchen_sink.c
+++ b/test/kitchen_sink/kitchen_sink.c
@@ -18,6 +18,7 @@
 #include "hardware/interp.h"
 #include "hardware/irq.h"
 #include "hardware/pio.h"
+#include "hardware/pio_instructions.h"
 #include "hardware/pll.h"
 #include "hardware/pwm.h"
 #include "hardware/resets.h"
@@ -40,11 +41,45 @@
 #include "pico/malloc.h"
 #include "pico/multicore.h"
 #include "pico/printf.h"
+#include "pico/runtime.h"
+#include "pico/stdio.h"
 #include "pico/stdlib.h"
 #include "pico/sync.h"
 #include "pico/time.h"
 #include "pico/unique_id.h"
 
+#include "hardware/structs/adc.h"
+#include "hardware/structs/bus_ctrl.h"
+#include "hardware/structs/clocks.h"
+#include "hardware/structs/dma.h"
+#include "hardware/structs/i2c.h"
+#include "hardware/structs/interp.h"
+#include "hardware/structs/iobank0.h"
+#include "hardware/structs/ioqspi.h"
+#include "hardware/structs/mpu.h"
+#include "hardware/structs/padsbank0.h"
+#include "hardware/structs/pads_qspi.h"
+#include "hardware/structs/pio.h"
+#include "hardware/structs/pll.h"
+#include "hardware/structs/psm.h"
+#include "hardware/structs/pwm.h"
+#include "hardware/structs/resets.h"
+#include "hardware/structs/rosc.h"
+#include "hardware/structs/rtc.h"
+#include "hardware/structs/scb.h"
+#include "hardware/structs/sio.h"
+#include "hardware/structs/spi.h"
+#include "hardware/structs/ssi.h"
+#include "hardware/structs/syscfg.h"
+#include "hardware/structs/systick.h"
+#include "hardware/structs/timer.h"
+#include "hardware/structs/uart.h"
+#include "hardware/structs/usb.h"
+#include "hardware/structs/vreg_and_chip_reset.h"
+#include "hardware/structs/watchdog.h"
+#include "hardware/structs/xip_ctrl.h"
+#include "hardware/structs/xosc.h"
+        
 bi_decl(bi_block_device(
                            BINARY_INFO_MAKE_TAG('K', 'S'),
                            "foo",
@@ -84,7 +119,7 @@
     printf("HELLO B\n");
     if (dma_hw->ints1 & 1) {
         dma_hw->ints1 = 1;
-        printf("B WINS DNA_TO %08x\n", (uint) dma_to);
+        printf("B WINS DMA_TO %08x\n", (uint) dma_to);
 //        irq_remove_handler(DMA_IRQ_1, dma_handler_b);
     }
 }
diff --git a/test/pico_divider_test/pico_divider_nesting_test.c b/test/pico_divider_test/pico_divider_nesting_test.c
index 0e0db94..3b5a745 100644
--- a/test/pico_divider_test/pico_divider_nesting_test.c
+++ b/test/pico_divider_test/pico_divider_nesting_test.c
@@ -158,6 +158,23 @@
             if (0xffffffffu != a * 11 + b) {
                 FAILED();
             }
+            static uint64_t z64;
+            z64 -= 47;
+            uint64_t a64 = z64 / -13635;
+            uint64_t b64 = z64 % -13635;
+            if (z64 != a64 * -13635 + b64) {
+                FAILED();
+            }
+            // specifically check 64/32 divide
+            static uint64_t c64 = 0x13ffffffffull;
+            static uint32_t cd = 1;
+            a64 = c64 / cd;
+            b64 = c64 % cd;
+            if (c64 != a64 * cd + b64) {
+                FAILED();
+            }
+            cd++;
+
         }
         // these use the divider
         for(uint i=0;i<=100;i+=20) {
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 2e908b2..f66f9d0 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -27,10 +27,10 @@
             )
     add_dependencies(${TARGET} ${HEADER_GEN_TARGET})
     get_target_property(target_type ${TARGET} TYPE)
-    if ("EXECUTABLE" STREQUAL "${target_type}")
-        target_include_directories(${TARGET} PRIVATE ${HEADER_DIR})
-    else()
+    if ("INTERFACE_LIBRARY" STREQUAL "${target_type}")
         target_include_directories(${TARGET} INTERFACE ${HEADER_DIR})
+    else()
+        target_include_directories(${TARGET} PUBLIC ${HEADER_DIR})
     endif()
 endfunction()
 
@@ -41,6 +41,6 @@
     endif()
     if (ELF2UF2_FOUND)
         add_custom_command(TARGET ${TARGET} POST_BUILD
-                COMMAND ELF2UF2 ${TARGET}${CMAKE_EXECUTABLE_SUFFIX} ${TARGET}.uf2)
+                COMMAND ELF2UF2 $<TARGET_FILE:${TARGET}> $<IF:$<BOOL:$<TARGET_PROPERTY:${TARGET},OUTPUT_NAME>>,$<TARGET_PROPERTY:${TARGET},OUTPUT_NAME>,$<TARGET_PROPERTY:${TARGET},NAME>>.uf2)
     endif()
 endfunction()
diff --git a/tools/elf2uf2/main.cpp b/tools/elf2uf2/main.cpp
index b66f082..2c0ddcd 100644
--- a/tools/elf2uf2/main.cpp
+++ b/tools/elf2uf2/main.cpp
@@ -143,6 +143,9 @@
     }
     if (eh.ph_num) {
         std::vector<elf32_ph_entry> entries(eh.ph_num);
+        if (fseek(in, eh.ph_offset, SEEK_SET)) {
+            return fail_read_error();
+        }
         if (eh.ph_num != fread(&entries[0], sizeof(struct elf32_ph_entry), eh.ph_num, in)) {
             return fail_read_error();
         }
diff --git a/tools/pioasm/gen/parser.cpp b/tools/pioasm/gen/parser.cpp
index 1e41a09..c9bd036 100644
--- a/tools/pioasm/gen/parser.cpp
+++ b/tools/pioasm/gen/parser.cpp
@@ -1945,9 +1945,9 @@
      -52,    97,   132,   -52,   -52,   -52,   -52,    87,   -52,   -52,
        1,     5,     5,     5,     5,   -52,     5,     5,   -52,   -52,
      -52,   -52,    29,   118,     5,   -52,   170,   -52,   -52,   -52,
-     107,   177,     1,     1,     1,     1,     1,     1,     1,   -52,
+     182,   177,     1,     1,     1,     1,     1,     1,     1,   -52,
      -52,   -51,   -52,   177,   119,   -52,   -52,   -52,   -52,   -52,
-     -52,   -52,    82,   -52,   -52,   -52,   107,   107,   184,   184,
+     -52,   -52,    82,   -52,   -52,   -52,   182,   182,   107,   107,
      -52,   -52,   -52,   -52,   -52,   -52,   -52,   -52,   -52,   -52,
      -52,   -52,   -52,   -52,   -52
   };
@@ -1979,9 +1979,9 @@
   const short
   parser::yypgoto_[] =
   {
-     -52,   -52,   -52,    98,   -52,   -52,   -52,    -7,   -14,   168,
-     -52,    99,   102,   -52,   148,    25,   -52,   -52,   -52,   -52,
-     -52,   -52,   -52,   -52,   128,   -52,   199
+     -52,   -52,   -52,   102,   -52,   -52,   -52,    -7,   -14,   172,
+     -52,    99,   103,   -52,   146,    25,   -52,   -52,   -52,   -52,
+     -52,   -52,   -52,   -52,   128,   -52,   198
   };
 
   const short
@@ -2014,8 +2014,8 @@
       12,    13,    14,    15,    16,    17,    18,    19,    20,   149,
      163,   176,   142,   143,   144,   145,   146,   147,   148,   165,
      142,   143,   144,   145,   146,   147,   148,   142,   143,   144,
-     145,   146,   147,   148,   142,   143,   135,    99,   146,   147,
-     148,   125,   139,   131,   138,    36
+     145,   146,   147,   148,   144,   145,   146,   147,   148,   125,
+     135,    99,   139,   131,    36,   138
   };
 
   const unsigned char
@@ -2040,8 +2040,8 @@
       31,    32,    33,    34,    35,    36,    37,    38,    39,     7,
       52,    52,    10,    11,    12,    13,    14,    15,    16,     9,
       10,    11,    12,    13,    14,    15,    16,    10,    11,    12,
-      13,    14,    15,    16,    10,    11,    98,    29,    14,    15,
-      16,    53,   103,    75,   102,     6
+      13,    14,    15,    16,    12,    13,    14,    15,    16,    53,
+      98,    29,   103,    75,     6,   102
   };
 
   const signed char
diff --git a/tools/pioasm/main.cpp b/tools/pioasm/main.cpp
index 1c86bea..e7ff686 100644
--- a/tools/pioasm/main.cpp
+++ b/tools/pioasm/main.cpp
@@ -37,14 +37,14 @@
     for (; !res && i < argc; i++) {
         if (argv[i][0] != '-') break;
         if (argv[i] == std::string("-o")) {
-            if (i++ < argc) {
+            if (++i < argc) {
                 format = argv[i];
             } else {
                 std::cerr << "error: -o requires format value" << std::endl;
                 res = 1;
             }
         } else if (argv[i] == std::string("-p")) {
-            if (i++ < argc) {
+            if (++i < argc) {
                 options.emplace_back(argv[i]);
             } else {
                 std::cerr << "error: -p requires parameter value" << std::endl;
diff --git a/tools/pioasm/parser.yy b/tools/pioasm/parser.yy
index f1f51dd..467ca89 100644
--- a/tools/pioasm/parser.yy
+++ b/tools/pioasm/parser.yy
@@ -124,8 +124,8 @@
 
 
 %left REVERSE
-%left MULTIPLY DIVIDE
 %left PLUS MINUS
+%left MULTIPLY DIVIDE
 %left AND OR XOR
 
 %printer { yyo << "..."; } <*>;
diff --git a/tools/pioasm/pio_assembler.cpp b/tools/pioasm/pio_assembler.cpp
index 7a83831..469d733 100644
--- a/tools/pioasm/pio_assembler.cpp
+++ b/tools/pioasm/pio_assembler.cpp
@@ -127,7 +127,7 @@
         throw syntax_error(l, msg.str());
     }
     if (instructions.empty()) {
-        throw syntax_error(l, ".wrap cannot be pleaced before the first program instruction");
+        throw syntax_error(l, ".wrap cannot be placed before the first program instruction");
     }
     wrap = resolvable_int(l, instructions.size() - 1);
 }
diff --git a/tools/pioasm/python_output.cpp b/tools/pioasm/python_output.cpp
index fb94e52..38f7ffe 100644
--- a/tools/pioasm/python_output.cpp
+++ b/tools/pioasm/python_output.cpp
@@ -195,9 +195,12 @@
                         if (arg2 & 0x8u) {
                             invalid = true;
                         } else {
-                            guts = "irq, " + std::to_string(arg2 & 7u);
+                            guts = "irq, ";
+                            auto irq = std::to_string(arg2 & 7u);
                             if (arg2 & 0x10u) {
-                                guts += " rel";
+                                guts += "rel(" + irq + ")";
+                            } else {
+                                guts += irq;
                             }
                         }
                         break;
@@ -233,12 +236,11 @@
                     std::string guts = "";
                     if (arg1 & 4u) {
                         op("pull");
-                        if (arg1 & 2u) guts = "ifempty";
+                        if (arg1 & 2u) guts = "ifempty, ";
                     } else {
                         op("push");
-                        if (arg1 & 2u) guts = "iffull";
+                        if (arg1 & 2u) guts = "iffull, ";
                     }
-                    guts += ", ";
                     guts += ((arg1 & 0x1u) ? "block" : "noblock");
                     op_guts(guts);
                 }
@@ -279,15 +281,17 @@
                     op("irq");
                     std::string guts;
                     if (arg1 & 0x2u) {
-                        guts += "clear ";
+                        guts += "clear, ";
                     } else if (arg1 & 0x1u) {
-                        guts += "wait ";
+                        guts += "wait, ";
                     } else {
-                        guts += "nowait ";
+                        guts += "nowait, ";
                     }
-                    guts += std::to_string(arg2 & 7u);
+                    auto irq = std::to_string(arg2 & 7u);
                     if (arg2 & 0x10u) {
-                        guts += " rel";
+                        guts += "rel(" + irq + ")";
+                    } else {
+                        guts += irq;
                     }
                     op_guts(guts);
                 }