1
1
use std:: borrow:: Cow ;
2
2
use std:: cmp:: Ordering ;
3
+ use std:: collections:: HashMap ;
3
4
4
5
use quote:: { ToTokens , Tokens } ;
5
- use crate :: svd:: { Cluster , ClusterInfo , Defaults , Peripheral , Register , RegisterCluster } ;
6
+ use crate :: svd:: { Cluster , ClusterInfo , Defaults , Peripheral , Register , RegisterCluster , RegisterInfo } ;
6
7
use syn:: { self , Ident } ;
7
8
use log:: warn;
8
9
@@ -12,26 +13,36 @@ use crate::util::{self, ToSanitizedSnakeCase, ToSanitizedUpperCase, BITS_PER_BYT
12
13
use crate :: generate:: register;
13
14
14
15
pub fn render (
15
- p : & Peripheral ,
16
+ p_original : & Peripheral ,
16
17
all_peripherals : & [ Peripheral ] ,
17
18
defaults : & Defaults ,
18
19
nightly : bool ,
19
20
) -> Result < Vec < Tokens > > {
20
21
let mut out = vec ! [ ] ;
21
22
23
+ let p_derivedfrom = p_original. derived_from . as_ref ( ) . and_then ( |s| {
24
+ all_peripherals. iter ( ) . find ( |x| x. name == * s)
25
+ } ) ;
26
+
27
+ let p_merged = p_derivedfrom. map ( |ancestor| p_original. derive_from ( ancestor) ) ;
28
+ let p = p_merged. as_ref ( ) . unwrap_or ( p_original) ;
29
+
30
+ if p_original. derived_from . is_some ( ) && p_derivedfrom. is_none ( ) {
31
+ eprintln ! ( "Couldn't find derivedFrom original: {} for {}, skipping" ,
32
+ p_original. derived_from. as_ref( ) . unwrap( ) , p_original. name) ;
33
+ return Ok ( out) ;
34
+ }
35
+
22
36
let name_pc = Ident :: new ( & * p. name . to_sanitized_upper_case ( ) ) ;
23
37
let address = util:: hex ( p. base_address ) ;
24
- let description =
25
- util :: escape_brackets ( util :: respace ( p . description . as_ref ( ) . unwrap_or ( & p . name ) ) . as_ref ( ) ) ;
38
+ let description = util :: respace ( p . description . as_ref ( ) . unwrap_or ( & p . name ) ) ;
39
+ let derive_regs = p_derivedfrom . is_some ( ) && p_original . registers . is_none ( ) ;
26
40
27
41
let name_sc = Ident :: new ( & * p. name . to_sanitized_snake_case ( ) ) ;
28
- let ( base, derived) = if let Some ( base) = p. derived_from . as_ref ( ) {
29
- // TODO Verify that base exists
30
- // TODO We don't handle inheritance style `derivedFrom`, we should raise
31
- // an error in that case
32
- ( Ident :: new ( & * base. to_sanitized_snake_case ( ) ) , true )
42
+ let base = if derive_regs {
43
+ Ident :: new ( & * p_derivedfrom. unwrap ( ) . name . to_sanitized_snake_case ( ) )
33
44
} else {
34
- ( name_sc. clone ( ) , false )
45
+ name_sc. clone ( )
35
46
} ;
36
47
37
48
// Insert the peripheral structure
@@ -57,17 +68,92 @@ pub fn render(
57
68
}
58
69
} ) ;
59
70
60
- // Derived peripherals do not require re-implementation, and will instead
61
- // use a single definition of the non-derived version
62
- if derived {
71
+ // Derived peripherals may not require re-implementation, and will instead
72
+ // use a single definition of the non-derived version.
73
+ if derive_regs {
63
74
return Ok ( out) ;
64
75
}
65
76
66
77
// erc: *E*ither *R*egister or *C*luster
67
78
let ercs = p. registers . as_ref ( ) . map ( |x| x. as_ref ( ) ) . unwrap_or ( & [ ] [ ..] ) ;
68
-
69
79
let registers: & [ & Register ] = & util:: only_registers ( & ercs) [ ..] ;
80
+
81
+ // make a pass to expand derived registers. Ideally, for the most minimal
82
+ // code size, we'd do some analysis to figure out if we can 100% reuse the
83
+ // code that we're deriving from. For the sake of proving the concept, we're
84
+ // just going to emit a second copy of the accessor code. It'll probably
85
+ // get inlined by the compiler anyway, right? :-)
86
+
87
+ // Build a map so that we can look up registers within this peripheral
88
+ let mut reg_map = HashMap :: new ( ) ;
89
+ for r in registers {
90
+ reg_map. insert ( & r. name , r. clone ( ) ) ;
91
+ }
92
+
93
+ // Compute the effective, derived version of a register given the definition
94
+ // with the derived_from property on it (`info`) and its `ancestor`
95
+ fn derive_reg_info ( info : & RegisterInfo , ancestor : & RegisterInfo ) -> RegisterInfo {
96
+ let mut derived = info. clone ( ) ;
97
+
98
+ if derived. size . is_none ( ) {
99
+ derived. size = ancestor. size . clone ( ) ;
100
+ }
101
+ if derived. access . is_none ( ) {
102
+ derived. access = ancestor. access . clone ( ) ;
103
+ }
104
+ if derived. reset_value . is_none ( ) {
105
+ derived. reset_value = ancestor. reset_value . clone ( ) ;
106
+ }
107
+ if derived. reset_mask . is_none ( ) {
108
+ derived. reset_mask = ancestor. reset_mask . clone ( ) ;
109
+ }
110
+ if derived. fields . is_none ( ) {
111
+ derived. fields = ancestor. fields . clone ( ) ;
112
+ }
113
+ if derived. write_constraint . is_none ( ) {
114
+ derived. write_constraint = ancestor. write_constraint . clone ( ) ;
115
+ }
116
+
117
+ derived
118
+ }
119
+
120
+ // Build up an alternate erc list by expanding any derived registers
121
+ let mut alt_erc : Vec < RegisterCluster > = registers. iter ( ) . filter_map ( |r| {
122
+ match r. derived_from {
123
+ Some ( ref derived) => {
124
+ let ancestor = match reg_map. get ( derived) {
125
+ Some ( r) => r,
126
+ None => {
127
+ eprintln ! ( "register {} derivedFrom missing register {}" , r. name, derived) ;
128
+ return None
129
+ }
130
+ } ;
131
+
132
+ let d = match * * ancestor {
133
+ Register :: Array ( ref info, ref array_info) => {
134
+ Some ( RegisterCluster :: Register ( Register :: Array ( derive_reg_info ( * r, info) , array_info. clone ( ) ) ) )
135
+ }
136
+ Register :: Single ( ref info) => {
137
+ Some ( RegisterCluster :: Register ( Register :: Single ( derive_reg_info ( * r, info) ) ) )
138
+ }
139
+ } ;
140
+
141
+ d
142
+ }
143
+ None => Some ( RegisterCluster :: Register ( ( * r) . clone ( ) ) ) ,
144
+ }
145
+ } ) . collect ( ) ;
146
+
147
+ // Now add the clusters to our alternate erc list
148
+ let clusters = util:: only_clusters ( ercs) ;
149
+ for cluster in & clusters {
150
+ alt_erc. push ( RegisterCluster :: Cluster ( ( * cluster) . clone ( ) ) ) ;
151
+ }
152
+
153
+ // And revise registers, clusters and ercs to refer to our expanded versions
154
+ let registers: & [ & Register ] = & util:: only_registers ( & alt_erc) [ ..] ;
70
155
let clusters = util:: only_clusters ( ercs) ;
156
+ let ercs = & alt_erc;
71
157
72
158
// No `struct RegisterBlock` can be generated
73
159
if registers. is_empty ( ) && clusters. is_empty ( ) {
0 commit comments