1
1
use std:: borrow:: Cow ;
2
+ use std:: collections:: HashMap ;
2
3
3
4
use either:: Either ;
4
5
use quote:: { ToTokens , Tokens } ;
5
- use svd:: { Cluster , ClusterInfo , Defaults , Peripheral , Register } ;
6
+ use svd:: { Cluster , ClusterInfo , Defaults , Peripheral , Register , RegisterInfo } ;
6
7
use syn:: { self , Ident } ;
7
8
8
9
use errors:: * ;
9
10
use util:: { self , ToSanitizedSnakeCase , ToSanitizedUpperCase , BITS_PER_BYTE } ;
10
11
11
12
use generate:: register;
12
13
14
+ // This is a clone of the helper function from https://github.com/japaric/svd/pull/49
15
+ // and can go away once that is resolved
16
+ fn derive_peripheral ( p : & Peripheral , other : & Peripheral ) -> Peripheral {
17
+ let mut derived = p. clone ( ) ;
18
+ if derived. group_name . is_none ( ) {
19
+ derived. group_name = other. group_name . clone ( ) ;
20
+ }
21
+ if derived. description . is_none ( ) {
22
+ derived. description = other. description . clone ( ) ;
23
+ }
24
+ if derived. registers . is_none ( ) {
25
+ derived. registers = other. registers . clone ( ) ;
26
+ }
27
+ if derived. interrupt . is_empty ( ) {
28
+ derived. interrupt = other. interrupt . clone ( ) ;
29
+ }
30
+ derived
31
+ }
32
+
13
33
pub fn render (
14
34
p_original : & Peripheral ,
15
35
all_peripherals : & [ Peripheral ] ,
@@ -21,7 +41,7 @@ pub fn render(
21
41
all_peripherals. iter ( ) . find ( |x| x. name == * s)
22
42
} ) ;
23
43
24
- let p_merged = p_derivedfrom. map ( |x| p_original . derive_from ( x ) ) ;
44
+ let p_merged = p_derivedfrom. map ( |ancestor| derive_peripheral ( p_original , ancestor ) ) ;
25
45
let p = p_merged. as_ref ( ) . unwrap_or ( p_original) ;
26
46
27
47
if p_original. derived_from . is_some ( ) && p_derivedfrom. is_none ( ) {
@@ -73,9 +93,84 @@ pub fn render(
73
93
74
94
// erc: *E*ither *R*egister or *C*luster
75
95
let ercs = p. registers . as_ref ( ) . map ( |x| x. as_ref ( ) ) . unwrap_or ( & [ ] [ ..] ) ;
76
-
77
96
let registers: & [ & Register ] = & util:: only_registers ( & ercs) [ ..] ;
97
+
98
+ // make a pass to expand derived registers. Ideally, for the most minimal
99
+ // code size, we'd do some analysis to figure out if we can 100% reuse the
100
+ // code that we're deriving from. For the sake of proving the concept, we're
101
+ // just going to emit a second copy of the accessor code. It'll probably
102
+ // get inlined by the compiler anyway, right? :-)
103
+
104
+ // Build a map so that we can look up registers within this peripheral
105
+ let mut reg_map = HashMap :: new ( ) ;
106
+ for r in registers {
107
+ reg_map. insert ( & r. name , r. clone ( ) ) ;
108
+ }
109
+
110
+ // Compute the effective, derived version of a register given the definition
111
+ // with the derived_from property on it (`info`) and its `ancestor`
112
+ fn derive_reg_info ( info : & RegisterInfo , ancestor : & RegisterInfo ) -> RegisterInfo {
113
+ let mut derived = info. clone ( ) ;
114
+
115
+ if derived. size . is_none ( ) {
116
+ derived. size = ancestor. size . clone ( ) ;
117
+ }
118
+ if derived. access . is_none ( ) {
119
+ derived. access = ancestor. access . clone ( ) ;
120
+ }
121
+ if derived. reset_value . is_none ( ) {
122
+ derived. reset_value = ancestor. reset_value . clone ( ) ;
123
+ }
124
+ if derived. reset_mask . is_none ( ) {
125
+ derived. reset_mask = ancestor. reset_mask . clone ( ) ;
126
+ }
127
+ if derived. fields . is_none ( ) {
128
+ derived. fields = ancestor. fields . clone ( ) ;
129
+ }
130
+ if derived. write_constraint . is_none ( ) {
131
+ derived. write_constraint = ancestor. write_constraint . clone ( ) ;
132
+ }
133
+
134
+ derived
135
+ }
136
+
137
+ // Build up an alternate erc list by expanding any derived registers
138
+ let mut alt_erc : Vec < Either < Register , Cluster > > = registers. iter ( ) . filter_map ( |r| {
139
+ match r. derived_from {
140
+ Some ( ref derived) => {
141
+ let ancestor = match reg_map. get ( derived) {
142
+ Some ( r) => r,
143
+ None => {
144
+ eprintln ! ( "register {} derivedFrom missing register {}" , r. name, derived) ;
145
+ return None
146
+ }
147
+ } ;
148
+
149
+ let d = match * * ancestor {
150
+ Register :: Array ( ref info, ref array_info) => {
151
+ Some ( Either :: Left ( Register :: Array ( derive_reg_info ( * r, info) , array_info. clone ( ) ) ) )
152
+ }
153
+ Register :: Single ( ref info) => {
154
+ Some ( Either :: Left ( Register :: Single ( derive_reg_info ( * r, info) ) ) )
155
+ }
156
+ } ;
157
+
158
+ d
159
+ }
160
+ None => Some ( Either :: Left ( ( * r) . clone ( ) ) ) ,
161
+ }
162
+ } ) . collect ( ) ;
163
+
164
+ // Now add the clusters to our alternate erc list
165
+ let clusters = util:: only_clusters ( ercs) ;
166
+ for cluster in & clusters {
167
+ alt_erc. push ( Either :: Right ( ( * cluster) . clone ( ) ) ) ;
168
+ }
169
+
170
+ // And revise registers, clusters and ercs to refer to our expanded versions
171
+ let registers: & [ & Register ] = & util:: only_registers ( & alt_erc) [ ..] ;
78
172
let clusters = util:: only_clusters ( ercs) ;
173
+ let ercs = & alt_erc;
79
174
80
175
// No `struct RegisterBlock` can be generated
81
176
if registers. is_empty ( ) && clusters. is_empty ( ) {
0 commit comments