use crate::device::{Device, DeviceContext, RegisterFile};
use crate::soc::stm32h743::generated::syscfg::{Register, cccsr, pwrcr};
use crate::soc::{Access, FieldSpec, WriteModify};
pub static ODEN: FieldSpec = FieldSpec {
width: 1,
..*pwrcr::ODEN
};
pub static READY: FieldSpec = cccsr::READY
.with_access(Access::ReadOnly)
.with_write(WriteModify::None);
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct Syscfg;
impl Device for Syscfg {
type Register = Register;
fn write(
&mut self,
register: Register,
_value: u64,
registers: &mut RegisterFile,
_context: &mut DeviceContext<'_>,
) {
match register {
Register::Cccsr => {
let control = registers.get(Register::Cccsr);
let ready = cccsr::EN.is_set(control);
registers.set(Register::Cccsr, READY.set(control, u64::from(ready)));
}
Register::Pmcr
| Register::Pwrcr
| Register::Exticr1
| Register::Exticr2
| Register::Exticr3
| Register::Exticr4
| Register::Ccvr
| Register::Cccr
| Register::Pkgr
| Register::Ur0
| Register::Ur2
| Register::Ur3
| Register::Ur4
| Register::Ur5
| Register::Ur6
| Register::Ur7
| Register::Ur8
| Register::Ur9
| Register::Ur10
| Register::Ur11
| Register::Ur12
| Register::Ur13
| Register::Ur14
| Register::Ur15
| Register::Ur16
| Register::Ur17 => {}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mcu::{Operate, Single};
use crate::soc::stm32h743::builder;
use crate::soc::stm32h743::generated::SYSCFG;
use crate::soc::stm32h743::generated::syscfg::{
cccr, exticr1, exticr2, exticr4, pmcr, ur2, ur14,
};
use crate::soc::{Layout, Width};
use crate::time::VirtualNanos;
const NOW: VirtualNanos = VirtualNanos(0);
fn syscfg() -> Single<Syscfg> {
Single::new(builder(), "SYSCFG", Syscfg).expect("the bus builds")
}
fn address(register: Register) -> u64 {
SYSCFG.base + u64::from(register.spec().offset)
}
fn read(soc: &mut Single<Syscfg>, register: Register) -> u64 {
soc.read(NOW, address(register), Width::W32).unwrap()
}
fn write(soc: &mut Single<Syscfg>, register: Register, value: u64) {
soc.write(NOW, address(register), Width::W32, value)
.unwrap();
}
#[test]
fn every_register_resets_to_the_files_value() {
let mut soc = syscfg();
for register in Register::ALL {
assert_eq!(
read(&mut soc, register),
register.spec().reset,
"{}",
register.spec().name
);
}
}
#[test]
fn pmcr_stores_every_defined_field() {
let mut soc = syscfg();
let every_bit = Register::Pmcr
.spec()
.fields
.iter()
.fold(0, |bits, field| bits | field.mask());
write(&mut soc, Register::Pmcr, every_bit);
assert_eq!(read(&mut soc, Register::Pmcr), every_bit, "12.3.1");
assert_eq!(
pmcr::EPIS.get(read(&mut soc, Register::Pmcr)),
0b111,
"the PHY interface selection is three bits"
);
write(&mut soc, Register::Pmcr, 0);
assert_eq!(read(&mut soc, Register::Pmcr), 0);
}
#[test]
fn each_exti_line_stores_its_port_selection() {
let mut soc = syscfg();
let first = [
exticr1::EXTI0,
exticr1::EXTI1,
exticr1::EXTI2,
exticr1::EXTI3,
];
let value = first
.iter()
.zip([0, 4, 10, 7])
.fold(0, |value, (field, port)| field.set(value, port));
write(&mut soc, Register::Exticr1, value);
let stored = read(&mut soc, Register::Exticr1);
for (field, port) in first.iter().zip([0, 4, 10, 7]) {
assert_eq!(field.get(stored), port, "{}, 12.3.2", field.name);
}
write(&mut soc, Register::Exticr4, exticr4::EXTI15.set(0, 2));
assert_eq!(
exticr4::EXTI15.get(read(&mut soc, Register::Exticr4)),
2,
"12.3.5"
);
write(&mut soc, Register::Exticr2, exticr2::EXTI5.set(0, 0xB));
assert_eq!(
read(&mut soc, Register::Exticr2),
exticr2::EXTI5.set(0, 0xB),
"a reserved selection is stored, and selects no port, 12.3.3"
);
}
#[test]
fn the_compensation_cell_control_bits_are_stored() {
let mut soc = syscfg();
write(
&mut soc,
Register::Cccsr,
cccsr::CS.mask() | cccsr::HSLV.mask(),
);
let stored = read(&mut soc, Register::Cccsr);
assert!(cccsr::CS.is_set(stored), "12.3.7");
assert!(cccsr::HSLV.is_set(stored));
assert!(!cccsr::EN.is_set(stored));
assert!(!cccsr::READY.is_set(stored), "not enabled, not ready");
}
#[test]
fn ready_follows_the_enable() {
let mut soc = syscfg();
write(&mut soc, Register::Cccsr, cccsr::EN.mask());
assert!(
cccsr::READY.is_set(read(&mut soc, Register::Cccsr)),
"enabled, the cell is ready, 12.3.7"
);
write(
&mut soc,
Register::Cccsr,
cccsr::EN.mask() | cccsr::CS.mask(),
);
assert!(
cccsr::READY.is_set(read(&mut soc, Register::Cccsr)),
"a write that leaves it enabled leaves it ready"
);
write(&mut soc, Register::Cccsr, 0);
assert_eq!(
read(&mut soc, Register::Cccsr),
0,
"disabled, it isn't ready"
);
}
#[test]
fn ready_is_read_only() {
let mut soc = syscfg();
write(&mut soc, Register::Cccsr, cccsr::READY.mask());
assert!(
!cccsr::READY.is_set(read(&mut soc, Register::Cccsr)),
"software can't make the cell ready, 12.3.7"
);
}
#[test]
fn the_compensation_code_is_stored() {
let mut soc = syscfg();
write(
&mut soc,
Register::Cccr,
cccr::PCC.set(cccr::NCC.set(0, 0x3), 0xC),
);
let stored = read(&mut soc, Register::Cccr);
assert_eq!(cccr::NCC.get(stored), 0x3, "12.3.9");
assert_eq!(cccr::PCC.get(stored), 0xC);
}
#[test]
fn ccvr_pkgr_and_the_user_registers_ignore_writes() {
let mut soc = syscfg();
for register in [
Register::Ccvr,
Register::Pkgr,
Register::Ur0,
Register::Ur4,
Register::Ur5,
Register::Ur6,
Register::Ur7,
Register::Ur8,
Register::Ur9,
Register::Ur10,
Register::Ur11,
Register::Ur12,
Register::Ur13,
Register::Ur15,
Register::Ur16,
Register::Ur17,
] {
write(&mut soc, register, 0xFFFF_FFFF);
assert_eq!(
read(&mut soc, register),
register.spec().reset,
"{} is read-only, 12.3.8 to 12.3.28",
register.spec().name
);
}
}
#[test]
fn the_writable_user_registers_are_stored() {
let mut soc = syscfg();
write(&mut soc, Register::Ur2, ur2::BOOT_ADD0.set(0, 0x0800));
assert_eq!(
ur2::BOOT_ADD0.get(read(&mut soc, Register::Ur2)),
0x0800,
"12.3.13"
);
write(&mut soc, Register::Ur14, ur14::D1STPRST.mask());
assert!(
ur14::D1STPRST.is_set(read(&mut soc, Register::Ur14)),
"the file types it read-write, and it is stored as such"
);
}
#[test]
fn oden_is_stored_as_one_bit() {
let mut soc = syscfg();
write(&mut soc, Register::Pwrcr, 1);
assert_eq!(read(&mut soc, Register::Pwrcr), 1, "12.3.10");
assert_eq!(ODEN.width, 1, "one bit, where the file has four");
let row = Register::Pwrcr.index();
let oden = Operate::registers(&soc, "SYSCFG")
.expect("an instance")
.fields(row)
.iter()
.find(|field| field.name == "ODEN")
.copied()
.expect("the register has ODEN");
assert_eq!(oden.width, 1, "the part carries the correction");
}
}