@@ -378,10 +378,12 @@ pub fn fields(
378
378
// Reader and writer use one common `Enum_A` unless a fields have two `enumeratedValues`,
379
379
// then we have one for read-only `Enum_A` and another for write-only `Enum_AW`
380
380
let name_constant_case_a = Ident :: new ( & ( name_constant_case. clone ( ) + "_A" ) , span) ;
381
- let mut name_constant_case_aw = & name_constant_case_a;
381
+ let mut value_write_ty = & name_constant_case_a;
382
382
383
383
let mut evs_r = None ;
384
384
385
+ // Reads dim information from svd field. If it has dim index, the field is treated as an
386
+ // array; or it should be treated as a single register field.
385
387
let field_dim = match f {
386
388
Field :: Array ( _, de) => {
387
389
let first = if let Some ( dim_index) = & de. dim_index {
@@ -412,27 +414,8 @@ pub fn fields(
412
414
}
413
415
} ;
414
416
417
+ // If this field can be read, generate read proxy structure and value structure.
415
418
if can_read {
416
- let mut readerdoc = if let Some ( ( _, _, _, _, suffixes_str) ) = & field_dim {
417
- format ! (
418
- "Fields `{}` reader - {}" ,
419
- util:: replace_suffix( & f. name, suffixes_str) ,
420
- description,
421
- )
422
- } else {
423
- format ! ( "Field `{}` reader - {}" , f. name, description)
424
- } ;
425
- if let Some ( action) = f. read_action {
426
- readerdoc += match action {
427
- ReadAction :: Clear => "\n \n The field is **cleared** (set to zero) following a read operation." ,
428
- ReadAction :: Set => "\n \n The field is **set** (set to ones) following a read operation." ,
429
- ReadAction :: Modify => "\n \n The field is **modified** in some way after a read operation." ,
430
- ReadAction :: ModifyExternal => "\n \n One or more dependent resources other than the current field are immediately affected by a read operation." ,
431
- } ;
432
- }
433
-
434
- let reader_ty = Ident :: new ( & ( name_constant_case. clone ( ) + "_R" ) , span) ;
435
-
436
419
let cast = if width == 1 {
437
420
quote ! { != 0 }
438
421
} else {
@@ -453,6 +436,29 @@ pub fn fields(
453
436
}
454
437
} ;
455
438
439
+ // get a brief description for this field
440
+ // the suffix string from field name is removed in brief description.
441
+ let mut field_reader_brief = if let Some ( ( _, _, _, _, suffixes_str) ) = & field_dim {
442
+ format ! (
443
+ "Fields `{}` reader - {}" ,
444
+ util:: replace_suffix( & f. name, suffixes_str) ,
445
+ description,
446
+ )
447
+ } else {
448
+ format ! ( "Field `{}` reader - {}" , f. name, description)
449
+ } ;
450
+ if let Some ( action) = f. read_action {
451
+ field_reader_brief += match action {
452
+ ReadAction :: Clear => "\n \n The field is **cleared** (set to zero) following a read operation." ,
453
+ ReadAction :: Set => "\n \n The field is **set** (set to ones) following a read operation." ,
454
+ ReadAction :: Modify => "\n \n The field is **modified** in some way after a read operation." ,
455
+ ReadAction :: ModifyExternal => "\n \n One or more dependent resources other than the current field are immediately affected by a read operation." ,
456
+ } ;
457
+ }
458
+
459
+ // name of read proxy type
460
+ let reader_ty = Ident :: new ( & ( name_constant_case. clone ( ) + "_R" ) , span) ;
461
+
456
462
if let Some ( ( first, dim, increment, suffixes, suffixes_str) ) = & field_dim {
457
463
let offset_calc = calculate_offset ( * first, * increment, offset, true ) ;
458
464
let value = quote ! { ( ( self . bits >> #offset_calc) & #hexmask) #cast } ;
@@ -507,9 +513,13 @@ pub fn fields(
507
513
} ) ;
508
514
}
509
515
516
+ // collect information on items in enumeration to generate it later.
510
517
let mut enum_items = TokenStream :: new ( ) ;
511
- let mut derived = false ;
518
+ let mut should_derive_reader = true ;
512
519
let mut ftype = fty. clone ( ) ;
520
+
521
+ // if this is an enumeratedValues not derived from base, generate the enum structure
522
+ // and implement functions for each value in enumeration.
513
523
if let Some ( ( evs, base) ) = lookup_filter ( & lookup_results, Usage :: Read ) {
514
524
evs_r = Some ( evs. clone ( ) ) ;
515
525
@@ -528,13 +538,26 @@ pub fn fields(
528
538
529
539
let pc = pc_orig. to_sanitized_constant_case ( ) ;
530
540
let base_pc_r = Ident :: new ( & ( pc + "_R" ) , span) ;
531
- derive_from_base ( mod_items, & base, & reader_ty, & base_pc_r, & readerdoc) ;
532
- derived = true ;
541
+ derive_from_base (
542
+ mod_items,
543
+ & base,
544
+ & reader_ty,
545
+ & base_pc_r,
546
+ & field_reader_brief,
547
+ ) ;
548
+ should_derive_reader = false ;
533
549
} else {
550
+ // do we have finite definition of this enumeration in svd? If not, the later code would
551
+ // return an Option when the value read from field does not match any defined values.
534
552
let has_reserved_variant = evs. values . len ( ) != ( 1 << width) ;
553
+ // parse enum variants from enumeratedValues svd record
535
554
let variants = Variant :: from_enumerated_values ( evs, config. pascal_enum_values ) ?;
536
555
556
+ // if there's no variant defined in enumeratedValues, generate enumeratedValues with new-type
557
+ // wrapper struct, and generate From conversation only.
558
+ // else, generate enumeratedValues into a Rust enum with functions for each variant.
537
559
if variants. is_empty ( ) {
560
+ // generate struct VALUE_READ_TY_A(fty) and From<fty> for VALUE_READ_TY_A.
538
561
add_with_no_variants (
539
562
mod_items,
540
563
& name_constant_case_a,
@@ -543,6 +566,7 @@ pub fn fields(
543
566
rv,
544
567
) ;
545
568
} else {
569
+ // generate enum VALUE_READ_TY_A { ... each variants ... } and and From<fty> for VALUE_READ_TY_A.
546
570
add_from_variants (
547
571
mod_items,
548
572
& variants,
@@ -552,6 +576,8 @@ pub fn fields(
552
576
rv,
553
577
) ;
554
578
579
+ // prepare code for each match arm. If we have reserved variant, the match operation would
580
+ // return an Option, thus we wrap the return value with Some.
555
581
let mut arms = TokenStream :: new ( ) ;
556
582
for v in variants. iter ( ) . map ( |v| {
557
583
let i = util:: unsuffixed_or_bool ( v. value , width) ;
@@ -566,6 +592,11 @@ pub fn fields(
566
592
arms. extend ( v) ;
567
593
}
568
594
595
+ // if we have reserved variant, for all values other than defined we return None.
596
+ // if svd suggests it only would return defined variants but FieldReader has
597
+ // other values, it's regarded as unreachable and we enter unreachable! macro.
598
+ // This situation is rare and only exists if unsafe code casts any illegal value
599
+ // into a FieldReader structure.
569
600
if has_reserved_variant {
570
601
arms. extend ( quote ! {
571
602
_ => None ,
@@ -576,6 +607,8 @@ pub fn fields(
576
607
} ) ;
577
608
}
578
609
610
+ // prepare the `variant` function. This function would return field value in
611
+ // Rust structure; if we have reserved variant we return by Option.
579
612
if has_reserved_variant {
580
613
enum_items. extend ( quote ! {
581
614
#[ doc = "Get enumerated values variant" ]
@@ -597,6 +630,7 @@ pub fn fields(
597
630
} } ) ;
598
631
}
599
632
633
+ // for each variant defined, we generate an `is_variant` function.
600
634
for v in & variants {
601
635
let pc = & v. pc ;
602
636
let sc = & v. nksc ;
@@ -624,17 +658,20 @@ pub fn fields(
624
658
ftype = name_constant_case_a. clone ( ) ;
625
659
}
626
660
}
627
- if !derived {
661
+
662
+ // derive the read proxy structure if necessary.
663
+ if should_derive_reader {
628
664
let reader = if width == 1 {
629
665
quote ! { crate :: BitReader <#ftype> }
630
666
} else {
631
667
quote ! { crate :: FieldReader <#fty, #ftype> }
632
668
} ;
633
669
mod_items. extend ( quote ! {
634
- #[ doc = #readerdoc ]
670
+ #[ doc = #field_reader_brief ]
635
671
pub type #reader_ty = #reader;
636
672
} ) ;
637
673
}
674
+ // generate the enumeration functions prepared before.
638
675
if !enum_items. is_empty ( ) {
639
676
mod_items. extend ( quote ! {
640
677
impl #reader_ty {
@@ -644,12 +681,15 @@ pub fn fields(
644
681
}
645
682
}
646
683
684
+ // If this field can be written, generate write proxy. Generate write value if it differs from
685
+ // the read value, or else we reuse read value.
647
686
if can_write {
648
687
let mwv = f
649
688
. modified_write_values
650
689
. or ( register. modified_write_values )
651
690
. unwrap_or_default ( ) ;
652
- let writerdoc = if let Some ( ( _, _, _, _, suffixes_str) ) = & field_dim {
691
+ // gets a brief of write proxy
692
+ let field_writer_brief = if let Some ( ( _, _, _, _, suffixes_str) ) = & field_dim {
653
693
format ! (
654
694
"Fields `{}` writer - {}" ,
655
695
util:: replace_suffix( & f. name, suffixes_str) ,
@@ -660,45 +700,37 @@ pub fn fields(
660
700
} ;
661
701
662
702
let new_pc_aw = Ident :: new ( & ( name_constant_case. clone ( ) + "_AW" ) , span) ;
703
+ // name of write proxy type
663
704
let writer_ty = Ident :: new ( & ( name_constant_case. clone ( ) + "_W" ) , span) ;
664
705
665
706
let mut proxy_items = TokenStream :: new ( ) ;
666
707
let mut unsafety = unsafety ( f. write_constraint . as_ref ( ) , width) ;
667
708
668
- let mut derived = false ;
709
+ let mut should_derive_writer = true ;
710
+ // if we writes to enumeratedValues, generate its structure if it differs from read structure.
669
711
if let Some ( ( evs, base) ) = lookup_filter ( & lookup_results, Usage :: Write ) {
712
+ // parse variants from enumeratedValues svd record
670
713
let variants = Variant :: from_enumerated_values ( evs, config. pascal_enum_values ) ?;
671
714
715
+ // if the write structure is finite, it can be safely written.
672
716
if variants. len ( ) == 1 << width {
673
717
unsafety = false ;
674
718
}
675
719
676
720
if Some ( evs) != evs_r. as_ref ( ) {
677
- name_constant_case_aw = & new_pc_aw;
721
+ value_write_ty = & new_pc_aw;
678
722
if let Some ( base) = base. as_ref ( ) {
679
723
let pc = util:: replace_suffix ( base. field , "" ) ;
680
724
let pc = pc. to_sanitized_constant_case ( ) ;
681
725
let base_pc_w = Ident :: new ( & ( pc + "_AW" ) , span) ;
682
- derive_from_base (
683
- mod_items,
684
- base,
685
- name_constant_case_aw,
686
- & base_pc_w,
687
- & description,
688
- ) ;
726
+ derive_from_base ( mod_items, base, value_write_ty, & base_pc_w, & description) ;
689
727
} else if variants. is_empty ( ) {
690
- add_with_no_variants (
691
- mod_items,
692
- name_constant_case_aw,
693
- & fty,
694
- & description,
695
- rv,
696
- ) ;
728
+ add_with_no_variants ( mod_items, value_write_ty, & fty, & description, rv) ;
697
729
} else {
698
730
add_from_variants (
699
731
mod_items,
700
732
& variants,
701
- name_constant_case_aw ,
733
+ value_write_ty ,
702
734
& fty,
703
735
& description,
704
736
rv,
@@ -711,32 +743,39 @@ pub fn fields(
711
743
let pc = util:: replace_suffix ( base. field , "" ) ;
712
744
let pc = pc. to_sanitized_constant_case ( ) ;
713
745
let base_pc_w = Ident :: new ( & ( pc + "_W" ) , span) ;
714
- derive_from_base ( mod_items, & base, & writer_ty, & base_pc_w, & writerdoc) ;
715
- derived = true ;
746
+ derive_from_base (
747
+ mod_items,
748
+ & base,
749
+ & writer_ty,
750
+ & base_pc_w,
751
+ & field_writer_brief,
752
+ ) ;
753
+ should_derive_writer = false ;
716
754
}
717
755
_ => {
718
756
if !variants. is_empty ( ) {
757
+ // for each variant defined, generate a write function to this field.
719
758
for v in & variants {
720
759
let pc = & v. pc ;
721
760
let sc = & v. sc ;
722
-
723
761
let doc = util:: escape_brackets ( util:: respace ( & v. doc ) . as_ref ( ) ) ;
724
762
proxy_items. extend ( quote ! {
725
763
#[ doc = #doc]
726
764
#inline
727
765
pub fn #sc( self ) -> & ' a mut W {
728
- self . variant( #name_constant_case_aw :: #pc)
766
+ self . variant( #value_write_ty :: #pc)
729
767
}
730
768
} ) ;
731
769
}
732
770
}
733
771
}
734
772
}
735
773
} else {
736
- name_constant_case_aw = & fty;
774
+ value_write_ty = & fty;
737
775
}
738
776
739
- if !derived {
777
+ // derive writer structure by type alias to generic write proxy structure.
778
+ if should_derive_writer {
740
779
let proxy = if width == 1 {
741
780
let wproxy = Ident :: new (
742
781
match mwv {
@@ -754,7 +793,7 @@ pub fn fields(
754
793
} ,
755
794
span,
756
795
) ;
757
- quote ! { crate :: #wproxy<' a, #rty, #name_constant_case_spec, #name_constant_case_aw , O > }
796
+ quote ! { crate :: #wproxy<' a, #rty, #name_constant_case_spec, #value_write_ty , O > }
758
797
} else {
759
798
let wproxy = Ident :: new (
760
799
if unsafety {
@@ -765,13 +804,15 @@ pub fn fields(
765
804
span,
766
805
) ;
767
806
let width = & util:: unsuffixed ( width as _ ) ;
768
- quote ! { crate :: #wproxy<' a, #rty, #name_constant_case_spec, #fty, #name_constant_case_aw , #width, O > }
807
+ quote ! { crate :: #wproxy<' a, #rty, #name_constant_case_spec, #fty, #value_write_ty , #width, O > }
769
808
} ;
770
809
mod_items. extend ( quote ! {
771
- #[ doc = #writerdoc ]
810
+ #[ doc = #field_writer_brief ]
772
811
pub type #writer_ty<' a, const O : u8 > = #proxy;
773
812
} ) ;
774
813
}
814
+
815
+ // generate proxy items from collected information
775
816
if !proxy_items. is_empty ( ) {
776
817
mod_items. extend ( quote ! {
777
818
impl <' a, const O : u8 > #writer_ty<' a, O > {
@@ -1121,7 +1162,7 @@ fn lookup_filter<'a>(
1121
1162
) -> Option < ( & ' a EnumeratedValues , Option < Base < ' a > > ) > {
1122
1163
for ( evs, base) in evs. iter ( ) {
1123
1164
if evs. usage == Some ( usage) {
1124
- return Some ( ( * evs, base. clone ( ) ) ) ;
1165
+ return Some ( ( * evs, * base) ) ;
1125
1166
}
1126
1167
}
1127
1168
0 commit comments