Skip to content

Commit 87934d7

Browse files
committed
[SVD Import] Fix misc mapper issues
- Fix unordered register fields causing spurious __offset fields to be rendered for the structure - Fix registers overlayed onto an alternate register not being treated as a union Fixes #7918
1 parent 8c0c59e commit 87934d7

File tree

1 file changed

+48
-12
lines changed

1 file changed

+48
-12
lines changed

plugins/svd/src/mapper.rs

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use binaryninja::segment::{SegmentBuilder, SegmentFlags};
88
use binaryninja::symbol::{SymbolBuilder, SymbolType};
99
use binaryninja::types::{
1010
BaseStructure, EnumerationBuilder, MemberAccess, MemberScope, NamedTypeReference,
11-
NamedTypeReferenceClass, StructureBuilder, StructureMember, Type, TypeBuilder,
11+
NamedTypeReferenceClass, StructureBuilder, StructureMember, StructureType, Type, TypeBuilder,
1212
};
13-
use std::collections::HashMap;
13+
use std::collections::{BTreeMap, HashMap};
1414
use std::num::NonZeroUsize;
1515
use svd_parser::svd::{
1616
Access, AddressBlock, AddressBlockUsage, DataType, Device, EnumeratedValues, Field, FieldInfo,
@@ -373,22 +373,55 @@ impl DeviceMapper {
373373
peripheral_struct.width(address_block.size as u64);
374374

375375
if let Some(register_clusters) = &peripheral.registers {
376+
// Collect registers by offset so we can handle overlapping registers by creating a union.
377+
let mut registers_by_offset: BTreeMap<u64, Vec<&Register>> = BTreeMap::new();
376378
for register_cluster in register_clusters {
377379
match register_cluster {
378380
RegisterCluster::Register(register) => {
379-
let mut register_member = self.register_member(register);
380-
// TODO: If we want registers to be relative to the peripheral than we must
381-
// TODO: assert that we create the peripheral type at offset 0 from the base address.
382-
// Make the register member relative to the address block, not the peripheral.
383-
register_member.offset -= address_block.offset as u64;
384-
let overwrite = false; // TODO: Handle overwrites?
385-
peripheral_struct.insert_member(register_member, overwrite);
381+
registers_by_offset
382+
.entry(register.address_offset as u64)
383+
.or_default()
384+
.push(register);
386385
}
387386
RegisterCluster::Cluster(_cluster) => {
388387
// TODO: Support clusters
389388
}
390389
}
391390
}
391+
392+
for (offset, registers) in registers_by_offset {
393+
match registers.as_slice() {
394+
[register] => {
395+
// We only have one register at this offset, just insert it.
396+
let mut register_member = self.register_member(register);
397+
register_member.offset -= address_block.offset as u64;
398+
peripheral_struct.insert_member(register_member, false);
399+
}
400+
_ => {
401+
// We have multiple registers at the same offset, create a union of them.
402+
// This happens typically when there is some mode field that changes the
403+
// behavior of the register region.
404+
// NOTE: Typically overlapping registers are specified with an alternate register.
405+
let mut union_builder = StructureBuilder::new();
406+
union_builder.structure_type(StructureType::UnionStructureType);
407+
for register in registers {
408+
let mut register_member = self.register_member(register);
409+
register_member.offset = 0;
410+
union_builder.insert_member(register_member, false);
411+
}
412+
413+
let union_ty = Type::structure(&union_builder.finalize());
414+
let union_member = StructureMember::new(
415+
Conf::new(union_ty, MAX_CONFIDENCE),
416+
"".to_string(),
417+
offset - address_block.offset as u64,
418+
MemberAccess::PublicAccess,
419+
MemberScope::NoScope,
420+
);
421+
peripheral_struct.insert_member(union_member, false);
422+
}
423+
}
424+
}
392425
}
393426

394427
Type::structure(&peripheral_struct.finalize())
@@ -440,10 +473,13 @@ impl DeviceMapper {
440473
register_struct.base_structures(&[base_struct]);
441474
}
442475

443-
let type_builder = match &register.fields {
444-
Some(fields) => {
476+
let type_builder = match register.fields.clone() {
477+
Some(mut fields) => {
478+
// Order the fields by offset so that rendering of the structure will not
479+
// insert "offset" fields, which happens when fields are unordered.
480+
fields.sort_by(|a, b| a.bit_range.offset.cmp(&b.bit_range.offset));
445481
for field in fields {
446-
let field_member = self.field_member(field);
482+
let field_member = self.field_member(&field);
447483
let overwrites = true; // TODO: Handle overwrites?
448484
register_struct.insert_member(field_member, overwrites);
449485
}

0 commit comments

Comments
 (0)