11use anyhow:: { anyhow, Context } ;
22use svd_parser:: svd:: {
3- BitRange , DimElement , EnumeratedValues , Field , FieldInfo , ModifiedWriteValues , ReadAction ,
4- Register , RegisterInfo , Usage , WriteConstraint , WriteConstraintRange ,
3+ Access , BitRange , DimElement , EnumeratedValues , Field , FieldInfo , ModifiedWriteValues ,
4+ ReadAction , Register , RegisterInfo , Usage , WriteConstraint , WriteConstraintRange ,
55} ;
66use yaml_rust:: { yaml:: Hash , Yaml } ;
77
@@ -55,7 +55,7 @@ pub trait RegisterExt {
5555 pname : & str ,
5656 fspec : & str ,
5757 fmod : & Hash ,
58- usage : Usage ,
58+ usage : Option < Usage > ,
5959 ) -> PatchResult ;
6060
6161 /// Set readAction for field
@@ -493,14 +493,14 @@ impl RegisterExt for Register {
493493 . iter ( )
494494 . any ( |key| fmod. contains_key ( & key. to_yaml ( ) ) ) ;
495495 if !is_read && !is_write {
496- self . process_field_enum ( pname, fspec, fmod, Usage :: ReadWrite )
496+ self . process_field_enum ( pname, fspec, fmod, None )
497497 . with_context ( || "Adding read-write enumeratedValues" ) ?;
498498 } else {
499499 if is_read {
500500 for ( key, action) in READ_KEYS . into_iter ( ) . zip ( READ_VALS . into_iter ( ) ) {
501501 if let Some ( fmod) = fmod. get_hash ( key) ? {
502502 if !fmod. is_empty ( ) {
503- self . process_field_enum ( pname, fspec, fmod, Usage :: Read )
503+ self . process_field_enum ( pname, fspec, fmod, Some ( Usage :: Read ) )
504504 . with_context ( || "Adding read-only enumeratedValues" ) ?;
505505 }
506506 if let Some ( action) = action {
@@ -514,7 +514,7 @@ impl RegisterExt for Register {
514514 for ( key, mwv) in WRITE_KEYS . into_iter ( ) . zip ( WRITE_VALS . into_iter ( ) ) {
515515 if let Some ( fmod) = fmod. get_hash ( key) ? {
516516 if !fmod. is_empty ( ) {
517- self . process_field_enum ( pname, fspec, fmod, Usage :: Write )
517+ self . process_field_enum ( pname, fspec, fmod, Some ( Usage :: Write ) )
518518 . with_context ( || "Adding write-only enumeratedValues" ) ?;
519519 }
520520 if let Some ( mwv) = mwv {
@@ -555,42 +555,58 @@ impl RegisterExt for Register {
555555 pname : & str ,
556556 fspec : & str ,
557557 mut fmod : & Hash ,
558- usage : Usage ,
558+ usage : Option < Usage > ,
559559 ) -> PatchResult {
560560 fn set_enum (
561561 f : & mut FieldInfo ,
562- val : EnumeratedValues ,
562+ mut val : EnumeratedValues ,
563563 usage : Usage ,
564564 replace : bool ,
565+ access : Access ,
565566 ) -> PatchResult {
567+ let occupied_error = || {
568+ Err ( anyhow ! (
569+ "field {} already has {:?} enumeratedValues" ,
570+ f. name,
571+ usage
572+ ) )
573+ } ;
566574 if usage == Usage :: ReadWrite {
567575 if f. enumerated_values . is_empty ( ) || replace {
568576 f. enumerated_values = vec ! [ val] ;
569577 } else {
570- return Err ( anyhow ! (
571- "field {} already has {:?} enumeratedValues" ,
572- f. name,
573- usage
574- ) ) ;
578+ return occupied_error ( ) ;
575579 }
576580 } else {
577581 match f. enumerated_values . as_mut_slice ( ) {
578582 [ ] => f. enumerated_values . push ( val) ,
579- [ v] => {
580- if v. usage == Some ( usage) || v. usage == Some ( Usage :: ReadWrite ) {
583+ [ v] if v. usage == Some ( usage) || v. usage == Some ( Usage :: ReadWrite ) => {
584+ if replace {
585+ * v = val;
586+ } else {
587+ return occupied_error ( ) ;
588+ }
589+ }
590+ [ v] if v. usage . is_none ( ) => match ( access, usage) {
591+ ( Access :: ReadWrite | Access :: ReadWriteOnce , Usage :: Read ) => {
592+ v. usage = Some ( Usage :: Write ) ;
593+ val. usage = Some ( Usage :: Read ) ;
594+ f. enumerated_values . push ( val) ;
595+ }
596+ ( Access :: ReadWrite | Access :: ReadWriteOnce , Usage :: Write ) => {
597+ v. usage = Some ( Usage :: Read ) ;
598+ val. usage = Some ( Usage :: Write ) ;
599+ f. enumerated_values . push ( val) ;
600+ }
601+ _ => {
581602 if replace {
582603 * v = val;
583604 } else {
584- return Err ( anyhow ! (
585- "field {} already has {:?} enumeratedValues" ,
586- f. name,
587- usage
588- ) ) ;
605+ return occupied_error ( ) ;
589606 }
590- } else {
591- f. enumerated_values . push ( val) ;
592607 }
593- }
608+ } ,
609+ [ _] => f. enumerated_values . push ( val) ,
594610 [ v1, v2] => {
595611 if replace {
596612 if v1. usage == Some ( usage) {
@@ -600,11 +616,7 @@ impl RegisterExt for Register {
600616 * v2 = val;
601617 }
602618 } else {
603- return Err ( anyhow ! (
604- "field {} already has {:?} enumeratedValues" ,
605- f. name,
606- usage
607- ) ) ;
619+ return occupied_error ( ) ;
608620 }
609621 }
610622 _ => return Err ( anyhow ! ( "Incorrect enumeratedValues" ) ) ,
@@ -619,6 +631,7 @@ impl RegisterExt for Register {
619631 replace_if_exists = true ;
620632 }
621633
634+ let reg_access = self . properties . access ;
622635 if let Some ( d) = fmod. get_str ( "_derivedFrom" ) ? {
623636 // This is a derived enumeratedValues => Try to find the
624637 // original definition to extract its <usage>
@@ -644,19 +657,22 @@ impl RegisterExt for Register {
644657 ) ) ;
645658 }
646659 } ;
647- if usage != orig_usage {
648- return Err ( anyhow ! (
649- "enumeratedValues with different usage was found: {:?} != {:?}" ,
650- usage,
651- orig_usage
652- ) ) ;
653- }
654660 let evs = make_derived_enumerated_values ( d) ?;
655661 for ftag in self . iter_fields ( fspec) {
662+ let access = ftag. access . or ( reg_access) . unwrap_or_default ( ) ;
663+ let checked_usage = check_usage ( access, usage)
664+ . with_context ( || format ! ( "In field {}" , ftag. name) ) ?;
665+ if checked_usage != orig_usage {
666+ return Err ( anyhow ! (
667+ "enumeratedValues with different usage was found: {:?} != {:?}" ,
668+ usage,
669+ orig_usage
670+ ) ) ;
671+ }
656672 if ftag. name == d {
657673 return Err ( anyhow ! ( "EnumeratedValues can't be derived from itself" ) ) ;
658674 }
659- set_enum ( ftag, evs. clone ( ) , usage , true ) ?;
675+ set_enum ( ftag, evs. clone ( ) , orig_usage , true , access ) ?;
660676 }
661677 } else {
662678 let offsets = self
@@ -669,14 +685,23 @@ impl RegisterExt for Register {
669685 let ( min_offset, name) = offsets. iter ( ) . min_by_key ( |on| on. 0 ) . unwrap ( ) ;
670686 let name = make_ev_name ( & name. replace ( "%s" , "" ) , usage) ?;
671687 for ftag in self . iter_fields ( fspec) {
688+ let access = ftag. access . or ( reg_access) . unwrap_or_default ( ) ;
689+ let checked_usage = check_usage ( access, usage)
690+ . with_context ( || format ! ( "In field {}" , ftag. name) ) ?;
672691 if ftag. bit_range . offset == * min_offset {
673692 let evs = make_ev_array ( fmod) ?
674693 . name ( Some ( name. clone ( ) ) )
675- . usage ( Some ( usage ) )
694+ . usage ( make_usage ( access , checked_usage ) )
676695 . build ( VAL_LVL ) ?;
677- set_enum ( ftag, evs, usage , replace_if_exists) ?;
696+ set_enum ( ftag, evs, checked_usage , replace_if_exists, access ) ?;
678697 } else {
679- set_enum ( ftag, make_derived_enumerated_values ( & name) ?, usage, true ) ?;
698+ set_enum (
699+ ftag,
700+ make_derived_enumerated_values ( & name) ?,
701+ checked_usage,
702+ true ,
703+ access,
704+ ) ?;
680705 }
681706 }
682707 }
@@ -698,3 +723,27 @@ impl RegisterExt for Register {
698723 Ok ( ( ) )
699724 }
700725}
726+
727+ fn check_usage ( access : Access , usage : Option < Usage > ) -> anyhow:: Result < Usage > {
728+ Ok ( match ( access, usage) {
729+ ( Access :: ReadWrite | Access :: ReadWriteOnce , usage) => usage. unwrap_or_default ( ) ,
730+ ( Access :: ReadOnly , None | Some ( Usage :: Read ) ) => Usage :: Read ,
731+ ( Access :: WriteOnly | Access :: WriteOnce , None | Some ( Usage :: Write ) ) => Usage :: Write ,
732+ ( _, _) => {
733+ return Err ( anyhow ! (
734+ "EnumeratedValues usage {:?} is incompatible with access {:?}" ,
735+ usage,
736+ access
737+ ) ) ;
738+ }
739+ } )
740+ }
741+
742+ fn make_usage ( access : Access , usage : Usage ) -> Option < Usage > {
743+ match ( access, usage) {
744+ ( Access :: ReadWrite | Access :: ReadWriteOnce , Usage :: ReadWrite )
745+ | ( Access :: ReadOnly , Usage :: Read )
746+ | ( Access :: WriteOnly | Access :: WriteOnce , Usage :: Write ) => None ,
747+ _ => Some ( usage) ,
748+ }
749+ }
0 commit comments