11use crate :: svd:: {
2- self , Access , BitRange , DimElement , EnumeratedValues , Field , MaybeArray , ModifiedWriteValues ,
3- ReadAction , Register , RegisterProperties , Usage , WriteConstraint ,
2+ self , Access , BitRange , DimElement , EnumeratedValue , EnumeratedValues , Field , MaybeArray ,
3+ ModifiedWriteValues , ReadAction , Register , RegisterProperties , Usage , WriteConstraint ,
44} ;
55use core:: u64;
66use log:: warn;
77use proc_macro2:: { Ident , Punct , Spacing , Span , TokenStream } ;
88use quote:: { quote, ToTokens } ;
9- use std:: borrow:: Cow ;
109use std:: collections:: HashSet ;
1110use std:: fmt:: Write ;
11+ use std:: { borrow:: Cow , collections:: BTreeMap } ;
1212use svd_parser:: expand:: {
1313 derive_enumerated_values, derive_field, BlockPath , EnumPath , FieldPath , Index , RegisterPath ,
1414} ;
@@ -472,7 +472,7 @@ fn render_register_mod_debug(
472472 log:: debug!( "register={} field={}" , name, f. name) ;
473473 if field_access. can_read ( ) && f. read_action . is_none ( ) {
474474 if let Field :: Array ( _, de) = & f {
475- for ( _ , suffix) in de. indexes ( ) . enumerate ( ) {
475+ for suffix in de. indexes ( ) {
476476 let f_name_n = util:: replace_suffix ( & f. name , & suffix)
477477 . to_snake_case_ident ( Span :: call_site ( ) ) ;
478478 let f_name_n_s = format ! ( "{f_name_n}" ) ;
@@ -730,11 +730,24 @@ pub fn fields(
730730 // later on is the same as the read enumeration, we reuse and do not generate again.
731731 evs_r = Some ( evs) ;
732732
733- // do we have finite definition of this enumeration in svd? If not, the later code would
734- // return an Option when the value read from field does not match any defined values.
735- let has_reserved_variant = evs. values . len ( ) != ( 1 << width) ;
736733 // parse enum variants from enumeratedValues svd record
737- let variants = Variant :: from_enumerated_values ( evs, config. pascal_enum_values ) ?;
734+ let mut variants = Variant :: from_enumerated_values ( evs, config. pascal_enum_values ) ?;
735+
736+ let map = enums_to_map ( evs) ;
737+ let mut def = evs
738+ . default_value ( )
739+ . and_then ( |def| {
740+ minimal_hole ( & map, width)
741+ . map ( |v| Variant :: from_value ( v, def, config. pascal_enum_values ) )
742+ } )
743+ . transpose ( ) ?;
744+ if variants. len ( ) == 1 << width {
745+ def = None ;
746+ } else if variants. len ( ) == ( 1 << width) - 1 {
747+ if let Some ( def) = def. take ( ) {
748+ variants. push ( def) ;
749+ }
750+ }
738751
739752 // if there's no variant defined in enumeratedValues, generate enumeratedValues with new-type
740753 // wrapper struct, and generate From conversation only.
@@ -743,8 +756,32 @@ pub fn fields(
743756 // generate struct VALUE_READ_TY_A(fty) and From<fty> for VALUE_READ_TY_A.
744757 add_with_no_variants ( mod_items, & value_read_ty, & fty, & description, rv) ;
745758 } else {
759+ // do we have finite definition of this enumeration in svd? If not, the later code would
760+ // return an Option when the value read from field does not match any defined values.
761+ let has_reserved_variant;
762+
746763 // generate enum VALUE_READ_TY_A { ... each variants ... } and and From<fty> for VALUE_READ_TY_A.
747- add_from_variants ( mod_items, & variants, & value_read_ty, & fty, & description, rv) ;
764+ if let Some ( def) = def. as_ref ( ) {
765+ add_from_variants (
766+ mod_items,
767+ variants. iter ( ) . chain ( std:: iter:: once ( def) ) ,
768+ & value_read_ty,
769+ & fty,
770+ & description,
771+ rv,
772+ ) ;
773+ has_reserved_variant = false ;
774+ } else {
775+ add_from_variants (
776+ mod_items,
777+ variants. iter ( ) ,
778+ & value_read_ty,
779+ & fty,
780+ & description,
781+ rv,
782+ ) ;
783+ has_reserved_variant = evs. values . len ( ) != ( 1 << width) ;
784+ }
748785
749786 // prepare code for each match arm. If we have reserved variant, the match operation would
750787 // return an Option, thus we wrap the return value with Some.
@@ -771,6 +808,11 @@ pub fn fields(
771808 arms. extend ( quote ! {
772809 _ => None ,
773810 } ) ;
811+ } else if let Some ( v) = def. as_ref ( ) {
812+ let pc = & v. pc ;
813+ arms. extend ( quote ! {
814+ _ => #value_read_ty:: #pc,
815+ } ) ;
774816 } else if 1 << width. to_ty_width ( ) ? != variants. len ( ) {
775817 arms. extend ( quote ! {
776818 _ => unreachable!( ) ,
@@ -779,26 +821,20 @@ pub fn fields(
779821
780822 // prepare the `variant` function. This function would return field value in
781823 // Rust structure; if we have reserved variant we return by Option.
782- if has_reserved_variant {
783- enum_items. extend ( quote ! {
784- #[ doc = "Get enumerated values variant" ]
785- #inline
786- pub const fn variant( & self ) -> Option <#value_read_ty> {
787- match self . bits {
788- #arms
789- }
790- }
791- } ) ;
824+ let ret_ty = if has_reserved_variant {
825+ quote ! ( Option <#value_read_ty>)
792826 } else {
793- enum_items. extend ( quote ! {
827+ quote ! ( #value_read_ty)
828+ } ;
829+ enum_items. extend ( quote ! {
794830 #[ doc = "Get enumerated values variant" ]
795831 #inline
796- pub const fn variant( & self ) -> #value_read_ty {
832+ pub const fn variant( & self ) -> #ret_ty {
797833 match self . bits {
798834 #arms
799835 }
800- } } ) ;
801- }
836+ }
837+ } ) ;
802838
803839 // for each variant defined, we generate an `is_variant` function.
804840 for v in & variants {
@@ -823,6 +859,28 @@ pub fn fields(
823859 }
824860 } ) ;
825861 }
862+ if let Some ( v) = def. as_ref ( ) {
863+ let pc = & v. pc ;
864+ let sc = & v. nksc ;
865+
866+ let is_variant = Ident :: new (
867+ & if sc. to_string ( ) . starts_with ( '_' ) {
868+ format ! ( "is{sc}" )
869+ } else {
870+ format ! ( "is_{sc}" )
871+ } ,
872+ span,
873+ ) ;
874+
875+ let doc = util:: escape_special_chars ( & util:: respace ( & v. doc ) ) ;
876+ enum_items. extend ( quote ! {
877+ #[ doc = #doc]
878+ #inline
879+ pub fn #is_variant( & self ) -> bool {
880+ matches!( self . variant( ) , #value_read_ty:: #pc)
881+ }
882+ } ) ;
883+ }
826884 }
827885 }
828886
@@ -876,7 +934,7 @@ pub fn fields(
876934 }
877935 } ) ;
878936
879- for fi in svd:: field:: expand ( & f, de) {
937+ for fi in svd:: field:: expand ( f, de) {
880938 let sub_offset = fi. bit_offset ( ) as u64 ;
881939 let value = if sub_offset != 0 {
882940 let sub_offset = & unsuffixed ( sub_offset) ;
@@ -961,7 +1019,20 @@ pub fn fields(
9611019 // if we writes to enumeratedValues, generate its structure if it differs from read structure.
9621020 if let Some ( ( evs, None ) ) = lookup_filter ( & lookup_results, Usage :: Write ) {
9631021 // parse variants from enumeratedValues svd record
964- let variants = Variant :: from_enumerated_values ( evs, config. pascal_enum_values ) ?;
1022+ let mut variants = Variant :: from_enumerated_values ( evs, config. pascal_enum_values ) ?;
1023+ let map = enums_to_map ( evs) ;
1024+ let mut def = evs
1025+ . default_value ( )
1026+ . and_then ( |def| {
1027+ minimal_hole ( & map, width)
1028+ . map ( |v| Variant :: from_value ( v, def, config. pascal_enum_values ) )
1029+ } )
1030+ . transpose ( ) ?;
1031+ if variants. len ( ) == 1 << width {
1032+ } else if let Some ( def) = def. take ( ) {
1033+ variants. push ( def) ;
1034+ unsafety = false ;
1035+ }
9651036
9661037 // if the write structure is finite, it can be safely written.
9671038 if variants. len ( ) == 1 << width {
@@ -979,7 +1050,7 @@ pub fn fields(
9791050 } else {
9801051 add_from_variants (
9811052 mod_items,
982- & variants,
1053+ variants. iter ( ) ,
9831054 & value_write_ty,
9841055 & fty,
9851056 & description,
@@ -1130,7 +1201,7 @@ pub fn fields(
11301201 }
11311202 } ) ;
11321203
1133- for fi in svd:: field:: expand ( & f, de) {
1204+ for fi in svd:: field:: expand ( f, de) {
11341205 let sub_offset = fi. bit_offset ( ) as u64 ;
11351206 let name_snake_case_n = & fi. name . to_snake_case_ident ( Span :: call_site ( ) ) ;
11361207 let doc = description_with_bits (
@@ -1212,36 +1283,38 @@ struct Variant {
12121283
12131284impl Variant {
12141285 fn from_enumerated_values ( evs : & EnumeratedValues , pc : bool ) -> Result < Vec < Self > > {
1215- let span = Span :: call_site ( ) ;
12161286 evs. values
12171287 . iter ( )
12181288 // filter out all reserved variants, as we should not
12191289 // generate code for them
1220- . filter ( |field| field . name . to_lowercase ( ) != "reserved" && field . is_default . is_none ( ) )
1290+ . filter ( |ev| ev . name . to_lowercase ( ) != "reserved" && !ev . is_default ( ) )
12211291 . map ( |ev| {
12221292 let value = ev
12231293 . value
1224- . ok_or_else ( || anyhow ! ( "EnumeratedValue {} has no `<value>` field" , ev. name) ) ?;
1225-
1226- let nksc = ev. name . to_sanitized_not_keyword_snake_case ( ) ;
1227- let sc = util:: sanitize_keyword ( nksc. clone ( ) ) ;
1228- Ok ( Variant {
1229- doc : ev
1230- . description
1231- . clone ( )
1232- . unwrap_or_else ( || format ! ( "`{value:b}`" ) ) ,
1233- pc : if pc {
1234- ev. name . to_pascal_case_ident ( span)
1235- } else {
1236- ev. name . to_constant_case_ident ( span)
1237- } ,
1238- nksc : Ident :: new ( & nksc, span) ,
1239- sc : Ident :: new ( & sc, span) ,
1240- value,
1241- } )
1294+ . ok_or_else ( || anyhow ! ( "EnumeratedValue {} has no `<value>` entry" , ev. name) ) ?;
1295+ Self :: from_value ( value, ev, pc)
12421296 } )
12431297 . collect :: < Result < Vec < _ > > > ( )
12441298 }
1299+ fn from_value ( value : u64 , ev : & EnumeratedValue , pc : bool ) -> Result < Self > {
1300+ let span = Span :: call_site ( ) ;
1301+ let nksc = ev. name . to_sanitized_not_keyword_snake_case ( ) ;
1302+ let sc = util:: sanitize_keyword ( nksc. clone ( ) ) ;
1303+ Ok ( Variant {
1304+ doc : ev
1305+ . description
1306+ . clone ( )
1307+ . unwrap_or_else ( || format ! ( "`{value:b}`" ) ) ,
1308+ pc : if pc {
1309+ ev. name . to_pascal_case_ident ( span)
1310+ } else {
1311+ ev. name . to_constant_case_ident ( span)
1312+ } ,
1313+ nksc : Ident :: new ( & nksc, span) ,
1314+ sc : Ident :: new ( & sc, span) ,
1315+ value,
1316+ } )
1317+ }
12451318}
12461319
12471320fn add_with_no_variants (
@@ -1283,9 +1356,9 @@ fn add_with_no_variants(
12831356 }
12841357}
12851358
1286- fn add_from_variants (
1359+ fn add_from_variants < ' a > (
12871360 mod_items : & mut TokenStream ,
1288- variants : & [ Variant ] ,
1361+ variants : impl Iterator < Item = & ' a Variant > ,
12891362 pc : & Ident ,
12901363 fty : & Ident ,
12911364 desc : & str ,
@@ -1298,7 +1371,7 @@ fn add_from_variants(
12981371 } ;
12991372
13001373 let mut vars = TokenStream :: new ( ) ;
1301- for v in variants. iter ( ) . map ( |v| {
1374+ for v in variants. map ( |v| {
13021375 let desc = util:: escape_special_chars ( & util:: respace ( & format ! ( "{}: {}" , v. value, v. doc) ) ) ;
13031376 let pcv = & v. pc ;
13041377 let pcval = & unsuffixed ( v. value ) ;
@@ -1400,3 +1473,17 @@ fn lookup_filter(
14001473 . find ( |evsbase| evsbase. 0 . usage == Some ( usage) )
14011474 . or_else ( || evs. first ( ) )
14021475}
1476+
1477+ fn enums_to_map ( evs : & EnumeratedValues ) -> BTreeMap < u64 , & EnumeratedValue > {
1478+ let mut map = BTreeMap :: new ( ) ;
1479+ for ev in & evs. values {
1480+ if let Some ( v) = ev. value {
1481+ map. insert ( v, ev) ;
1482+ }
1483+ }
1484+ map
1485+ }
1486+
1487+ fn minimal_hole ( map : & BTreeMap < u64 , & EnumeratedValue > , width : u32 ) -> Option < u64 > {
1488+ ( 0 ..( 1u64 << width) ) . find ( |& v| !map. contains_key ( & v) )
1489+ }
0 commit comments