File Coverage

blib/lib/Device/AVR/Info/Module.pm
Criterion Covered Total %
statement 15 62 24.1
branch 0 12 0.0
condition 0 3 0.0
subroutine 5 20 25.0
pod 2 2 100.0
total 22 99 22.2


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