11use std:: borrow:: Cow ;
22use std:: cmp:: Ordering ;
3+ use std:: collections:: HashMap ;
34
45use either:: Either ;
56use quote:: { ToTokens , Tokens } ;
6- use svd:: { Cluster , ClusterInfo , Defaults , Peripheral , Register } ;
7+ use svd:: { Cluster , ClusterInfo , Defaults , Peripheral , Register , RegisterInfo } ;
78use syn:: { self , Ident } ;
89
910use errors:: * ;
@@ -23,7 +24,7 @@ pub fn render(
2324 all_peripherals. iter ( ) . find ( |x| x. name == * s)
2425 } ) ;
2526
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 ) ) ;
2728 let p = p_merged. as_ref ( ) . unwrap_or ( p_original) ;
2829
2930 if p_original. derived_from . is_some ( ) && p_derivedfrom. is_none ( ) {
@@ -75,9 +76,84 @@ pub fn render(
7576
7677 // erc: *E*ither *R*egister or *C*luster
7778 let ercs = p. registers . as_ref ( ) . map ( |x| x. as_ref ( ) ) . unwrap_or ( & [ ] [ ..] ) ;
78-
7979 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) [ ..] ;
80155 let clusters = util:: only_clusters ( ercs) ;
156+ let ercs = & alt_erc;
81157
82158 // No `struct RegisterBlock` can be generated
83159 if registers. is_empty ( ) && clusters. is_empty ( ) {
0 commit comments