The STM32F427 as a Rigless SoC: the vendor's own register description turned into Rust a person can implement peripherals against.
## What is here
| `../stm32f427.rs` | The index: what this module is made of, and the surface a machine uses, `CPU`, `MEMORY`, `builder()`, and `soc()`. The memory map itself is private to the module |
| `STM32F427.svd` | ST's CMSIS-SVD file for the SoC, committed unchanged |
| `generated.rs`, `generated/` | What `rigless svd generate` emits from it: for each register layout the `Reg` enum, a constant per field, and the table; never edited by hand |
| `memory_map.rs` | What the SVD cannot say: the memory map from RM0090, and every correction where the file disagrees with the manual, with its section named |
| `peripherals.rs`, `peripherals/gpio.rs`, `peripherals/tim.rs` | The models of release 0.1: the GPIO port of RM0090 chapter 8, bound to GPIOA, and the general-purpose timer of chapter 18, written against the `tim2` layout and so bound to TIM2, each with a table of what it covers, what it corrects, and which erratum of ES0206 it models |
## The SVD
| Origin | ST, as published in the Arm STM32F4xx device family pack, tag `v3.1.1`, `CMSIS/SVD/STM32F427.svd` at <https://github.com/Open-CMSIS-Pack/STM32F4xx_DFP> |
| Version | SVD version 1.7, copyright 2024 ST |
| License | Apache-2.0, stated in the file's own header |
| Corrections | Four, all in `memory_map.rs`: the file names no interrupt count, so the CPU gets the 91 lines of RM0090 rev 22 table 63; it names no interrupt for SAI1 (line 87) or DMA2D (line 90), so those instances get theirs; and it carries no write rules, so every timer's status register gets the manual's `rc_w0`, cleared by writing zero. Every reset value checked against RM0090 rev 22 matched |
The file needs no special treatment from the generator: no clusters, no arrays, every register 32 bits wide, and 33 of its 83 peripherals derive their layout from a sibling. Interrupt lines are not unique; HASH and RNG share one, as do TIM1 and TIM9. A correction is a struct update in `memory_map.rs`, never an edit to the file or the generated tables.
To bump the file, replace it, regenerate, and review the diff of the tables:
```text
rigless svd generate src/soc/stm32f427
```
CI runs the same command and fails when the committed tables differ from the result.
## Writing a model against it
```rust
use rigless::device::{Device, DeviceContext, RegisterFile};
use rigless::time::VirtualNanos;
use rigless::soc::Width;
use rigless::soc::stm32f427::generated::spi1::{cr1, Register};
#[derive(Default)]
struct Spi { enabled: bool }
impl Device for Spi {
type Register = Register;
fn write(&mut self, register: Register, value: u64, _registers: &mut RegisterFile, _context: &mut DeviceContext<'_>) {
if register == Register::Cr1 { self.enabled = cr1::SPE.is_set(value); }
}
}
let mut soc = rigless::soc::stm32f427::builder().bind("SPI1", Spi::default()).build()?;
soc.write(VirtualNanos(0), rigless::soc::stm32f427::generated::SPI1.base, Width::W32, 1 << 6)?;
# Ok::<(), Box<dyn std::error::Error>>(())
```
The model is bound to an instance here, and `build` checks it was written for that instance's layout. Instances with no model are register-only.