@@ -104,48 +104,146 @@ pub fn render(
104
104
Ok ( out)
105
105
}
106
106
107
+ #[ derive( Clone , Debug ) ]
107
108
struct RegisterBlockField {
108
109
field : syn:: Field ,
109
110
description : String ,
110
111
offset : u32 ,
111
112
size : u32 ,
112
113
}
113
114
115
+ #[ derive( Clone , Debug ) ]
116
+ struct Region {
117
+ fields : Vec < RegisterBlockField > ,
118
+ offset : u32 ,
119
+ end : u32 ,
120
+ }
121
+
122
+ /// FieldRegions keeps track of overlapping field regions,
123
+ /// merging fields into appropriate regions as we process them.
124
+ /// This allows us to reason about when to create a union
125
+ /// rather than a struct.
126
+ #[ derive( Default , Debug ) ]
127
+ struct FieldRegions {
128
+ /// The set of regions we know about. This is maintained
129
+ /// in sorted order, keyed by Region::offset.
130
+ regions : Vec < Region > ,
131
+ }
132
+
133
+ impl FieldRegions {
134
+ /// Track a field. If the field overlaps with 1 or more existing
135
+ /// entries, they will be merged together.
136
+ fn add ( & mut self , field : & RegisterBlockField ) {
137
+
138
+ // When merging, this holds the indices in self.regions
139
+ // that the input `field` will be merging with.
140
+ let mut indices = Vec :: new ( ) ;
141
+
142
+ let field_start = field. offset ;
143
+ let field_end = field_start + field. size / BITS_PER_BYTE ;
144
+
145
+ // The region that we're going to insert
146
+ let mut new_region = Region {
147
+ fields : vec ! [ field. clone( ) ] ,
148
+ offset : field. offset ,
149
+ end : field. offset + field. size / BITS_PER_BYTE
150
+ } ;
151
+
152
+ // Locate existing region(s) that we intersect with and
153
+ // fold them into the new region we're creating. There
154
+ // may be multiple regions that we intersect with, so
155
+ // we keep looping to find them all.
156
+ for ( idx, mut f) in self . regions . iter_mut ( ) . enumerate ( ) {
157
+ let f_start = f. offset ;
158
+ let f_end = f. end ;
159
+
160
+ // Compute intersection range
161
+ let begin = f_start. max ( field_start) ;
162
+ let end = f_end. min ( field_end) ;
163
+
164
+ if end > begin {
165
+ // We're going to remove this element and fold it
166
+ // into our new region
167
+ indices. push ( idx) ;
168
+
169
+ // Expand the existing entry
170
+ new_region. offset = new_region. offset . min ( f_start) ;
171
+ new_region. end = new_region. end . max ( f_end) ;
172
+
173
+ // And merge in the fields
174
+ new_region. fields . append ( & mut f. fields ) ;
175
+ }
176
+ }
177
+
178
+ // Now remove the entries that we collapsed together.
179
+ // We do this in reverse order to ensure that the indices
180
+ // are stable in the face of removal.
181
+ for idx in indices. iter ( ) . rev ( ) {
182
+ self . regions . remove ( * idx) ;
183
+ }
184
+
185
+ new_region. fields . sort_by_key ( |f| f. offset ) ;
186
+
187
+ // maintain the regions ordered by starting offset
188
+ let idx = self . regions . binary_search_by_key ( & new_region. offset , |r| r. offset ) ;
189
+ match idx {
190
+ Ok ( idx) => {
191
+ panic ! ( "we shouldn't exist in the vec, but are at idx {} {:#?}\n {:#?}" ,
192
+ idx, new_region, self . regions) ;
193
+ }
194
+ Err ( idx) => self . regions . insert ( idx, new_region)
195
+ }
196
+ }
197
+ }
198
+
114
199
fn register_or_cluster_block (
115
200
ercs : & [ Either < Register , Cluster > ] ,
116
201
defs : & Defaults ,
117
202
name : Option < & str > ,
118
203
) -> Result < Tokens > {
119
204
let mut fields = Tokens :: new ( ) ;
120
- // enumeration of reserved fields
121
- let mut i = 0 ;
122
- // offset from the base address, in bytes
123
- let mut offset = 0 ;
124
205
125
206
let ercs_expanded = expand ( ercs, defs, name) ?;
126
207
127
- for reg_block_field in ercs_expanded {
128
- let pad = if let Some ( pad) = reg_block_field. offset . checked_sub ( offset) {
129
- pad
130
- } else {
131
- eprintln ! (
132
- "WARNING {:?} overlaps with another register block at offset {}. \
133
- Ignoring.",
134
- reg_block_field. field. ident,
135
- reg_block_field. offset
136
- ) ;
137
- continue ;
138
- } ;
208
+ // Locate conflicting regions; we'll need to use unions to represent them.
209
+ let mut regions = FieldRegions :: default ( ) ;
139
210
140
- if pad != 0 {
141
- let name = Ident :: new ( format ! ( "_reserved{}" , i) ) ;
142
- let pad = pad as usize ;
143
- fields. append ( quote ! {
144
- #name : [ u8 ; #pad] ,
145
- } ) ;
146
- i += 1 ;
211
+ for reg_block_field in & ercs_expanded {
212
+ regions. add ( reg_block_field) ;
213
+ }
214
+
215
+ // The end of the region from the prior iteration of the loop
216
+ let mut last_end = None ;
217
+
218
+ for ( i, region) in regions. regions . iter ( ) . enumerate ( ) {
219
+ // Check if we need padding
220
+ if let Some ( end) = last_end {
221
+ let pad = region. offset - end;
222
+ if pad != 0 {
223
+ let name = Ident :: new ( format ! ( "_reserved{}" , i) ) ;
224
+ let pad = pad as usize ;
225
+ fields. append ( quote ! {
226
+ #name : [ u8 ; #pad] ,
227
+ } ) ;
228
+ }
147
229
}
148
230
231
+ last_end = Some ( region. end ) ;
232
+
233
+ if region. fields . len ( ) > 1 {
234
+ // TODO: this is where we'd emit a union container
235
+ eprintln ! ( "WARNING: overlaps for region offset={}-{}. \
236
+ Using the first one of these:",
237
+ region. offset, region. end-1 ) ;
238
+
239
+ for f in & region. fields {
240
+ eprintln ! ( " {:?} {}-{}" , f. field. ident, f. offset,
241
+ ( f. offset + f. size / BITS_PER_BYTE ) -1 ) ;
242
+ }
243
+ }
244
+
245
+ let reg_block_field = & region. fields [ 0 ] ;
246
+
149
247
let comment = & format ! (
150
248
"0x{:02x} - {}" ,
151
249
reg_block_field. offset,
@@ -158,8 +256,6 @@ fn register_or_cluster_block(
158
256
159
257
reg_block_field. field . to_tokens ( & mut fields) ;
160
258
Ident :: new ( "," ) . to_tokens ( & mut fields) ;
161
-
162
- offset = reg_block_field. offset + reg_block_field. size / BITS_PER_BYTE ;
163
259
}
164
260
165
261
let name = Ident :: new ( match name {
0 commit comments