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 -- leonerd@leonerd.org.uk
5              
6             package Device::AVR::Info::Module;
7              
8 1     1   8 use strict;
  1         3  
  1         28  
9 1     1   5 use warnings;
  1         2  
  1         22  
10 1     1   21 use 5.010;
  1         4  
11              
12             our $VERSION = '0.02';
13              
14 1     1   5 use Carp;
  1         1  
  1         62  
15              
16 1     1   7 use Struct::Dumb 'readonly_struct';
  1         8  
  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 = $module->name
53              
54             Returns the name of the module
55              
56             =cut
57              
58 0     0 1   sub name { shift->{_module}{name} }
59              
60             =head2 @registers = $module->registers( $groupname )
61              
62             Returns a list of register instances, representing the registers in the named
63             group.
64              
65             Each is a structure of the following fields.
66              
67             $register->name
68             $register->offset
69             $register->size
70             $register->initval
71             $register->caption
72             $register->mask
73             @fields = $register->bitfields
74              
75             The C field returns a list of structures of the following fields:
76              
77             $field->name
78             $field->caption
79             $field->mask
80              
81             =cut
82              
83             {
84             package
85             Device::AVR::Info::Module::_Register;
86              
87 0     0     sub name { shift->[0] }
88 0     0     sub offset { shift->[1] }
89 0     0     sub size { shift->[2] }
90 0     0     sub initval { shift->[3] }
91 0     0     sub caption { shift->[4] }
92 0     0     sub mask { shift->[5] }
93 0     0     sub bitfields { @{ shift->[6] } }
  0            
94              
95             package
96             Device::AVR::Info::Module::_Bitfield;
97              
98 0     0     sub name { shift->[0] }
99 0     0     sub caption { shift->[1] }
100 0     0     sub mask { shift->[2] }
101 0     0     sub values { @{ shift->[3] } }
  0            
102             }
103              
104             sub registers
105             {
106 0     0 1   my $self = shift;
107 0           my ( $name ) = @_;
108 0           $self->_registers_offset( $name, 0 );
109             }
110              
111             sub _registers_offset
112             {
113 0     0     my $self = shift;
114 0           my ( $name, $offset ) = @_;
115              
116 0 0         my $registers = $self->{_module}{"register-group"}( name => eq => $name )
117             or croak "No register group named '$name'";
118              
119             map {
120             my @fields = exists $_->{bitfield} ?
121             map {
122 0           my $mask = hex "$_->{mask}";
123 0 0         my $values = exists $_->{values} ? $self->_value_group( $_->{values}, $mask ) : [];
124 0           bless [ "$_->{name}", "$_->{caption}", $mask, $values ], "Device::AVR::Info::Module::_Bitfield";
125 0 0         } @{ $_->{bitfield} } : ();
  0            
126              
127 0           bless [ "$_->{name}", $offset + hex "$_->{offset}", "$_->{size}", hex "$_->{initval}",
128             "$_->{caption}", hex "$_->{mask}", \@fields ], "Device::AVR::Info::Module::_Register";
129 0           } @{ $registers->{register} };
  0            
130             }
131              
132             readonly_struct Value => [qw( name caption value )];
133              
134             sub _value_group
135             {
136 0     0     my $self = shift;
137 0           my ( $name, $mask ) = @_;
138              
139 0 0         my $values = $self->{_module}{"value-group"}( name => eq => $name )
140             or croak "No value group named '$name'";
141              
142             [ map {
143 0           my $value_in = hex "$_->{value}";
144              
145             # The bits in $value are "compressed", and have to be expanded out to
146             # only the bit positions set in $mask.
147 0           my $value_out = 0;
148 0           my $in_bit = 0;
149 0           my $out_bit = 0;
150 0           while( $value_in ) {
151 0   0       $out_bit++ until $out_bit > 16 or $mask & 1<<$out_bit;
152 0 0         die "Ran out of mask bits before value bits" if $in_bit > 16;
153              
154 0 0         $value_out |= 1<<$out_bit if $value_in & 1<<$in_bit;
155 0           $value_in &= ~( 1<<$in_bit );
156              
157 0           $in_bit++;
158 0           $out_bit++;
159             }
160              
161 0           Value( "$_->{name}", "$_->{caption}", $value_out )
162 0           } @{ $values->{value} } ];
  0            
163             }
164              
165             =head1 AUTHOR
166              
167             Paul Evans
168              
169             =cut
170              
171             0x55AA;