use std::fmt;
use crate::device::{Level, RequestChange};
use crate::soc::{Layout, RegisterSpec, find_row};
pub(crate) const ROWS: usize = 28;
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub(crate) enum Slot {
Cr1,
Cr2,
Smcr,
Dier,
Sr,
Egr,
Ccmr1,
Ccmr2,
Ccer,
Cnt,
Psc,
Arr,
Rcr,
Ccr1,
Ccr2,
Ccr3,
Ccr4,
Bdtr,
Dcr,
Dmar,
Or,
Ccmr3,
Ccr5,
Ccr6,
Af1,
Af2,
Tisel,
}
pub(crate) const SLOTS: usize = 27;
impl Slot {
pub(crate) 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::Or,
Self::Ccmr3,
Self::Ccr5,
Self::Ccr6,
Self::Af1,
Self::Af2,
Self::Tisel,
];
const fn name(self) -> &'static str {
match self {
Self::Cr1 => "CR1",
Self::Cr2 => "CR2",
Self::Smcr => "SMCR",
Self::Dier => "DIER",
Self::Sr => "SR",
Self::Egr => "EGR",
Self::Ccmr1 => "CCMR1_Input",
Self::Ccmr2 => "CCMR2_Input",
Self::Ccer => "CCER",
Self::Cnt => "CNT",
Self::Psc => "PSC",
Self::Arr => "ARR",
Self::Rcr => "RCR",
Self::Ccr1 => "CCR1",
Self::Ccr2 => "CCR2",
Self::Ccr3 => "CCR3",
Self::Ccr4 => "CCR4",
Self::Bdtr => "BDTR",
Self::Dcr => "DCR",
Self::Dmar => "DMAR",
Self::Or => "OR",
Self::Ccmr3 => "CCMR3_Output",
Self::Ccr5 => "CCR5",
Self::Ccr6 => "CCR6",
Self::Af1 => "AF1",
Self::Af2 => "AF2",
Self::Tisel => "TISEL",
}
}
pub(crate) const fn index(self) -> usize {
self as usize
}
}
pub(crate) const fn offsets(part: &Part) -> [Option<u32>; SLOTS] {
let mut offsets = [None; SLOTS];
let mut slot = 0;
while slot < SLOTS {
let name = Slot::ALL[slot].name();
let mut table = 0;
while table < part.tables.len() && offsets[slot].is_none() {
if let Some(row) = find_row(part.tables[table], name) {
offsets[slot] = Some(part.tables[table][row].offset);
}
table += 1;
}
slot += 1;
}
offsets
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub(crate) struct Map {
rows: [Option<u8>; SLOTS],
slots: [Option<Slot>; ROWS],
}
impl Map {
pub(crate) fn of(table: &[RegisterSpec], offsets: &[Option<u32>; SLOTS]) -> Self {
let mut map = Self {
rows: [None; SLOTS],
slots: [None; ROWS],
};
for (row, spec) in table.iter().enumerate() {
let slot = Slot::ALL
.into_iter()
.find(|slot| offsets[slot.index()] == Some(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(crate) fn row(&self, slot: Slot) -> Option<usize> {
self.rows[slot.index()].map(usize::from)
}
pub(crate) 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,
FourChannelBreak,
General,
TwoChannelSlave,
OneChannel,
TwoChannelBreak,
OneChannelBreak,
Basic,
}
impl Kind {
#[must_use]
pub const fn channels(self) -> u8 {
match self {
Self::Advanced => 6,
Self::FourChannelBreak | 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::FourChannelBreak | Self::General
)
}
pub(super) const fn external_trigger(self) -> bool {
self.up_down()
}
pub(super) const fn slave(self) -> bool {
matches!(
self,
Self::Advanced
| Self::FourChannelBreak
| Self::General
| Self::TwoChannelSlave
| Self::TwoChannelBreak
)
}
pub(super) const fn master(self) -> bool {
self.slave() || matches!(self, Self::Basic)
}
pub(super) const fn dma(self) -> bool {
!matches!(self, Self::TwoChannelSlave | Self::OneChannel)
}
pub(super) const fn repetition_mask(self) -> u64 {
match self {
Self::Advanced => super::HALF_WORD,
Self::FourChannelBreak | Self::TwoChannelBreak | Self::OneChannelBreak => {
super::fields::BYTE
}
_ => 0,
}
}
pub(super) const fn breaks(self) -> usize {
match self {
Self::Advanced => 2,
Self::FourChannelBreak | Self::TwoChannelBreak | Self::OneChannelBreak => 1,
_ => 0,
}
}
pub(super) const fn gathers_break_sources(self) -> bool {
matches!(
self,
Self::Advanced | Self::TwoChannelBreak | Self::OneChannelBreak
)
}
pub(super) const fn complementary(self) -> usize {
match self {
Self::Advanced | Self::FourChannelBreak => 3,
Self::TwoChannelBreak | Self::OneChannelBreak => 1,
_ => 0,
}
}
pub(super) const fn xor_inputs(self) -> usize {
match self {
Self::Advanced | Self::FourChannelBreak | 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 second_trigger(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 {
#[must_use]
pub const fn new(instance: &'static str, counter: Counter, kind: Kind) -> Self {
Self {
instance,
counter,
kind,
}
}
}
pub trait Instance: Copy {
fn counter(self) -> Counter;
fn kind(self) -> Option<Kind>;
fn name(self) -> Option<&'static str>;
}
impl Instance for Timer {
fn counter(self) -> Counter {
self.counter
}
fn kind(self) -> Option<Kind> {
Some(self.kind)
}
fn name(self) -> Option<&'static str> {
Some(self.instance)
}
}
impl Instance for Counter {
fn counter(self) -> Counter {
self
}
fn kind(self) -> Option<Kind> {
None
}
fn name(self) -> Option<&'static str> {
None
}
}
#[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;
type Instance: Instance;
const PART: &'static Part;
const KINDS: &'static [Kind];
const LINES: usize = 1;
fn line(_: Flags) -> usize {
GLOBAL
}
fn layout(_counter: Counter) -> &'static [RegisterSpec] {
<Self::Register as Layout>::REGISTERS
}
}
#[derive(Debug)]
pub struct Part {
pub tables: &'static [&'static [RegisterSpec]],
pub spellings: &'static [Spelling],
pub wakeups: Wakeups,
pub break_pin: Option<Level>,
pub acknowledged: Option<fn(&str, &RequestChange) -> Option<usize>>,
pub errata: Errata,
}
#[derive(Debug)]
pub struct Spelling {
pub register: &'static str,
pub manual: &'static str,
pub file: &'static str,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Wakeups {
Every,
WhenSeen,
}
#[derive(Debug)]
pub struct Errata {
pub consecutive_compare_missed: bool,
pub clear_outlasts_reset: bool,
pub trigger_lost_at_reload: bool,
}
const GLOBAL: usize = 0;
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;