@@ -8,9 +8,9 @@ use binaryninja::segment::{SegmentBuilder, SegmentFlags};
88use binaryninja:: symbol:: { SymbolBuilder , SymbolType } ;
99use 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 } ;
1414use std:: num:: NonZeroUsize ;
1515use 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