mirror of
https://gitlab.cern.ch/wotsubo/endcap-sl-software-ri-generator.git
synced 2025-04-20 11:46:04 +09:00
Allow definition of overlapped register with non-overlapped fields
This commit is contained in:
parent
8732afd297
commit
205b08400b
2 changed files with 190 additions and 21 deletions
|
@ -117,15 +117,19 @@ pub fn generate_flatmap(xml: &path::Path, out: Option<&path::Path>) -> Result<()
|
||||||
for (addr, reg) in maps.iter().enumerate() {
|
for (addr, reg) in maps.iter().enumerate() {
|
||||||
match reg {
|
match reg {
|
||||||
Some(reg) => {
|
Some(reg) => {
|
||||||
let path = reg.0.join("/");
|
let path = reg.path.join("/");
|
||||||
let multiple_id = reg.2.map_or("".to_string(), |x| x.to_string());
|
let multiple_id = reg.multiple_id.map_or("".to_string(), |x| x.to_string());
|
||||||
wtr.write_record([
|
wtr.write_record([
|
||||||
format!("0x{:04x}", addr),
|
format!("0x{:04x}", addr),
|
||||||
path,
|
path,
|
||||||
reg.1.name.clone(),
|
reg.register.name.clone(),
|
||||||
multiple_id,
|
multiple_id,
|
||||||
reg.1.modf.to_string(),
|
reg.register.modf.to_string(),
|
||||||
reg.1.desc.as_ref().unwrap_or(&"".to_string()).to_string(),
|
reg.register
|
||||||
|
.desc
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&"".to_string())
|
||||||
|
.to_string(),
|
||||||
])?;
|
])?;
|
||||||
}
|
}
|
||||||
None => wtr.write_record([
|
None => wtr.write_record([
|
||||||
|
|
197
src/validator.rs
197
src/validator.rs
|
@ -4,7 +4,19 @@ use thiserror::Error;
|
||||||
|
|
||||||
use crate::types::{Block, Module, ModuleBlockElements, Register};
|
use crate::types::{Block, Module, ModuleBlockElements, Register};
|
||||||
|
|
||||||
type FlattenedRegisterMap<'a> = Vec<Option<(Vec<&'a str>, &'a Register, Option<u32>)>>;
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct FlattenedRegisterEntry<'a> {
|
||||||
|
/// contains all parents
|
||||||
|
pub path: Vec<&'a str>,
|
||||||
|
pub register: &'a Register,
|
||||||
|
/// Id of multiple, if the register is multiple
|
||||||
|
pub multiple_id: Option<u32>,
|
||||||
|
/// Used bits
|
||||||
|
pub field_masks: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Flattened register map.
|
||||||
|
type FlattenedRegisterMap<'a> = Vec<Option<FlattenedRegisterEntry<'a>>>;
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
/// Validate the address assignment, generating a flatten register map.
|
/// Validate the address assignment, generating a flatten register map.
|
||||||
|
@ -19,13 +31,19 @@ impl Module {
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ValidationError {
|
pub enum ValidationError {
|
||||||
#[error("address duplicated at 0x{address:08x}: \"{existing_name}\", \"{new_name}\"")]
|
#[error("address duplicated at 0x{address:08x}: \"{existing_name}\", \"{new_name}\"")]
|
||||||
AddressDuplicated {
|
RegisterAddressDuplicated {
|
||||||
address: u32,
|
address: u32,
|
||||||
existing_name: String,
|
existing_name: String,
|
||||||
new_name: String,
|
new_name: String,
|
||||||
},
|
},
|
||||||
#[error("address 0x{address:08x} is out of range: \"{name}\"")]
|
#[error("address 0x{address:08x} is out of range: \"{name}\"")]
|
||||||
AddressOutofRange { address: u32, name: String },
|
AddressOutofRange { address: u32, name: String },
|
||||||
|
#[error("field masks are duplicated at 0x{address:08x}: \"{reg_name}\", bits: 0x{duplicated_mask:08x}")]
|
||||||
|
FieldMaskDuplicated {
|
||||||
|
address: u32,
|
||||||
|
reg_name: String,
|
||||||
|
duplicated_mask: u32,
|
||||||
|
},
|
||||||
#[error("unsupported structure: {msg}")]
|
#[error("unsupported structure: {msg}")]
|
||||||
UnsupportedStructure { msg: &'static str },
|
UnsupportedStructure { msg: &'static str },
|
||||||
}
|
}
|
||||||
|
@ -101,6 +119,30 @@ impl Validate for Register {
|
||||||
) -> (FlattenedRegisterMap<'a>, Vec<ValidationError>) {
|
) -> (FlattenedRegisterMap<'a>, Vec<ValidationError>) {
|
||||||
let addr = base.0 + self.addr;
|
let addr = base.0 + self.addr;
|
||||||
let path = base.1;
|
let path = base.1;
|
||||||
|
|
||||||
|
let new_name = {
|
||||||
|
let mut path = path.clone();
|
||||||
|
path.push(&self.name);
|
||||||
|
path.join("/")
|
||||||
|
};
|
||||||
|
let (reg_mask, duplicate_bits) = match self.elements.is_empty() {
|
||||||
|
true => (0xffff_ffff, 0),
|
||||||
|
false => self
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.fold((0, 0), |(sum, _duplicate_bits), field| {
|
||||||
|
(sum + field.mask, sum & field.mask)
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
if duplicate_bits != 0 {
|
||||||
|
errors.push(ValidationError::FieldMaskDuplicated {
|
||||||
|
address: addr,
|
||||||
|
reg_name: new_name,
|
||||||
|
duplicated_mask: duplicate_bits,
|
||||||
|
});
|
||||||
|
return (mapping, errors);
|
||||||
|
}
|
||||||
|
|
||||||
let (len, offset) = match &self.multiple {
|
let (len, offset) = match &self.multiple {
|
||||||
Some(multiple) => (multiple.multiple, multiple.offset),
|
Some(multiple) => (multiple.multiple, multiple.offset),
|
||||||
None => (1, 1),
|
None => (1, 1),
|
||||||
|
@ -119,23 +161,47 @@ impl Validate for Register {
|
||||||
};
|
};
|
||||||
if let Some(old) = regmap {
|
if let Some(old) = regmap {
|
||||||
let existing_name = {
|
let existing_name = {
|
||||||
let mut path = old.0.clone();
|
let mut path = old.path.clone();
|
||||||
path.push(&old.1.name);
|
path.push(&old.register.name);
|
||||||
path.join("/")
|
path.join("/")
|
||||||
};
|
};
|
||||||
let new_name = {
|
|
||||||
let mut path = path.clone();
|
if old.register.name != self.name {
|
||||||
path.push(&self.name);
|
errors.push(ValidationError::RegisterAddressDuplicated {
|
||||||
path.join("/")
|
address: addr,
|
||||||
};
|
existing_name,
|
||||||
errors.push(ValidationError::AddressDuplicated {
|
new_name: new_name.clone(),
|
||||||
address: addr,
|
});
|
||||||
existing_name,
|
continue;
|
||||||
new_name,
|
}
|
||||||
});
|
log::trace!(
|
||||||
|
"defining same register at 0x{addr:08x}: {:?}, {:?}",
|
||||||
|
old.register,
|
||||||
|
self
|
||||||
|
);
|
||||||
|
let duplicate_bits = old.field_masks & reg_mask;
|
||||||
|
if duplicate_bits != 0 {
|
||||||
|
errors.push(ValidationError::FieldMaskDuplicated {
|
||||||
|
address: addr,
|
||||||
|
reg_name: new_name.clone(),
|
||||||
|
duplicated_mask: duplicate_bits,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let multiple_id = if len == 1 { None } else { Some(id) };
|
||||||
|
*regmap = Some(FlattenedRegisterEntry {
|
||||||
|
path: path.clone(),
|
||||||
|
register: self,
|
||||||
|
multiple_id,
|
||||||
|
field_masks: old.field_masks | reg_mask,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
let multiple_id = if len == 1 { None } else { Some(id) };
|
let multiple_id = if len == 1 { None } else { Some(id) };
|
||||||
*regmap = Some((path.clone(), self, multiple_id))
|
*regmap = Some(FlattenedRegisterEntry {
|
||||||
|
path: path.clone(),
|
||||||
|
register: self,
|
||||||
|
multiple_id,
|
||||||
|
field_masks: reg_mask,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +214,7 @@ mod test {
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
Module, ModuleBlockElements, MultipleParams, Register, RwSpecifier, XmlGitInfo,
|
Field, Module, ModuleBlockElements, MultipleParams, Register, RwSpecifier, XmlGitInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -255,6 +321,105 @@ mod test {
|
||||||
|
|
||||||
let (maps, errors) = module.validate();
|
let (maps, errors) = module.validate();
|
||||||
assert_eq!(maps.len(), 0x1000);
|
assert_eq!(maps.len(), 0x1000);
|
||||||
|
assert!(!errors.is_empty());
|
||||||
assert_eq!(errors.len(), 1);
|
assert_eq!(errors.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fields are orthogonal
|
||||||
|
#[test]
|
||||||
|
fn duplicate_reg_but_fields_are_ok() {
|
||||||
|
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![
|
||||||
|
Field {
|
||||||
|
name: "field_1".to_string(),
|
||||||
|
mask: 0x0000_00ff,
|
||||||
|
interface: None,
|
||||||
|
multiple: None,
|
||||||
|
default: None,
|
||||||
|
sclr: None,
|
||||||
|
desc: Some("field 1 description".to_string()),
|
||||||
|
elements: vec![],
|
||||||
|
},
|
||||||
|
Field {
|
||||||
|
name: "field_2".to_string(),
|
||||||
|
mask: 0x0000_ff00,
|
||||||
|
interface: None,
|
||||||
|
multiple: None,
|
||||||
|
default: None,
|
||||||
|
sclr: None,
|
||||||
|
desc: Some("field 2 description".to_string()),
|
||||||
|
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![
|
||||||
|
Field {
|
||||||
|
name: "field_3".to_string(),
|
||||||
|
mask: 0x00ff_0000,
|
||||||
|
interface: None,
|
||||||
|
multiple: None,
|
||||||
|
default: None,
|
||||||
|
sclr: None,
|
||||||
|
desc: Some("field 3 description".to_string()),
|
||||||
|
elements: vec![],
|
||||||
|
},
|
||||||
|
Field {
|
||||||
|
name: "field_4".to_string(),
|
||||||
|
mask: 0xff00_0000,
|
||||||
|
interface: None,
|
||||||
|
multiple: None,
|
||||||
|
default: None,
|
||||||
|
sclr: None,
|
||||||
|
desc: Some("field 4 description".to_string()),
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue