11use std:: borrow:: Cow ;
22use std:: cmp:: Ordering ;
3- use std :: collections :: HashMap ;
3+ use svd_parser :: expand :: { derive_cluster , derive_peripheral , derive_register , BlockPath , Index } ;
44
55use crate :: svd:: {
6- array:: names, Cluster , ClusterInfo , DeriveFrom , DimElement , Peripheral , Register ,
7- RegisterCluster ,
6+ array:: names, Cluster , ClusterInfo , DimElement , Peripheral , Register , RegisterCluster ,
87} ;
98use log:: { debug, trace, warn} ;
109use proc_macro2:: { Ident , Punct , Spacing , Span , TokenStream } ;
@@ -19,41 +18,32 @@ use anyhow::{anyhow, bail, Context, Result};
1918
2019use crate :: generate:: register;
2120
22- pub fn render (
23- p_original : & Peripheral ,
24- all_peripherals : & [ Peripheral ] ,
25- config : & Config ,
26- ) -> Result < TokenStream > {
21+ pub fn render ( p_original : & Peripheral , index : & Index , config : & Config ) -> Result < TokenStream > {
2722 let mut out = TokenStream :: new ( ) ;
2823
29- let p_derivedfrom = p_original
30- . derived_from
31- . as_ref ( )
32- . and_then ( |s| all_peripherals. iter ( ) . find ( |x| x. name == * s) ) ;
33-
34- let p_merged = p_derivedfrom. map ( |ancestor| p_original. derive_from ( ancestor) ) ;
35- let p = p_merged. as_ref ( ) . unwrap_or ( p_original) ;
36-
37- if let ( Some ( df) , None ) = ( p_original. derived_from . as_ref ( ) , & p_derivedfrom) {
38- return Err ( anyhow ! (
39- "Couldn't find derivedFrom original: {} for {}, skipping" ,
40- df,
41- p_original. name
42- ) ) ;
24+ let mut p = p_original. clone ( ) ;
25+ let mut path = None ;
26+ let dpath = p. derived_from . take ( ) ;
27+ if let Some ( dpath) = dpath {
28+ path = derive_peripheral ( & mut p, & dpath, index) ?;
4329 }
4430
45- let name = util:: name_of ( p, config. ignore_groups ) ;
31+ let name = util:: name_of ( & p, config. ignore_groups ) ;
4632 let span = Span :: call_site ( ) ;
4733 let name_str = name. to_sanitized_constant_case ( ) ;
4834 let name_constant_case = Ident :: new ( & name_str, span) ;
4935 let address = util:: hex ( p. base_address as u64 ) ;
5036 let description = util:: respace ( p. description . as_ref ( ) . unwrap_or ( & p. name ) ) ;
5137
5238 let name_snake_case = Ident :: new ( & name. to_sanitized_snake_case ( ) , span) ;
53- let ( derive_regs, base) = if let ( Some ( df) , None ) = ( p_derivedfrom, & p_original. registers ) {
54- ( true , Ident :: new ( & df. name . to_sanitized_snake_case ( ) , span) )
39+ let ( derive_regs, base, path) = if let Some ( path) = path {
40+ (
41+ true ,
42+ Ident :: new ( & path. peripheral . to_sanitized_snake_case ( ) , span) ,
43+ path,
44+ )
5545 } else {
56- ( false , name_snake_case. clone ( ) )
46+ ( false , name_snake_case. clone ( ) , BlockPath :: new ( & p . name ) )
5747 } ;
5848
5949 let feature_attribute = if config. feature_group && p. group_name . is_some ( ) {
@@ -63,7 +53,7 @@ pub fn render(
6353 quote ! { }
6454 } ;
6555
66- match p_original {
56+ match & p {
6757 Peripheral :: Array ( p, dim) => {
6858 let names: Vec < Cow < str > > = names ( p, dim) . map ( |n| n. into ( ) ) . collect ( ) ;
6959 let names_str = names. iter ( ) . map ( |n| n. to_sanitized_constant_case ( ) ) ;
@@ -166,68 +156,63 @@ pub fn render(
166156 return Ok ( out) ;
167157 }
168158
169- // erc: *E*ither *R*egister or *C*luster
170- let ercs_in = p. registers . as_ref ( ) . map ( |x| x. as_ref ( ) ) . unwrap_or ( & [ ] [ ..] ) ;
171-
172- // make a pass to expand derived registers and clusters. Ideally, for the most minimal
173- // code size, we'd do some analysis to figure out if we can 100% reuse the
174- // code that we're deriving from. For the sake of proving the concept, we're
175- // just going to emit a second copy of the accessor code. It'll probably
176- // get inlined by the compiler anyway, right? :-)
177-
178- // Build a map so that we can look up registers within this peripheral
179- let mut erc_map = HashMap :: new ( ) ;
180- for erc in ercs_in {
181- erc_map. insert ( util:: erc_name ( erc) , erc) ;
182- }
159+ let description = util:: escape_brackets (
160+ util:: respace ( p. description . as_ref ( ) . unwrap_or ( & name. as_ref ( ) . to_owned ( ) ) ) . as_ref ( ) ,
161+ ) ;
183162
184163 // Build up an alternate erc list by expanding any derived registers/clusters
185- let mut ercs = Vec :: with_capacity ( ercs_in. len ( ) ) ;
186- for erc in ercs_in {
187- ercs. push ( derive_register_cluster ( erc, & erc_map) ?. into_owned ( ) ) ;
188- }
189-
190- // And revise registers, clusters and ercs to refer to our expanded versions
191- let registers: & [ & Register ] = & util:: only_registers ( & ercs) [ ..] ;
192- let clusters = util:: only_clusters ( & ercs) ;
164+ // erc: *E*ither *R*egister or *C*luster
165+ let mut ercs = p. registers . take ( ) . unwrap_or_default ( ) ;
193166
194167 // No `struct RegisterBlock` can be generated
195- if registers . is_empty ( ) && clusters . is_empty ( ) {
168+ if ercs . is_empty ( ) {
196169 // Drop the definition of the peripheral
197170 return Ok ( TokenStream :: new ( ) ) ;
198171 }
199172
200- // Push any register or cluster blocks into the output
201- debug ! (
202- "Pushing {} register or cluster blocks into output" ,
203- ercs. len( )
204- ) ;
173+ debug ! ( "Pushing cluster & register information into output" ) ;
174+ // Push all cluster & register related information into the peripheral module
175+
205176 let mut mod_items = TokenStream :: new ( ) ;
206- mod_items. extend ( register_or_cluster_block ( & ercs, None , config) ?) ;
207177
208- debug ! ( "Pushing cluster information into output" ) ;
209- // Push all cluster related information into the peripheral module
210- for c in & clusters {
211- trace ! ( "Cluster: {}" , c. name) ;
212- mod_items. extend ( cluster_block ( c, p, all_peripherals, config) ?) ;
213- }
178+ for erc in & mut ercs {
179+ match erc {
180+ RegisterCluster :: Cluster ( c) => {
181+ trace ! ( "Cluster: {}" , c. name) ;
182+ let mut cpath = None ;
183+ let dpath = c. derived_from . take ( ) ;
184+ if let Some ( dpath) = dpath {
185+ cpath = derive_cluster ( c, & dpath, & path, index) ?;
186+ }
187+ let cpath = cpath. unwrap_or_else ( || path. new_cluster ( & c. name ) ) ;
188+ mod_items. extend ( cluster_block ( c, & cpath, index, config) ?) ;
189+ }
214190
215- debug ! ( "Pushing register information into output" ) ;
216- // Push all register related information into the peripheral module
217- for reg in registers {
218- trace ! ( "Register: {}" , reg. name) ;
219- match register:: render ( reg, registers, p, all_peripherals, config) {
220- Ok ( rendered_reg) => mod_items. extend ( rendered_reg) ,
221- Err ( e) => {
222- let res: Result < TokenStream > = Err ( e) ;
223- return handle_reg_error ( "Error rendering register" , * reg, res) ;
191+ RegisterCluster :: Register ( reg) => {
192+ trace ! ( "Register: {}" , reg. name) ;
193+ let mut rpath = None ;
194+ let dpath = reg. derived_from . take ( ) ;
195+ if let Some ( dpath) = dpath {
196+ rpath = derive_register ( reg, & dpath, & path, index) ?;
197+ }
198+ let rpath = rpath. unwrap_or_else ( || path. new_register ( & reg. name ) ) ;
199+ match register:: render ( reg, & rpath, index, config) {
200+ Ok ( rendered_reg) => mod_items. extend ( rendered_reg) ,
201+ Err ( e) => {
202+ let res: Result < TokenStream > = Err ( e) ;
203+ return handle_reg_error ( "Error rendering register" , reg, res) ;
204+ }
205+ } ;
224206 }
225- } ;
207+ }
226208 }
227209
228- let description = util:: escape_brackets (
229- util:: respace ( p. description . as_ref ( ) . unwrap_or ( & name. as_ref ( ) . to_owned ( ) ) ) . as_ref ( ) ,
210+ // Push any register or cluster blocks into the output
211+ debug ! (
212+ "Pushing {} register or cluster blocks into output" ,
213+ ercs. len( )
230214 ) ;
215+ let reg_block = register_or_cluster_block ( & ercs, None , config) ?;
231216
232217 let open = Punct :: new ( '{' , Spacing :: Alone ) ;
233218 let close = Punct :: new ( '}' , Spacing :: Alone ) ;
@@ -238,47 +223,14 @@ pub fn render(
238223 pub mod #name_snake_case #open
239224 } ) ;
240225
226+ out. extend ( reg_block) ;
241227 out. extend ( mod_items) ;
242228
243229 close. to_tokens ( & mut out) ;
244230
245- Ok ( out)
246- }
247-
248- fn derive_register_cluster < ' a > (
249- erc : & ' a RegisterCluster ,
250- erc_map : & ' a HashMap < & ' a String , & ' a RegisterCluster > ,
251- ) -> Result < Cow < ' a , RegisterCluster > > {
252- Ok ( if let Some ( derived) = util:: erc_derived_from ( erc) {
253- let ancestor = erc_map. get ( derived) . ok_or_else ( || {
254- anyhow ! (
255- "register/cluster {} derivedFrom missing register/cluster {}" ,
256- util:: erc_name( erc) ,
257- derived
258- )
259- } ) ?;
231+ p. registers = Some ( ercs) ;
260232
261- let ancestor = derive_register_cluster ( ancestor, erc_map) ?;
262-
263- use RegisterCluster :: * ;
264- match ( erc, ancestor. as_ref ( ) ) {
265- ( Register ( reg) , Register ( other_reg) ) => {
266- Cow :: Owned ( Register ( reg. derive_from ( other_reg) ) )
267- }
268- ( Cluster ( cluster) , Cluster ( other_cluster) ) => {
269- Cow :: Owned ( Cluster ( cluster. derive_from ( other_cluster) ) )
270- }
271- _ => {
272- return Err ( anyhow ! (
273- "{} can't be derived from {}" ,
274- util:: erc_name( erc) ,
275- util:: erc_name( & ancestor)
276- ) ) ;
277- }
278- }
279- } else {
280- Cow :: Borrowed ( erc)
281- } )
233+ Ok ( out)
282234}
283235
284236#[ derive( Clone , Debug ) ]
@@ -956,16 +908,48 @@ fn expand_register(
956908
957909/// Render a Cluster Block into `TokenStream`
958910fn cluster_block (
959- c : & Cluster ,
960- p : & Peripheral ,
961- all_peripherals : & [ Peripheral ] ,
911+ c : & mut Cluster ,
912+ path : & BlockPath ,
913+ index : & Index ,
962914 config : & Config ,
963915) -> Result < TokenStream > {
964916 let mut mod_items = TokenStream :: new ( ) ;
965917
966- // name_snake_case needs to take into account array type.
967- let description =
968- util:: escape_brackets ( util:: respace ( c. description . as_ref ( ) . unwrap_or ( & c. name ) ) . as_ref ( ) ) ;
918+ for rc in & mut c. children {
919+ match rc {
920+ // Generate the sub-cluster blocks.
921+ RegisterCluster :: Cluster ( c) => {
922+ let mut cpath = None ;
923+ let dpath = c. derived_from . take ( ) ;
924+ if let Some ( dpath) = dpath {
925+ cpath = derive_cluster ( c, & dpath, path, index) ?;
926+ }
927+ let cpath = cpath. unwrap_or_else ( || path. new_cluster ( & c. name ) ) ;
928+ mod_items. extend ( cluster_block ( c, & cpath, index, config) ?) ;
929+ }
930+
931+ // Generate definition for each of the registers.
932+ RegisterCluster :: Register ( reg) => {
933+ let mut rpath = None ;
934+ let dpath = reg. derived_from . take ( ) ;
935+ if let Some ( dpath) = dpath {
936+ rpath = derive_register ( reg, & dpath, path, index) ?;
937+ }
938+ let rpath = rpath. unwrap_or_else ( || path. new_register ( & reg. name ) ) ;
939+ match register:: render ( reg, & rpath, index, config) {
940+ Ok ( rendered_reg) => mod_items. extend ( rendered_reg) ,
941+ Err ( e) => {
942+ let res: Result < TokenStream > = Err ( e) ;
943+ return handle_reg_error (
944+ "Error generating register definition for a register cluster" ,
945+ reg,
946+ res,
947+ ) ;
948+ }
949+ } ;
950+ }
951+ }
952+ }
969953
970954 // Generate the register block.
971955 let mod_name = util:: replace_suffix (
@@ -975,31 +959,14 @@ fn cluster_block(
975959 } ,
976960 "" ,
977961 ) ;
978- let name_snake_case = Ident :: new ( & mod_name. to_sanitized_snake_case ( ) , Span :: call_site ( ) ) ;
979962
980963 let reg_block = register_or_cluster_block ( & c. children , Some ( & mod_name) , config) ?;
981964
982- // Generate definition for each of the registers.
983- let registers = util:: only_registers ( & c. children ) ;
984- for reg in & registers {
985- match register:: render ( reg, & registers, p, all_peripherals, config) {
986- Ok ( rendered_reg) => mod_items. extend ( rendered_reg) ,
987- Err ( e) => {
988- let res: Result < TokenStream > = Err ( e) ;
989- return handle_reg_error (
990- "Error generating register definition for a register cluster" ,
991- * reg,
992- res,
993- ) ;
994- }
995- } ;
996- }
965+ // name_snake_case needs to take into account array type.
966+ let description =
967+ util:: escape_brackets ( util:: respace ( c. description . as_ref ( ) . unwrap_or ( & c. name ) ) . as_ref ( ) ) ;
997968
998- // Generate the sub-cluster blocks.
999- let clusters = util:: only_clusters ( & c. children ) ;
1000- for c in & clusters {
1001- mod_items. extend ( cluster_block ( c, p, all_peripherals, config) ?) ;
1002- }
969+ let name_snake_case = Ident :: new ( & mod_name. to_sanitized_snake_case ( ) , Span :: call_site ( ) ) ;
1003970
1004971 Ok ( quote ! {
1005972 #reg_block
0 commit comments