File Coverage

blib/lib/Device/Jtag/PP.pm
Criterion Covered Total %
statement 9 125 7.2
branch 0 16 0.0
condition 0 3 0.0
subroutine 3 15 20.0
pod 3 12 25.0
total 15 171 8.7


line stmt bran cond sub pod time code
1             package Device::Jtag::PP;
2            
3             #use 5.008008;
4 1     1   33230 use strict;
  1         2  
  1         37  
5 1     1   4 use warnings;
  1         2  
  1         105  
6            
7             require Exporter;
8            
9             our @ISA = qw(Exporter);
10            
11             # Items to export into callers namespace by default. Note: do not export
12             # names by default without a very good reason. Use EXPORT_OK instead.
13             # Do not simply export all your public functions/methods/constants.
14            
15             # This allows declaration use Device::Jtag::PP ':all';
16             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
17             # will save memory.
18             our %EXPORT_TAGS = ( 'all' => [ qw(
19            
20             ) ] );
21            
22             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
23            
24             our @EXPORT = qw(
25            
26             );
27            
28             our $VERSION = '0.02';
29            
30            
31             # Preloaded methods go here.
32            
33 1     1   762 use Device::ParallelPort;
  1         308  
  1         1236  
34            
35             ###################################################################################################
36             # Construct the new JTAG object by specifying port and pin mapping
37             ###################################################################################################
38             sub new {
39 0     0 0   my $self = {};
40 0           $self->{PORT} = Device::ParallelPort->new();
41 0           $self->{PINMAP} = {TDI => 0, # this is the parallel port pin mapping
42             TCK => 1, # for the Digilent Parallel Cable 3
43             TMS => 2,
44             TDO => 12};
45            
46 0           bless($self);
47 0           return $self;
48             }
49            
50            
51             ###################################################################################################
52             # Set TMS to specified value by driving TMS port/pin specified in configuration
53             ###################################################################################################
54             sub set_tms {
55 0     0 0   my $self = shift;
56 0           my $data = shift;
57 0           $self->{PORT} -> set_bit($self->{PINMAP}->{TMS},$data);
58             }
59             ###################################################################################################
60             # Set TDI to specified value by driving TDI port/pin specified in configuration
61             ###################################################################################################
62             sub set_tdi {
63 0     0 0   my $self = shift;
64 0           my $data = shift;
65 0           $self->{PORT} -> set_bit($self->{PINMAP}->{TDI},$data);
66             }
67             ###################################################################################################
68             # Toggle clock ->1->0 by driving TCK port/pin specified in configuration
69             ###################################################################################################
70             sub tog_tck {
71 0     0 0   my $self = shift;
72 0           my $ncycles = shift;
73 0           foreach my $c (1..$ncycles) {
74 0           $self->{PORT} -> set_bit($self->{PINMAP}->{TCK},1);
75 0           $self->{PORT} -> set_bit($self->{PINMAP}->{TCK},0);
76             }
77             }
78             ###################################################################################################
79             # Read TDO from port/pin specified in configuration
80             ###################################################################################################
81             sub get_tdo {
82 0     0 0   my $self = shift;
83 0           return $self->{PORT} -> get_bit($self->{PINMAP}->{TDO});
84             }
85            
86             ###################################################################################################
87             # Convert string of binary numbers to string of hex numbers
88             ###################################################################################################
89             sub convert_hex {
90 0     0 0   my $str = shift;
91 0           my $nbits = length($str);
92 0           my $hexstr = '';
93            
94             # if length of string is not a multiple of 4, add preceeding 0's
95 0           while (length($str)%4 ne 0) {
96 0           $str = '0'.$str;
97             }
98             # convert each nibble from binary to hex
99 0           foreach my $nibble (0..(length($str)/4)-1) {
100 0           $hexstr .= sprintf("%x", oct('0b'.substr($str,4*$nibble,4)));
101             }
102 0           return $hexstr;
103             }
104             ###################################################################################################
105             # Instruction register shift to/from specified device in chain
106             # Required initial state : RTI
107             # Final state : RTI
108             ###################################################################################################
109             sub shiftir {
110 0     0 1   my $self = shift;
111 0           my $device = shift;
112 0           my $instruction = shift;
113            
114             # assumes RTI is beginning state
115             # Go to the SELECT-IR state
116 0           set_tms($self,1);
117 0           tog_tck($self,2);
118            
119             # Go to the SHIFT-IR state
120 0           set_tms($self,0);
121 0           tog_tck($self,2);
122            
123             # Find the number of devices on the scan chain
124 0           my $numdev = scalar(@{$self->{CHAIN}});
  0            
125            
126             # Start with the last device in the chain, working backwards to device 0.
127             # All but the selected device receive the BYPASS instruction.
128             # The selected device receives the instruction designated by $instruction.
129 0           for (my $d=$numdev-1;$d>=0;$d--) {
130 0           my $irlen = $self->{CHAIN}->[$d]->{IRLEN};
131 0 0         my $instr = ($d eq $device)? $instruction : 'BYPASS';
132 0           my $data = $self->{CHAIN}->[$d]->{IRCMDS}->{$instr};
133            
134             #print "Sending $instr ($data) to device $d\n";
135 0           for (my $b=length($data)-1;$b>=0;$b--) {
136 0 0 0       my $tms = ($d eq 0 and $b eq 0)? 1 : 0; #set TMS=1 on the very last shift to go to the EXIT1-IR state
137 0           set_tms($self,$tms);
138 0           set_tdi($self,substr($data,$b,1));
139 0           tog_tck($self,1);
140             }
141             }
142            
143             # Return to RTI state
144 0           set_tms($self,1);
145 0           tog_tck($self,1);
146            
147 0           set_tms($self,0);
148 0           tog_tck($self,1);
149            
150             }
151            
152             ###################################################################################################
153             # Data register shift to/from specified device in chain
154             # Required initial state : RTI
155             # Final state : RTI
156             ###################################################################################################
157             sub shiftdr {
158 0     0 0   my $self = shift;
159 0           my $device = shift;
160 0           my $data = shift;
161 0           my $tdo = undef;
162            
163             #print "Sending data $data to device $device...\n";
164            
165             # assumes RTI is beginning state
166             # Go to the SELECT-DR state
167 0           set_tms($self,1);
168 0           tog_tck($self,1);
169            
170             # Go to the SHIFT-DR state
171 0           set_tms($self,0);
172 0           tog_tck($self,2);
173            
174             # The first bit of data we want is now sitting on TDO of the selected
175             # device. If there are any devices in the chain after the selected
176             # device, the data we want must get through the each subsequent
177             # device's BYPASS register, which is 1 bit long. This means that if
178             # there are N devices in the chain after the selected device, and the
179             # number of bits of data being shifted is M, the total number of shifts
180             # must be N+M. Additionally, the first N bits of data received on
181             # TDO should be discarded.
182 0           $tdo = get_tdo($self);
183            
184             # Shift data, the rightmost bit goes first
185 0           for ($b=length($data)-1;$b>=0;$b--) {
186 0           set_tdi($self,substr($data,$b,1));
187 0 0         my $tms = $b eq 0? 1 : 0; #set TMS=1 on the last shift to go to the EXIT1-IR state
188 0           set_tms($self,$tms);
189 0           tog_tck($self,1);
190 0           $tdo = get_tdo($self) . $tdo; # get tdo, build word from right to left
191             }
192            
193             # Return to RTI state
194 0           set_tms($self,1);
195 0           tog_tck($self,1);
196            
197 0           set_tms($self,0);
198 0           tog_tck($self,1);
199            
200             # Find the number of devices on the scan chain
201 0           my $numdev = scalar(@{$self->{CHAIN}});
  0            
202            
203             # Find the number of subsequent devices on the chain following the selected device
204 0           my $subdev = ($numdev-1)-$device;
205            
206             # Return tdo as hex string
207 0           return convert_hex(substr($tdo, -1*(32+$subdev), 32));
208             }
209            
210             ###################################################################################################
211             # Initialize the JTAG chain to the RTI state.
212             # Required initial state : none
213             # Final state : RTI
214             ###################################################################################################
215             sub initialize {
216 0     0 0   my $self = shift;
217            
218             #print "Initializing JTAG scan chain to RTI state...\n";
219             # Put device(s) into TLR state
220 0           set_tms($self,1);
221 0           set_tdi($self,0);
222 0           tog_tck($self,6);
223            
224             # Go to the RTI state
225 0           set_tms($self,0);
226 0           tog_tck($self,1);
227             }
228             ###################################################################################################
229             # Autodetect devices in the JTAG chain and assign configuration information for each device.
230             # Required initial state : none
231             # Final state : RTI
232             ###################################################################################################
233             sub autodetect {
234 0     0 1   my $self = shift;
235 0           my $tdo = '';
236 0           my $ndevs = 0;
237 0           my @idcodes = ();
238            
239             # Initialize the chain to ensure we start from the RTI state
240 0           initialize($self);
241            
242             # Go to the SELECT-DR state
243 0           set_tms($self,1);
244 0           tog_tck($self,1);
245            
246             # Go to the SHIFT-DR state
247 0           set_tms($self,0);
248 0           tog_tck($self,2);
249            
250 0           print "Beginning scan chain auto-detection\n";
251            
252             # Collect 32 bits of data from each device's IDCODE register. It would
253             # seem that the JTAG spec requires that each device select its IDCODE register
254             # for shifting out on TDO after device reset (probably during the TLR state).
255             # I say this because empirically I see that this is the case. This is a good
256             # thing, because otherwise it would be impossible to autodetect the devices in
257             # the chain since different devices have different binary codes for the IDCODE
258             # instruction.
259             #
260             # All 0's are shifted in on TDI, so when the 32 bits collected is all 0's, we
261             # know all the devices in the chain have been identified.
262 0           while ($tdo ne '0'x32) {
263 0           $tdo = ''; # reset TDO for each new set of 32 bits
264 0           for my $b (0..31) { # shift 32 bits of data
265 0           $tdo = get_tdo($self) . $tdo; # collect 32 bits of TDO data; build word from right to left
266 0           set_tdi($self,0); # shift in 0s on TDI
267 0           set_tms($self,0);
268 0           tog_tck($self,1);
269             }
270 0 0         if ($tdo ne '0'x32) {
271 0           push(@idcodes, $tdo); # push idcodes onto stack, last device in the chain goes in first
272 0           $ndevs++
273             }
274             }
275            
276             # Now reorder the device numbers so the that the last device in the
277             # chain has the highest number. The first device in the chain (closest
278             # to the TDI signal from the PC) must be device 0.
279 0           foreach my $d (0..$ndevs-1) {
280 0           my $idcode = convert_hex(pop(@idcodes));
281 0           idcode_lookup($self, $idcode, $d);
282 0           printf("Device %d : IDCODE %s : %s\n", $d, $idcode, $self->{CHAIN}->[$d]->{NAME});
283             }
284            
285             # Return to RTI state
286 0           initialize($self);
287            
288 0           print "Auto-detect complete\n";
289            
290             }
291            
292             ###################################################################################################
293             # Assign JTAG chain configuration information based upon the IDCODE.
294             ###################################################################################################
295             sub idcode_lookup {
296 0     0 1   my $self = shift;
297 0           my $idcode = shift;
298 0           my $devnum = shift;
299            
300 0 0         $self->{CHAIN}->[$devnum] =
    0          
    0          
301            
302             ($idcode =~ /^.14..093/i) ? {NAME => 'Spartan-3 FPGA', # device name
303             IRLEN => 6, # device instruction register length
304             IRCMDS => {IDCODE => '001001', # device instructions (length must match IRLEN)
305             USER1 => '000010',
306             USER2 => '000011',
307             BYPASS => '111111'}}:
308            
309             ($idcode =~ /^.1c2e093/i) ? {NAME => 'XC3S12O0E FPGA', # device name
310             IRLEN => 6, # device instruction register length
311             IRCMDS => {IDCODE => '001001', # device instructions (length must match IRLEN)
312             USER1 => '000010',
313             USER2 => '000011',
314             BYPASS => '111111'}}:
315            
316             ($idcode =~ /^.504.093/i) ? {NAME => 'XCF0xS Platform Flash', # device name
317             IRLEN => 8, # device instruction register length
318             IRCMDS => {IDCODE => '11111110', # device instructions (length must match IRLEN)
319             BYPASS => '11111111'}}:
320            
321             {NAME => 'Unknown device', # device name
322             IRLEN => 0, # device instruction register length
323             IRCMDS => {}}; # device instructions (length must match IRLEN)
324             }
325             ###################################################################################################
326             # Read the IDCODE register for a pre-configured device in the chain.
327             # Required initial state : none
328             # Final state : RTI
329             ###################################################################################################
330             sub identify {
331 0     0 0   my $self = shift;
332 0           my $device = shift;
333            
334             # Initialize the chain to ensure we start from the RTI state
335 0           initialize($self);
336            
337             # Get the number of devices on the scan chain from the chain configuration
338 0           my $ndevices = scalar(@{$self->{CHAIN}});
  0            
339            
340             # Ensure selected device is in range
341 0 0         if ($device >= $ndevices) {
342 0           die("Selected device to identify ($device) is not defined in scan chain\n") ;
343             }
344            
345 0           shiftir($self, $device, 'IDCODE');
346 0           print "Identifying Device $device: IDCODE = 0x". shiftdr($self, $device, '0'x32) . "\n";
347            
348             }
349             1;
350             __END__