mirror of
https://gitlab.cern.ch/wotsubo/endcap-sl-software-ri-generator.git
synced 2025-02-23 17:17:08 +09:00
fix: add values pattern to "single" registers, introducing FieldType
This commit is contained in:
parent
49a9698a32
commit
f96aab4d9d
1 changed files with 146 additions and 21 deletions
|
@ -6,7 +6,7 @@ use itertools::Itertools;
|
||||||
use proc_macro2::{Ident, Literal, TokenStream};
|
use proc_macro2::{Ident, Literal, TokenStream};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
use crate::types::{DataType, Field, MultipleParams, Register};
|
use crate::types::{DataType, Field, MultipleParams, Register, Value};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
util::{self, RustUxTypes},
|
util::{self, RustUxTypes},
|
||||||
|
@ -153,6 +153,11 @@ fn reg_type_def_with_field(
|
||||||
Ok((out, upper_camel_name.clone(), type_ux))
|
Ok((out, upper_camel_name.clone(), type_ux))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum FieldType<'a> {
|
||||||
|
RustType(RustUxTypes),
|
||||||
|
CustomValue(&'a [Value]),
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate code for each field, which consists of these three.
|
/// Generate code for each field, which consists of these three.
|
||||||
/// 1. mask definition
|
/// 1. mask definition
|
||||||
/// 2. getter method
|
/// 2. getter method
|
||||||
|
@ -172,7 +177,10 @@ fn generate_field(
|
||||||
let base_type = util::RustUxTypes::from(basetype).to_rust_type_token();
|
let base_type = util::RustUxTypes::from(basetype).to_rust_type_token();
|
||||||
|
|
||||||
let snake_case_name = util::parse_to_ident(&field.name.to_snake_case())?;
|
let snake_case_name = util::parse_to_ident(&field.name.to_snake_case())?;
|
||||||
let field_type = util::RustUxTypes::from_mask(field.mask);
|
let field_type = match field.elements.is_empty() {
|
||||||
|
true => FieldType::RustType(util::RustUxTypes::from_mask(field.mask)),
|
||||||
|
false => FieldType::CustomValue(&field.elements),
|
||||||
|
};
|
||||||
|
|
||||||
let (code_mask, code_getter, code_setter) = match &field.multiple {
|
let (code_mask, code_getter, code_setter) = match &field.multiple {
|
||||||
Some(multiple_params) => generate_multiple_field(
|
Some(multiple_params) => generate_multiple_field(
|
||||||
|
@ -198,10 +206,11 @@ fn generate_field(
|
||||||
/// Generate "single" field definition (mask, getter, setter).
|
/// Generate "single" field definition (mask, getter, setter).
|
||||||
///
|
///
|
||||||
/// # Cases
|
/// # Cases
|
||||||
/// This function is separated into two cases.
|
/// This function is separated into three cases based on field types [`FieldType`].
|
||||||
///
|
///
|
||||||
/// - field is `bool` => [`generate_single_bool_field`]
|
/// - field is `bool` => [`generate_single_bool_field`]
|
||||||
/// - field is `u8`/`u16`/`u32` => [`generate_single_ux_field`]
|
/// - field is `u8`/`u16`/`u32` => [`generate_single_ux_field`]
|
||||||
|
/// - field is custom [`Value`] => [`generate_custom_values_mask_enumdef`] & todo
|
||||||
///
|
///
|
||||||
/// For the details of types of register/field, see [`DataType`].
|
/// For the details of types of register/field, see [`DataType`].
|
||||||
/// Note that in both cases, mask definitions are the same.
|
/// Note that in both cases, mask definitions are the same.
|
||||||
|
@ -209,17 +218,34 @@ fn generate_single_field(
|
||||||
mask_name: Ident,
|
mask_name: Ident,
|
||||||
base_type: Ident,
|
base_type: Ident,
|
||||||
mask_val: u32,
|
mask_val: u32,
|
||||||
field_type: RustUxTypes,
|
field_type: FieldType,
|
||||||
snake_case_name: Ident,
|
snake_case_name: Ident,
|
||||||
) -> (TokenStream, TokenStream, TokenStream) {
|
) -> (TokenStream, TokenStream, TokenStream) {
|
||||||
let mask_val = util::parse_to_literal(&format!("0x{:x}", mask_val)).unwrap();
|
let mask_val = util::parse_to_literal(&format!("0x{:x}", mask_val)).unwrap();
|
||||||
let code_mask = quote! {
|
let code_mask = match field_type {
|
||||||
const #mask_name: #base_type = #mask_val;
|
FieldType::RustType(_) => {
|
||||||
|
quote! {
|
||||||
|
const #mask_name: #base_type = #mask_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FieldType::CustomValue(values) => {
|
||||||
|
let additional =
|
||||||
|
generate_custom_values_mask_enumdef(&base_type, &snake_case_name, values);
|
||||||
|
quote! {
|
||||||
|
const #mask_name: #base_type = #mask_val;
|
||||||
|
#additional
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let (code_getter, code_setter) = match field_type {
|
let (code_getter, code_setter) = match field_type {
|
||||||
RustUxTypes::Bool => generate_single_bool_field(mask_name, snake_case_name),
|
FieldType::RustType(field_type) => match field_type {
|
||||||
RustUxTypes::U8 | RustUxTypes::U16 | RustUxTypes::U32 => {
|
RustUxTypes::Bool => generate_single_bool_field(mask_name, snake_case_name),
|
||||||
generate_single_ux_field(mask_name, base_type, snake_case_name, field_type)
|
RustUxTypes::U8 | RustUxTypes::U16 | RustUxTypes::U32 => {
|
||||||
|
generate_single_ux_field(mask_name, base_type, snake_case_name, field_type)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FieldType::CustomValue(values) => {
|
||||||
|
generate_custom_values_field(mask_name, snake_case_name, values)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -281,6 +307,96 @@ fn generate_single_ux_field(
|
||||||
(code_getter, code_setter)
|
(code_getter, code_setter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn custom_value_const_name(field_name: &Ident, value_name: &String) -> Ident {
|
||||||
|
util::parse_to_ident(&format!(
|
||||||
|
"{}_{}",
|
||||||
|
field_name.to_string().to_shouty_snake_case(),
|
||||||
|
value_name.to_shouty_snake_case()
|
||||||
|
))
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate const var and value enum definition.
|
||||||
|
fn generate_custom_values_mask_enumdef(
|
||||||
|
base_type: &Ident,
|
||||||
|
field_name: &Ident,
|
||||||
|
values: &[Value],
|
||||||
|
) -> TokenStream {
|
||||||
|
let masks = values.iter().map(|value| {
|
||||||
|
let const_name = custom_value_const_name(field_name, &value.name);
|
||||||
|
let val = value.data;
|
||||||
|
quote! {
|
||||||
|
const #const_name: #base_type = #val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let variants = values.iter().map(|value| {
|
||||||
|
let desc = value.desc.clone().unwrap_or("".to_string());
|
||||||
|
let variant_name = util::parse_to_ident(&value.name.to_upper_camel_case()).unwrap();
|
||||||
|
quote! {
|
||||||
|
#[doc = #desc]
|
||||||
|
#variant_name
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let value_enum_name =
|
||||||
|
util::parse_to_ident(&field_name.to_string().to_upper_camel_case()).unwrap();
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#(#masks)*
|
||||||
|
pub enum #value_enum_name {
|
||||||
|
#(#variants),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_custom_values_field(
|
||||||
|
mask_name: Ident,
|
||||||
|
snake_case_name: Ident,
|
||||||
|
values: &[Value],
|
||||||
|
) -> (TokenStream, TokenStream) {
|
||||||
|
let setter_name = util::parse_to_ident(&format!("set_{}", snake_case_name)).unwrap();
|
||||||
|
let value_enum_name =
|
||||||
|
util::parse_to_ident(&snake_case_name.to_string().to_upper_camel_case()).unwrap();
|
||||||
|
let (getter_match_arms, setter_match_arms): (Vec<_>, Vec<_>) = values
|
||||||
|
.iter()
|
||||||
|
.map(|value| {
|
||||||
|
let const_name = custom_value_const_name(&snake_case_name, &value.name);
|
||||||
|
let variant_name = util::parse_to_ident(&value.name.to_upper_camel_case()).unwrap();
|
||||||
|
(
|
||||||
|
quote! {
|
||||||
|
#const_name => #value_enum_name::#variant_name
|
||||||
|
},
|
||||||
|
quote! {
|
||||||
|
#value_enum_name::#variant_name => #const_name
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unzip();
|
||||||
|
let code_getter = quote! {
|
||||||
|
pub fn #snake_case_name(&self) -> #value_enum_name {
|
||||||
|
match (self.inner & #mask_name)
|
||||||
|
>> #mask_name.trailing_zeros()
|
||||||
|
{
|
||||||
|
#(#getter_match_arms),*,
|
||||||
|
_ => panic!("must not reachable"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let code_setter = quote! {
|
||||||
|
pub fn #setter_name(self, val: #value_enum_name) -> Self {
|
||||||
|
let val = match val {
|
||||||
|
#(#setter_match_arms),*
|
||||||
|
};
|
||||||
|
let mut inner = self.inner;
|
||||||
|
inner &= !#mask_name;
|
||||||
|
inner |= val;
|
||||||
|
|
||||||
|
Self { inner }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(code_getter, code_setter)
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate "multiple" field definition (mask, getter, setter).
|
/// Generate "multiple" field definition (mask, getter, setter).
|
||||||
///
|
///
|
||||||
/// # Cases
|
/// # Cases
|
||||||
|
@ -288,17 +404,21 @@ fn generate_single_ux_field(
|
||||||
///
|
///
|
||||||
/// - fields are `bool` => [`generate_multiple_bool_field`]
|
/// - fields are `bool` => [`generate_multiple_bool_field`]
|
||||||
/// - fields are `u8`/`u16`/`u32` => [`generate_multiple_ux_field`]
|
/// - fields are `u8`/`u16`/`u32` => [`generate_multiple_ux_field`]
|
||||||
|
/// - fields are custom [`Value`] => todo
|
||||||
fn generate_multiple_field(
|
fn generate_multiple_field(
|
||||||
mask_name: Ident,
|
mask_name: Ident,
|
||||||
base_type: Ident,
|
base_type: Ident,
|
||||||
single_mask_val: u32,
|
single_mask_val: u32,
|
||||||
single_field_type: RustUxTypes,
|
single_field_type: FieldType,
|
||||||
snake_case_name: Ident,
|
snake_case_name: Ident,
|
||||||
multiple_params: &MultipleParams,
|
multiple_params: &MultipleParams,
|
||||||
) -> (TokenStream, TokenStream, TokenStream) {
|
) -> (TokenStream, TokenStream, TokenStream) {
|
||||||
let num_multiple = multiple_params.multiple;
|
let num_multiple = multiple_params.multiple;
|
||||||
let id_num_multiple = util::parse_to_literal(&num_multiple.to_string()).unwrap();
|
let id_num_multiple = util::parse_to_literal(&num_multiple.to_string()).unwrap();
|
||||||
let id_field_type = single_field_type.to_rust_type_token();
|
let id_field_type = match single_field_type {
|
||||||
|
FieldType::RustType(ref single_field_type) => single_field_type.to_rust_type_token(),
|
||||||
|
FieldType::CustomValue(_) => todo!("HERE NEXT"),
|
||||||
|
};
|
||||||
let masks: Vec<_> = (0..multiple_params.multiple)
|
let masks: Vec<_> = (0..multiple_params.multiple)
|
||||||
.map(|x| x * multiple_params.offset)
|
.map(|x| x * multiple_params.offset)
|
||||||
.map(|offset| single_mask_val << offset)
|
.map(|offset| single_mask_val << offset)
|
||||||
|
@ -310,21 +430,26 @@ fn generate_multiple_field(
|
||||||
};
|
};
|
||||||
|
|
||||||
let (code_getter, code_setter) = match single_field_type {
|
let (code_getter, code_setter) = match single_field_type {
|
||||||
RustUxTypes::Bool => {
|
FieldType::RustType(single_field_type) => match single_field_type {
|
||||||
generate_multiple_bool_field(mask_name, base_type, snake_case_name, masks.clone())
|
RustUxTypes::Bool => {
|
||||||
}
|
generate_multiple_bool_field(mask_name, base_type, snake_case_name, masks.clone())
|
||||||
RustUxTypes::U8 | RustUxTypes::U16 | RustUxTypes::U32 => generate_multiple_ux_field(
|
}
|
||||||
mask_name,
|
RustUxTypes::U8 | RustUxTypes::U16 | RustUxTypes::U32 => generate_multiple_ux_field(
|
||||||
base_type,
|
mask_name,
|
||||||
snake_case_name,
|
base_type,
|
||||||
single_field_type,
|
snake_case_name,
|
||||||
masks,
|
single_field_type,
|
||||||
),
|
masks,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
FieldType::CustomValue(_) => todo!("HERE NEXT"),
|
||||||
};
|
};
|
||||||
|
|
||||||
(code_mask, code_getter, code_setter)
|
(code_mask, code_getter, code_setter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_single_value_field() -> () {}
|
||||||
|
|
||||||
/// Generate bool "multiple" field definition (getter, setter).
|
/// Generate bool "multiple" field definition (getter, setter).
|
||||||
fn generate_multiple_bool_field(
|
fn generate_multiple_bool_field(
|
||||||
mask_name: Ident,
|
mask_name: Ident,
|
||||||
|
|
Loading…
Reference in a new issue