rust: pl011: fix break errors and definition of Data struct

The Data struct is wrong, and does not show how bits 8-15 of DR
are the receive status.  Fix it, and use it to fix break
errors ("c >> 8" in the C code does not translate to
"c.to_be_bytes()[3]").

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2024-12-04 17:14:00 +01:00
parent f65314bdd0
commit e1f9353334
2 changed files with 36 additions and 20 deletions

View file

@ -30,8 +30,6 @@ const IBRD_MASK: u32 = 0xffff;
/// Fractional Baud Rate Divider, `UARTFBRD`
const FBRD_MASK: u32 = 0x3f;
const DATA_BREAK: u32 = 1 << 10;
/// QEMU sourced constant.
pub const PL011_FIFO_DEPTH: usize = 16_usize;
@ -75,7 +73,7 @@ pub struct PL011State {
pub dmacr: u32,
pub int_enabled: u32,
pub int_level: u32,
pub read_fifo: [u32; PL011_FIFO_DEPTH],
pub read_fifo: [registers::Data; PL011_FIFO_DEPTH],
pub ilpr: u32,
pub ibrd: u32,
pub fbrd: u32,
@ -210,10 +208,11 @@ impl PL011State {
self.int_level &= !registers::INT_RX;
}
// Update error bits.
self.receive_status_error_clear = c.to_be_bytes()[3].into();
self.receive_status_error_clear.set_from_data(c);
self.update();
// Must call qemu_chr_fe_accept_input, so return Continue:
return std::ops::ControlFlow::Continue(c.into());
let c = u32::from(c);
return std::ops::ControlFlow::Continue(u64::from(c));
}
Ok(RSR) => u8::from(self.receive_status_error_clear).into(),
Ok(FR) => u16::from(self.flags).into(),
@ -406,7 +405,7 @@ impl PL011State {
fn loopback_break(&mut self, enable: bool) {
if enable {
self.loopback_tx(DATA_BREAK);
self.loopback_tx(registers::Data::BREAK.into());
}
}
@ -470,7 +469,7 @@ impl PL011State {
pub fn event(&mut self, event: QEMUChrEvent) {
if event == bindings::QEMUChrEvent::CHR_EVENT_BREAK && !self.loopback_enabled() {
self.put_fifo(DATA_BREAK);
self.put_fifo(registers::Data::BREAK.into());
}
}
@ -497,7 +496,7 @@ impl PL011State {
let depth = self.fifo_depth();
assert!(depth > 0);
let slot = (self.read_pos + self.read_count) & (depth - 1);
self.read_fifo[slot] = value;
self.read_fifo[slot] = registers::Data::from(value);
self.read_count += 1;
self.flags.set_receive_fifo_empty(false);
if self.read_count == depth {

View file

@ -139,6 +139,21 @@ pub mod registers {
//! unused thus treated as zero when read or written.
use bilge::prelude::*;
/// Receive Status Register / Data Register common error bits
///
/// The `UARTRSR` register is updated only when a read occurs
/// from the `UARTDR` register with the same status information
/// that can also be obtained by reading the `UARTDR` register
#[bitsize(8)]
#[derive(Clone, Copy, Default, DebugBits, FromBits)]
pub struct Errors {
pub framing_error: bool,
pub parity_error: bool,
pub break_error: bool,
pub overrun_error: bool,
_reserved_unpredictable: u4,
}
// TODO: FIFO Mode has different semantics
/// Data Register, `UARTDR`
///
@ -181,16 +196,18 @@ pub mod registers {
///
/// # Source
/// ARM DDI 0183G 3.3.1 Data Register, UARTDR
#[bitsize(16)]
#[derive(Clone, Copy, DebugBits, FromBits)]
#[bitsize(32)]
#[derive(Clone, Copy, Default, DebugBits, FromBits)]
#[doc(alias = "UARTDR")]
pub struct Data {
_reserved: u4,
pub data: u8,
pub framing_error: bool,
pub parity_error: bool,
pub break_error: bool,
pub overrun_error: bool,
pub errors: Errors,
_reserved: u16,
}
impl Data {
// bilge is not very const-friendly, unfortunately
pub const BREAK: Self = Self { value: 1 << 10 };
}
// TODO: FIFO Mode has different semantics
@ -220,14 +237,14 @@ pub mod registers {
#[bitsize(8)]
#[derive(Clone, Copy, DebugBits, FromBits)]
pub struct ReceiveStatusErrorClear {
pub framing_error: bool,
pub parity_error: bool,
pub break_error: bool,
pub overrun_error: bool,
_reserved_unpredictable: u4,
pub errors: Errors,
}
impl ReceiveStatusErrorClear {
pub fn set_from_data(&mut self, data: Data) {
self.set_errors(data.errors());
}
pub fn reset(&mut self) {
// All the bits are cleared to 0 on reset.
*self = Self::default();