Merge pull request #77 from phdussud/dirtyjtag2
Support for new DirtyJtag2 protocol
This commit is contained in:
commit
b5d18369bb
|
|
@ -59,6 +59,7 @@ __Supported cables:__
|
||||||
* anlogic JTAG adapter
|
* anlogic JTAG adapter
|
||||||
* [digilent_hs2](https://store.digilentinc.com/jtag-hs2-programming-cable/): jtag programmer cable from digilent
|
* [digilent_hs2](https://store.digilentinc.com/jtag-hs2-programming-cable/): jtag programmer cable from digilent
|
||||||
* [DirtyJTAG](https://github.com/jeanthom/DirtyJTAG): JTAG probe firmware for STM32F1
|
* [DirtyJTAG](https://github.com/jeanthom/DirtyJTAG): JTAG probe firmware for STM32F1
|
||||||
|
(Best to use release (1.4 or newer) or limit the --freq to 600000 with older releases. New version https://github.com/jeanthom/DirtyJTAG/tree/dirtyjtag2 is also supported)
|
||||||
* Intel USB Blaster: jtag programmer cable from intel/altera
|
* Intel USB Blaster: jtag programmer cable from intel/altera
|
||||||
* JTAG-HS3: jtag programmer cable from digilent
|
* JTAG-HS3: jtag programmer cable from digilent
|
||||||
* FT2232: generic programmer cable based on Ftdi FT2232
|
* FT2232: generic programmer cable based on Ftdi FT2232
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include "dirtyJtag.hpp"
|
#include "dirtyJtag.hpp"
|
||||||
#include "display.hpp"
|
#include "display.hpp"
|
||||||
|
|
@ -32,9 +33,11 @@ using namespace std;
|
||||||
#define DIRTYJTAG_VID 0x1209
|
#define DIRTYJTAG_VID 0x1209
|
||||||
#define DIRTYJTAG_PID 0xC0CA
|
#define DIRTYJTAG_PID 0xC0CA
|
||||||
|
|
||||||
|
#define DIRTYJTAG_INTF 0
|
||||||
#define DIRTYJTAG_WRITE_EP 0x01
|
#define DIRTYJTAG_WRITE_EP 0x01
|
||||||
#define DIRTYJTAG_READ_EP 0x82
|
#define DIRTYJTAG_READ_EP 0x82
|
||||||
|
|
||||||
|
|
||||||
enum dirtyJtagCmd {
|
enum dirtyJtagCmd {
|
||||||
CMD_STOP = 0x00,
|
CMD_STOP = 0x00,
|
||||||
CMD_INFO = 0x01,
|
CMD_INFO = 0x01,
|
||||||
|
|
@ -45,6 +48,21 @@ enum dirtyJtagCmd {
|
||||||
CMD_CLK = 0x06
|
CMD_CLK = 0x06
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//Modifiers applicable only to DirtyJTAG2
|
||||||
|
enum CommandModifier {
|
||||||
|
EXTEND_LENGTH = 0x40,
|
||||||
|
NO_READ = 0x80
|
||||||
|
};
|
||||||
|
|
||||||
|
struct version_specific
|
||||||
|
{
|
||||||
|
uint8_t no_read; //command modifer for xfer no read
|
||||||
|
uint16_t max_bits; //max bit count that can be transferred
|
||||||
|
};
|
||||||
|
|
||||||
|
static version_specific v_options[4] ={{0, 240}, {0, 240}, {NO_READ, 496}, {NO_READ, 4000}};
|
||||||
|
|
||||||
|
|
||||||
enum dirtyJtagSig {
|
enum dirtyJtagSig {
|
||||||
SIG_TCK = (1 << 1),
|
SIG_TCK = (1 << 1),
|
||||||
SIG_TDI = (1 << 2),
|
SIG_TDI = (1 << 2),
|
||||||
|
|
@ -71,14 +89,17 @@ DirtyJtag::DirtyJtag(uint32_t clkHZ, bool verbose):
|
||||||
throw std::exception();
|
throw std::exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = libusb_claim_interface(dev_handle, 0);
|
ret = libusb_claim_interface(dev_handle, DIRTYJTAG_INTF);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
cerr << "libusb error while claiming DirtyJTAG interface #0" << endl;
|
cerr << "libusb error while claiming DirtyJTAG interface" << endl;
|
||||||
libusb_close(dev_handle);
|
libusb_close(dev_handle);
|
||||||
libusb_exit(usb_ctx);
|
libusb_exit(usb_ctx);
|
||||||
throw std::exception();
|
throw std::exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_version = 0;
|
||||||
|
getVersion();
|
||||||
|
|
||||||
if (setClkFreq(clkHZ) < 0) {
|
if (setClkFreq(clkHZ) < 0) {
|
||||||
cerr << "Fail to set frequency" << endl;
|
cerr << "Fail to set frequency" << endl;
|
||||||
throw std::exception();
|
throw std::exception();
|
||||||
|
|
@ -93,14 +114,49 @@ DirtyJtag::~DirtyJtag()
|
||||||
libusb_exit(usb_ctx);
|
libusb_exit(usb_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DirtyJtag::getVersion()
|
||||||
|
{
|
||||||
|
int actual_length;
|
||||||
|
int ret;
|
||||||
|
uint8_t buf[] = {CMD_INFO,
|
||||||
|
CMD_STOP};
|
||||||
|
uint8_t rx_buf[64];
|
||||||
|
ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_WRITE_EP,
|
||||||
|
buf, 2, &actual_length, 1000);
|
||||||
|
if (ret < 0) {
|
||||||
|
cerr << "getVersion: usb bulk write failed " << ret << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP,
|
||||||
|
rx_buf, 64, &actual_length, 1000);
|
||||||
|
if (ret < 0) {
|
||||||
|
cerr << "getVersion: read: usb bulk read failed " << ret << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} while (actual_length == 0);
|
||||||
|
if (!strncmp("DJTAG1\n", (char*)rx_buf, 7)) {
|
||||||
|
_version = 1;
|
||||||
|
} else if (!strncmp("DJTAG2\n", (char*)rx_buf, 7)) {
|
||||||
|
_version = 2;
|
||||||
|
} else if (!strncmp("DJTAG3\n", (char*)rx_buf, 7)) {
|
||||||
|
_version = 3;
|
||||||
|
} else {
|
||||||
|
cerr << "dirtyJtag version unknown" << endl;
|
||||||
|
_version = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int DirtyJtag::setClkFreq(uint32_t clkHZ)
|
int DirtyJtag::setClkFreq(uint32_t clkHZ)
|
||||||
{
|
{
|
||||||
int actual_length;
|
int actual_length;
|
||||||
int ret, req_freq = clkHZ;
|
int ret, req_freq = clkHZ;
|
||||||
|
|
||||||
if (clkHZ > 600000) {
|
if (clkHZ > 16000000) {
|
||||||
printWarn("DirtyJTAG probe limited to 600kHz");
|
printWarn("DirtyJTAG probe limited to 16000kHz");
|
||||||
clkHZ = 600000;
|
clkHZ = 16000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
printInfo("Jtag frequency : requested " + std::to_string(req_freq) +
|
printInfo("Jtag frequency : requested " + std::to_string(req_freq) +
|
||||||
|
|
@ -142,7 +198,7 @@ int DirtyJtag::toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len)
|
||||||
0,
|
0,
|
||||||
CMD_STOP};
|
CMD_STOP};
|
||||||
while (clk_len > 0) {
|
while (clk_len > 0) {
|
||||||
buf[2] = (clk_len > 100) ? 100 : (uint8_t)clk_len;
|
buf[2] = (clk_len > 64) ? 64 : (uint8_t)clk_len;
|
||||||
|
|
||||||
int ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_WRITE_EP,
|
int ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_WRITE_EP,
|
||||||
buf, 4, &actual_length, 1000);
|
buf, 4, &actual_length, 1000);
|
||||||
|
|
@ -168,7 +224,7 @@ int DirtyJtag::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
|
||||||
uint32_t real_byte_len = (len + 7) / 8;
|
uint32_t real_byte_len = (len + 7) / 8;
|
||||||
|
|
||||||
uint8_t tx_cpy[real_byte_len];
|
uint8_t tx_cpy[real_byte_len];
|
||||||
uint8_t tx_buf[33], rx_buf[32];
|
uint8_t tx_buf[512], rx_buf[512];
|
||||||
uint8_t *tx_ptr = tx, *rx_ptr = rx;
|
uint8_t *tx_ptr = tx, *rx_ptr = rx;
|
||||||
|
|
||||||
if (tx)
|
if (tx)
|
||||||
|
|
@ -177,31 +233,51 @@ int DirtyJtag::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
|
||||||
memset(tx_cpy, 0, real_byte_len);
|
memset(tx_cpy, 0, real_byte_len);
|
||||||
tx_ptr = tx_cpy;
|
tx_ptr = tx_cpy;
|
||||||
|
|
||||||
/* first send 30 x 8 bits */
|
tx_buf[0] = CMD_XFER | (rx ? 0 : v_options[_version].no_read );
|
||||||
tx_buf[0] = CMD_XFER;
|
uint16_t max_bit_transfer_length = v_options[_version].max_bits;
|
||||||
|
assert(max_bit_transfer_length %8 == 0);//need to cut the bits on byte size.
|
||||||
while (real_bit_len != 0) {
|
while (real_bit_len != 0) {
|
||||||
uint8_t bit_to_send = (real_bit_len > 240) ? 240 : real_bit_len;
|
uint16_t bit_to_send = (real_bit_len > max_bit_transfer_length) ? max_bit_transfer_length : real_bit_len;
|
||||||
uint8_t byte_to_send = (bit_to_send + 7) / 8;
|
size_t byte_to_send = (bit_to_send + 7) / 8;
|
||||||
tx_buf[1] = bit_to_send;
|
size_t header_offset = 0;
|
||||||
memset(tx_buf + 2, 0, 30);
|
if (_version == 3) {
|
||||||
|
tx_buf[1] = (bit_to_send >> 8) & 0xFF;
|
||||||
|
tx_buf[2] = bit_to_send & 0xFF;
|
||||||
|
header_offset = 3;
|
||||||
|
} else if (bit_to_send > 255) {
|
||||||
|
tx_buf[0] |= EXTEND_LENGTH;
|
||||||
|
tx_buf[1] = bit_to_send - 256;
|
||||||
|
header_offset = 2;
|
||||||
|
}else {
|
||||||
|
tx_buf[0] &= ~EXTEND_LENGTH;
|
||||||
|
tx_buf[1] = bit_to_send;
|
||||||
|
header_offset = 2;
|
||||||
|
}
|
||||||
|
memset(tx_buf + header_offset, 0, byte_to_send);
|
||||||
for (int i = 0; i < bit_to_send; i++)
|
for (int i = 0; i < bit_to_send; i++)
|
||||||
if (tx_ptr[i >> 3] & (1 << (i & 0x07)))
|
if (tx_ptr[i >> 3] & (1 << (i & 0x07)))
|
||||||
tx_buf[2 + (i >> 3)] |= (0x80 >> (i & 0x07));
|
tx_buf[header_offset + (i >> 3)] |= (0x80 >> (i & 0x07));
|
||||||
|
|
||||||
tx_buf[2 + byte_to_send] = CMD_STOP;
|
|
||||||
|
|
||||||
|
actual_length = 0;
|
||||||
int ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_WRITE_EP,
|
int ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_WRITE_EP,
|
||||||
(unsigned char *)tx_buf, 33, &actual_length, 1000);
|
(unsigned char *)tx_buf, (byte_to_send + header_offset), &actual_length, 1000);
|
||||||
if (ret < 0) {
|
if ((ret < 0) || (actual_length != (int)(byte_to_send + header_offset))) {
|
||||||
cerr << "writeTDI: fill: usb bulk write failed " << ret << endl;
|
cerr << "writeTDI: fill: usb bulk write failed " << ret << "actual length: " << actual_length << endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
//cerr << actual_length << ", " << bit_to_send << endl;
|
||||||
|
|
||||||
ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP,
|
if (rx || (_version <= 1)) {
|
||||||
rx_buf, 32, &actual_length, 1000);
|
int transfer_length = (bit_to_send > 255) ? byte_to_send :32;
|
||||||
if (ret < 0) {
|
do {
|
||||||
cerr << "writeTDI: read: usb bulk write failed " << ret << endl;
|
ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP,
|
||||||
return EXIT_FAILURE;
|
rx_buf, transfer_length, &actual_length, 1000);
|
||||||
|
if (ret < 0) {
|
||||||
|
cerr << "writeTDI: read: usb bulk read failed " << ret << endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
} while (actual_length == 0);
|
||||||
|
assert((size_t)actual_length >= byte_to_send);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rx) {
|
if (rx) {
|
||||||
|
|
@ -223,7 +299,7 @@ int DirtyJtag::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
|
||||||
(tx_cpy[pos >> 3] & (1 << (pos & 0x07))) ? SIG_TDI: 0;
|
(tx_cpy[pos >> 3] & (1 << (pos & 0x07))) ? SIG_TDI: 0;
|
||||||
|
|
||||||
if (sendBitBang(SIG_TMS | SIG_TDI,
|
if (sendBitBang(SIG_TMS | SIG_TDI,
|
||||||
SIG_TMS | (last_bit), &sig, true) != 0) {
|
SIG_TMS | (last_bit), (rx ? &sig : 0), true) != 0) {
|
||||||
cerr << "writeTDI: last bit error" << endl;
|
cerr << "writeTDI: last bit error" << endl;
|
||||||
return -EXIT_FAILURE;
|
return -EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -264,11 +340,13 @@ int DirtyJtag::sendBitBang(uint8_t mask, uint8_t val, uint8_t *read, bool last)
|
||||||
return -EXIT_FAILURE;
|
return -EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP,
|
do {
|
||||||
read, 1, &actual_length, 1000) < 0) {
|
if (libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP,
|
||||||
cerr << "sendBitBang: usb bulk write failed 4" << endl;
|
read, 1, &actual_length, 1000) < 0) {
|
||||||
return -EXIT_FAILURE;
|
cerr << "sendBitBang: usb bulk read failed 4" << endl;
|
||||||
}
|
return -EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
} while (actual_length == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last) {
|
if (last) {
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,12 @@ class DirtyJtag : public JtagInterface {
|
||||||
bool _verbose;
|
bool _verbose;
|
||||||
|
|
||||||
int sendBitBang(uint8_t mask, uint8_t val, uint8_t *read, bool last);
|
int sendBitBang(uint8_t mask, uint8_t val, uint8_t *read, bool last);
|
||||||
|
void getVersion();
|
||||||
|
|
||||||
libusb_device_handle *dev_handle;
|
libusb_device_handle *dev_handle;
|
||||||
libusb_context *usb_ctx;
|
libusb_context *usb_ctx;
|
||||||
uint8_t _tdi;
|
uint8_t _tdi;
|
||||||
uint8_t _tms;
|
uint8_t _tms;
|
||||||
|
uint8_t _version;
|
||||||
};
|
};
|
||||||
#endif // SRC_DIRTYJTAG_HPP_
|
#endif // SRC_DIRTYJTAG_HPP_
|
||||||
|
|
|
||||||
|
|
@ -107,8 +107,12 @@ int FtdiJtagBitBang::setBitmode(uint8_t mode)
|
||||||
_bitmode = mode;
|
_bitmode = mode;
|
||||||
|
|
||||||
int ret = ftdi_set_bitmode(_ftdi, _tck_pin | _tms_pin | _tdi_pin, _bitmode);
|
int ret = ftdi_set_bitmode(_ftdi, _tck_pin | _tms_pin | _tdi_pin, _bitmode);
|
||||||
|
#if (FTDI_VERSION < 105)
|
||||||
ftdi_usb_purge_rx_buffer(_ftdi);
|
ftdi_usb_purge_rx_buffer(_ftdi);
|
||||||
ftdi_usb_purge_tx_buffer(_ftdi);
|
ftdi_usb_purge_tx_buffer(_ftdi);
|
||||||
|
#else
|
||||||
|
ftdi_tcioflush(_ftdi);
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue