use crate::device::{Device, DeviceContext, Level, RegisterFile, RequestChange};
use crate::soc::{Layout, RegisterSpec};
use crate::time::{EventId, VirtualNanos};
use super::count::TriggerEvent;
use super::family::{
CHANNEL_REQUESTS, COMMUTATION_REQUEST, Family, Slot, TRIGGER_REQUEST, UPDATE_REQUEST,
};
use super::fields::{
CCS_OUTPUT, CMS_EDGE_ALIGNED, LOCK_LEVEL_2, LOCK_LEVEL_3, OCM_FORCE_ACTIVE, OCM_FORCE_INACTIVE,
OCM_FROZEN, OCM_RETRIGGERABLE_1, OCM_RETRIGGERABLE_2, SMS_ENCODER_1, SMS_ENCODER_2,
SMS_ENCODER_3,
};
use super::{Channel, Direction, Epoch, Tim, UpdateSource, present};
impl<F: Family> Tim<F> {
fn channel_of(slot: Slot) -> Option<Channel> {
Some(Channel(match slot {
Slot::Ccr1 => 0,
Slot::Ccr2 => 1,
Slot::Ccr3 => 2,
Slot::Ccr4 => 3,
Slot::Ccr5 => 4,
Slot::Ccr6 => 5,
_ => return None,
}))
}
pub(super) fn has_channel(&self, channel: Channel) -> bool {
channel.index() < usize::from(self.kind.channels())
}
fn burst_slot(&self, registers: &RegisterFile) -> Option<Slot> {
let control = self.reg(registers, Slot::Dcr);
let index = self.burst_index % (Self::DBL.get(control) + 1);
let word = Self::DBA.get(control) + index;
Self::slot_at(u32::try_from(4 * word).ok()?)
}
fn burst_step(&mut self, registers: &RegisterFile) -> Option<F::Register> {
let target = self
.burst_slot(registers)
.filter(|slot| *slot != Slot::Dmar)
.and_then(|slot| self.own(slot));
self.count_transfer(registers);
target
}
fn count_transfer(&mut self, registers: &RegisterFile) {
let length = Self::DBL.get(self.reg(registers, Slot::Dcr)) + 1;
self.burst_index = (self.burst_index % length + 1) % length;
if self.burst_index == 0 {
for output in [UPDATE_REQUEST, TRIGGER_REQUEST, COMMUTATION_REQUEST] {
self.requested[output] = false;
}
}
}
pub fn acknowledge(
&mut self,
output: usize,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
self.settle(registers, context);
match output {
UPDATE_REQUEST | TRIGGER_REQUEST | COMMUTATION_REQUEST => {
if Self::DBL.get(self.reg(registers, Slot::Dcr)) == 0 {
self.count_transfer(registers);
}
}
_ => {
if let Some(standing) = self.requested.get_mut(output) {
*standing = false;
}
}
}
self.finish(registers, context);
}
fn write_cr1(&mut self, value: u64, registers: &mut RegisterFile, context: &DeviceContext<'_>) {
if self.kind.up_down() {
let center = Self::CMS.get(value) != CMS_EDGE_ALIGNED;
let encoder = matches!(
self.sms(registers),
SMS_ENCODER_1 | SMS_ENCODER_2 | SMS_ENCODER_3
);
if center || encoder {
self.set_direction_bit(registers);
} else {
let direction = if Self::DIR.is_set(value) {
Direction::Down
} else {
Direction::Up
};
if direction != self.direction {
let count = self.count_now(context.now());
self.direction = direction;
self.set_count(count, context);
self.note_pins(self.clock_cycle(context.now()), registers);
}
}
} else {
let cleared = Self::DIR.set(Self::CMS.set(value, 0), 0);
self.put(registers, Slot::Cr1, cleared);
}
let arr = self.reg(registers, Slot::Arr) & self.width.mask();
if !Self::ARPE.is_set(value) && arr != self.arr {
self.rebase(context);
self.arr = arr;
}
}
fn write_egr(
&mut self,
value: u64,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
if Self::UG.is_set(value) {
let cycle = self.counter_cycle(context.now());
self.update(UpdateSource::Software, cycle, registers, context);
self.matches_at_segment_start(Some(self.direction), registers);
self.trigger_pulse(registers, TriggerEvent::Reset);
}
for channel in present(self.kind.channels().min(4)) {
if Self::CC_G[channel.index()].is_set(value) {
if self.channel_selection(channel, registers) == CCS_OUTPUT {
self.flag_compare(channel, registers);
} else {
let count = self.count_now(context.now());
self.put(registers, channel.ccr(), count);
self.channels[channel.index()].shadow = count;
self.flag_capture(channel, registers);
}
}
}
if self.kind.slave() && Self::TG.is_set(value) {
self.flag_trigger(registers);
}
if self.kind.complementary() > 0 && Self::COMG.is_set(value) {
self.commutate(registers, context);
}
if Self::BG.is_set(value) {
self.software_break(0, registers);
}
if Self::B2G.is_set(value) {
self.software_break(1, registers);
}
self.put(registers, Slot::Egr, 0);
}
fn write_ccmr(
&mut self,
slot: Slot,
before: u64,
registers: &mut RegisterFile,
context: &DeviceContext<'_>,
) {
let first = Channel(match slot {
Slot::Ccmr1 => 0,
Slot::Ccmr2 => 2,
_ => 4,
});
let pair = [first, first.partner()];
let previous = pair.map(|channel| {
let mode = Self::OC_M[channel.index()].get(before);
if self.kind.has_mode(mode) {
mode
} else {
OCM_FROZEN
}
});
let ccer_value = self.ccer(registers);
let locked = self.lock_level(registers) >= LOCK_LEVEL_3;
let mut held = self.reg(registers, slot);
for channel in pair {
let index = channel.index();
if channel.has_input() && Self::CC_E[index].is_set(ccer_value) {
held = Self::CC_S[index].set(held, self.channels[index].selection);
}
if locked && self.channels[index].selection == CCS_OUTPUT {
held = Self::OC_M[index].set(held, Self::OC_M[index].get(before));
held = Self::OC_PE[index].set(held, Self::OC_PE[index].get(before));
}
}
self.put(registers, slot, held);
let cycle = self.counter_cycle(context.now());
let clock = self.clock_cycle(context.now());
for (channel, was) in pair.into_iter().zip(previous) {
if !self.has_channel(channel) {
continue;
}
let index = channel.index();
let selection = self.channel_selection(channel, registers);
if selection == CCS_OUTPUT
&& !Self::OC_PE[index].is_set(self.control(channel, registers))
{
self.channels[index].shadow =
self.reg(registers, channel.ccr()) & self.width.mask();
}
self.channels[index].selection = selection;
let mode = self.output_mode(channel, registers);
match mode {
OCM_FORCE_ACTIVE => self.set_reference(channel, true, clock, registers),
OCM_FORCE_INACTIVE => self.set_reference(channel, false, clock, registers),
OCM_RETRIGGERABLE_1 | OCM_RETRIGGERABLE_2 if mode != was => {
self.channels[index].armed = true;
}
_ => {}
}
self.refresh_pwm(channel, cycle, registers);
}
}
fn write_ccer(
&mut self,
before: u64,
registers: &mut RegisterFile,
context: &DeviceContext<'_>,
) {
if self.lock_level(registers) >= LOCK_LEVEL_2 {
let mut mask = 0;
for channel in present(self.kind.channels().min(4)) {
if self.channel_selection(channel, registers) == CCS_OUTPUT {
mask |=
Self::CC_P[channel.index()].mask() | Self::CC_NP[channel.index()].mask();
}
}
self.keep(registers, Slot::Ccer, mask, before);
}
let cycle = self.counter_cycle(context.now());
let ccer_value = self.ccer(registers);
for channel in present(self.kind.channels()) {
if !Self::CC_E[channel.index()].is_set(ccer_value) {
self.channels[channel.index()].prescaled_edges = 0;
}
self.refresh_pwm(channel, cycle, registers);
}
}
fn write_ccr(&mut self, channel: Channel, registers: &mut RegisterFile) {
if channel.has_input() && self.channel_selection(channel, registers) != CCS_OUTPUT {
self.put(
registers,
channel.ccr(),
self.channels[channel.index()].shadow,
);
return;
}
if !Self::OC_PE[channel.index()].is_set(self.control(channel, registers)) {
self.channels[channel.index()].shadow =
self.reg(registers, channel.ccr()) & self.width.mask();
}
if channel.index() == 4 {
self.load_group(registers, false);
}
}
fn settle_before_write(
&mut self,
register: F::Register,
written: u64,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
let Some(slot) = self.map.slot(register.index()) else {
return;
};
if matches!(
slot,
Slot::Cr1 | Slot::Bdtr | Slot::Sr | Slot::Egr | Slot::Cnt | Slot::Dmar
) {
self.settle(registers, context);
if slot == Slot::Sr {
let settled = registers.get(register);
registers.set(register, settled & written);
}
return;
}
let landed = registers.get(register);
registers.set(register, self.power.kept[slot.index()]);
self.settle(registers, context);
registers.set(register, landed);
}
}
impl<F: Family> Device for Tim<F> {
type Register = F::Register;
fn layout(&self) -> &'static [RegisterSpec] {
F::layout(self.width)
}
fn read(
&mut self,
register: F::Register,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) -> Option<u64> {
self.settle(registers, context);
let slot = self.map.slot(register.index());
let answer = match slot {
Some(Slot::Cnt) => Some(self.count_register(registers, context.now())),
Some(Slot::Dmar) if self.kind.dma() => match self.burst_step(registers) {
Some(target) => {
let answer = self.read(target, registers, context);
Some(answer.unwrap_or_else(|| registers.get(target)))
}
None => Some(0),
},
Some(slot) => {
if let Some(channel) = Self::channel_of(slot)
&& channel.has_input()
{
self.requested[CHANNEL_REQUESTS[channel.index()]] = false;
}
let channel = Self::channel_of(slot).filter(|channel| {
channel.has_input()
&& self.has_channel(*channel)
&& self.channel_selection(*channel, registers) != CCS_OUTPUT
});
if let Some(channel) = channel {
let status = self.reg(registers, Slot::Sr);
self.put(
registers,
Slot::Sr,
Self::CC_IF[channel.index()].set(status, 0),
);
}
None
}
None => None,
};
self.finish(registers, context);
answer
}
fn peek(
&self,
register: F::Register,
registers: &RegisterFile,
now: VirtualNanos,
) -> Option<u64> {
match self.map.slot(register.index()) {
Some(Slot::Cnt) => Some(self.count_register(registers, now)),
Some(Slot::Dmar) if self.kind.dma() => Some(
self.burst_slot(registers)
.filter(|slot| *slot != Slot::Dmar)
.and_then(|slot| self.own(slot))
.map_or(0, |target| {
self.peek(target, registers, now)
.unwrap_or_else(|| registers.get(target))
}),
),
_ => None,
}
}
fn write(
&mut self,
register: F::Register,
value: u64,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
let Some(slot) = self.map.slot(register.index()) else {
self.settle(registers, context);
return;
};
let before = self.power.kept[slot.index()];
let value = match slot {
Slot::Cnt
| Slot::Arr
| Slot::Ccr1
| Slot::Ccr2
| Slot::Ccr3
| Slot::Ccr4
| Slot::Ccr6 => {
let narrowed = value & self.width.mask();
registers.set(register, narrowed);
narrowed
}
Slot::Ccr5 => {
let narrowed = value & (self.width.mask() | Self::GROUP_MASK);
registers.set(register, narrowed);
narrowed
}
_ => value,
};
self.settle_before_write(register, value, registers, context);
match slot {
Slot::Cr1 => {
let was_counting = self.counting;
self.write_cr1(value, registers, context);
let counting = self.should_count(registers);
self.set_counting(counting, context);
if counting && !was_counting {
self.matches_at_segment_start(Some(self.direction), registers);
}
}
Slot::Cr2 => self.write_cr2(before, registers, context),
Slot::Smcr => self.write_smcr(registers, context),
Slot::Egr => self.write_egr(value, registers, context),
Slot::Ccmr1 | Slot::Ccmr2 | Slot::Ccmr3 => {
self.write_ccmr(slot, before, registers, context);
}
Slot::Ccer => self.write_ccer(before, registers, context),
Slot::Cnt => {
self.set_count(value, context);
self.matches_at_segment_start(Some(self.direction), registers);
}
Slot::Arr => {
if !Self::ARPE.is_set(self.reg(registers, Slot::Cr1)) && value != self.arr {
self.rebase(context);
self.arr = value;
}
}
Slot::Ccr1 | Slot::Ccr2 | Slot::Ccr3 | Slot::Ccr4 | Slot::Ccr5 | Slot::Ccr6 => {
if let Some(channel) = Self::channel_of(slot).filter(|c| self.has_channel(*c)) {
if channel.has_input() {
self.requested[CHANNEL_REQUESTS[channel.index()]] = false;
}
self.rebase(context);
self.write_ccr(channel, registers);
let cycle = self.counter_cycle(context.now());
self.refresh_pwm(channel, cycle, registers);
}
}
Slot::Dmar if self.kind.dma() => {
if let Some(target) = self.burst_step(registers) {
registers.write_over_bus(target, value);
self.write(target, value, registers, context);
return;
}
}
Slot::Bdtr => self.write_bdtr(before, registers),
Slot::Af1 | Slot::Af2 => {
self.write_alternate(slot, before, registers);
self.write_selections(registers, context);
}
Slot::Tisel => self.write_selections(registers, context),
_ => {}
}
self.power.kept[slot.index()] = registers.get(register);
self.finish(registers, context);
}
fn on_clock(&mut self, hz: u64, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
let now = context.now();
self.settle(registers, context);
self.epoch = Epoch {
at: now,
cycle: self.clock_cycle(now),
};
self.clock_hz = hz;
self.finish(registers, context);
}
fn on_event(
&mut self,
event: EventId,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
if self.wakeup.map(|(_, id)| id) != Some(event) {
return;
}
self.settle(registers, context);
self.finish(registers, context);
}
fn on_request(
&mut self,
change: RequestChange,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
let acknowledged = F::PART
.acknowledged
.zip(self.name[0])
.and_then(|(acknowledged, name)| acknowledged(name, &change));
if let Some(request) = acknowledged {
self.acknowledge(request, registers, context);
return;
}
let wired = self
.system_breaks
.iter()
.any(|(instance, request)| *instance == change.instance && *request == change.request);
if !wired || change.level != Level::High {
return;
}
self.settle(registers, context);
self.system_break(registers);
self.finish(registers, context);
}
fn reset(&mut self) {
let mut fresh = Self::build(self.clock_hz, self.width, self.kind);
fresh.epoch = self.epoch;
fresh.sources = self.sources;
fresh.system_breaks = std::mem::take(&mut self.system_breaks);
fresh.name = self.name;
for (channel, input) in fresh.inputs.iter_mut().enumerate() {
input.level = fresh.sources.ti[channel][0];
input.filtered = input.level;
}
*self = fresh;
}
fn reset_line(&mut self, _registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
context.lower_requests(&self.driven);
self.reset();
}
}