Skip to content

Commit 4522976

Browse files
bors[bot]burrbull
andauthored
Merge #630
630: docs from #627 r=therealprof a=burrbull Some non-breaking changes from #627 Co-authored-by: Andrey Zgarbul <[email protected]>
2 parents d9423df + afaa486 commit 4522976

File tree

2 files changed

+96
-54
lines changed

2 files changed

+96
-54
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1212
- Add new feature `feature_group` which will generate cfg attribute for
1313
every group name when it is on
1414
- Sort fields by offset before process
15+
- advanced comments
1516

1617
## [v0.24.1] - 2022-07-04
1718

src/generate/register.rs

Lines changed: 95 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -378,10 +378,12 @@ pub fn fields(
378378
// Reader and writer use one common `Enum_A` unless a fields have two `enumeratedValues`,
379379
// then we have one for read-only `Enum_A` and another for write-only `Enum_AW`
380380
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;
382382

383383
let mut evs_r = None;
384384

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.
385387
let field_dim = match f {
386388
Field::Array(_, de) => {
387389
let first = if let Some(dim_index) = &de.dim_index {
@@ -412,27 +414,8 @@ pub fn fields(
412414
}
413415
};
414416

417+
// If this field can be read, generate read proxy structure and value structure.
415418
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\nThe field is **cleared** (set to zero) following a read operation.",
428-
ReadAction::Set => "\n\nThe field is **set** (set to ones) following a read operation.",
429-
ReadAction::Modify => "\n\nThe field is **modified** in some way after a read operation.",
430-
ReadAction::ModifyExternal => "\n\nOne 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-
436419
let cast = if width == 1 {
437420
quote! { != 0 }
438421
} else {
@@ -453,6 +436,29 @@ pub fn fields(
453436
}
454437
};
455438

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\nThe field is **cleared** (set to zero) following a read operation.",
453+
ReadAction::Set => "\n\nThe field is **set** (set to ones) following a read operation.",
454+
ReadAction::Modify => "\n\nThe field is **modified** in some way after a read operation.",
455+
ReadAction::ModifyExternal => "\n\nOne 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+
456462
if let Some((first, dim, increment, suffixes, suffixes_str)) = &field_dim {
457463
let offset_calc = calculate_offset(*first, *increment, offset, true);
458464
let value = quote! { ((self.bits >> #offset_calc) & #hexmask) #cast };
@@ -507,9 +513,13 @@ pub fn fields(
507513
});
508514
}
509515

516+
// collect information on items in enumeration to generate it later.
510517
let mut enum_items = TokenStream::new();
511-
let mut derived = false;
518+
let mut should_derive_reader = true;
512519
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.
513523
if let Some((evs, base)) = lookup_filter(&lookup_results, Usage::Read) {
514524
evs_r = Some(evs.clone());
515525

@@ -528,13 +538,26 @@ pub fn fields(
528538

529539
let pc = pc_orig.to_sanitized_constant_case();
530540
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;
533549
} 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.
534552
let has_reserved_variant = evs.values.len() != (1 << width);
553+
// parse enum variants from enumeratedValues svd record
535554
let variants = Variant::from_enumerated_values(evs, config.pascal_enum_values)?;
536555

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.
537559
if variants.is_empty() {
560+
// generate struct VALUE_READ_TY_A(fty) and From<fty> for VALUE_READ_TY_A.
538561
add_with_no_variants(
539562
mod_items,
540563
&name_constant_case_a,
@@ -543,6 +566,7 @@ pub fn fields(
543566
rv,
544567
);
545568
} else {
569+
// generate enum VALUE_READ_TY_A { ... each variants ... } and and From<fty> for VALUE_READ_TY_A.
546570
add_from_variants(
547571
mod_items,
548572
&variants,
@@ -552,6 +576,8 @@ pub fn fields(
552576
rv,
553577
);
554578

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.
555581
let mut arms = TokenStream::new();
556582
for v in variants.iter().map(|v| {
557583
let i = util::unsuffixed_or_bool(v.value, width);
@@ -566,6 +592,11 @@ pub fn fields(
566592
arms.extend(v);
567593
}
568594

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.
569600
if has_reserved_variant {
570601
arms.extend(quote! {
571602
_ => None,
@@ -576,6 +607,8 @@ pub fn fields(
576607
});
577608
}
578609

610+
// prepare the `variant` function. This function would return field value in
611+
// Rust structure; if we have reserved variant we return by Option.
579612
if has_reserved_variant {
580613
enum_items.extend(quote! {
581614
#[doc = "Get enumerated values variant"]
@@ -597,6 +630,7 @@ pub fn fields(
597630
}});
598631
}
599632

633+
// for each variant defined, we generate an `is_variant` function.
600634
for v in &variants {
601635
let pc = &v.pc;
602636
let sc = &v.nksc;
@@ -624,17 +658,20 @@ pub fn fields(
624658
ftype = name_constant_case_a.clone();
625659
}
626660
}
627-
if !derived {
661+
662+
// derive the read proxy structure if necessary.
663+
if should_derive_reader {
628664
let reader = if width == 1 {
629665
quote! { crate::BitReader<#ftype> }
630666
} else {
631667
quote! { crate::FieldReader<#fty, #ftype> }
632668
};
633669
mod_items.extend(quote! {
634-
#[doc = #readerdoc]
670+
#[doc = #field_reader_brief]
635671
pub type #reader_ty = #reader;
636672
});
637673
}
674+
// generate the enumeration functions prepared before.
638675
if !enum_items.is_empty() {
639676
mod_items.extend(quote! {
640677
impl #reader_ty {
@@ -644,12 +681,15 @@ pub fn fields(
644681
}
645682
}
646683

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.
647686
if can_write {
648687
let mwv = f
649688
.modified_write_values
650689
.or(register.modified_write_values)
651690
.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 {
653693
format!(
654694
"Fields `{}` writer - {}",
655695
util::replace_suffix(&f.name, suffixes_str),
@@ -660,45 +700,37 @@ pub fn fields(
660700
};
661701

662702
let new_pc_aw = Ident::new(&(name_constant_case.clone() + "_AW"), span);
703+
// name of write proxy type
663704
let writer_ty = Ident::new(&(name_constant_case.clone() + "_W"), span);
664705

665706
let mut proxy_items = TokenStream::new();
666707
let mut unsafety = unsafety(f.write_constraint.as_ref(), width);
667708

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.
669711
if let Some((evs, base)) = lookup_filter(&lookup_results, Usage::Write) {
712+
// parse variants from enumeratedValues svd record
670713
let variants = Variant::from_enumerated_values(evs, config.pascal_enum_values)?;
671714

715+
// if the write structure is finite, it can be safely written.
672716
if variants.len() == 1 << width {
673717
unsafety = false;
674718
}
675719

676720
if Some(evs) != evs_r.as_ref() {
677-
name_constant_case_aw = &new_pc_aw;
721+
value_write_ty = &new_pc_aw;
678722
if let Some(base) = base.as_ref() {
679723
let pc = util::replace_suffix(base.field, "");
680724
let pc = pc.to_sanitized_constant_case();
681725
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);
689727
} 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);
697729
} else {
698730
add_from_variants(
699731
mod_items,
700732
&variants,
701-
name_constant_case_aw,
733+
value_write_ty,
702734
&fty,
703735
&description,
704736
rv,
@@ -711,32 +743,39 @@ pub fn fields(
711743
let pc = util::replace_suffix(base.field, "");
712744
let pc = pc.to_sanitized_constant_case();
713745
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;
716754
}
717755
_ => {
718756
if !variants.is_empty() {
757+
// for each variant defined, generate a write function to this field.
719758
for v in &variants {
720759
let pc = &v.pc;
721760
let sc = &v.sc;
722-
723761
let doc = util::escape_brackets(util::respace(&v.doc).as_ref());
724762
proxy_items.extend(quote! {
725763
#[doc = #doc]
726764
#inline
727765
pub fn #sc(self) -> &'a mut W {
728-
self.variant(#name_constant_case_aw::#pc)
766+
self.variant(#value_write_ty::#pc)
729767
}
730768
});
731769
}
732770
}
733771
}
734772
}
735773
} else {
736-
name_constant_case_aw = &fty;
774+
value_write_ty = &fty;
737775
}
738776

739-
if !derived {
777+
// derive writer structure by type alias to generic write proxy structure.
778+
if should_derive_writer {
740779
let proxy = if width == 1 {
741780
let wproxy = Ident::new(
742781
match mwv {
@@ -754,7 +793,7 @@ pub fn fields(
754793
},
755794
span,
756795
);
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> }
758797
} else {
759798
let wproxy = Ident::new(
760799
if unsafety {
@@ -765,13 +804,15 @@ pub fn fields(
765804
span,
766805
);
767806
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> }
769808
};
770809
mod_items.extend(quote! {
771-
#[doc = #writerdoc]
810+
#[doc = #field_writer_brief]
772811
pub type #writer_ty<'a, const O: u8> = #proxy;
773812
});
774813
}
814+
815+
// generate proxy items from collected information
775816
if !proxy_items.is_empty() {
776817
mod_items.extend(quote! {
777818
impl<'a, const O: u8> #writer_ty<'a, O> {
@@ -1121,7 +1162,7 @@ fn lookup_filter<'a>(
11211162
) -> Option<(&'a EnumeratedValues, Option<Base<'a>>)> {
11221163
for (evs, base) in evs.iter() {
11231164
if evs.usage == Some(usage) {
1124-
return Some((*evs, base.clone()));
1165+
return Some((*evs, *base));
11251166
}
11261167
}
11271168

0 commit comments

Comments
 (0)