summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/svd/src/mapper.rs118
1 files changed, 71 insertions, 47 deletions
diff --git a/plugins/svd/src/mapper.rs b/plugins/svd/src/mapper.rs
index bf305eb2..c0ca5e99 100644
--- a/plugins/svd/src/mapper.rs
+++ b/plugins/svd/src/mapper.rs
@@ -32,7 +32,6 @@ pub fn byte_width(bit_width: u32) -> u32 {
#[derive(Clone, Debug)]
pub struct AddressBlockMemoryInfo {
- pub name: String,
pub segment: SegmentBuilder,
pub segment_flags: SegmentFlags,
pub section: SectionBuilder,
@@ -96,9 +95,43 @@ impl DeviceMapper {
// TODO: Add address blocks from derived peripherals?
pub fn map_peripheral_to_view(&self, view: &BinaryView, peripheral: &PeripheralInfo) {
+ // Get the size to extend the current block by.
+ let extend_block_size = |current_block: &AddressBlock, new_block: &AddressBlock| {
+ (new_block.offset + new_block.size - current_block.offset).max(current_block.size)
+ };
+
+ let merge_blocks = |mut coalesced_blocks: Vec<AddressBlock>,
+ new_block: AddressBlock|
+ -> Vec<AddressBlock> {
+ if let Some(current_block) = coalesced_blocks.last_mut() {
+ // Check if the new block can be merged with the last block.
+ // TODO: We don't account for the offset between the blocks
+ // TODO: Because we dont that means a register block 0x1000 away from another register block
+ // TODO: will still be merged, which is undesirable considering that SVD address blocks
+ // TODO: are suppose to be distinct memory regions!
+ if current_block.usage == new_block.usage {
+ current_block.size = extend_block_size(current_block, &new_block);
+ return coalesced_blocks;
+ }
+ }
+ // Push as a new block if not mergeable.
+ coalesced_blocks.push(new_block);
+ coalesced_blocks
+ };
+
if let Some(address_blocks) = &peripheral.address_block {
- for address_block in address_blocks {
- self.map_peripheral_block_to_view(view, peripheral, address_block);
+ // Because some SVD authors decided to create address blocks for sub-regions
+ // we must first coalesce all contiguous register address blocks.
+ let mut sorted_blocks = address_blocks.clone();
+ sorted_blocks.sort_by_key(|block| block.offset);
+ let merged_blocks: Vec<AddressBlock> =
+ sorted_blocks.into_iter().fold(Vec::new(), merge_blocks);
+ // Update the peripheral so downstream usage sees only merged blocks.
+ let mut updated_peripheral = peripheral.clone();
+ updated_peripheral.address_block = Some(merged_blocks.clone());
+
+ for address_block in merged_blocks {
+ self.map_peripheral_block_to_view(view, &updated_peripheral, &address_block);
}
}
}
@@ -115,12 +148,25 @@ impl DeviceMapper {
block_addr,
peripheral.name
);
- let memory_info = self.peripheral_block_memory_info(peripheral, address_block);
+
+ // We don't postfix the block offset in case we only have a single peripheral address block
+ // as it is unnecessary to talk about a unique block in that case.
+ let periph_block_len = peripheral.address_block.as_ref().unwrap().len();
+ let block_name = if address_block.offset == 0 || periph_block_len == 1 {
+ // Block name: "PERIPH"
+ peripheral.name.to_owned()
+ } else {
+ // Block name: "PERIPH_0x40"
+ format!("{}_0x{:x}", peripheral.name, address_block.offset)
+ };
+
+ let memory_info =
+ self.peripheral_block_memory_info(peripheral, address_block, block_name.clone());
// Add the block segment, section and backing memory.
let data_memory = DataBuffer::new(&vec![0; address_block.size as usize]).unwrap();
let added_memory = view.memory_map().add_data_memory_region(
- &memory_info.name,
+ &block_name,
block_addr,
&data_memory,
Some(memory_info.segment_flags),
@@ -131,7 +177,7 @@ impl DeviceMapper {
if !added_memory {
log::error!(
"Failed to add memory for peripheral block! {} @ 0x{:x}",
- memory_info.name,
+ block_name,
block_addr
);
}
@@ -146,11 +192,11 @@ impl DeviceMapper {
view.set_comment_at(block_addr, periph_desc);
}
// Add register descriptions
- self.add_comments_for_registers(view, peripheral, address_block);
+ self.add_comments_for_registers(view, peripheral);
}
// Registers will get the peripheral type.
- let peripheral_ty = self.peripheral_type(peripheral);
+ let peripheral_ty = self.peripheral_type(peripheral, address_block);
let peripheral_ty_id = format!("SVD:{}", peripheral.name);
let id = view.define_auto_type_with_id(
&peripheral.name,
@@ -186,19 +232,12 @@ impl DeviceMapper {
}
}
- pub fn add_comments_for_registers(
- &self,
- view: &BinaryView,
- peripheral: &PeripheralInfo,
- address_block: &AddressBlock,
- ) {
- let block_addr = peripheral.base_address + address_block.offset as u64;
+ pub fn add_comments_for_registers(&self, view: &BinaryView, peripheral: &PeripheralInfo) {
// Adding comments will add a bunch of undo actions.
let undo_id = view.file().begin_undo_actions(true);
for register in peripheral.all_registers() {
- // TODO: The register offset is the enclosing element.
- // TODO: We need to add a recursive function that keeps track of the offset.
- let register_addr = block_addr + register.address_offset as u64;
+ // Turns out the "enclosing element" seems to always be the peripheral base address?
+ let register_addr = peripheral.base_address + register.address_offset as u64;
if let Some(description) = &register.description {
view.set_comment_at(register_addr, description);
}
@@ -253,16 +292,10 @@ impl DeviceMapper {
&self,
peripheral: &PeripheralInfo,
address_block: &AddressBlock,
+ block_name: String,
) -> AddressBlockMemoryInfo {
let block_addr = peripheral.base_address + address_block.offset as u64;
let block_range = block_addr..(block_addr + address_block.size as u64);
- let block_name = if address_block.offset == 0 {
- // Block name: "PERIPH"
- peripheral.name.to_owned()
- } else {
- // Block name: "PERIPH_0x40"
- format!("{}_0x{:x}", peripheral.name, address_block.offset)
- };
let block_access = peripheral.default_register_properties.access;
let semantics = match block_access {
@@ -292,7 +325,7 @@ impl DeviceMapper {
}
};
- let section = SectionBuilder::new(block_name.clone(), block_range.clone())
+ let section = SectionBuilder::new(block_name, block_range.clone())
.section_type(section_type_str)
.semantics(semantics);
let segment_flags = SegmentFlags::new()
@@ -304,7 +337,6 @@ impl DeviceMapper {
let segment = SegmentBuilder::new(block_range).flags(segment_flags);
AddressBlockMemoryInfo {
- name: block_name,
segment,
segment_flags,
section,
@@ -314,7 +346,11 @@ impl DeviceMapper {
// TODO: In the future we might need to have partial types for each [`AddressBlock`]
// TODO: Support using header name, this requires we define the peripheral type id as the real peripheral name.
// TODO: cont. the reason is so that we can resolve the derived peripheral.
- pub fn peripheral_type(&self, peripheral: &PeripheralInfo) -> Ref<Type> {
+ pub fn peripheral_type(
+ &self,
+ peripheral: &PeripheralInfo,
+ address_block: &AddressBlock,
+ ) -> Ref<Type> {
let mut peripheral_struct = StructureBuilder::new();
if let Some(derived_periph_name) = &peripheral.derived_from {
@@ -327,30 +363,19 @@ impl DeviceMapper {
peripheral_struct.base_structures(&[base_struct]);
}
+ // Take the address block size and use it as the structure width.
// TODO: Support non-contiguous register address blocks (i.e. partial types).
- if let Some(address_blocks) = &peripheral.address_block {
- // If we have more than one address block with registers we likely have an incorrect type.
- let register_address_blocks: Vec<_> = address_blocks
- .iter()
- .filter(|a| a.usage == AddressBlockUsage::Registers)
- .collect();
- if register_address_blocks.len() > 1 {
- log::warn!(
- "Peripheral {} has more than one register address block. The type likely is incorrect.",
- peripheral.name
- );
- } else if register_address_blocks.len() == 1 {
- // Take the address block size and use it as the structure width.
- let register_address_block = register_address_blocks[0];
- peripheral_struct.width(register_address_block.size as u64);
- }
- }
+ peripheral_struct.width(address_block.size as u64);
if let Some(register_clusters) = &peripheral.registers {
for register_cluster in register_clusters {
match register_cluster {
RegisterCluster::Register(register) => {
- let register_member = self.register_member(register);
+ let mut register_member = self.register_member(register);
+ // TODO: If we want registers to be relative to the peripheral than we must
+ // TODO: assert that we create the peripheral type at offset 0 from the base address.
+ // Make the register member relative to the address block, not the peripheral.
+ register_member.offset -= address_block.offset as u64;
let overwrite = false; // TODO: Handle overwrites?
peripheral_struct.insert_member(register_member, overwrite);
}
@@ -367,7 +392,6 @@ impl DeviceMapper {
pub fn register_member(&self, register: &Register) -> StructureMember {
let register_ty = self.register_type(register);
let conf_register_ty = Conf::new(register_ty, MAX_CONFIDENCE);
- // TODO: Offset in peripheral
StructureMember::new(
conf_register_ty,
register.name.to_owned(),