use std::fmt;
use crate::soc::Layout;
use crate::soc::stm32h743::generated::{tim1, tim2, tim6, tim15, tim16, tim17};
pub(super) const ROWS: usize = 28;
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub(super) enum Slot {
Cr1,
Cr2,
Smcr,
Dier,
Sr,
Egr,
Ccmr1,
Ccmr2,
Ccmr3,
Ccer,
Cnt,
Psc,
Arr,
Rcr,
Ccr1,
Ccr2,
Ccr3,
Ccr4,
Ccr5,
Ccr6,
Bdtr,
Dcr,
Dmar,
Af1,
Af2,
Tisel,
}
pub(super) const SLOTS: usize = 26;
impl Slot {
pub(super) const ALL: [Self; SLOTS] = [
Self::Cr1,
Self::Cr2,
Self::Smcr,
Self::Dier,
Self::Sr,
Self::Egr,
Self::Ccmr1,
Self::Ccmr2,
Self::Ccer,
Self::Cnt,
Self::Psc,
Self::Arr,
Self::Rcr,
Self::Ccr1,
Self::Ccr2,
Self::Ccr3,
Self::Ccr4,
Self::Bdtr,
Self::Dcr,
Self::Dmar,
Self::Ccmr3,
Self::Ccr5,
Self::Ccr6,
Self::Af1,
Self::Af2,
Self::Tisel,
];
pub(super) const fn superset(self) -> tim1::Register {
match self {
Self::Cr1 => tim1::Register::Cr1,
Self::Cr2 => tim1::Register::Cr2,
Self::Smcr => tim1::Register::Smcr,
Self::Dier => tim1::Register::Dier,
Self::Sr => tim1::Register::Sr,
Self::Egr => tim1::Register::Egr,
Self::Ccmr1 => tim1::Register::Ccmr1Input,
Self::Ccmr2 => tim1::Register::Ccmr2Input,
Self::Ccmr3 => tim1::Register::Ccmr3Output,
Self::Ccer => tim1::Register::Ccer,
Self::Cnt => tim1::Register::Cnt,
Self::Psc => tim1::Register::Psc,
Self::Arr => tim1::Register::Arr,
Self::Rcr => tim1::Register::Rcr,
Self::Ccr1 => tim1::Register::Ccr1,
Self::Ccr2 => tim1::Register::Ccr2,
Self::Ccr3 => tim1::Register::Ccr3,
Self::Ccr4 => tim1::Register::Ccr4,
Self::Ccr5 => tim1::Register::Ccr5,
Self::Ccr6 => tim1::Register::Ccr6,
Self::Bdtr => tim1::Register::Bdtr,
Self::Dcr => tim1::Register::Dcr,
Self::Dmar => tim1::Register::Dmar,
Self::Af1 => tim1::Register::Af1,
Self::Af2 => tim1::Register::Af2,
Self::Tisel => tim1::Register::Tisel,
}
}
pub(super) fn offset(self) -> u32 {
self.superset().spec().offset
}
pub(super) fn at(offset: u32) -> Option<Self> {
Self::ALL.into_iter().find(|slot| slot.offset() == offset)
}
pub(super) const fn index(self) -> usize {
self as usize
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub(super) struct Map {
rows: [Option<u8>; SLOTS],
slots: [Option<Slot>; ROWS],
}
impl Map {
pub(super) fn of<R: Layout>() -> Self {
let mut map = Self {
rows: [None; SLOTS],
slots: [None; ROWS],
};
for (row, spec) in R::REGISTERS.iter().enumerate() {
let slot = Slot::at(spec.offset);
map.slots[row] = slot;
if let Some(slot) = slot
&& map.rows[slot.index()].is_none()
{
map.rows[slot.index()] = u8::try_from(row).ok();
}
}
map
}
pub(super) fn row(&self, slot: Slot) -> Option<usize> {
self.rows[slot.index()].map(usize::from)
}
pub(super) fn slot(&self, row: usize) -> Option<Slot> {
self.slots.get(row).copied().flatten()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum Counter {
Narrow,
Wide,
}
impl Counter {
#[must_use]
pub const fn mask(self) -> u64 {
match self {
Self::Narrow => super::HALF_WORD,
Self::Wide => super::WORD,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum Kind {
Advanced,
General,
TwoChannelSlave,
OneChannel,
TwoChannelBreak,
OneChannelBreak,
Basic,
}
impl Kind {
#[must_use]
pub const fn channels(self) -> u8 {
match self {
Self::Advanced => 6,
Self::General => 4,
Self::TwoChannelSlave | Self::TwoChannelBreak => 2,
Self::OneChannel | Self::OneChannelBreak => 1,
Self::Basic => 0,
}
}
pub(super) const fn up_down(self) -> bool {
matches!(self, Self::Advanced | Self::General)
}
pub(super) const fn external_trigger(self) -> bool {
matches!(self, Self::Advanced | Self::General)
}
pub(super) const fn slave(self) -> bool {
matches!(
self,
Self::Advanced | Self::General | Self::TwoChannelSlave | Self::TwoChannelBreak
)
}
pub(super) const fn master(self) -> bool {
matches!(
self,
Self::Advanced
| Self::General
| Self::TwoChannelSlave
| Self::TwoChannelBreak
| Self::Basic
)
}
pub(super) const fn dma(self) -> bool {
!matches!(self, Self::TwoChannelSlave | Self::OneChannel)
}
pub(super) const fn repetition(self) -> bool {
matches!(
self,
Self::Advanced | Self::TwoChannelBreak | Self::OneChannelBreak
)
}
pub(super) const fn breaks(self) -> usize {
match self {
Self::Advanced => 2,
Self::TwoChannelBreak | Self::OneChannelBreak => 1,
_ => 0,
}
}
pub(super) const fn complementary(self) -> usize {
match self {
Self::Advanced => 3,
Self::TwoChannelBreak | Self::OneChannelBreak => 1,
_ => 0,
}
}
pub(super) const fn xor_inputs(self) -> usize {
match self {
Self::Advanced | Self::General => 3,
Self::TwoChannelSlave | Self::TwoChannelBreak => 2,
_ => 0,
}
}
pub(super) const fn system_break_flag(self) -> bool {
matches!(self, Self::Advanced)
}
pub(super) const fn has_mode(self, mode: u64) -> bool {
match mode {
0..=7 => true,
8 | 9 | 12 | 13 => matches!(
self,
Self::Advanced | Self::General | Self::TwoChannelSlave | Self::TwoChannelBreak
),
14 | 15 => matches!(self, Self::Advanced | Self::General),
_ => false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Timer {
pub instance: &'static str,
pub counter: Counter,
pub kind: Kind,
}
impl Timer {
const fn new(instance: &'static str, counter: Counter, kind: Kind) -> Self {
Self {
instance,
counter,
kind,
}
}
}
pub const TIMERS: [Timer; 7] = [
Timer::new("TIM2", Counter::Wide, Kind::General),
Timer::new("TIM3", Counter::Narrow, Kind::General),
Timer::new("TIM4", Counter::Narrow, Kind::General),
Timer::new("TIM5", Counter::Wide, Kind::General),
Timer::new("TIM12", Counter::Narrow, Kind::TwoChannelSlave),
Timer::new("TIM13", Counter::Narrow, Kind::OneChannel),
Timer::new("TIM14", Counter::Narrow, Kind::OneChannel),
];
pub const ADVANCED_TIMERS: [Timer; 2] = [
Timer::new("TIM1", Counter::Narrow, Kind::Advanced),
Timer::new("TIM8", Counter::Narrow, Kind::Advanced),
];
pub const BASIC_TIMERS: [Timer; 2] = [
Timer::new("TIM6", Counter::Narrow, Kind::Basic),
Timer::new("TIM7", Counter::Narrow, Kind::Basic),
];
pub const TIMER_15: Timer = Timer::new("TIM15", Counter::Narrow, Kind::TwoChannelBreak);
pub const TIMER_16: Timer = Timer::new("TIM16", Counter::Narrow, Kind::OneChannelBreak);
pub const TIMER_17: Timer = Timer::new("TIM17", Counter::Narrow, Kind::OneChannelBreak);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Flags {
Break,
Update,
TriggerAndCommutation,
CaptureCompare,
}
pub trait Family: fmt::Debug + Copy + Send + Sync + 'static {
type Register: Layout + Send;
const KINDS: &'static [Kind];
const LINES: usize = 1;
fn line(_: Flags) -> usize {
GLOBAL
}
}
#[derive(Debug, Clone, Copy)]
pub struct General;
#[derive(Debug, Clone, Copy)]
pub struct Advanced;
#[derive(Debug, Clone, Copy)]
pub struct Basic;
#[derive(Debug, Clone, Copy)]
pub struct Tim15;
#[derive(Debug, Clone, Copy)]
pub struct Tim16;
#[derive(Debug, Clone, Copy)]
pub struct Tim17;
const BREAK: usize = 0;
const UPDATE: usize = 1;
const TRIGGER_AND_COMMUTATION: usize = 2;
const CAPTURE_COMPARE: usize = 3;
const GLOBAL: usize = 0;
impl Family for General {
type Register = tim2::Register;
const KINDS: &'static [Kind] = &[Kind::General, Kind::TwoChannelSlave, Kind::OneChannel];
}
impl Family for Advanced {
type Register = tim1::Register;
const KINDS: &'static [Kind] = &[Kind::Advanced];
const LINES: usize = 4;
fn line(flags: Flags) -> usize {
match flags {
Flags::Break => BREAK,
Flags::Update => UPDATE,
Flags::TriggerAndCommutation => TRIGGER_AND_COMMUTATION,
Flags::CaptureCompare => CAPTURE_COMPARE,
}
}
}
impl Family for Basic {
type Register = tim6::Register;
const KINDS: &'static [Kind] = &[Kind::Basic];
}
impl Family for Tim15 {
type Register = tim15::Register;
const KINDS: &'static [Kind] = &[Kind::TwoChannelBreak];
}
impl Family for Tim16 {
type Register = tim16::Register;
const KINDS: &'static [Kind] = &[Kind::OneChannelBreak];
}
impl Family for Tim17 {
type Register = tim17::Register;
const KINDS: &'static [Kind] = &[Kind::OneChannelBreak];
}
pub const UPDATE_REQUEST: usize = 0;
pub const CHANNEL_REQUESTS: [usize; 4] = [1, 2, 3, 4];
pub const TRIGGER_REQUEST: usize = 5;
pub const COMMUTATION_REQUEST: usize = 6;
#[cfg(test)]
mod tests {
use super::*;
use crate::soc::{FieldSpec, RegisterSpec};
fn layouts() -> [(&'static str, &'static [RegisterSpec]); 6] {
[
("tim1", <tim1::Register as Layout>::REGISTERS),
("tim2", <tim2::Register as Layout>::REGISTERS),
("tim6", <tim6::Register as Layout>::REGISTERS),
("tim15", <tim15::Register as Layout>::REGISTERS),
("tim16", <tim16::Register as Layout>::REGISTERS),
("tim17", <tim17::Register as Layout>::REGISTERS),
]
}
#[test]
fn the_slots_are_the_advanced_timers_registers_in_offset_order() {
let offsets: Vec<u32> = Slot::ALL.iter().map(|slot| slot.offset()).collect();
let mut sorted = offsets.clone();
sorted.sort_unstable();
sorted.dedup();
assert_eq!(offsets, sorted, "ascending and distinct");
let distinct: std::collections::BTreeSet<u32> = tim1::REGISTERS
.iter()
.map(|register| register.offset)
.collect();
assert_eq!(
distinct.len(),
SLOTS,
"a slot for every offset of the advanced timer's table, the two views of a mode register one"
);
}
#[test]
fn every_row_of_every_layout_is_a_slot_at_its_offset() {
assert_eq!(tim1::REGISTERS.len(), ROWS);
for (name, table) in layouts() {
assert!(table.len() <= ROWS, "{name}");
for (row, register) in table.iter().enumerate() {
let slot = Slot::at(register.offset)
.unwrap_or_else(|| panic!("{name} {} has no slot", register.name));
assert_eq!(slot.offset(), register.offset, "{name} {}", register.name);
assert!(row < ROWS);
}
}
let map = Map::of::<tim1::Register>();
assert_eq!(
map.row(Slot::Ccmr1),
Some(tim1::Register::Ccmr1Input.index())
);
assert_eq!(map.row(Slot::Ccr6), Some(tim1::Register::Ccr6.index()));
assert_eq!(
map.slot(tim1::Register::Ccmr1Output.index()),
Some(Slot::Ccmr1)
);
let basic = Map::of::<tim6::Register>();
assert_eq!(
basic.row(Slot::Smcr),
None,
"the basic timer has no slave mode controller"
);
assert_eq!(basic.row(Slot::Cnt), Some(tim6::Register::Cnt.index()));
let small = Map::of::<tim16::Register>();
assert_eq!(small.row(Slot::Ccr2), None);
assert_eq!(
small.row(Slot::Af1),
Some(tim16::Register::Tim16Af1.index())
);
}
fn field_of(
table: &'static [RegisterSpec],
register: &str,
name: &str,
) -> Option<&'static FieldSpec> {
table
.iter()
.find(|candidate| candidate.name == register)?
.fields
.iter()
.find(|field| field.name == name)
}
#[test]
fn a_field_the_layouts_share_sits_at_the_same_bits_in_each() {
const RENAMED: [(&str, &str, &str, &str); 3] = [
("tim2", "CCMR2_Output", "O24CE", "OC4CE"),
("tim15", "SMCR", "TS_2_0", "TS"),
("tim1", "CCMR2_Output", "OC4M_4", "OC4M_3"),
];
let mut compared = 0;
for (name, table) in layouts() {
if name == "tim1" {
continue;
}
for register in table {
let Some(twin) = tim1::REGISTERS.iter().find(|candidate| {
candidate.offset == register.offset
&& candidate.name.split('_').next() == register.name.split('_').next()
}) else {
continue;
};
for field in register.fields {
let renamed = RENAMED
.iter()
.find(|(layout, owner, from, _)| {
*layout == name && *owner == register.name && *from == field.name
})
.map(|(_, _, _, to)| *to);
let wanted = renamed.unwrap_or(field.name);
let Some(counterpart) = twin
.fields
.iter()
.find(|candidate| candidate.name == wanted)
else {
continue;
};
assert_eq!(
(field.bit, field.width),
(counterpart.bit, counterpart.width),
"{name} {}.{}",
register.name,
field.name
);
compared += 1;
}
}
}
assert!(compared > 150, "{compared} fields compared");
assert!(field_of(tim1::REGISTERS.as_slice(), "SMCR", "TS_4_3").is_some());
}
#[test]
fn each_kind_belongs_to_the_family_whose_layout_has_its_channels() {
fn channels<F: Family>() -> Vec<(Kind, usize)> {
F::KINDS
.iter()
.map(|kind| {
let capture = <F::Register as Layout>::REGISTERS
.iter()
.filter(|register| {
(13..=16).contains(&(register.offset / 4))
|| (22..=23).contains(&(register.offset / 4))
})
.count();
(*kind, capture)
})
.collect()
}
for (kind, registers) in channels::<Advanced>() {
assert_eq!(registers, usize::from(kind.channels()), "{kind:?}");
}
for (kind, registers) in channels::<General>() {
assert!(registers >= usize::from(kind.channels()), "{kind:?}");
}
for (kind, registers) in channels::<Tim15>() {
assert_eq!(registers, usize::from(kind.channels()), "{kind:?}");
}
for (kind, registers) in channels::<Tim16>() {
assert_eq!(registers, usize::from(kind.channels()), "{kind:?}");
}
for (kind, registers) in channels::<Basic>() {
assert_eq!(registers, usize::from(kind.channels()), "{kind:?}");
}
let every: Vec<Kind> = [
General::KINDS,
Advanced::KINDS,
Basic::KINDS,
Tim15::KINDS,
Tim16::KINDS,
Tim17::KINDS,
]
.concat();
for kind in [
Kind::Advanced,
Kind::General,
Kind::TwoChannelSlave,
Kind::OneChannel,
Kind::TwoChannelBreak,
Kind::OneChannelBreak,
Kind::Basic,
] {
assert!(every.contains(&kind), "{kind:?} has a family");
}
}
#[test]
fn the_instance_tables_name_the_fourteen_timers_once() {
let mut names: Vec<&str> = TIMERS
.iter()
.chain(&ADVANCED_TIMERS)
.chain(&BASIC_TIMERS)
.chain([&TIMER_15, &TIMER_16, &TIMER_17])
.map(|timer| timer.instance)
.collect();
assert_eq!(names.len(), 14, "TIM9 to TIM11 are not in this part");
names.sort_unstable();
names.dedup();
assert_eq!(names.len(), 14);
let wide: Vec<&str> = TIMERS
.iter()
.filter(|timer| timer.counter == Counter::Wide)
.map(|timer| timer.instance)
.collect();
assert_eq!(wide, ["TIM2", "TIM5"], "39.2");
for timer in TIMERS {
assert!(General::KINDS.contains(&timer.kind));
}
}
}