1
1
use std:: borrow:: Cow ;
2
2
use std:: cmp:: Ordering ;
3
- use std :: collections :: HashMap ;
3
+ use svd_parser :: expand :: { derive_cluster , derive_peripheral , derive_register , BlockPath , Index } ;
4
4
5
5
use crate :: svd:: {
6
- array:: names, Cluster , ClusterInfo , DeriveFrom , DimElement , Peripheral , Register ,
7
- RegisterCluster ,
6
+ array:: names, Cluster , ClusterInfo , DimElement , Peripheral , Register , RegisterCluster ,
8
7
} ;
9
8
use log:: { debug, trace, warn} ;
10
9
use proc_macro2:: { Ident , Punct , Spacing , Span , TokenStream } ;
@@ -19,41 +18,32 @@ use anyhow::{anyhow, bail, Context, Result};
19
18
20
19
use crate :: generate:: register;
21
20
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 > {
27
22
let mut out = TokenStream :: new ( ) ;
28
23
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) ?;
43
29
}
44
30
45
- let name = util:: name_of ( p, config. ignore_groups ) ;
31
+ let name = util:: name_of ( & p, config. ignore_groups ) ;
46
32
let span = Span :: call_site ( ) ;
47
33
let name_str = name. to_sanitized_constant_case ( ) ;
48
34
let name_constant_case = Ident :: new ( & name_str, span) ;
49
35
let address = util:: hex ( p. base_address as u64 ) ;
50
36
let description = util:: respace ( p. description . as_ref ( ) . unwrap_or ( & p. name ) ) ;
51
37
52
38
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
+ )
55
45
} else {
56
- ( false , name_snake_case. clone ( ) )
46
+ ( false , name_snake_case. clone ( ) , BlockPath :: new ( & p . name ) )
57
47
} ;
58
48
59
49
let feature_attribute = if config. feature_group && p. group_name . is_some ( ) {
@@ -63,7 +53,7 @@ pub fn render(
63
53
quote ! { }
64
54
} ;
65
55
66
- match p_original {
56
+ match & p {
67
57
Peripheral :: Array ( p, dim) => {
68
58
let names: Vec < Cow < str > > = names ( p, dim) . map ( |n| n. into ( ) ) . collect ( ) ;
69
59
let names_str = names. iter ( ) . map ( |n| n. to_sanitized_constant_case ( ) ) ;
@@ -166,68 +156,63 @@ pub fn render(
166
156
return Ok ( out) ;
167
157
}
168
158
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
+ ) ;
183
162
184
163
// 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 ( ) ;
193
166
194
167
// No `struct RegisterBlock` can be generated
195
- if registers . is_empty ( ) && clusters . is_empty ( ) {
168
+ if ercs . is_empty ( ) {
196
169
// Drop the definition of the peripheral
197
170
return Ok ( TokenStream :: new ( ) ) ;
198
171
}
199
172
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
+
205
176
let mut mod_items = TokenStream :: new ( ) ;
206
- mod_items. extend ( register_or_cluster_block ( & ercs, None , config) ?) ;
207
177
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
+ }
214
190
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
+ } ;
224
206
}
225
- } ;
207
+ }
226
208
}
227
209
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( )
230
214
) ;
215
+ let reg_block = register_or_cluster_block ( & ercs, None , config) ?;
231
216
232
217
let open = Punct :: new ( '{' , Spacing :: Alone ) ;
233
218
let close = Punct :: new ( '}' , Spacing :: Alone ) ;
@@ -238,47 +223,14 @@ pub fn render(
238
223
pub mod #name_snake_case #open
239
224
} ) ;
240
225
226
+ out. extend ( reg_block) ;
241
227
out. extend ( mod_items) ;
242
228
243
229
close. to_tokens ( & mut out) ;
244
230
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) ;
260
232
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)
282
234
}
283
235
284
236
#[ derive( Clone , Debug ) ]
@@ -956,16 +908,48 @@ fn expand_register(
956
908
957
909
/// Render a Cluster Block into `TokenStream`
958
910
fn cluster_block (
959
- c : & Cluster ,
960
- p : & Peripheral ,
961
- all_peripherals : & [ Peripheral ] ,
911
+ c : & mut Cluster ,
912
+ path : & BlockPath ,
913
+ index : & Index ,
962
914
config : & Config ,
963
915
) -> Result < TokenStream > {
964
916
let mut mod_items = TokenStream :: new ( ) ;
965
917
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
+ }
969
953
970
954
// Generate the register block.
971
955
let mod_name = util:: replace_suffix (
@@ -975,31 +959,14 @@ fn cluster_block(
975
959
} ,
976
960
"" ,
977
961
) ;
978
- let name_snake_case = Ident :: new ( & mod_name. to_sanitized_snake_case ( ) , Span :: call_site ( ) ) ;
979
962
980
963
let reg_block = register_or_cluster_block ( & c. children , Some ( & mod_name) , config) ?;
981
964
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 ( ) ) ;
997
968
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 ( ) ) ;
1003
970
1004
971
Ok ( quote ! {
1005
972
#reg_block
0 commit comments