Support for new DirtyJtag2 protocol. Merged with head

This commit is contained in:
phdussud 2021-02-26 10:01:15 -08:00
parent 43caa612ca
commit 9ee8e84fba
3 changed files with 118 additions and 33 deletions

View File

@ -23,17 +23,33 @@
#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"
using namespace std; using namespace std;
//#define DIRTY_JTAG_TEENSY_4
#ifdef DIRTY_JTAG_TEENSY_4
#define DIRTYJTAG_VID 0x16C0
#define DIRTYJTAG_PID 0x1485
#define DIRTYJTAG_INTF 0
#define DIRTYJTAG_WRITE_EP 0x2
#define DIRTYJTAG_READ_EP 0x82
#else
#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
#endif
enum dirtyJtagCmd { enum dirtyJtagCmd {
CMD_STOP = 0x00, CMD_STOP = 0x00,
@ -45,6 +61,11 @@ enum dirtyJtagCmd {
CMD_CLK = 0x06 CMD_CLK = 0x06
}; };
enum CommandModifier {
EXTEND_LENGTH = 0x40,
NO_READ = 0x80
};
enum dirtyJtagSig { enum dirtyJtagSig {
SIG_TCK = (1 << 1), SIG_TCK = (1 << 1),
SIG_TDI = (1 << 2), SIG_TDI = (1 << 2),
@ -71,14 +92,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 +117,50 @@ 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 +202,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 +228,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,32 +237,52 @@ 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 || (_version <= 1)) ? 0 : NO_READ);
tx_buf[0] = CMD_XFER; uint16_t max_bit_transfer_length = (uint16_t[]){240, 496, 4000}[_version -1];
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;
size_t header_offset = 0;
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; tx_buf[1] = bit_to_send;
memset(tx_buf + 2, 0, 30); 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 " << actual_length << endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
//cerr << actual_length << ", " << bit_to_send << endl;
if (rx || (_version <= 1)) {
int transfer_length = (bit_to_send > 255) ? byte_to_send :32;
do {
ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP, ret = libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP,
rx_buf, 32, &actual_length, 1000); rx_buf, transfer_length, &actual_length, 1000);
if (ret < 0) { if (ret < 0) {
cerr << "writeTDI: read: usb bulk write failed " << ret << endl; cerr << "writeTDI: read: usb bulk read failed " << ret << endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} while (actual_length == 0);
assert((size_t)actual_length >= byte_to_send);
}
if (rx) { if (rx) {
for (int i = 0; i < bit_to_send; i++) for (int i = 0; i < bit_to_send; i++)
@ -223,7 +303,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;
} }
@ -235,6 +315,7 @@ int DirtyJtag::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
} }
} }
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@ -264,11 +345,13 @@ int DirtyJtag::sendBitBang(uint8_t mask, uint8_t val, uint8_t *read, bool last)
return -EXIT_FAILURE; return -EXIT_FAILURE;
} }
do {
if (libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP, if (libusb_bulk_transfer(dev_handle, DIRTYJTAG_READ_EP,
read, 1, &actual_length, 1000) < 0) { read, 1, &actual_length, 1000) < 0) {
cerr << "sendBitBang: usb bulk write failed 4" << endl; cerr << "sendBitBang: usb bulk read failed 4" << endl;
return -EXIT_FAILURE; return -EXIT_FAILURE;
} }
} while (actual_length == 0);
} }
if (last) { if (last) {

View File

@ -58,10 +58,13 @@ 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_

View File

@ -107,8 +107,7 @@ 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);
ftdi_usb_purge_rx_buffer(_ftdi); ftdi_tcioflush(_ftdi);
ftdi_usb_purge_tx_buffer(_ftdi);
return ret; return ret;
} }