mirror of
https://gitlab.cern.ch/wotsubo/endcap-sl-software-ri-generator.git
synced 2025-04-15 09:57:55 +09:00
260 lines
7.9 KiB
Rust
260 lines
7.9 KiB
Rust
//! Validate the address assignment and generate a flattened register map.
|
|
|
|
use thiserror::Error;
|
|
|
|
use crate::types::{Block, Module, ModuleBlockElements, Register};
|
|
|
|
type FlattenedRegisterMap<'a> = Vec<Option<(Vec<&'a str>, &'a Register, Option<u32>)>>;
|
|
|
|
impl Module {
|
|
/// Validate the address assignment, generating a flatten register map.
|
|
pub fn validate(&self) -> (FlattenedRegisterMap, Vec<ValidationError>) {
|
|
let mut mapping = Vec::new();
|
|
mapping.resize(self.size.try_into().unwrap(), None);
|
|
let errors = Vec::new();
|
|
self.fill(mapping, errors, (0x0, Vec::new()))
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum ValidationError {
|
|
#[error("address duplicated at 0x{address:08x}: \"{existing_name}\", \"{new_name}\"")]
|
|
AddressDuplicated {
|
|
address: u32,
|
|
existing_name: String,
|
|
new_name: String,
|
|
},
|
|
#[error("address 0x{address:08x} is out of range: \"{name}\"")]
|
|
AddressOutofRange { address: u32, name: String },
|
|
#[error("unsupported structure: {msg}")]
|
|
UnsupportedStructure { msg: &'static str },
|
|
}
|
|
|
|
trait Validate {
|
|
fn fill<'a>(
|
|
&'a self,
|
|
mapping: FlattenedRegisterMap<'a>,
|
|
errors: Vec<ValidationError>,
|
|
base: (u32, Vec<&'a str>),
|
|
) -> (FlattenedRegisterMap<'a>, Vec<ValidationError>);
|
|
}
|
|
|
|
impl Validate for Module {
|
|
fn fill<'a>(
|
|
&'a self,
|
|
mut mapping: FlattenedRegisterMap<'a>,
|
|
mut errors: Vec<ValidationError>,
|
|
base: (u32, Vec<&'a str>),
|
|
) -> (FlattenedRegisterMap<'a>, Vec<ValidationError>) {
|
|
for child in &self.elements_other {
|
|
(mapping, errors) = child.fill(mapping, errors, base.clone());
|
|
}
|
|
(mapping, errors)
|
|
}
|
|
}
|
|
|
|
impl Validate for ModuleBlockElements {
|
|
fn fill<'a>(
|
|
&'a self,
|
|
mapping: FlattenedRegisterMap<'a>,
|
|
errors: Vec<ValidationError>,
|
|
base: (u32, Vec<&'a str>),
|
|
) -> (FlattenedRegisterMap<'a>, Vec<ValidationError>) {
|
|
match self {
|
|
ModuleBlockElements::Block(block) => block.fill(mapping, errors, base),
|
|
ModuleBlockElements::Register(register) => register.fill(mapping, errors, base),
|
|
ModuleBlockElements::Memory(_memory) => todo!(),
|
|
ModuleBlockElements::Fifo(_fifo) => todo!(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Validate for Block {
|
|
fn fill<'a>(
|
|
&'a self,
|
|
mut mapping: FlattenedRegisterMap<'a>,
|
|
mut errors: Vec<ValidationError>,
|
|
base: (u32, Vec<&'a str>),
|
|
) -> (FlattenedRegisterMap<'a>, Vec<ValidationError>) {
|
|
if self.multiple.is_some() {
|
|
errors.push(ValidationError::UnsupportedStructure {
|
|
msg: "multiple in block",
|
|
});
|
|
}
|
|
|
|
let addr = base.0 + self.addr;
|
|
let mut path = base.1;
|
|
path.push(&self.name);
|
|
for child in &self.elements {
|
|
(mapping, errors) = child.fill(mapping, errors, (addr, path.clone()));
|
|
}
|
|
(mapping, errors)
|
|
}
|
|
}
|
|
|
|
impl Validate for Register {
|
|
fn fill<'a>(
|
|
&'a self,
|
|
mut mapping: FlattenedRegisterMap<'a>,
|
|
mut errors: Vec<ValidationError>,
|
|
base: (u32, Vec<&'a str>),
|
|
) -> (FlattenedRegisterMap<'a>, Vec<ValidationError>) {
|
|
let addr = base.0 + self.addr;
|
|
let path = base.1;
|
|
let (len, offset) = match &self.multiple {
|
|
Some(multiple) => (multiple.multiple, multiple.offset),
|
|
None => (1, 1),
|
|
};
|
|
for id in 0..len {
|
|
let addr = addr + id * offset;
|
|
let regmap: &mut Option<_> = match mapping.get_mut::<usize>(addr.try_into().unwrap()) {
|
|
Some(regmap) => regmap,
|
|
None => {
|
|
errors.push(ValidationError::AddressOutofRange {
|
|
address: addr,
|
|
name: self.name.clone(),
|
|
});
|
|
continue;
|
|
}
|
|
};
|
|
if let Some(old) = regmap {
|
|
let existing_name = {
|
|
let mut path = old.0.clone();
|
|
path.push(&old.1.name);
|
|
path.join("/")
|
|
};
|
|
let new_name = {
|
|
let mut path = path.clone();
|
|
path.push(&self.name);
|
|
path.join("/")
|
|
};
|
|
errors.push(ValidationError::AddressDuplicated {
|
|
address: addr,
|
|
existing_name,
|
|
new_name,
|
|
});
|
|
} else {
|
|
let multiple_id = if len == 1 { None } else { Some(id) };
|
|
*regmap = Some((path.clone(), self, multiple_id))
|
|
}
|
|
}
|
|
|
|
(mapping, errors)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use itertools::Itertools;
|
|
|
|
use crate::types::{
|
|
Module, ModuleBlockElements, MultipleParams, Register, RwSpecifier, XmlGitInfo,
|
|
};
|
|
|
|
#[test]
|
|
fn duplicate() {
|
|
let reg1 = Register {
|
|
name: "test1".to_string(),
|
|
addr: 0,
|
|
r#type: crate::types::DataType::D32,
|
|
mask: None,
|
|
modf: RwSpecifier::R,
|
|
multiple: None,
|
|
default: None,
|
|
desc: None,
|
|
elements: vec![],
|
|
};
|
|
let reg2 = Register {
|
|
name: "test1".to_string(),
|
|
addr: 0,
|
|
r#type: crate::types::DataType::D32,
|
|
mask: None,
|
|
modf: RwSpecifier::R,
|
|
multiple: None,
|
|
default: None,
|
|
desc: None,
|
|
elements: vec![],
|
|
};
|
|
let module = Module {
|
|
name: "module".to_string(),
|
|
addr: 0,
|
|
size: 0x10,
|
|
amod: None,
|
|
r#type: None,
|
|
desc: None,
|
|
elements_bitstring: vec![],
|
|
elements_other: vec![
|
|
ModuleBlockElements::Register(reg1),
|
|
ModuleBlockElements::Register(reg2),
|
|
],
|
|
xmlhash: [0; 32],
|
|
git_info: XmlGitInfo {
|
|
describe: "".to_string(),
|
|
commit_timestamp: "".to_string(),
|
|
sha: "".to_string(),
|
|
},
|
|
};
|
|
|
|
let (maps, errors) = module.validate();
|
|
eprintln!("{:#?}", maps);
|
|
eprintln!(
|
|
"{:#?}",
|
|
maps.iter().filter(|e| e.is_some()).collect_vec().len()
|
|
);
|
|
assert_eq!(maps.len(), 0x10);
|
|
assert!(!errors.is_empty());
|
|
assert_eq!(maps.iter().filter(|e| e.is_some()).collect_vec().len(), 0x1);
|
|
}
|
|
|
|
#[test]
|
|
fn duplicate_with_multiple() {
|
|
let reg1 = Register {
|
|
name: "test1".to_string(),
|
|
addr: 0,
|
|
r#type: crate::types::DataType::D32,
|
|
mask: None,
|
|
modf: RwSpecifier::R,
|
|
multiple: Some(MultipleParams {
|
|
multiple: 16,
|
|
offset: 1,
|
|
}),
|
|
default: None,
|
|
desc: None,
|
|
elements: vec![],
|
|
};
|
|
let reg2 = Register {
|
|
name: "test1".to_string(),
|
|
addr: 15,
|
|
r#type: crate::types::DataType::D32,
|
|
mask: None,
|
|
modf: RwSpecifier::R,
|
|
multiple: None,
|
|
default: None,
|
|
desc: None,
|
|
elements: vec![],
|
|
};
|
|
let module = Module {
|
|
name: "module".to_string(),
|
|
addr: 0,
|
|
size: 0x1000,
|
|
amod: None,
|
|
r#type: None,
|
|
desc: None,
|
|
elements_bitstring: vec![],
|
|
elements_other: vec![
|
|
ModuleBlockElements::Register(reg1),
|
|
ModuleBlockElements::Register(reg2),
|
|
],
|
|
xmlhash: [0; 32],
|
|
git_info: XmlGitInfo {
|
|
describe: "".to_string(),
|
|
commit_timestamp: "".to_string(),
|
|
sha: "".to_string(),
|
|
},
|
|
};
|
|
|
|
let (maps, errors) = module.validate();
|
|
assert_eq!(maps.len(), 0x1000);
|
|
assert_eq!(errors.len(), 1);
|
|
}
|
|
}
|