use crate::soc::{Builder, Bus, Cpu, Peripheral, Region, WriteModify};
use super::generated;
pub static MEMORY: [Region; 5] = [
Region::flash("flash", 0x0800_0000, 2 << 20),
Region::ram("ccm", 0x1000_0000, 64 << 10),
Region::system("system", 0x1FFF_0000, 32 << 10),
Region::ram("sram", 0x2000_0000, 192 << 10),
Region::ram("backup_sram", 0x4002_4000, 4 << 10),
];
const INTERRUPT_LINES: u16 = 91;
const SAI1_INTERRUPT: u16 = 87;
const DMA2D_INTERRUPT: u16 = 90;
pub static CPU: Cpu = Cpu {
interrupt_lines: INTERRUPT_LINES,
..generated::CPU
};
fn instances() -> impl Iterator<Item = Peripheral> {
generated::PERIPHERALS
.iter()
.map(|&peripheral| match peripheral.name {
"SAI1" => Peripheral {
interrupts: &[SAI1_INTERRUPT],
..peripheral
},
"DMA2D" => Peripheral {
interrupts: &[DMA2D_INTERRUPT],
..peripheral
},
_ => peripheral,
})
}
const TIMERS: [&str; 14] = [
"TIM1", "TIM2", "TIM3", "TIM4", "TIM5", "TIM6", "TIM7", "TIM8", "TIM9", "TIM10", "TIM11",
"TIM12", "TIM13", "TIM14",
];
const UARTS: [&str; 8] = [
"USART1", "USART2", "USART3", "USART6", "UART4", "UART5", "UART7", "UART8",
];
const SPIS: [&str; 8] = [
"SPI1", "SPI2", "SPI3", "SPI4", "SPI5", "SPI6", "I2S2ext", "I2S3ext",
];
pub fn builder() -> Builder {
let builder = Bus::builder(CPU, &MEMORY, instances())
.reset("RCC", "PLLI2SCFGR", 0x2400_3000)
.reset("RCC", "AHB1LPENR", 0x7EEF_97FF)
.reset("RCC", "APB1LPENR", 0xF6FE_C9FF)
.reset("RCC", "APB2LPENR", 0x0477_7F33)
.reset("DBG", "DBGMCU_IDCODE", 0x1007_0419);
let builder = UARTS.iter().fold(builder, |builder, instance| {
builder.reset(instance, "SR", 0x0000_00C0)
});
let builder = SPIS.iter().fold(builder, |builder, instance| {
builder.reset(instance, "I2SPR", 0x0000_0002)
});
TIMERS.iter().fold(builder, |builder, timer| {
builder.write_modify(timer, "SR", WriteModify::ZeroToClear)
})
}
#[cfg(test)]
mod tests {
use crate::soc::{Layout, Width};
use super::generated::spi1;
use super::*;
use crate::mcu::Mcu;
use crate::time::VirtualNanos;
#[test]
fn the_bus_carries_every_instance() {
let soc = builder().build().unwrap();
assert_eq!(soc.peripherals().count(), generated::PERIPHERALS.len());
assert_eq!(soc.cpu().interrupt_lines, INTERRUPT_LINES);
assert!(
soc.memory()
.iter()
.any(|region| region.name == "backup_sram")
);
}
#[test]
fn every_uart_comes_out_of_reset_ready_to_be_written_to() {
use super::generated::{uart4, usart6};
let soc = builder().build().unwrap();
assert_eq!(usart6::sr::TXE.bit, uart4::sr::TXE.bit);
assert_eq!(usart6::sr::TC.bit, uart4::sr::TC.bit);
let expected = usart6::sr::TXE.mask() | usart6::sr::TC.mask();
assert_eq!(expected, 0x0000_00C0, "30.6.1: TXE is bit 7 and TC bit 6");
for instance in UARTS {
let registers = soc
.registers(instance)
.unwrap_or_else(|| panic!("{instance} is an instance"));
let value = match instance {
"UART4" | "UART5" => registers.get(uart4::Register::Sr),
_ => registers.get(usart6::Register::Sr),
};
assert_eq!(value, expected, "30.6.1: {instance} out of reset");
}
}
#[test]
fn the_lines_the_vendor_omitted_are_filled_in() {
let soc = builder().build().unwrap();
assert_eq!(
soc.peripheral("SAI1")
.map(|peripheral| peripheral.interrupts),
Some(&[SAI1_INTERRUPT][..])
);
assert_eq!(
soc.peripheral("DMA2D")
.map(|peripheral| peripheral.interrupts),
Some(&[DMA2D_INTERRUPT][..])
);
assert!(
generated::SAI1.interrupts.is_empty(),
"the generated table is the vendor's, untouched"
);
}
#[test]
fn instances_derived_from_a_sibling_share_its_table() {
let soc = builder().build().unwrap();
let (spi1, spi2) = (
soc.peripheral("SPI1").unwrap(),
soc.peripheral("SPI2").unwrap(),
);
assert!(std::ptr::eq(spi1.registers, spi2.registers));
assert_eq!(spi2.base, 0x4000_3800);
}
#[test]
fn a_register_reads_its_reset_value_through_the_bus() {
let mut soc = crate::soc::stm32f427::Stm32f427::new().unwrap();
let status = generated::SPI1.base + u64::from(spi1::Register::Sr.spec().offset);
assert_eq!(
soc.read(VirtualNanos(0), status, Width::W32),
Ok(0x2),
"SPI_SR resets with TXE set, RM0090 28.5.3"
);
assert_eq!(spi1::cr1::SPE.bit, 6);
}
}