1
1
use std:: borrow:: Cow ;
2
2
use std:: cmp:: Ordering ;
3
+ use std:: collections:: HashMap ;
3
4
4
5
use either:: Either ;
5
6
use quote:: { ToTokens , Tokens } ;
6
- use svd:: { Cluster , ClusterInfo , Defaults , Peripheral , Register } ;
7
+ use svd:: { Cluster , ClusterInfo , Defaults , Peripheral , Register , RegisterInfo } ;
7
8
use syn:: { self , Ident } ;
8
9
9
10
use errors:: * ;
@@ -23,7 +24,7 @@ pub fn render(
23
24
all_peripherals. iter ( ) . find ( |x| x. name == * s)
24
25
} ) ;
25
26
26
- let p_merged = p_derivedfrom. map ( |x | p_original. derive_from ( x ) ) ;
27
+ let p_merged = p_derivedfrom. map ( |ancestor | p_original. derive_from ( ancestor ) ) ;
27
28
let p = p_merged. as_ref ( ) . unwrap_or ( p_original) ;
28
29
29
30
if p_original. derived_from . is_some ( ) && p_derivedfrom. is_none ( ) {
@@ -75,9 +76,84 @@ pub fn render(
75
76
76
77
// erc: *E*ither *R*egister or *C*luster
77
78
let ercs = p. registers . as_ref ( ) . map ( |x| x. as_ref ( ) ) . unwrap_or ( & [ ] [ ..] ) ;
78
-
79
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 < Either < Register , Cluster > > = 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 ( Either :: Left ( Register :: Array ( derive_reg_info ( * r, info) , array_info. clone ( ) ) ) )
135
+ }
136
+ Register :: Single ( ref info) => {
137
+ Some ( Either :: Left ( Register :: Single ( derive_reg_info ( * r, info) ) ) )
138
+ }
139
+ } ;
140
+
141
+ d
142
+ }
143
+ None => Some ( Either :: Left ( ( * 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 ( Either :: Right ( ( * 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) [ ..] ;
80
155
let clusters = util:: only_clusters ( ercs) ;
156
+ let ercs = & alt_erc;
81
157
82
158
// No `struct RegisterBlock` can be generated
83
159
if registers. is_empty ( ) && clusters. is_empty ( ) {
0 commit comments