line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Device::Jtag::USB::FTCJTAG;
|
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
#use 5.008008;
|
4
|
1
|
|
|
1
|
|
45278
|
use strict;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
34
|
|
5
|
1
|
|
|
1
|
|
4
|
use warnings;
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
108
|
|
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::USB::FTCJTAG ':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.12';
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# Preloaded methods go here.
|
32
|
|
|
|
|
|
|
|
33
|
1
|
|
|
1
|
|
366
|
use Win32::API 0.46;
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
use Bit::Vector 6.4;
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
###################################################################################################
|
37
|
|
|
|
|
|
|
# Set debug verbosity level
|
38
|
|
|
|
|
|
|
###################################################################################################
|
39
|
|
|
|
|
|
|
my $DEBUG = 1;
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
###################################################################################################
|
42
|
|
|
|
|
|
|
# Define FTC_STATUS return values
|
43
|
|
|
|
|
|
|
###################################################################################################
|
44
|
|
|
|
|
|
|
my $ftc_status_type_aref;
|
45
|
|
|
|
|
|
|
$ftc_status_type_aref->[ 0] = 'FTC_SUCCESS';
|
46
|
|
|
|
|
|
|
$ftc_status_type_aref->[ 1] = 'FTC_INVALID_HANDLE';
|
47
|
|
|
|
|
|
|
$ftc_status_type_aref->[ 2] = 'FTC_DEVICE_NOT_FOUND';
|
48
|
|
|
|
|
|
|
$ftc_status_type_aref->[ 3] = 'FTC_DEVICE_NOT_OPENED';
|
49
|
|
|
|
|
|
|
$ftc_status_type_aref->[ 4] = 'FTC_IO_ERROR';
|
50
|
|
|
|
|
|
|
$ftc_status_type_aref->[ 5] = 'FTC_INSUFFICIENT_RESOURCES';
|
51
|
|
|
|
|
|
|
$ftc_status_type_aref->[20] = 'FTC_FAILED_TO_COMPLETE_COMMAND';
|
52
|
|
|
|
|
|
|
$ftc_status_type_aref->[21] = 'FTC_FAILED_TO_SYCHRONIZE_DEVICE_MPSSE';
|
53
|
|
|
|
|
|
|
$ftc_status_type_aref->[22] = 'FTC_INVALID_DEVICE_NAME_INDEX';
|
54
|
|
|
|
|
|
|
$ftc_status_type_aref->[23] = 'FTC_NULL_DEVICE_NAME_BUFFER_POINTER';
|
55
|
|
|
|
|
|
|
$ftc_status_type_aref->[24] = 'FTC_DEVICE_NAME_BUFFER_TOO_SMALL';
|
56
|
|
|
|
|
|
|
$ftc_status_type_aref->[25] = 'FTC_INVALID_DEVICE_NAME';
|
57
|
|
|
|
|
|
|
$ftc_status_type_aref->[26] = 'FTC_INVALID_LOCATION_ID';
|
58
|
|
|
|
|
|
|
$ftc_status_type_aref->[27] = 'FTC_DEVICE_IN_USE';
|
59
|
|
|
|
|
|
|
$ftc_status_type_aref->[28] = 'FTC_TOO_MANY_DEVICES';
|
60
|
|
|
|
|
|
|
$ftc_status_type_aref->[29] = 'FTC_INVALID_FREQUENCY_VALUE';
|
61
|
|
|
|
|
|
|
$ftc_status_type_aref->[30] = 'FTC_NULL_INPUT_OUTPUT_BUFFER_POINTER';
|
62
|
|
|
|
|
|
|
$ftc_status_type_aref->[31] = 'FTC_INVALID_NUMBER_BITS';
|
63
|
|
|
|
|
|
|
$ftc_status_type_aref->[32] = 'FTC_NULL_WRITE_DATA_BUFFER_POINTER';
|
64
|
|
|
|
|
|
|
$ftc_status_type_aref->[33] = 'FTC_INVALID_NUMBER_BYTES';
|
65
|
|
|
|
|
|
|
$ftc_status_type_aref->[34] = 'FTC_NUMBER_BYTES_TOO_SMALL';
|
66
|
|
|
|
|
|
|
$ftc_status_type_aref->[35] = 'FTC_INVALID_TAP_CONTROLLER_STATE';
|
67
|
|
|
|
|
|
|
$ftc_status_type_aref->[36] = 'FTC_NULL_READ_DATA_BUFFER_POINTER';
|
68
|
|
|
|
|
|
|
$ftc_status_type_aref->[37] = 'FTC_NULL_DLL_VERSION_BUFFER_POINTER';
|
69
|
|
|
|
|
|
|
$ftc_status_type_aref->[38] = 'FTC_DLL_VERSION_BUFFER_TOO_SMALL';
|
70
|
|
|
|
|
|
|
$ftc_status_type_aref->[39] = 'FTC_NULL_LANGUAGE_CODE_BUFFER_POINTER';
|
71
|
|
|
|
|
|
|
$ftc_status_type_aref->[40] = 'FTC_NULL_ERROR_MESSAGE_BUFFER_POINTER';
|
72
|
|
|
|
|
|
|
$ftc_status_type_aref->[41] = 'FTC_ERROR_MESSAGE_BUFFER_TOO_SMALL';
|
73
|
|
|
|
|
|
|
$ftc_status_type_aref->[42] = 'FTC_INVALID_LANGUAGE_CODE';
|
74
|
|
|
|
|
|
|
$ftc_status_type_aref->[43] = 'FTC_INVALID_STATUS_CODE';
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
###################################################################################################
|
77
|
|
|
|
|
|
|
# Define JTAG TAP controller states
|
78
|
|
|
|
|
|
|
###################################################################################################
|
79
|
|
|
|
|
|
|
use constant TEST_LOGIC_STATE => 1;
|
80
|
|
|
|
|
|
|
use constant RUN_TEST_IDLE_STATE => 2;
|
81
|
|
|
|
|
|
|
use constant PAUSE_TEST_DATA_REGISTER_STATE => 3;
|
82
|
|
|
|
|
|
|
use constant PAUSE_INSTRUCTION_REGISTER_STATE => 4;
|
83
|
|
|
|
|
|
|
use constant SHIFT_TEST_DATA_REGISTER_STATE => 5;
|
84
|
|
|
|
|
|
|
use constant SHIFT_INSTRUCTION_REGISTER_STATE => 6;
|
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
###################################################################################################
|
87
|
|
|
|
|
|
|
# Define FTDI chip buffer size (64k bits)
|
88
|
|
|
|
|
|
|
###################################################################################################
|
89
|
|
|
|
|
|
|
my $ftdi_buffer_size = 65535;
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
###################################################################################################
|
92
|
|
|
|
|
|
|
# Define Instruction Register vs Data Register constants
|
93
|
|
|
|
|
|
|
###################################################################################################
|
94
|
|
|
|
|
|
|
use constant IRSHIFT => 1;
|
95
|
|
|
|
|
|
|
use constant DRSHIFT => 0;
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
###################################################################################################
|
98
|
|
|
|
|
|
|
# Construct the new object
|
99
|
|
|
|
|
|
|
##################################################################################################
|
100
|
|
|
|
|
|
|
sub new {
|
101
|
|
|
|
|
|
|
my $self = {};
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
debug('new', 1, "Debug level set to $DEBUG");
|
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# Import API functions and assign to function handles
|
106
|
|
|
|
|
|
|
debug('new', 1, "Importing APIs");
|
107
|
|
|
|
|
|
|
foreach my $href (
|
108
|
|
|
|
|
|
|
{perl_name => 'get_ndev', c_name => 'JTAG_GetNumDevices' , inputs => 'P' , outputs => 'N'},
|
109
|
|
|
|
|
|
|
{perl_name => 'open' , c_name => 'JTAG_Open' , inputs => 'P' , outputs => 'N'},
|
110
|
|
|
|
|
|
|
{perl_name => 'init' , c_name => 'JTAG_InitDevice' , inputs => 'NN' , outputs => 'N'},
|
111
|
|
|
|
|
|
|
{perl_name => 'write' , c_name => 'JTAG_Write' , inputs => 'NNNPNN', outputs => 'N'},
|
112
|
|
|
|
|
|
|
{perl_name => 'read' , c_name => 'JTAG_Read' , inputs => 'NNNPPN', outputs => 'N'},
|
113
|
|
|
|
|
|
|
{perl_name => 'gen_clks', c_name => 'JTAG_GenerateClockPulses', inputs => 'NN' , outputs => 'N'},
|
114
|
|
|
|
|
|
|
{perl_name => 'get_gpio', c_name => 'JTAG_GetGPIOs' , inputs => 'NNPNP' , outputs => 'N'},
|
115
|
|
|
|
|
|
|
{perl_name => 'set_gpio', c_name => 'JTAG_SetGPIOs' , inputs => 'NNPNP' , outputs => 'N'}) {
|
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
$self->{fh}->{$href->{perl_name}} = Win32::API->new('FTCJTAG', $href->{c_name}, $href->{inputs}, $href->{outputs});
|
118
|
|
|
|
|
|
|
die(debug('new', 0, sprintf("Unable to import API %s: %s", $href->{c_name}, $!))) if(not defined $self->{fh}->{$href->{perl_name}});
|
119
|
|
|
|
|
|
|
}
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# Open JTAG key
|
123
|
|
|
|
|
|
|
debug('new', 1, "Opening JTAGKey");
|
124
|
|
|
|
|
|
|
my $ftc_handle_lw = ' 'x4; # pre-allocate 4 bytes to long word
|
125
|
|
|
|
|
|
|
my $ftc_status = $self->{fh}->{open}->Call($ftc_handle_lw);
|
126
|
|
|
|
|
|
|
die(debug('new', 0, sprintf("Unable to open JTAGKey : %s", $ftc_status_type_aref->[$ftc_status]))) if ($ftc_status);
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# Assign JTAGKey device handle
|
129
|
|
|
|
|
|
|
$self->{key} = unpack('L', $ftc_handle_lw); # unpack long word
|
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# Initialize JTAGKey to 6MHz transfer rate
|
132
|
|
|
|
|
|
|
debug('new', 1, "Setting JTAGKey transfer rate");
|
133
|
|
|
|
|
|
|
$ftc_status = $self->{fh}->{init}->Call($self->{key},0);
|
134
|
|
|
|
|
|
|
die(debug('new', 0, sprintf("Unable to initialize JTAGkey : %s", $ftc_status_type_aref->[$ftc_status]))) if ($ftc_status);
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# Read JTAGKey GPIOs to see that VREF is powered
|
137
|
|
|
|
|
|
|
debug('new', 1, "Checking JTAGKey power");
|
138
|
|
|
|
|
|
|
my $gpio_lo_lw = ' 'x16; # pre-allocate 4x4 long words
|
139
|
|
|
|
|
|
|
my $gpio_hi_lw = ' 'x16; # pre-allocate 4x4 long words
|
140
|
|
|
|
|
|
|
$ftc_status = $self->{fh}->{get_gpio}->Call($self->{key}, 1, $gpio_lo_lw, 1, $gpio_hi_lw);
|
141
|
|
|
|
|
|
|
die(debug('new', 0, sprintf("Unable to read JTAGkey GPIOs : %s", $ftc_status_type_aref->[$ftc_status]))) if ($ftc_status);
|
142
|
|
|
|
|
|
|
my $gpio_lo_aref = [unpack('L4', $gpio_lo_lw)]; # unpack 4 long words into array ref
|
143
|
|
|
|
|
|
|
my $gpio_hi_aref = [unpack('L4', $gpio_hi_lw)]; # unpack 4 long words into array ref
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
#foreach $b (0..3) {
|
146
|
|
|
|
|
|
|
# printf("GPIOL-%d = %d\n", $b, $gpio_lo_aref->[$b]);
|
147
|
|
|
|
|
|
|
#}
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
# Check JTAGKey VREF (GPIO LO bit 1 low if powered)
|
150
|
|
|
|
|
|
|
die(debug('new', 0, "JTAGKey VREF not powered")) if ($gpio_lo_aref->[1] eq 1);
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# Set JTAGKey GPIO controlling output enable
|
153
|
|
|
|
|
|
|
debug('new', 1, "Setting JTAGKey output enable");
|
154
|
|
|
|
|
|
|
my $gpiol_data = (0,0,0,0,0,0,0,1); # this does not make sense, but happens to work
|
155
|
|
|
|
|
|
|
my $gpioh_data = (0,0,0,0,0,0,0,0);
|
156
|
|
|
|
|
|
|
$ftc_status = $self->{fh}->{set_gpio}->Call($self->{key}, 1, pack('L8',$gpiol_data), 0, pack('L8',$gpioh_data));
|
157
|
|
|
|
|
|
|
die(debug('new', 0, sprintf("[FTCJTAG.PM] Unable to set JTAGkey GPIOs : %s", $ftc_status_type_aref->[$ftc_status]))) if ($ftc_status);
|
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# Check JTAGKey output enable (GPIO LO bit 0 low)
|
160
|
|
|
|
|
|
|
#die("ERROR: JTAG_OE_N not driven low\n") if ($gpio_lo_aref->[0] eq 0);
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# Send JTAG devices to TEST LOGIC RESET state
|
163
|
|
|
|
|
|
|
init_chain($self);
|
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# Autodetect devices on scan chain
|
166
|
|
|
|
|
|
|
autodetect($self);
|
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
bless($self);
|
169
|
|
|
|
|
|
|
return $self;
|
170
|
|
|
|
|
|
|
}
|
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
###########################################################################################################
|
173
|
|
|
|
|
|
|
# Initialized scan chain devices to TEST_LOGIC_STATE
|
174
|
|
|
|
|
|
|
###########################################################################################################
|
175
|
|
|
|
|
|
|
sub init_chain {
|
176
|
|
|
|
|
|
|
my $self = shift;
|
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
debug('init_chain', 1, "Initializing scan chain");
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# Perform the USB operation
|
181
|
|
|
|
|
|
|
my $data_lw = pack('L', 0);
|
182
|
|
|
|
|
|
|
my $ftc_status = $self->{fh}->{write}->Call($self->{key}, IRSHIFT, 2, $data_lw, $ftdi_buffer_size, TEST_LOGIC_STATE);
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
}
|
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
###########################################################################################################
|
187
|
|
|
|
|
|
|
# Autodetect the IDCODEs of the devices on the chain and assign info
|
188
|
|
|
|
|
|
|
###########################################################################################################
|
189
|
|
|
|
|
|
|
sub autodetect {
|
190
|
|
|
|
|
|
|
my $self = shift;
|
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# Allocate memory
|
193
|
|
|
|
|
|
|
my $rbuffer_lw = ' 'x$ftdi_buffer_size; # allocate memory for read string
|
194
|
|
|
|
|
|
|
my $nbytes_lw = ' 'x4; # allocate memory for number of bytes read
|
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
my $idcode = '';
|
197
|
|
|
|
|
|
|
my $dev = 0;
|
198
|
|
|
|
|
|
|
my @idcodes = ();
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
debug('autodetect', 1, "Autodetecting devices on scan chain");
|
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# Read IDCODEs, up to a max of 10 (this is arbitrary), until all zeroes are received
|
203
|
|
|
|
|
|
|
while ($idcode ne '0'x32 and $dev < 10) {
|
204
|
|
|
|
|
|
|
# Shift 32 bits through data registers, be sure to end in the PAUSE-DR state. If we return to the RUN-TEST-IDLE state
|
205
|
|
|
|
|
|
|
# then each device will reload its IDCODE data register.
|
206
|
|
|
|
|
|
|
my $ftc_status = $self->{fh}->{read}->Call($self->{key}, DRSHIFT, 32, $rbuffer_lw, $nbytes_lw, PAUSE_TEST_DATA_REGISTER_STATE);
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# Check return status
|
209
|
|
|
|
|
|
|
die(debug('autodetect', 0, sprintf("Unable to read via JTAGkey : %s", $ftc_status_type_aref->[$ftc_status]))) if ($ftc_status);
|
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# Unpack long words into binary string
|
212
|
|
|
|
|
|
|
$idcode = sprintf("%032b", unpack('L', $rbuffer_lw));
|
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
# Add current IDCODE to array of IDCODEs
|
215
|
|
|
|
|
|
|
push(@idcodes, $idcode) if $idcode ne '0'x32;
|
216
|
|
|
|
|
|
|
debug('autodetect', 2, "Read IDCODE = $idcode");
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
$dev++;
|
219
|
|
|
|
|
|
|
}
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# Assign device information and store in object. The last idcode pushed onto the array is the first one in the chain, which
|
222
|
|
|
|
|
|
|
# is defined here as device 0.
|
223
|
|
|
|
|
|
|
$dev = 0;
|
224
|
|
|
|
|
|
|
while (my $idcode = pop(@idcodes)) {
|
225
|
|
|
|
|
|
|
debug('autodetect', 2, sprintf("Looking up device information for IDCODE = %s", $idcode));
|
226
|
|
|
|
|
|
|
$self->{di}->[$dev] = idcode_lookup($idcode);
|
227
|
|
|
|
|
|
|
debug('autodetect', 1, sprintf("DEVICE %d : %s", $dev, $self->{di}->[$dev]->{name}));
|
228
|
|
|
|
|
|
|
$dev++;
|
229
|
|
|
|
|
|
|
}
|
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
return;
|
232
|
|
|
|
|
|
|
}
|
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
###########################################################################################################
|
235
|
|
|
|
|
|
|
# Instruction register write to JTAG scan chain device
|
236
|
|
|
|
|
|
|
# Usage: write_dev_ir($self, $devid, $imntr, [$endstate]);
|
237
|
|
|
|
|
|
|
# Return: nothing
|
238
|
|
|
|
|
|
|
###########################################################################################################
|
239
|
|
|
|
|
|
|
sub write_dev_ir {
|
240
|
|
|
|
|
|
|
my $self = shift; # jtagusb object
|
241
|
|
|
|
|
|
|
my $href = shift; # href containing parameters
|
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
my $dev = $href->{dev}; # integer scan chain position of device to write, beginning with 0
|
244
|
|
|
|
|
|
|
my $imn = $href->{imn}; # string containing instruction mnemonic to write to selected device
|
245
|
|
|
|
|
|
|
my $end = $href->{end}; # optional state to leave device in
|
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
# Find number of devices in scan chain
|
248
|
|
|
|
|
|
|
my $nscdevs = scalar(@{$self->{di}});
|
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
# Construct full binary string to be shifted by padding the non-selected device data with the BYPASS command
|
251
|
|
|
|
|
|
|
my $data = '';
|
252
|
|
|
|
|
|
|
foreach my $d (0..$nscdevs-1) {
|
253
|
|
|
|
|
|
|
# All devices on the chain other than the selected device get the BYPASS instruction
|
254
|
|
|
|
|
|
|
my $imn_tmp = ($d eq $dev)? $imn : 'bypass';
|
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
# Flag an error if the binary equivalent of the instruction isn't defined
|
257
|
|
|
|
|
|
|
if (not defined $self->{di}->[$d]->{ircmds}->{$imn_tmp}) {
|
258
|
|
|
|
|
|
|
die(debug('write_dev_ir', 0, "Instruction $imn_tmp not defined for scan chain device $d"));
|
259
|
|
|
|
|
|
|
}
|
260
|
|
|
|
|
|
|
# Get binary equivalent of instruction and add it to the binary string of write data
|
261
|
|
|
|
|
|
|
my $i0b = $self->{di}->[$d]->{ircmds}->{$imn_tmp};
|
262
|
|
|
|
|
|
|
$data .= $i0b;
|
263
|
|
|
|
|
|
|
debug('write_dev_ir', 2, sprintf("Writing %s (0b%s) to device %d", uc($imn_tmp), $i0b, $d));
|
264
|
|
|
|
|
|
|
}
|
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# Form Bit::Vector object containing binary string
|
267
|
|
|
|
|
|
|
my $vec = Bit::Vector->new_Bin(length($data), $data);
|
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# Call write_dev subroutine
|
270
|
|
|
|
|
|
|
write_dev($self,
|
271
|
|
|
|
|
|
|
{vec => $vec,
|
272
|
|
|
|
|
|
|
typ => IRSHIFT,
|
273
|
|
|
|
|
|
|
end => $end});
|
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
return;
|
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
}
|
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
###########################################################################################################
|
280
|
|
|
|
|
|
|
# Data register write to JTAG scan chain device
|
281
|
|
|
|
|
|
|
# Usage: write_dev_dr($self, $deviceid, $vec, [$end]);
|
282
|
|
|
|
|
|
|
# Return: nothing
|
283
|
|
|
|
|
|
|
###########################################################################################################
|
284
|
|
|
|
|
|
|
sub write_dev_dr {
|
285
|
|
|
|
|
|
|
my $self = shift; # jtagusb object
|
286
|
|
|
|
|
|
|
my $href = shift; # href containing parameters
|
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
my $dev = $href->{dev}; # integer scan chain position of device to write, beginning with 0
|
289
|
|
|
|
|
|
|
my $vec = $href->{vec}; # Bit::Vector object containing data to be written to device
|
290
|
|
|
|
|
|
|
my $end = $href->{end}; # optional state to leave device in
|
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# Pad the data with 0's on the left, depending upon the desired device's position in the scan chain
|
293
|
|
|
|
|
|
|
# All devices in the scan chain -- other than the one that we're interested in -- are assumed to
|
294
|
|
|
|
|
|
|
# be in the BYPASS state, representing a single flip flop in the chain. So, if there are any devices
|
295
|
|
|
|
|
|
|
# in the chain before the one we're writing to (this would be represented by the $dev of the device
|
296
|
|
|
|
|
|
|
# we're writing to being nonzero), then pad the end of the write string with a 0 for each device in
|
297
|
|
|
|
|
|
|
# the chain preceeding the one we're writing to.
|
298
|
|
|
|
|
|
|
my $pad_vec = Bit::Vector->new_Bin($dev, 0)->Concat($vec); # pad vector with additional 0's on the left
|
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# Write to device
|
301
|
|
|
|
|
|
|
write_dev($self,
|
302
|
|
|
|
|
|
|
{vec => $pad_vec,
|
303
|
|
|
|
|
|
|
typ => DRSHIFT,
|
304
|
|
|
|
|
|
|
end => $end});
|
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
return;
|
307
|
|
|
|
|
|
|
}
|
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
###########################################################################################################
|
310
|
|
|
|
|
|
|
# Write to JTAG device
|
311
|
|
|
|
|
|
|
# Usage: write_dev($self, $deviceid, $vector, $type (IRSHIFT or DRSHIFT), [$endstate]);
|
312
|
|
|
|
|
|
|
# Return: nothing
|
313
|
|
|
|
|
|
|
###########################################################################################################
|
314
|
|
|
|
|
|
|
sub write_dev {
|
315
|
|
|
|
|
|
|
my $self = shift; # jtagusb object
|
316
|
|
|
|
|
|
|
my $href = shift; # href containing parameters
|
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
my $vec = $href->{vec}; # Bit::Vector object containing data to be written to device
|
319
|
|
|
|
|
|
|
my $typ = $href->{typ}; # shift type: IRSHIFT or DRSHIFT
|
320
|
|
|
|
|
|
|
my $end = $href->{end}; # optional state to leave device in
|
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
# Trap unspecified endstate
|
323
|
|
|
|
|
|
|
if (not $end) {
|
324
|
|
|
|
|
|
|
$end = RUN_TEST_IDLE_STATE;
|
325
|
|
|
|
|
|
|
}
|
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# Convert Data::Vector object to binary string
|
328
|
|
|
|
|
|
|
my $data = $vec->to_Bin();
|
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# Determine number of bits to shift
|
331
|
|
|
|
|
|
|
my $nbits = length($data);
|
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
debug('write_dev', 2, sprintf("Performing %s of 0b$data ($nbits bits)", $typ eq IRSHIFT? 'IRSHIFT' : 'DRSHIFT'));
|
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
# Convert data to integer array @words, must be done 32 bits at a time
|
336
|
|
|
|
|
|
|
my $nlw = int((length($data)-1)/32) + 1;
|
337
|
|
|
|
|
|
|
my @words;
|
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
debug('write_dev', 2, "Packing $nlw words");
|
340
|
|
|
|
|
|
|
for my $i (1..$nlw) {
|
341
|
|
|
|
|
|
|
my $datalen = length($data);
|
342
|
|
|
|
|
|
|
debug('write_dev', 2, sprintf("Data: %s (Length %s)", $data, $datalen));
|
343
|
|
|
|
|
|
|
my $offset = ($datalen > 32)? -32 : 0;
|
344
|
|
|
|
|
|
|
my $length = ($datalen > 32)? 32 : $datalen;
|
345
|
|
|
|
|
|
|
my $word = substr($data,$offset,$length); # get rightmost 32 bits
|
346
|
|
|
|
|
|
|
debug('write_dev', 2, sprintf("Long Word $i (%d,%d): %s", $offset,$length, $word));
|
347
|
|
|
|
|
|
|
substr($data,$offset,$length) = '';
|
348
|
|
|
|
|
|
|
push(@words, oct('0b'.$word));
|
349
|
|
|
|
|
|
|
}
|
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
# pack integer data
|
352
|
|
|
|
|
|
|
my $data_lw = pack('L'x$nlw, @words);
|
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
# Perform the USB operation
|
355
|
|
|
|
|
|
|
my $ftc_status = $self->{fh}->{write}->Call($self->{key}, $typ, $nbits, $data_lw, $ftdi_buffer_size, $end);
|
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# Check return status
|
358
|
|
|
|
|
|
|
die(debug('write_dev', 0, "Unable to write")) if ($ftc_status);
|
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
return;
|
361
|
|
|
|
|
|
|
}
|
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
###########################################################################################################
|
364
|
|
|
|
|
|
|
# Read from data register of specified JTAG scan chain device
|
365
|
|
|
|
|
|
|
# Usage: read_dev($self, $devid, $nbits, [$endstate]);
|
366
|
|
|
|
|
|
|
# Return: Bit::Vector containing data read from selected device
|
367
|
|
|
|
|
|
|
###########################################################################################################
|
368
|
|
|
|
|
|
|
sub read_dev_dr {
|
369
|
|
|
|
|
|
|
my $self = shift; # jtagusb object
|
370
|
|
|
|
|
|
|
my $href = shift; # href containing parameters
|
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
my $dev = $href->{dev}; # integer scan chain position of device to read, beginning with 0
|
373
|
|
|
|
|
|
|
my $nbits = $href->{nbits}; # number of bits to read
|
374
|
|
|
|
|
|
|
my $end = $href->{end}; # optional state to leave device in
|
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
my $rbuffer_lw = ' 'x$ftdi_buffer_size; # allocate memory for read string
|
377
|
|
|
|
|
|
|
my $nbytes_lw = ' 'x4; # allocate memory for number of bytes read
|
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
# Trap unspecified endstate
|
380
|
|
|
|
|
|
|
if (not $end) {
|
381
|
|
|
|
|
|
|
$end = RUN_TEST_IDLE_STATE;
|
382
|
|
|
|
|
|
|
}
|
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
# The first bit of data we want is sitting on TDO of the selected device. If there are any devices in
|
385
|
|
|
|
|
|
|
# the chain after the selected device, the data we want must get through those subsequent devices.
|
386
|
|
|
|
|
|
|
# If this is a DRSHIFT, we assume each non-selected device has been given the BYPASS command, thus each
|
387
|
|
|
|
|
|
|
# non-selected device will place the 1-bit BYPASS register on the chain. This means that if there are
|
388
|
|
|
|
|
|
|
# N devices in the chain after the selected device, and the number of bits of data being shifted is M,
|
389
|
|
|
|
|
|
|
# the total number of shifts must be 1*N+M. Finally, the first N bits of data received on TDO should be
|
390
|
|
|
|
|
|
|
# discarded.
|
391
|
|
|
|
|
|
|
my $nbits_extra = scalar(@{$self->{di}}) - ($dev+1); # Num devices on the scan chain after the selected device
|
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
debug('read_dev', 2, sprintf("Reading %d bits from device %d", $nbits, $dev));
|
394
|
|
|
|
|
|
|
debug('read_dev', 2, sprintf("Reading %d extra bits from device %d", $nbits_extra, $dev));
|
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
# Perform the USB operation
|
397
|
|
|
|
|
|
|
my $ftc_status = $self->{fh}->{read}->Call($self->{key}, DRSHIFT, $nbits + $nbits_extra, $rbuffer_lw, $nbytes_lw, $end);
|
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
# Check return status
|
400
|
|
|
|
|
|
|
die(debug('read_dev', 0, sprintf("Unable to read via JTAGkey : %s", $ftc_status_type_aref->[$ftc_status]))) if ($ftc_status);
|
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
# Calculate the number of long words to convert (each long word is 32 bytes)
|
403
|
|
|
|
|
|
|
my $nlw = int(($nbits+$nbits_extra-1)/32) + 1;
|
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
debug('read_dev', 2, "Converting $nlw long words");
|
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# Unpack long words into binary string
|
408
|
|
|
|
|
|
|
my $rdata_bstr = '';
|
409
|
|
|
|
|
|
|
foreach my $d (unpack('L'x$nlw, $rbuffer_lw)) {
|
410
|
|
|
|
|
|
|
$rdata_bstr = sprintf("%032b",$d) . $rdata_bstr;
|
411
|
|
|
|
|
|
|
}
|
412
|
|
|
|
|
|
|
debug('read_dev', 2, sprintf("Binary read data: %s", $rdata_bstr));
|
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
my $vector = Bit::Vector->new_Bin($nbits, substr($rdata_bstr, -1*($nbits+$nbits_extra), $nbits));
|
415
|
|
|
|
|
|
|
return($vector);
|
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
}
|
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
###########################################################################################################
|
420
|
|
|
|
|
|
|
# IDCODE LOOKUP
|
421
|
|
|
|
|
|
|
# This information is lifted from Xilinx BSDL files
|
422
|
|
|
|
|
|
|
###########################################################################################################
|
423
|
|
|
|
|
|
|
sub idcode_lookup {
|
424
|
|
|
|
|
|
|
my $idcode0b = shift;
|
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
my $bsdl_info_href;
|
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
$bsdl_info_href->{'....0001010000011100000010010011'} = {name => 'XC3S400_FT256',
|
429
|
|
|
|
|
|
|
ircmds => {extest => '000000', #
|
430
|
|
|
|
|
|
|
sample => '000001', #
|
431
|
|
|
|
|
|
|
user1 => '000010', # -- Not available until after configuration
|
432
|
|
|
|
|
|
|
user2 => '000011', # -- Not available until after configuration
|
433
|
|
|
|
|
|
|
cfg_out => '000100', # -- Not available during configuration with another mode.
|
434
|
|
|
|
|
|
|
cfg_in => '000101', # -- Not available during configuration with another mode.
|
435
|
|
|
|
|
|
|
intest => '000111', #
|
436
|
|
|
|
|
|
|
usercode => '001000', #
|
437
|
|
|
|
|
|
|
idcode => '001001', #
|
438
|
|
|
|
|
|
|
highz => '001010', #
|
439
|
|
|
|
|
|
|
jprogram => '001011', # -- Not available during configuration with another mode.
|
440
|
|
|
|
|
|
|
jstart => '001100', # -- Not available during configuration with another mode.
|
441
|
|
|
|
|
|
|
jshutdown => '001101', # -- Not available during configuration with another mode.
|
442
|
|
|
|
|
|
|
bypass => '111111' #
|
443
|
|
|
|
|
|
|
}};
|
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
$bsdl_info_href->{'....0001010000101000000010010011'} = {name => 'XC3S1000_FT256',
|
446
|
|
|
|
|
|
|
ircmds => {extest => '000000', #
|
447
|
|
|
|
|
|
|
sample => '000001', #
|
448
|
|
|
|
|
|
|
user1 => '000010', # -- Not available until after configuration
|
449
|
|
|
|
|
|
|
user2 => '000011', # -- Not available until after configuration
|
450
|
|
|
|
|
|
|
cfg_out => '000100', # -- Not available during configuration with another mode.
|
451
|
|
|
|
|
|
|
cfg_in => '000101', # -- Not available during configuration with another mode.
|
452
|
|
|
|
|
|
|
intest => '000111', #
|
453
|
|
|
|
|
|
|
usercode => '001000', #
|
454
|
|
|
|
|
|
|
idcode => '001001', #
|
455
|
|
|
|
|
|
|
highz => '001010', #
|
456
|
|
|
|
|
|
|
jprogram => '001011', # -- Not available during configuration with another mode.
|
457
|
|
|
|
|
|
|
jstart => '001100', # -- Not available during configuration with another mode.
|
458
|
|
|
|
|
|
|
jshutdown => '001101', # -- Not available during configuration with another mode.
|
459
|
|
|
|
|
|
|
bypass => '111111' #
|
460
|
|
|
|
|
|
|
}};
|
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
$bsdl_info_href->{'....0101000001000110000010010011'} = {name => 'XCF04S_VO20',
|
463
|
|
|
|
|
|
|
ircmds => {bypass => '11111111',
|
464
|
|
|
|
|
|
|
sample => '00000001',
|
465
|
|
|
|
|
|
|
preload => '00000001',
|
466
|
|
|
|
|
|
|
extest => '00000000',
|
467
|
|
|
|
|
|
|
idcode => '11111110',
|
468
|
|
|
|
|
|
|
usercode => '11111101',
|
469
|
|
|
|
|
|
|
highz => '11111100',
|
470
|
|
|
|
|
|
|
clamp => '11111010',
|
471
|
|
|
|
|
|
|
config => '11101110'}};
|
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
$bsdl_info_href->{'....0001110000100010000010010011'} = {name => 'XC3S500E_FT256',
|
474
|
|
|
|
|
|
|
ircmds => {extest => '001111', #
|
475
|
|
|
|
|
|
|
sample => '000001', #
|
476
|
|
|
|
|
|
|
preload => '000001', # Not available until after configuration
|
477
|
|
|
|
|
|
|
user1 => '000010', # Not available until after configuration
|
478
|
|
|
|
|
|
|
user2 => '000011', # Not available during configuration with another mode.
|
479
|
|
|
|
|
|
|
cfg_out => '000100', # Not available during configuration with another mode.
|
480
|
|
|
|
|
|
|
cfg_in => '000101', #
|
481
|
|
|
|
|
|
|
intest => '000111', #
|
482
|
|
|
|
|
|
|
usercode => '001000', #
|
483
|
|
|
|
|
|
|
idcode => '001001', #
|
484
|
|
|
|
|
|
|
highz => '001010', # Not available during configuration with another mode.
|
485
|
|
|
|
|
|
|
jprogram => '001011', # Not available during configuration with another mode.
|
486
|
|
|
|
|
|
|
jstart => '001100', # Not available during configuration with another mode.
|
487
|
|
|
|
|
|
|
jshutdown => '001101', #
|
488
|
|
|
|
|
|
|
bypass => '111111', #
|
489
|
|
|
|
|
|
|
isc_enable => '010000', #
|
490
|
|
|
|
|
|
|
isc_program => '010001', #
|
491
|
|
|
|
|
|
|
isc_noop => '010100', #
|
492
|
|
|
|
|
|
|
isc_read => '010101',
|
493
|
|
|
|
|
|
|
isc_disable => '010110'}};
|
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
$bsdl_info_href->{'....0001110000101110000010010011'} = {name => 'XC3S1200E_FT256',
|
497
|
|
|
|
|
|
|
ircmds => {EXTEST => '001111', #
|
498
|
|
|
|
|
|
|
SAMPLE => '000001', #
|
499
|
|
|
|
|
|
|
PRELOAD => '000001', # Not available until after configuration
|
500
|
|
|
|
|
|
|
USER1 => '000010', # Not available until after configuration
|
501
|
|
|
|
|
|
|
USER2 => '000011', # Not available during configuration with another mode.
|
502
|
|
|
|
|
|
|
CFG_OUT => '000100', # Not available during configuration with another mode.
|
503
|
|
|
|
|
|
|
CFG_IN => '000101', #
|
504
|
|
|
|
|
|
|
INTEST => '000111', #
|
505
|
|
|
|
|
|
|
USERCODE => '001000', #
|
506
|
|
|
|
|
|
|
IDCODE => '001001', #
|
507
|
|
|
|
|
|
|
HIGHZ => '001010', # Not available during configuration with another mode.
|
508
|
|
|
|
|
|
|
JPROGRAM => '001011', # Not available during configuration with another mode.
|
509
|
|
|
|
|
|
|
JSTART => '001100', # Not available during configuration with another mode.
|
510
|
|
|
|
|
|
|
JSHUTDOWN => '001101', #
|
511
|
|
|
|
|
|
|
BYPASS => '111111', #
|
512
|
|
|
|
|
|
|
ISC_ENABLE => '010000', #
|
513
|
|
|
|
|
|
|
ISC_PROGRAM => '010001', #
|
514
|
|
|
|
|
|
|
ISC_NOOP => '010100', #
|
515
|
|
|
|
|
|
|
ISC_READ => '010101',
|
516
|
|
|
|
|
|
|
ISC_DISABLE => '010110'}};
|
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
foreach my $key (keys %$bsdl_info_href) {
|
519
|
|
|
|
|
|
|
if ($idcode0b =~ m/$key/) {
|
520
|
|
|
|
|
|
|
return $bsdl_info_href->{$key};
|
521
|
|
|
|
|
|
|
}
|
522
|
|
|
|
|
|
|
}
|
523
|
|
|
|
|
|
|
die(debug('idcode_lookup', 0, "No IDCODE match for $idcode0b found"));
|
524
|
|
|
|
|
|
|
}
|
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
###########################################################################################################
|
527
|
|
|
|
|
|
|
# PRINT DEBUGGING INFORMATION
|
528
|
|
|
|
|
|
|
###########################################################################################################
|
529
|
|
|
|
|
|
|
sub debug {
|
530
|
|
|
|
|
|
|
my $sub = shift;
|
531
|
|
|
|
|
|
|
my $print_level = shift;
|
532
|
|
|
|
|
|
|
my $message = shift;
|
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
if ($DEBUG >= $print_level) {
|
535
|
|
|
|
|
|
|
printf("[%s][%-12.12s] %s\n", 'FTCJTAG', uc($sub), $message);
|
536
|
|
|
|
|
|
|
}
|
537
|
|
|
|
|
|
|
}
|
538
|
|
|
|
|
|
|
1;
|
539
|
|
|
|
|
|
|
__END__
|