use tracing::warn;
use crate::{Addressing, BitField, ByteOrder, XmlError};
#[derive(Debug, Default)]
pub struct AddressingBuilder {
pub(crate) fixed_address: Option<u64>,
pub(crate) length: Option<u32>,
pub(crate) selector: Option<String>,
pub(crate) entries: Vec<AddressEntry>,
pub(crate) pending_value: Option<String>,
pub(crate) pending_len: Option<u32>,
pub(crate) p_address_node: Option<String>,
}
#[derive(Debug, Clone)]
pub struct AddressEntry {
pub value: String,
pub address: u64,
pub len: Option<u32>,
}
impl AddressingBuilder {
pub fn new(_node: &str) -> Self {
Self {
fixed_address: None,
length: None,
selector: None,
entries: Vec::new(),
pending_value: None,
pending_len: None,
p_address_node: None,
}
}
pub fn build(self) -> Addressing {
let len = self.length.unwrap_or(0);
if let Some(p_address_node) = self.p_address_node {
Addressing::Indirect {
p_address_node,
len,
}
} else if let Some(address) = self.fixed_address {
Addressing::Fixed { address, len }
} else if !self.entries.is_empty() {
let selector = self.selector.unwrap_or_default();
let map = self
.entries
.iter()
.map(|e| (e.value.clone(), (e.address, e.len.unwrap_or(len))))
.collect();
Addressing::BySelector { selector, map }
} else {
Addressing::Fixed { address: 0, len }
}
}
pub fn set_fixed_address(&mut self, address: u64) {
self.fixed_address = Some(address);
}
pub fn set_length(&mut self, len: u32) {
self.length = Some(len);
}
pub fn set_p_address_node(&mut self, node: &str) {
self.p_address_node = Some(node.to_string());
}
pub fn register_selector(&mut self, selector: &str) {
if self.selector.is_none() {
self.selector = Some(selector.to_string());
}
}
pub fn push_selected_value(&mut self, value: String) {
self.pending_value = Some(value);
self.pending_len = None;
}
pub fn apply_length(&mut self, len: u32) {
if self.pending_value.is_some() {
self.pending_len = Some(len);
} else {
self.length = Some(len);
}
}
pub fn attach_selected_address(&mut self, address: u64, len_override: Option<u32>) {
if let Some(value) = self.pending_value.take() {
let len = len_override.or(self.pending_len.take());
self.entries.push(AddressEntry {
value,
address,
len,
});
} else {
self.fixed_address = Some(address);
if let Some(len) = len_override {
self.length = Some(len);
}
}
}
pub fn finalize(self, node: &str, default_len: Option<u32>) -> Result<Addressing, XmlError> {
if !self.entries.is_empty() {
let selector = self.selector.ok_or_else(|| {
XmlError::Invalid(format!(
"node {node} provides <Selected> addresses without <pSelected>"
))
})?;
let mut map = Vec::new();
for entry in self.entries {
let len = entry.len.or(self.length).or(default_len).ok_or_else(|| {
XmlError::Invalid(format!(
"node {node} is missing <Length> for selector value {}",
entry.value
))
})?;
if let Some(existing) = map.iter_mut().find(|(value, _)| *value == entry.value) {
*existing = (entry.value.clone(), (entry.address, len));
} else {
map.push((entry.value.clone(), (entry.address, len)));
}
}
if self.p_address_node.is_some() {
warn!(
node = %node,
"ignoring <pAddress> in favour of selector table"
);
}
if self.fixed_address.is_some() {
warn!(
node = %node,
selector = %selector,
"ignoring fixed <Address> in favour of selector table"
);
}
Ok(Addressing::BySelector { selector, map })
} else {
let len = self
.length
.or(default_len)
.ok_or_else(|| XmlError::Invalid(format!("node {node} is missing <Length>")))?;
if let Some(p_address_node) = self.p_address_node {
if self.fixed_address.is_some() {
warn!(
node = %node,
address_node = %p_address_node,
"ignoring fixed <Address> in favour of <pAddress>"
);
}
Ok(Addressing::Indirect {
p_address_node,
len,
})
} else {
let address = self.fixed_address.ok_or_else(|| {
XmlError::Invalid(format!("node {node} is missing <Address>"))
})?;
Ok(Addressing::Fixed { address, len })
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BitfieldSource {
LsbMsb,
BitLength,
Mask,
}
#[derive(Debug, Default)]
pub struct BitfieldBuilder {
lsb: Option<u32>,
msb: Option<u32>,
bit: Option<u32>,
bit_length: Option<u32>,
mask: Option<u64>,
byte_order: Option<ByteOrder>,
source: Option<BitfieldSource>,
}
impl BitfieldBuilder {
pub fn note_lsb(&mut self, value: u32) {
if self
.source
.map(|source| source != BitfieldSource::LsbMsb)
.unwrap_or(false)
{
return;
}
self.source.get_or_insert(BitfieldSource::LsbMsb);
self.lsb = Some(value);
}
pub fn note_msb(&mut self, value: u32) {
if self
.source
.map(|source| source != BitfieldSource::LsbMsb)
.unwrap_or(false)
{
return;
}
self.source.get_or_insert(BitfieldSource::LsbMsb);
self.msb = Some(value);
}
pub fn note_bit(&mut self, value: u32) {
if self
.source
.map(|source| source != BitfieldSource::BitLength)
.unwrap_or(false)
{
return;
}
self.source.get_or_insert(BitfieldSource::BitLength);
self.bit = Some(value);
}
pub fn note_bit_length(&mut self, value: u32) {
if self
.source
.map(|source| source != BitfieldSource::BitLength)
.unwrap_or(false)
{
return;
}
self.source.get_or_insert(BitfieldSource::BitLength);
self.bit_length = Some(value);
}
pub fn note_mask(&mut self, mask: u64) {
if self.source.is_some() {
return;
}
self.source = Some(BitfieldSource::Mask);
self.mask = Some(mask);
}
pub fn note_byte_order(&mut self, order: ByteOrder) {
self.byte_order = Some(order);
}
pub fn finish(self, node: &str, lengths: &[u32]) -> Result<Option<BitField>, XmlError> {
let source = match self.source {
Some(source) => source,
None => return Ok(None),
};
let byte_order = self.byte_order.unwrap_or(ByteOrder::Little);
if lengths.is_empty() {
return Err(XmlError::Invalid(format!(
"node {node} is missing register length information"
)));
}
let mut unique_len = None;
for len in lengths {
if *len == 0 {
return Err(XmlError::Invalid(format!(
"node {node} declares zero-length register"
)));
}
if let Some(existing) = unique_len {
if existing != *len {
return Err(XmlError::Invalid(format!(
"node {node} uses inconsistent register lengths"
)));
}
} else {
unique_len = Some(*len);
}
}
let len_bytes = unique_len.unwrap_or(0);
let total_bits = len_bytes
.checked_mul(8)
.ok_or_else(|| XmlError::Invalid(format!("node {node} register length overflow")))?;
let (offset_lsb, bit_length) = match source {
BitfieldSource::LsbMsb => {
let lsb = self
.lsb
.ok_or_else(|| XmlError::Invalid(format!("node {node} is missing <Lsb>")))?;
let msb = self
.msb
.ok_or_else(|| XmlError::Invalid(format!("node {node} is missing <Msb>")))?;
let lower = lsb.min(msb);
let upper = lsb.max(msb);
let length = upper
.checked_sub(lower)
.and_then(|value| value.checked_add(1))
.ok_or_else(|| {
XmlError::Invalid(format!(
"node {node} has invalid bit range <Lsb>={lsb}, <Msb>={msb}"
))
})?;
(lower, length)
}
BitfieldSource::BitLength => {
let bit = self
.bit
.ok_or_else(|| XmlError::Invalid(format!("node {node} is missing <Bit>")))?;
let length = self.bit_length.unwrap_or(1);
(bit, length)
}
BitfieldSource::Mask => {
let mask = self.mask.ok_or_else(|| {
XmlError::Invalid(format!("node {node} is missing <Mask> value"))
})?;
if mask == 0 {
return Err(XmlError::Invalid(format!(
"node {node} mask must be non-zero"
)));
}
let offset = mask.trailing_zeros();
let length = mask.count_ones();
(offset, length)
}
};
if bit_length == 0 {
return Err(XmlError::Invalid(format!(
"node {node} bitfield must have positive length"
)));
}
if bit_length > 64 {
return Err(XmlError::Invalid(format!(
"node {node} bitfield length {bit_length} exceeds 64 bits"
)));
}
if offset_lsb > u16::MAX as u32 {
return Err(XmlError::Invalid(format!(
"node {node} bit offset {offset_lsb} exceeds u16 range"
)));
}
if bit_length > u16::MAX as u32 {
return Err(XmlError::Invalid(format!(
"node {node} bit length {bit_length} exceeds u16 range"
)));
}
if offset_lsb + bit_length > total_bits {
return Err(XmlError::Invalid(format!(
"node {node} bitfield exceeds register width"
)));
}
let offset = match byte_order {
ByteOrder::Little => offset_lsb,
ByteOrder::Big => total_bits - bit_length - offset_lsb,
};
Ok(Some(BitField {
bit_offset: u16::try_from(offset).map_err(|_| {
XmlError::Invalid(format!("node {node} bit offset {offset} exceeds u16 range"))
})?,
bit_length: u16::try_from(bit_length).map_err(|_| {
XmlError::Invalid(format!(
"node {node} bit length {bit_length} exceeds u16 range"
))
})?,
byte_order,
}))
}
}
pub fn addressing_lengths(addressing: &Addressing) -> Vec<u32> {
match addressing {
Addressing::Fixed { len, .. } => vec![*len],
Addressing::Indirect { len, .. } => vec![*len],
Addressing::BySelector { map, .. } => map.iter().map(|(_, (_, len))| *len).collect(),
}
}