use std::marker::PhantomData;
use crate::device::{Level, RegisterFile};
use crate::soc::FieldSpec;
use crate::time::{EventId, VirtualNanos};
mod access;
mod breaks;
mod count;
pub(crate) mod family;
mod fields;
mod inputs;
mod outputs;
pub use family::{
CHANNEL_REQUESTS, COMMUTATION_REQUEST, Counter, Errata, Family, Flags, Instance, Kind, Part,
Spelling, TRIGGER_REQUEST, Timer, UPDATE_REQUEST, Wakeups,
};
use family::{Map, SLOTS, Slot, offsets};
const HALF_WORD: u64 = 0xFFFF;
const WORD: u64 = u32::MAX as u64;
const CHANNEL_COUNT: u8 = 6;
const CHANNELS: usize = CHANNEL_COUNT as usize;
const INPUTS: usize = 4;
const TI_SOURCES: usize = 16;
const ETR_SOURCES: usize = 16;
const BREAKS: usize = 2;
const BREAK_SOURCES: usize = 4;
const MAX_LINES: usize = 4;
const REQUESTS: usize = 7;
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
)]
pub struct Channel(u8);
impl Channel {
#[must_use]
pub const fn new(number: u8) -> Option<Self> {
if number >= 1 && number <= CHANNEL_COUNT {
Some(Self(number - 1))
} else {
None
}
}
#[must_use]
pub const fn number(self) -> u8 {
self.0 + 1
}
const fn index(self) -> usize {
self.0 as usize
}
const fn partner(self) -> Self {
Self(self.0 ^ 1)
}
const fn has_input(self) -> bool {
self.index() < INPUTS
}
const fn ccr(self) -> Slot {
[
Slot::Ccr1,
Slot::Ccr2,
Slot::Ccr3,
Slot::Ccr4,
Slot::Ccr5,
Slot::Ccr6,
][self.index()]
}
const fn ccmr(self) -> Slot {
[Slot::Ccmr1, Slot::Ccmr2, Slot::Ccmr3][self.index() / 2]
}
}
fn present(count: u8) -> impl Iterator<Item = Channel> {
(0..count).map(Channel)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BreakInput {
First,
Second,
}
impl BreakInput {
const fn index(self) -> usize {
self as usize
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BreakSource {
Pin,
Comparator1,
Comparator2,
Dfsdm,
}
impl BreakSource {
const fn index(self) -> usize {
self as usize
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
enum Direction {
Up,
Down,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
enum UpdateSource {
Overflow,
Underflow,
Software,
Trigger,
}
#[derive(Debug, Clone, Copy, Default, serde::Serialize, serde::Deserialize)]
struct Input {
level: Level,
filtered: Level,
pending: Option<(u128, Level)>,
}
#[derive(Debug, Clone, Copy, Default, serde::Serialize, serde::Deserialize)]
struct ChannelState {
shadow: u64,
reference: bool,
pin: Level,
pin_since: u128,
cleared_for_updates: u8,
matched_since_clear: bool,
armed: bool,
prescaled_edges: u64,
last_match: Option<(u128, u64)>,
selection: u64,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct DmaRequests {
pub update: u64,
pub channels: [u64; INPUTS],
pub trigger: u64,
pub commutation: u64,
}
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
struct Controls {
ccer: u64,
ccmr: [u64; 2],
}
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
struct Epoch {
at: VirtualNanos,
cycle: u128,
}
impl Default for Epoch {
fn default() -> Self {
Self {
at: VirtualNanos(0),
cycle: 0,
}
}
}
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
struct Sources {
ti: [[Level; TI_SOURCES]; INPUTS],
etr: [Level; ETR_SOURCES],
breaks: [[Option<Level>; BREAK_SOURCES]; BREAKS],
}
impl Sources {
fn at_rest(break_pin: Option<Level>) -> Self {
let mut breaks = [[None; BREAK_SOURCES]; BREAKS];
for input in &mut breaks {
input[BreakSource::Pin.index()] = break_pin;
}
Self {
ti: [[Level::Low; TI_SOURCES]; INPUTS],
etr: [Level::Low; ETR_SOURCES],
breaks,
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
struct PowerStage {
repetition: u64,
controls: Option<Controls>,
filters: [Input; BREAKS],
active: [bool; BREAKS],
lock_frozen: bool,
kept: [u64; SLOTS],
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum CounterEvent {
Boundary(UpdateSource),
Match(Match),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Match {
channel: Channel,
cycle: u128,
value: u64,
}
impl CounterEvent {
const fn order(self) -> u8 {
match self {
Self::Boundary(_) => 0,
Self::Match(..) => 1,
}
}
}
#[derive(Debug, Clone, Copy)]
enum FilterEvent {
Input(usize),
Etr,
Break(usize),
}
#[derive(Debug, Clone, Copy)]
enum Pending {
Counter(u128, CounterEvent),
Filter(FilterEvent),
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(bound(deserialize = "'de: 'static"))]
pub struct Tim<F: Family> {
family: PhantomData<F>,
width: Counter,
kind: Kind,
map: Map,
clock_hz: u64,
epoch: Epoch,
external: bool,
counting: bool,
paused: u128,
stopped_at: u128,
external_cycles: u128,
psc: u64,
arr: u64,
segment_cycle: u128,
segment_count: u64,
direction: Direction,
channels: [ChannelState; CHANNELS],
group: u64,
inputs: [Input; INPUTS],
sources: Sources,
etr_polarized: Level,
etr_edges: u64,
etr: Input,
trigger: Level,
trigger_output: Level,
trigger_pulses: u64,
trigger2_output: Level,
trigger2_pulses: u64,
dma_requests: DmaRequests,
requested: [bool; REQUESTS],
driven: [Level; REQUESTS],
burst_index: u64,
interrupts: [Level; MAX_LINES],
seen: VirtualNanos,
wakeup: Option<(VirtualNanos, EventId)>,
power: PowerStage,
system_breaks: Vec<(&'static str, usize)>,
name: [Option<&'static str>; 1],
}
impl<F: Family> Tim<F> {
const OFFSETS: [Option<u32>; SLOTS] = offsets(F::PART);
#[must_use]
pub fn with_clock(clock_hz: u64, instance: F::Instance) -> Self {
let kind = instance.kind().unwrap_or(F::KINDS[0]);
assert!(
F::KINDS.contains(&kind),
"{} is a {kind:?} timer, which {} does not carry",
instance.name().unwrap_or("the instance"),
std::any::type_name::<F>(),
);
let mut tim = Self::build(clock_hz, instance.counter(), kind);
tim.name = [instance.name()];
tim
}
fn build(clock_hz: u64, width: Counter, kind: Kind) -> Self {
Self {
family: PhantomData,
width,
kind,
map: Map::of(F::layout(width), &Self::OFFSETS),
clock_hz,
epoch: Epoch::default(),
external: false,
counting: false,
paused: 0,
stopped_at: 0,
external_cycles: 0,
psc: 0,
arr: width.mask(),
segment_cycle: 0,
segment_count: 0,
direction: Direction::Up,
channels: [ChannelState::default(); CHANNELS],
group: 0,
inputs: [Input::default(); INPUTS],
sources: Sources::at_rest(F::PART.break_pin),
etr_polarized: Level::Low,
etr_edges: 0,
etr: Input::default(),
trigger: Level::Low,
trigger_output: Level::Low,
trigger_pulses: 0,
trigger2_output: Level::Low,
trigger2_pulses: 0,
dma_requests: DmaRequests::default(),
requested: [false; REQUESTS],
driven: [Level::Low; REQUESTS],
burst_index: 0,
interrupts: [Level::Low; MAX_LINES],
seen: VirtualNanos(0),
wakeup: None,
power: PowerStage {
repetition: 0,
controls: None,
filters: [Input::default(); BREAKS],
active: [false; BREAKS],
lock_frozen: false,
kept: Self::reset_values(kind, width),
},
system_breaks: Vec::new(),
name: [None],
}
}
fn reset_values(kind: Kind, width: Counter) -> [u64; SLOTS] {
let mut kept = [0; SLOTS];
kept[Slot::Arr.index()] = width.mask();
if kind.gathers_break_sources() {
kept[Slot::Af1.index()] = Self::BKINE.mask();
kept[Slot::Af2.index()] = Self::BK2INE.mask();
}
kept
}
#[must_use]
pub fn breaks_on(mut self, instance: &'static str, request: usize) -> Self {
self.system_breaks.push((instance, request));
self
}
fn slot_at(offset: u32) -> Option<Slot> {
Slot::ALL
.into_iter()
.find(|slot| Self::OFFSETS[slot.index()] == Some(offset))
}
fn own(&self, slot: Slot) -> Option<F::Register> {
self.map
.row(slot)
.and_then(<F::Register as crate::soc::Layout>::from_index)
}
fn reg(&self, registers: &RegisterFile, slot: Slot) -> u64 {
self.own(slot).map_or(0, |own| registers.get(own))
}
fn put(&self, registers: &mut RegisterFile, slot: Slot, value: u64) {
if let Some(own) = self.own(slot) {
registers.set(own, value);
}
}
fn flag(&self, registers: &mut RegisterFile, field: &FieldSpec) {
let status = self.reg(registers, Slot::Sr);
self.put(registers, Slot::Sr, field.set(status, 1));
}
fn count_register(&self, registers: &RegisterFile, now: VirtualNanos) -> u64 {
let count = self.count_now(now);
if Self::UIFREMAP.is_set(self.reg(registers, Slot::Cr1)) {
let copy = u64::from(Self::UIF.is_set(self.reg(registers, Slot::Sr)));
Self::UIFCPY.set(count, copy)
} else {
count
}
}
#[must_use]
pub fn trigger_output(&self) -> (Level, u64) {
(self.trigger_output, self.trigger_pulses)
}
#[must_use]
pub fn trigger2_output(&self) -> (Level, u64) {
(self.trigger2_output, self.trigger2_pulses)
}
#[must_use]
pub fn dma_requests(&self) -> DmaRequests {
self.dma_requests
}
}