11use anyhow:: { anyhow, Context } ;
22use svd_parser:: svd:: { Device , Peripheral , PeripheralInfo } ;
3- use yaml_rust:: yaml:: Hash ;
3+ use yaml_rust:: { yaml:: Hash , Yaml } ;
44
5+ use std:: collections:: HashSet ;
56use std:: { fs:: File , io:: Read , path:: Path } ;
67
8+ use super :: iterators:: { MatchIter , Matched } ;
79use super :: modify_register_properties;
810use super :: peripheral:: PeripheralExt ;
911use super :: yaml_ext:: { AsType , GetVal } ;
1012use super :: { abspath, matchname, PatchResult , VAL_LVL } ;
1113use super :: { make_address_block, make_address_blocks, make_cpu, make_interrupt, make_peripheral} ;
1214
13- pub struct PerIter < ' a , ' b > {
14- it : std:: slice:: IterMut < ' a , Peripheral > ,
15- spec : & ' b str ,
16- check_derived : bool ,
17- }
18-
19- impl < ' a , ' b > Iterator for PerIter < ' a , ' b > {
20- type Item = & ' a mut Peripheral ;
21- fn next ( & mut self ) -> Option < Self :: Item > {
22- self . it . by_ref ( ) . find ( |next| {
23- matchname ( & next. name , self . spec ) && !( self . check_derived && next. derived_from . is_some ( ) )
24- } )
25- }
26- }
15+ pub type PerMatchIterMut < ' a , ' b > = MatchIter < ' b , std:: slice:: IterMut < ' a , Peripheral > > ;
2716
2817/// Collecting methods for processing device contents
2918pub trait DeviceExt {
3019 /// Iterates over all peripherals that match pspec
31- fn iter_peripherals < ' a , ' b > (
32- & ' a mut self ,
33- spec : & ' b str ,
34- check_derived : bool ,
35- ) -> PerIter < ' a , ' b > ;
20+ fn iter_peripherals < ' a , ' b > ( & ' a mut self , spec : & ' b str ) -> PerMatchIterMut < ' a , ' b > ;
3621
3722 /// Work through a device, handling all peripherals
3823 fn process ( & mut self , device : & Hash , update_fields : bool ) -> PatchResult ;
@@ -54,7 +39,7 @@ pub trait DeviceExt {
5439
5540 /// Remove registers from pname and mark it as derivedFrom pderive.
5641 /// Update all derivedFrom referencing pname
57- fn derive_peripheral ( & mut self , pname : & str , pderive : & str ) -> PatchResult ;
42+ fn derive_peripheral ( & mut self , pname : & str , pderive : & Yaml ) -> PatchResult ;
5843
5944 /// Move registers from pold to pnew.
6045 /// Update all derivedFrom referencing pold
@@ -73,17 +58,8 @@ pub trait DeviceExt {
7358}
7459
7560impl DeviceExt for Device {
76- fn iter_peripherals < ' a , ' b > (
77- & ' a mut self ,
78- spec : & ' b str ,
79- check_derived : bool ,
80- ) -> PerIter < ' a , ' b > {
81- // check_derived=True
82- PerIter {
83- spec,
84- check_derived,
85- it : self . peripherals . iter_mut ( ) ,
86- }
61+ fn iter_peripherals < ' a , ' b > ( & ' a mut self , spec : & ' b str ) -> PerMatchIterMut < ' a , ' b > {
62+ self . peripherals . iter_mut ( ) . matched ( spec)
8763 }
8864
8965 fn process ( & mut self , device : & Hash , update_fields : bool ) -> PatchResult {
@@ -163,9 +139,8 @@ impl DeviceExt for Device {
163139 // Handle any derived peripherals
164140 for ( pname, pderive) in device. hash_iter ( "_derive" ) {
165141 let pname = pname. str ( ) ?;
166- let pderive = pderive. str ( ) ?;
167142 self . derive_peripheral ( pname, pderive)
168- . with_context ( || format ! ( "Deriving peripheral `{}` from `{}`" , pname, pderive) ) ?;
143+ . with_context ( || format ! ( "Deriving peripheral `{}` from `{:? }`" , pname, pderive) ) ?;
169144 }
170145
171146 // Handle any rebased peripherals
@@ -246,7 +221,10 @@ impl DeviceExt for Device {
246221 }
247222
248223 fn modify_peripheral ( & mut self , pspec : & str , pmod : & Hash ) -> PatchResult {
249- for ptag in self . iter_peripherals ( pspec, true ) {
224+ let mut modified = HashSet :: new ( ) ;
225+ for ptag in self . iter_peripherals ( pspec) {
226+ modified. insert ( ptag. name . clone ( ) ) ;
227+
250228 ptag. modify_from ( make_peripheral ( pmod, true ) ?, VAL_LVL ) ?;
251229 if let Some ( ints) = pmod. get_hash ( "interrupts" ) ? {
252230 for ( iname, val) in ints {
@@ -271,6 +249,17 @@ impl DeviceExt for Device {
271249 ptag. address_block = Some ( make_address_blocks ( abmod) ?) ;
272250 }
273251 }
252+ // If this peripheral has derivations, update the derived
253+ // peripherals to reference the new name.
254+ if let Some ( value) = pmod. get_str ( "name" ) ? {
255+ for p in self . peripherals . iter_mut ( ) {
256+ if let Some ( old_name) = p. derived_from . as_mut ( ) {
257+ if modified. contains ( old_name) {
258+ * old_name = value. into ( ) ;
259+ }
260+ }
261+ }
262+ }
274263 Ok ( ( ) )
275264 }
276265
@@ -288,15 +277,40 @@ impl DeviceExt for Device {
288277 Ok ( ( ) )
289278 }
290279
291- fn derive_peripheral ( & mut self , pname : & str , pderive : & str ) -> PatchResult {
292- self . get_peripheral ( pderive)
293- . ok_or_else ( || anyhow ! ( "peripheral {} not found" , pderive) ) ?;
294- self . get_mut_peripheral ( pname)
295- . ok_or_else ( || anyhow ! ( "peripheral {} not found" , pname) ) ?
296- . modify_from (
280+ fn derive_peripheral ( & mut self , pname : & str , pderive : & Yaml ) -> PatchResult {
281+ let ( pderive, info) = if let Some ( pderive) = pderive. as_str ( ) {
282+ (
283+ pderive,
297284 PeripheralInfo :: builder ( ) . derived_from ( Some ( pderive. into ( ) ) ) ,
298- VAL_LVL ,
299- ) ?;
285+ )
286+ } else if let Some ( hash) = pderive. as_hash ( ) {
287+ let pderive = hash. get_str ( "_from" ) ?. ok_or_else ( || {
288+ anyhow ! (
289+ "derive: source peripheral not given, please add a _from field to {}" ,
290+ pname
291+ )
292+ } ) ?;
293+ (
294+ pderive,
295+ make_peripheral ( hash, true ) ?. derived_from ( Some ( pderive. into ( ) ) ) ,
296+ )
297+ } else {
298+ return Err ( anyhow ! ( "derive: incorrect syntax for {}" , pname) ) ;
299+ } ;
300+
301+ if !pderive. contains ( '.' ) {
302+ self . get_peripheral ( pderive)
303+ . ok_or_else ( || anyhow ! ( "peripheral {} not found" , pderive) ) ?;
304+ }
305+
306+ match self . get_mut_peripheral ( pname) {
307+ Some ( peripheral) => peripheral. modify_from ( info, VAL_LVL ) ?,
308+ None => {
309+ let peripheral = info. name ( pname. into ( ) ) . build ( VAL_LVL ) ?. single ( ) ;
310+ self . peripherals . push ( peripheral) ;
311+ }
312+ }
313+
300314 for p in self
301315 . peripherals
302316 . iter_mut ( )
@@ -343,7 +357,10 @@ impl DeviceExt for Device {
343357 }
344358
345359 fn clear_fields ( & mut self , pspec : & str ) -> PatchResult {
346- for ptag in self . iter_peripherals ( pspec, false ) {
360+ for ptag in self . iter_peripherals ( pspec) {
361+ if ptag. derived_from . is_some ( ) {
362+ continue ;
363+ }
347364 ptag. clear_fields ( "*" ) ?;
348365 }
349366 Ok ( ( ) )
@@ -357,7 +374,7 @@ impl DeviceExt for Device {
357374 ) -> PatchResult {
358375 // Find all peripherals that match the spec
359376 let mut pcount = 0 ;
360- for ptag in self . iter_peripherals ( pspec, false ) {
377+ for ptag in self . iter_peripherals ( pspec) {
361378 pcount += 1 ;
362379 ptag. process ( peripheral, update_fields)
363380 . with_context ( || format ! ( "Processing peripheral `{}`" , ptag. name) ) ?;
0 commit comments