@@ -213,24 +213,9 @@ impl Region {
213
213
self . shortest_ident ( )
214
214
}
215
215
}
216
- /// Return a description of this region
217
- fn description ( & self ) -> String {
218
- let mut result = String :: new ( ) ;
219
- for f in & self . fields {
220
- // In the Atmel SVDs the union variants all tend to
221
- // have the same description. Rather than emitting
222
- // the same text three times over, only join in the
223
- // text from the other variants if it is different.
224
- // This isn't a foolproof way of emitting the most
225
- // reasonable short description, but it's good enough.
226
- if f. description != result {
227
- if !result. is_empty ( ) {
228
- result. push ( ' ' ) ;
229
- }
230
- result. push_str ( & f. description ) ;
231
- }
232
- }
233
- result
216
+
217
+ fn is_union ( & self ) -> bool {
218
+ self . fields . len ( ) > 1
234
219
}
235
220
}
236
221
@@ -318,10 +303,6 @@ impl FieldRegions {
318
303
Ok ( ( ) )
319
304
}
320
305
321
- pub fn is_union ( & self ) -> bool {
322
- self . regions . len ( ) == 1 && self . regions [ 0 ] . fields . len ( ) > 1
323
- }
324
-
325
306
/// Resolves type name conflicts
326
307
pub fn resolve_idents ( & mut self ) -> Result < ( ) > {
327
308
let idents: Vec < _ > = {
@@ -358,86 +339,11 @@ fn register_or_cluster_block(
358
339
ercs : & [ RegisterCluster ] ,
359
340
defs : & Defaults ,
360
341
name : Option < & str > ,
361
- nightly : bool ,
362
- ) -> Result < Tokens > {
363
- if nightly {
364
- register_or_cluster_block_nightly ( ercs, defs, name)
365
- } else {
366
- register_or_cluster_block_stable ( ercs, defs, name)
367
- }
368
- }
369
-
370
- fn register_or_cluster_block_stable (
371
- ercs : & [ RegisterCluster ] ,
372
- defs : & Defaults ,
373
- name : Option < & str > ,
342
+ _nightly : bool ,
374
343
) -> Result < Tokens > {
375
344
let mut fields = Tokens :: new ( ) ;
376
- // enumeration of reserved fields
377
- let mut i = 0 ;
378
- // offset from the base address, in bytes
379
- let mut offset = 0 ;
380
-
381
- let ercs_expanded = expand ( ercs, defs, name) ?;
382
-
383
- for reg_block_field in ercs_expanded {
384
- let pad = if let Some ( pad) = reg_block_field. offset . checked_sub ( offset) {
385
- pad
386
- } else {
387
- warn ! (
388
- "{:?} overlaps with another register block at offset {}. \
389
- Ignoring.",
390
- reg_block_field. field. ident, reg_block_field. offset
391
- ) ;
392
- continue ;
393
- } ;
394
-
395
- if pad != 0 {
396
- let name = Ident :: new ( format ! ( "_reserved{}" , i) ) ;
397
- let pad = pad as usize ;
398
- fields. append ( quote ! {
399
- #name : [ u8 ; #pad] ,
400
- } ) ;
401
- i += 1 ;
402
- }
403
-
404
- let comment = & format ! (
405
- "0x{:02x} - {}" ,
406
- reg_block_field. offset,
407
- util:: escape_brackets( util:: respace( & reg_block_field. description) . as_ref( ) ) ,
408
- ) [ ..] ;
409
-
410
- fields. append ( quote ! {
411
- #[ doc = #comment]
412
- } ) ;
413
-
414
- reg_block_field. field . to_tokens ( & mut fields) ;
415
- Ident :: new ( "," ) . to_tokens ( & mut fields) ;
416
-
417
- offset = reg_block_field. offset + reg_block_field. size / BITS_PER_BYTE ;
418
- }
419
-
420
- let name = Ident :: new ( match name {
421
- Some ( name) => name. to_sanitized_upper_case ( ) ,
422
- None => "RegisterBlock" . into ( ) ,
423
- } ) ;
424
-
425
- Ok ( quote ! {
426
- /// Register block
427
- #[ repr( C ) ]
428
- pub struct #name {
429
- #fields
430
- }
431
- } )
432
- }
433
-
434
- fn register_or_cluster_block_nightly (
435
- ercs : & [ RegisterCluster ] ,
436
- defs : & Defaults ,
437
- name : Option < & str > ,
438
- ) -> Result < Tokens > {
439
- let mut fields = Tokens :: new ( ) ;
440
- let mut helper_types = Tokens :: new ( ) ;
345
+ let mut accessors = Tokens :: new ( ) ;
346
+ let mut have_accessors = false ;
441
347
442
348
let ercs_expanded = expand ( ercs, defs, name) ?;
443
349
@@ -448,10 +354,9 @@ fn register_or_cluster_block_nightly(
448
354
regions. add ( reg_block_field) ?;
449
355
}
450
356
451
- let block_is_union = regions. is_union ( ) ;
452
357
// We need to compute the idents of each register/union block first to make sure no conflicts exists.
453
358
regions. resolve_idents ( ) ?;
454
- // The end of the region from the prior iteration of the loop
359
+ // The end of the region for which we previously emitted a field into `fields`
455
360
let mut last_end = 0 ;
456
361
457
362
for ( i, region) in regions. regions . iter ( ) . enumerate ( ) {
@@ -465,86 +370,96 @@ fn register_or_cluster_block_nightly(
465
370
} ) ;
466
371
}
467
372
468
- last_end = region. end ;
469
-
470
373
let mut region_fields = Tokens :: new ( ) ;
374
+ let is_region_a_union = region. is_union ( ) ;
471
375
472
376
for reg_block_field in & region. fields {
473
- if reg_block_field. offset != region. offset {
474
- // TODO: need to emit padding for this case.
475
- // Happens for freescale_mkl43z4
476
- warn ! (
477
- "field {:?} has different offset {} than its union container {}" ,
478
- reg_block_field. field. ident, reg_block_field. offset, region. offset
479
- ) ;
480
- }
481
377
let comment = & format ! (
482
378
"0x{:02x} - {}" ,
483
379
reg_block_field. offset,
484
380
util:: escape_brackets( util:: respace( & reg_block_field. description) . as_ref( ) ) ,
485
381
) [ ..] ;
486
382
487
- region_fields. append ( quote ! {
488
- #[ doc = #comment]
489
- } ) ;
490
-
491
- reg_block_field. field . to_tokens ( & mut region_fields) ;
492
- Ident :: new ( "," ) . to_tokens ( & mut region_fields) ;
493
- }
494
-
495
- if region. fields . len ( ) > 1 && !block_is_union {
496
- let ( type_name, name) = match region. ident . clone ( ) {
497
- Some ( prefix) => (
498
- Ident :: new ( format ! ( "{}_UNION" , prefix. to_sanitized_upper_case( ) ) ) ,
499
- Ident :: new ( prefix) ,
500
- ) ,
501
- // If we can't find a name, fall back to the region index as a
502
- // unique-within-this-block identifier counter.
503
- None => {
504
- let ident = Ident :: new ( format ! ( "U{}" , i) ) ;
505
- ( ident. clone ( ) , ident)
506
- }
507
- } ;
383
+ if is_region_a_union {
384
+ let name = & reg_block_field. field . ident ;
385
+ let mut_name = Ident :: new ( format ! ( "{}_mut" , name. as_ref( ) . unwrap( ) ) ) ;
386
+ let ty = & reg_block_field. field . ty ;
387
+ let offset = reg_block_field. offset as usize ;
388
+ have_accessors = true ;
389
+ accessors. append ( quote ! {
390
+ #[ doc = #comment]
391
+ #[ inline( always) ]
392
+ pub fn #name( & self ) -> & #ty {
393
+ unsafe {
394
+ & * ( ( ( self as * const Self ) as * const u8 ) . add( #offset) as * const #ty)
395
+ }
396
+ }
508
397
509
- let description = region. description ( ) ;
398
+ #[ doc = #comment]
399
+ #[ inline( always) ]
400
+ pub fn #mut_name( & self ) -> & mut #ty {
401
+ unsafe {
402
+ & mut * ( ( ( self as * const Self ) as * mut u8 ) . add( #offset) as * mut #ty)
403
+ }
404
+ }
405
+ } ) ;
406
+ } else {
407
+ region_fields. append ( quote ! {
408
+ #[ doc = #comment]
409
+ } ) ;
510
410
511
- helper_types. append ( quote ! {
512
- #[ doc = #description]
513
- #[ repr( C ) ]
514
- pub union #type_name {
515
- #region_fields
516
- }
517
- } ) ;
411
+ reg_block_field. field . to_tokens ( & mut region_fields) ;
412
+ Ident :: new ( "," ) . to_tokens ( & mut region_fields) ;
413
+ }
414
+ }
518
415
519
- fields. append ( quote ! {
520
- #[ doc = #description]
521
- pub #name: #type_name
522
- } ) ;
523
- Ident :: new ( "," ) . to_tokens ( & mut fields) ;
524
- } else {
416
+ if !is_region_a_union {
525
417
fields. append ( & region_fields) ;
418
+ } else {
419
+ // Emit padding for the items that we're not emitting
420
+ // as fields so that subsequent fields have the correct
421
+ // alignment in the struct. We could omit this and just
422
+ // not updated `last_end`, so that the padding check in
423
+ // the outer loop kicks in, but it is nice to be able to
424
+ // see that the padding is attributed to a union when
425
+ // visually inspecting the alignment in the struct.
426
+ //
427
+ // Include the computed ident for the union in the padding
428
+ // name, along with the region number, falling back to
429
+ // the offset and end in case we couldn't figure out a
430
+ // nice identifier.
431
+ let name = Ident :: new ( format ! ( "_reserved_{}_{}" , i, region. compute_ident( ) . unwrap_or_else( || format!( "{}_{}" , region. offset, region. end) ) ) ) ;
432
+ let pad = ( region. end - region. offset ) as usize ;
433
+ fields. append ( quote ! {
434
+ #name: [ u8 ; #pad] ,
435
+ } )
526
436
}
437
+ last_end = region. end ;
527
438
}
528
439
529
440
let name = Ident :: new ( match name {
530
441
Some ( name) => name. to_sanitized_upper_case ( ) ,
531
442
None => "RegisterBlock" . into ( ) ,
532
443
} ) ;
533
444
534
- let block_type = if block_is_union {
535
- Ident :: new ( "union" )
445
+ let accessors = if have_accessors {
446
+ quote ! {
447
+ impl #name {
448
+ #accessors
449
+ }
450
+ }
536
451
} else {
537
- Ident :: new ( "struct" )
452
+ quote ! { }
538
453
} ;
539
454
540
455
Ok ( quote ! {
541
456
/// Register block
542
457
#[ repr( C ) ]
543
- pub #block_type #name {
458
+ pub struct #name {
544
459
#fields
545
460
}
546
461
547
- #helper_types
462
+ #accessors
548
463
} )
549
464
}
550
465
0 commit comments