use std::any::Any;
use std::collections::VecDeque;
use crate::chip::uart::Peer;
use crate::device::{Device, DeviceContext, Level, RegisterFile};
use crate::soc::RegisterSpec;
use crate::soc::stm32f427::generated::{uart4, usart6};
use crate::time::{EventId, VirtualNanos};
use usart6::{Register, cr1, cr2, cr3, sr};
pub const RECEIVE_REQUEST: usize = 0;
pub const TRANSMIT_REQUEST: usize = 1;
const GLOBAL: usize = 0;
const NANOS_PER_SECOND: u128 = 1_000_000_000;
const REMEMBERED: usize = 64;
const EIGHT_BITS: u16 = 0xFF;
const NINE_BITS: u16 = 0x1FF;
const CLEARED_BY_ZERO: u64 = sr::CTS.mask() | sr::LBD.mask() | sr::TC.mask() | sr::RXNE.mask();
const CLEARED_BY_READING: u64 =
sr::IDLE.mask() | sr::ORE.mask() | sr::NF.mask() | sr::FE.mask() | sr::PE.mask();
const STOP_HALF_BITS: [u64; 4] = [2, 1, 4, 3];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Kind {
Usart,
Uart,
}
impl Kind {
#[must_use]
pub const fn layout(self) -> &'static [RegisterSpec] {
match self {
Self::Usart => &usart6::REGISTERS,
Self::Uart => &uart4::REGISTERS,
}
}
}
#[derive(Debug, Default)]
pub struct Pattern {
answers: VecDeque<u16>,
received: Vec<u16>,
}
impl Pattern {
#[must_use]
pub fn answering(words: impl IntoIterator<Item = u16>) -> Self {
Self {
answers: words.into_iter().collect(),
received: Vec::new(),
}
}
}
impl Peer for Pattern {
fn receive(&mut self, word: u16, _context: &DeviceContext<'_>) {
self.received.push(word);
}
fn transmit(&mut self, _now: VirtualNanos) -> Option<u16> {
self.answers.pop_front()
}
fn received(&self) -> &[u16] {
&self.received
}
}
#[derive(Debug, Clone, Copy)]
struct Frame {
event: EventId,
kind: FrameKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum FrameKind {
Data(u16),
Idle,
Break,
}
#[derive(Debug, Clone, Copy)]
struct Run {
ends: VirtualNanos,
carry: u64,
}
#[derive(Debug)]
pub struct Usart {
kind: Kind,
clock_hz: u64,
peer: Option<Box<dyn Peer>>,
status: u64,
holding: Option<u16>,
sending: Option<Frame>,
sent: VecDeque<u16>,
receiving: Option<Frame>,
received: u16,
idle: Option<EventId>,
idle_armed: bool,
status_read: bool,
outgoing: Option<Run>,
incoming: Option<Run>,
interrupt: Level,
requests: [Level; 2],
control: u64,
}
impl Usart {
#[must_use]
pub fn with_clock(kind: Kind, clock_hz: u64) -> Self {
Self {
kind,
clock_hz,
peer: None,
status: sr::TXE.mask() | sr::TC.mask(),
holding: None,
sending: None,
sent: VecDeque::new(),
receiving: None,
received: 0,
idle: None,
idle_armed: false,
status_read: false,
outgoing: None,
incoming: None,
interrupt: Level::Low,
requests: [Level::Low; 2],
control: 0,
}
}
pub fn attach(&mut self, peer: impl Peer) {
self.peer = Some(Box::new(peer));
}
pub fn attach_boxed(&mut self, peer: Box<dyn Peer>) {
self.peer = Some(peer);
}
pub fn inherit(&mut self, from: &mut Self) {
self.peer = from.peer.take();
}
#[must_use]
pub fn attached(&self) -> bool {
self.peer.is_some()
}
#[must_use]
pub fn peer(&self) -> Option<&dyn Peer> {
self.peer.as_deref()
}
pub fn peer_mut(&mut self) -> Option<&mut dyn Peer> {
self.peer.as_deref_mut()
}
pub fn chip_mut<P: Peer>(&mut self) -> Option<&mut P> {
let peer: &mut dyn Any = self.peer.as_deref_mut()?;
peer.downcast_mut()
}
#[must_use]
pub fn sent(&self) -> Vec<u16> {
self.sent.iter().copied().collect()
}
pub fn drive_rx(&mut self, words: impl IntoIterator<Item = u16>) {
self.attach(Pattern::answering(words));
}
fn enabled(registers: &RegisterFile) -> (bool, bool) {
let value = registers.get(Register::Cr1);
let on = cr1::UE.is_set(value);
(on && cr1::TE.is_set(value), on && cr1::RE.is_set(value))
}
fn bit_cycles(registers: &RegisterFile) -> u64 {
let brr = registers.get(Register::Brr);
let mantissa = usart6::brr::DIV_MANTISSA.get(brr);
let fraction = usart6::brr::DIV_FRACTION.get(brr);
if cr1::OVER8.is_set(registers.get(Register::Cr1)) {
(mantissa << 3) | (fraction & 0b111)
} else {
(mantissa << 4) | fraction
}
}
fn data_bits(registers: &RegisterFile) -> u64 {
if cr1::M.is_set(registers.get(Register::Cr1)) {
9
} else {
8
}
}
fn data_mask(registers: &RegisterFile) -> u16 {
if cr1::M.is_set(registers.get(Register::Cr1)) {
NINE_BITS
} else {
EIGHT_BITS
}
}
fn half_bits(kind: FrameKind, registers: &RegisterFile) -> u64 {
let stop = STOP_HALF_BITS
[usize::try_from(cr2::STOP.get(registers.get(Register::Cr2))).expect("two bits")];
match kind {
FrameKind::Break => 2 * (Self::data_bits(registers) + 2) + stop,
FrameKind::Data(_) | FrameKind::Idle => 2 + 2 * Self::data_bits(registers) + stop,
}
}
fn frame_end(
&self,
run: Option<Run>,
from: VirtualNanos,
kind: FrameKind,
registers: &RegisterFile,
) -> Option<(VirtualNanos, Run)> {
let cycles = Self::bit_cycles(registers);
if cycles == 0 || self.clock_hz == 0 {
return None;
}
let (start, carry) = match run {
Some(run) if run.ends >= from => (run.ends, run.carry),
_ => (from, 0),
};
let numerator =
u128::from(Self::half_bits(kind, registers)) * u128::from(cycles) * NANOS_PER_SECOND
+ u128::from(carry);
let denominator = 2 * u128::from(self.clock_hz);
let nanos = u64::try_from(numerator / denominator).expect("a frame fits the virtual clock");
let carry = u64::try_from(numerator % denominator).expect("less than the denominator");
let ends = VirtualNanos(start.0.saturating_add(nanos));
Some((ends, Run { ends, carry }))
}
fn framed(word: u16, registers: &RegisterFile) -> u16 {
let control = registers.get(Register::Cr1);
let mask = Self::data_mask(registers);
let word = word & mask;
if !cr1::PCE.is_set(control) {
return word;
}
let top = mask ^ (mask >> 1);
let ones = (word & (mask >> 1)).count_ones();
let odd = cr1::PS.is_set(control);
let parity = (ones % 2 == 1) != odd;
if parity { word | top } else { word & !top }
}
fn send(
&mut self,
kind: FrameKind,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) -> bool {
if self.sending.is_some() || !Self::enabled(registers).0 {
return false;
}
let Some((at, run)) = self.frame_end(self.outgoing, context.now(), kind, registers) else {
return false;
};
self.outgoing = Some(run);
self.sending = Some(Frame {
event: context.schedule(at),
kind,
});
true
}
fn start_sending(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
if self.sending.is_some() {
return;
}
if cr1::SBK.is_set(registers.get(Register::Cr1))
&& self.send(FrameKind::Break, registers, context)
{
return;
}
let Some(word) = self.holding else {
return;
};
if self.send(FrameKind::Data(word), registers, context) {
self.holding = None;
self.status = sr::TXE.set(self.status, 1);
}
}
fn finish_sending(
&mut self,
kind: FrameKind,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
self.sending = None;
match kind {
FrameKind::Data(word) => {
if self.sent.len() == REMEMBERED {
self.sent.pop_front();
}
self.sent.push_back(word);
if let Some(peer) = &mut self.peer {
peer.receive(word, context);
}
}
FrameKind::Break => {
let value = registers.get(Register::Cr1);
registers.set(Register::Cr1, cr1::SBK.set(value, 0));
}
FrameKind::Idle => {}
}
self.start_sending(registers, context);
if self.sending.is_none() {
self.outgoing = None;
if kind != FrameKind::Idle && sr::TXE.is_set(self.status) {
self.status = sr::TC.set(self.status, 1);
}
}
}
fn receive_next(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
if self.receiving.is_some() || !Self::enabled(registers).1 {
return;
}
let now = context.now();
let Some(word) = self.peer.as_mut().and_then(|peer| peer.transmit(now)) else {
self.arm_idle(registers, context);
return;
};
let Some((at, run)) = self.frame_end(self.incoming, now, FrameKind::Data(word), registers)
else {
return;
};
self.incoming = Some(run);
self.idle = None;
self.receiving = Some(Frame {
event: context.schedule(at),
kind: FrameKind::Data(word),
});
}
fn arm_idle(&mut self, registers: &RegisterFile, context: &mut DeviceContext<'_>) {
if !self.idle_armed || self.idle.is_some() {
return;
}
let Some((at, _)) =
self.frame_end(self.incoming, context.now(), FrameKind::Idle, registers)
else {
return;
};
self.idle = Some(context.schedule(at));
}
fn finish_receiving(
&mut self,
word: u16,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
self.receiving = None;
if sr::RXNE.is_set(self.status) {
self.status = sr::ORE.set(self.status, 1);
} else {
self.received = Self::framed(word, registers);
self.status = sr::RXNE.set(self.status, 1);
self.idle_armed = true;
}
self.receive_next(registers, context);
if self.receiving.is_none() {
self.incoming = self.incoming.filter(|run| run.ends >= context.now());
}
}
fn write_cr1(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
let value = registers.get(Register::Cr1);
let was = self.control;
self.control = value;
let (transmits, receives) = Self::enabled(registers);
let did = cr1::UE.is_set(was);
let transmitted = did && cr1::TE.is_set(was);
let received = did && cr1::RE.is_set(was);
if transmits && !cr1::TE.is_set(was) {
self.send(FrameKind::Idle, registers, context);
}
if !transmits && transmitted && cr1::UE.is_set(value) {
self.sending = None;
self.outgoing = None;
}
if !receives && received && cr1::UE.is_set(value) {
self.receiving = None;
self.incoming = None;
}
self.start_sending(registers, context);
self.receive_next(registers, context);
}
fn write_sr(&mut self, written: u64) {
self.status &= !(CLEARED_BY_ZERO & !written);
self.status_read = false;
}
fn refresh_signals(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
registers.set(Register::Sr, self.status);
let status = self.status;
let control = registers.get(Register::Cr1);
let control2 = registers.get(Register::Cr2);
let control3 = registers.get(Register::Cr3);
for (output, enable, flag) in [
(RECEIVE_REQUEST, cr3::DMAR, sr::RXNE),
(TRANSMIT_REQUEST, cr3::DMAT, sr::TXE),
] {
let wanted = Level::from(enable.is_set(control3) && flag.is_set(status));
if wanted != self.requests[output] {
self.requests[output] = wanted;
context.request(output, wanted);
}
}
let errors = sr::FE.mask() | sr::ORE.mask() | sr::NF.mask();
let wanted = (cr1::TXEIE.is_set(control) && sr::TXE.is_set(status))
|| (cr1::TCIE.is_set(control) && sr::TC.is_set(status))
|| (cr1::RXNEIE.is_set(control) && (sr::RXNE.is_set(status) || sr::ORE.is_set(status)))
|| (cr1::IDLEIE.is_set(control) && sr::IDLE.is_set(status))
|| (cr1::PEIE.is_set(control) && sr::PE.is_set(status))
|| (cr2::LBDIE.is_set(control2) && sr::LBD.is_set(status))
|| (cr3::CTSIE.is_set(control3) && sr::CTS.is_set(status))
|| (cr3::EIE.is_set(control3) && cr3::DMAR.is_set(control3) && status & errors != 0);
let wanted = Level::from(wanted);
if wanted != self.interrupt {
self.interrupt = wanted;
context.interrupt(GLOBAL, wanted);
}
}
}
impl Device for Usart {
type Register = Register;
fn layout(&self) -> &'static [RegisterSpec] {
self.kind.layout()
}
fn on_clock(
&mut self,
hz: u64,
_registers: &mut RegisterFile,
_context: &mut DeviceContext<'_>,
) {
self.clock_hz = hz;
for run in [&mut self.outgoing, &mut self.incoming]
.into_iter()
.flatten()
{
run.carry = 0;
}
}
fn read(
&mut self,
register: Register,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) -> Option<u64> {
match register {
Register::Sr => {
self.status_read = true;
Some(self.status)
}
Register::Dr => {
self.status = sr::RXNE.set(self.status, 0);
if self.status_read {
self.status &= !CLEARED_BY_READING;
self.status_read = false;
}
self.receive_next(registers, context);
self.refresh_signals(registers, context);
Some(u64::from(self.received))
}
_ => None,
}
}
fn write(
&mut self,
register: Register,
value: u64,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
match register {
Register::Dr => {
self.status = sr::TXE.set(self.status, 0);
if self.status_read {
self.status = sr::PE.set(sr::TC.set(self.status, 0), 0);
self.status_read = false;
}
let word = u16::try_from(value & u64::from(NINE_BITS)).expect("nine bits");
self.holding = Some(Self::framed(word, registers));
self.start_sending(registers, context);
}
Register::Sr => self.write_sr(value),
Register::Cr1 => self.write_cr1(registers, context),
_ => {}
}
self.refresh_signals(registers, context);
}
fn on_event(
&mut self,
event: EventId,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
let mut ended = false;
if let Some(frame) = self.sending.filter(|frame| frame.event == event) {
self.finish_sending(frame.kind, registers, context);
ended = true;
}
if let Some(frame) = self.receiving.filter(|frame| frame.event == event)
&& let FrameKind::Data(word) = frame.kind
{
self.finish_receiving(word, registers, context);
ended = true;
}
if self.idle == Some(event) {
self.idle = None;
self.idle_armed = false;
self.status = sr::IDLE.set(self.status, 1);
ended = true;
}
if ended {
self.refresh_signals(registers, context);
}
}
fn poll(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
if self.peer.is_none() || self.receiving.is_some() {
return;
}
self.receive_next(registers, context);
self.refresh_signals(registers, context);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::soc::Layout;
#[test]
fn the_shared_fields_sit_at_the_same_bits_in_both_layouts() {
for (row, register) in uart4::REGISTERS.iter().enumerate() {
let full = &usart6::REGISTERS[row];
assert_eq!(register.name, full.name);
assert_eq!(register.offset, full.offset);
for field in register.fields {
let shared = full
.fields
.iter()
.find(|candidate| candidate.name == field.name)
.unwrap_or_else(|| panic!("{} has no {}", full.name, field.name));
assert_eq!(field.bit, shared.bit, "{}.{}", register.name, field.name);
assert_eq!(
field.width, shared.width,
"{}.{}",
register.name, field.name
);
}
}
assert_eq!(uart4::Register::Cr3.index(), Register::Cr3.index());
assert_eq!(usart6::REGISTERS.len(), uart4::REGISTERS.len() + 1);
}
}