File Coverage

blib/lib/Device/AVR/Info/Module.pm
Criterion Covered Total %
statement 14 62 22.5
branch 0 12 0.0
condition 0 3 0.0
subroutine 5 21 23.8
pod 2 2 100.0
total 21 100 21.0


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2014-2019 -- leonerd@leonerd.org.uk
5              
6             package Device::AVR::Info::Module;
7              
8 1     1   8 use strict;
  1         2  
  1         34  
9 1     1   6 use warnings;
  1         2  
  1         32  
10 1     1   30 use 5.010;
  1         5  
11              
12             our $VERSION = '0.03';
13              
14 1     1   9 use Carp;
  1         2  
  1         84  
15              
16 1     1   8 use Struct::Dumb 'readonly_struct';
  1         2  
  1         7  
17              
18             =head1 NAME
19              
20             C - represent a single kind of peripheral module type from an F chip
21              
22             =head1 SYNOPSIS
23              
24             Instances in this class are returned from L:
25              
26             use Device::AVR::Info;
27              
28             my $avr = Device::AVR::Info->new_from_file( "devices/ATtiny84.xml" );
29              
30             my $fuses = $avr->peripheral( 'FUSE' );
31             my $module = $fuses->module;
32              
33             printf "The FUSE module has %d registers\n",
34             scalar $module->registers( 'FUSE' );
35              
36             =cut
37              
38             sub _new
39             {
40 0     0     my $class = shift;
41 0           my ( $module ) = @_;
42              
43 0           return bless {
44             _module => $module,
45             }, $class;
46             }
47              
48             =head1 ACCESSORS
49              
50             =cut
51              
52             =head2 name
53              
54             $name = $module->name
55              
56             Returns the name of the module
57              
58             =cut
59              
60 0     0 1   sub name { shift->{_module}{name} }
61              
62             =head2 registers
63              
64             @registers = $module->registers( $groupname )
65              
66             Returns a list of register instances, representing the registers in the named
67             group.
68              
69             Each is a structure of the following fields.
70              
71             $register->name
72             $register->offset
73             $register->size
74             $register->initval
75             $register->caption
76             $register->mask
77             @fields = $register->bitfields
78              
79             The C field returns a list of structures of the following fields:
80              
81             $field->name
82             $field->caption
83             $field->mask
84              
85             =cut
86              
87             {
88             package
89             Device::AVR::Info::Module::_Register;
90              
91 0     0     sub name { shift->[0] }
92 0     0     sub offset { shift->[1] }
93 0     0     sub size { shift->[2] }
94 0     0     sub initval { shift->[3] }
95 0     0     sub caption { shift->[4] }
96 0     0     sub mask { shift->[5] }
97 0     0     sub bitfields { @{ shift->[6] } }
  0            
98              
99             package
100             Device::AVR::Info::Module::_Bitfield;
101              
102 0     0     sub name { shift->[0] }
103 0     0     sub caption { shift->[1] }
104 0     0     sub mask { shift->[2] }
105 0     0     sub values { @{ shift->[3] } }
  0            
106             }
107              
108             sub registers
109             {
110 0     0 1   my $self = shift;
111 0           my ( $name ) = @_;
112 0           $self->_registers_offset( $name, 0 );
113             }
114              
115             sub _registers_offset
116             {
117 0     0     my $self = shift;
118 0           my ( $name, $offset ) = @_;
119              
120 0 0         my $registers = $self->{_module}{"register-group"}( name => eq => $name )
121             or croak "No register group named '$name'";
122              
123             map {
124             my @fields = exists $_->{bitfield} ?
125             map {
126 0           my $mask = hex "$_->{mask}";
127 0 0         my $values = exists $_->{values} ? $self->_value_group( $_->{values}, $mask ) : [];
128 0           bless [ "$_->{name}", "$_->{caption}", $mask, $values ], "Device::AVR::Info::Module::_Bitfield";
129 0 0         } @{ $_->{bitfield} } : ();
  0            
130              
131 0           bless [ "$_->{name}", $offset + hex "$_->{offset}", "$_->{size}", hex "$_->{initval}",
132             "$_->{caption}", hex "$_->{mask}", \@fields ], "Device::AVR::Info::Module::_Register";
133 0           } @{ $registers->{register} };
  0            
134             }
135              
136             readonly_struct Value => [qw( name caption value )];
137              
138             sub _value_group
139             {
140 0     0     my $self = shift;
141 0           my ( $name, $mask ) = @_;
142              
143 0 0         my $values = $self->{_module}{"value-group"}( name => eq => $name )
144             or croak "No value group named '$name'";
145              
146             [ map {
147 0           my $value_in = hex "$_->{value}";
148              
149             # The bits in $value are "compressed", and have to be expanded out to
150             # only the bit positions set in $mask.
151 0           my $value_out = 0;
152 0           my $in_bit = 0;
153 0           my $out_bit = 0;
154 0           while( $value_in ) {
155 0   0       $out_bit++ until $out_bit > 16 or $mask & 1<<$out_bit;
156 0 0         die "Ran out of mask bits before value bits" if $in_bit > 16;
157              
158 0 0         $value_out |= 1<<$out_bit if $value_in & 1<<$in_bit;
159 0           $value_in &= ~( 1<<$in_bit );
160              
161 0           $in_bit++;
162 0           $out_bit++;
163             }
164              
165 0           Value( "$_->{name}", "$_->{caption}", $value_out )
166 0           } @{ $values->{value} } ];
  0            
167             }
168              
169             =head1 AUTHOR
170              
171             Paul Evans
172              
173             =cut
174              
175             0x55AA;