2021-06-26 15:24:07 +02:00
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
2020-03-07 11:43:18 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2020 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <libusb.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <string>
|
2020-10-29 08:15:32 +01:00
|
|
|
#include <stdexcept>
|
2020-03-07 11:43:18 +01:00
|
|
|
|
2021-02-05 06:28:19 +01:00
|
|
|
#include "display.hpp"
|
2020-03-07 11:43:18 +01:00
|
|
|
#include "ftdiJtagBitbang.hpp"
|
|
|
|
|
#include "ftdipp_mpsse.hpp"
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
#define DEBUG 0
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
#define display(...) \
|
|
|
|
|
do { \
|
|
|
|
|
if (_verbose) fprintf(stdout, __VA_ARGS__); \
|
|
|
|
|
}while(0)
|
|
|
|
|
#else
|
|
|
|
|
#define display(...) do {}while(0)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
FtdiJtagBitBang::FtdiJtagBitBang(const FTDIpp_MPSSE::mpsse_bit_config &cable,
|
2020-10-05 14:49:42 +02:00
|
|
|
const jtag_pins_conf_t *pin_conf, string dev, const std::string &serial,
|
|
|
|
|
uint32_t clkHZ, bool verbose):
|
2020-10-29 07:39:47 +01:00
|
|
|
FTDIpp_MPSSE(cable, dev, serial, clkHZ, verbose), _bitmode(0),
|
2020-10-29 08:15:32 +01:00
|
|
|
_curr_tms(0), _rx_size(0)
|
2020-03-07 11:43:18 +01:00
|
|
|
{
|
2020-10-29 08:15:32 +01:00
|
|
|
unsigned char *ptr;
|
|
|
|
|
|
2020-10-31 08:40:18 +01:00
|
|
|
_tck_pin = pin_conf->tck_pin;
|
|
|
|
|
_tms_pin = pin_conf->tms_pin;
|
|
|
|
|
_tdi_pin = pin_conf->tdi_pin;
|
|
|
|
|
_tdo_pin = pin_conf->tdo_pin;
|
2020-03-07 11:43:18 +01:00
|
|
|
|
2020-10-29 08:15:32 +01:00
|
|
|
/* store FTDI TX Fifo size */
|
|
|
|
|
if (_pid == 0x6001) // FT232R
|
|
|
|
|
_rx_size = 256;
|
|
|
|
|
else if (_pid == 0x6015) // FT231X
|
|
|
|
|
_rx_size = 512;
|
|
|
|
|
else
|
|
|
|
|
_rx_size = _buffer_size;
|
|
|
|
|
|
|
|
|
|
/* RX Fifo size (rx: USB -> FTDI)
|
|
|
|
|
* is 128 or 256 Byte and MaxPacketSize ~= 64Byte
|
|
|
|
|
* but we let subsystem (libftdi, libusb, linux)
|
|
|
|
|
* sending with the correct size -> this reduce hierarchical calls
|
|
|
|
|
*/
|
|
|
|
|
_buffer_size = 4096;
|
|
|
|
|
|
|
|
|
|
/* _buffer_size has changed -> resize buffer */
|
|
|
|
|
ptr = (unsigned char *)realloc(_buffer, sizeof(char) * _buffer_size);
|
|
|
|
|
if (!ptr)
|
|
|
|
|
throw std::runtime_error("_buffer realloc failed\n");
|
|
|
|
|
_buffer = ptr;
|
2020-05-31 15:57:21 +02:00
|
|
|
|
2021-06-12 08:40:40 +02:00
|
|
|
setClkFreq(clkHZ);
|
2020-03-07 11:43:18 +01:00
|
|
|
|
2020-10-27 20:27:02 +01:00
|
|
|
init(1, _tck_pin | _tms_pin | _tdi_pin, BITMODE_BITBANG);
|
2020-03-07 11:43:18 +01:00
|
|
|
setBitmode(BITMODE_BITBANG);
|
2020-05-31 15:57:21 +02:00
|
|
|
}
|
2020-03-11 19:25:35 +01:00
|
|
|
|
2020-10-29 07:39:47 +01:00
|
|
|
FtdiJtagBitBang::~FtdiJtagBitBang()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-31 15:57:21 +02:00
|
|
|
int FtdiJtagBitBang::setClkFreq(uint32_t clkHZ)
|
|
|
|
|
{
|
2021-02-05 06:28:19 +01:00
|
|
|
uint32_t user_clk = clkHZ;
|
|
|
|
|
if (clkHZ > 3000000) {
|
|
|
|
|
printWarn("Jtag probe limited to 3MHz");
|
2020-05-31 15:57:21 +02:00
|
|
|
clkHZ = 3000000;
|
2021-02-05 06:28:19 +01:00
|
|
|
}
|
|
|
|
|
printInfo("Jtag frequency : requested " + std::to_string(user_clk) +
|
|
|
|
|
"Hz -> real " + std::to_string(clkHZ) + "Hz");
|
2020-05-31 15:57:21 +02:00
|
|
|
int ret = ftdi_set_baudrate(_ftdi, clkHZ);
|
|
|
|
|
printf("ret %d\n", ret);
|
|
|
|
|
return ret;
|
2020-03-07 11:43:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int FtdiJtagBitBang::setBitmode(uint8_t mode)
|
|
|
|
|
{
|
|
|
|
|
if (_bitmode == mode)
|
|
|
|
|
return 0;
|
|
|
|
|
_bitmode = mode;
|
2020-03-11 19:26:38 +01:00
|
|
|
|
|
|
|
|
int ret = ftdi_set_bitmode(_ftdi, _tck_pin | _tms_pin | _tdi_pin, _bitmode);
|
2021-02-27 22:12:21 +01:00
|
|
|
#if (FTDI_VERSION < 105)
|
|
|
|
|
ftdi_usb_purge_rx_buffer(_ftdi);
|
|
|
|
|
ftdi_usb_purge_tx_buffer(_ftdi);
|
|
|
|
|
#else
|
2021-02-26 19:01:15 +01:00
|
|
|
ftdi_tcioflush(_ftdi);
|
2021-02-27 22:12:21 +01:00
|
|
|
#endif
|
2020-03-11 19:26:38 +01:00
|
|
|
return ret;
|
2020-03-07 11:43:18 +01:00
|
|
|
}
|
|
|
|
|
|
2021-11-06 10:31:00 +01:00
|
|
|
int FtdiJtagBitBang::writeTMS(uint8_t *tms, uint32_t len, bool flush_buffer)
|
2020-03-07 11:43:18 +01:00
|
|
|
{
|
2020-05-31 15:57:21 +02:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
/* nothing to send
|
|
|
|
|
* but maybe need to flush internal buffer
|
|
|
|
|
*/
|
|
|
|
|
if (len == 0) {
|
|
|
|
|
if (flush_buffer) {
|
|
|
|
|
ret = flush();
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2020-03-07 11:43:18 +01:00
|
|
|
return 0;
|
2020-05-31 15:57:21 +02:00
|
|
|
}
|
2020-03-07 11:43:18 +01:00
|
|
|
|
2020-05-31 15:57:21 +02:00
|
|
|
/* check for at least one bit space in buffer */
|
2020-10-29 07:39:47 +01:00
|
|
|
if (_num+2 > _buffer_size) {
|
2020-05-31 15:57:21 +02:00
|
|
|
ret = flush();
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2020-03-07 11:43:18 +01:00
|
|
|
|
2020-05-31 15:57:21 +02:00
|
|
|
/* fill buffer to reduce USB transaction */
|
2021-11-06 10:31:00 +01:00
|
|
|
for (uint32_t i = 0; i < len; i++) {
|
2020-05-31 15:57:21 +02:00
|
|
|
_curr_tms = ((tms[i >> 3] & (1 << (i & 0x07)))? _tms_pin : 0);
|
|
|
|
|
uint8_t val = _tdi_pin | _curr_tms;
|
2020-10-29 07:39:47 +01:00
|
|
|
_buffer[_num++] = val;
|
|
|
|
|
_buffer[_num++] = val | _tck_pin;
|
2020-05-31 15:57:21 +02:00
|
|
|
|
2020-10-29 07:39:47 +01:00
|
|
|
if (_num + 2 > _buffer_size) {
|
2020-05-31 15:57:21 +02:00
|
|
|
ret = write(NULL, 0);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
2020-03-07 11:43:18 +01:00
|
|
|
}
|
2020-05-31 15:57:21 +02:00
|
|
|
}
|
2020-03-07 11:43:18 +01:00
|
|
|
|
2020-05-31 15:57:21 +02:00
|
|
|
/* security check: try to flush buffer */
|
|
|
|
|
if (flush_buffer) {
|
|
|
|
|
ret = write(NULL, 0);
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
2020-03-07 11:43:18 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-31 15:57:21 +02:00
|
|
|
return len;
|
2020-03-07 11:43:18 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-31 15:57:21 +02:00
|
|
|
int FtdiJtagBitBang::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
|
2020-03-07 11:43:18 +01:00
|
|
|
{
|
2020-05-31 15:57:21 +02:00
|
|
|
uint32_t iter;
|
2020-10-29 08:15:32 +01:00
|
|
|
uint32_t xfer_size = (rx) ? _rx_size : _buffer_size;
|
|
|
|
|
if (len * 2 + 1 < xfer_size) {
|
2020-05-31 15:57:21 +02:00
|
|
|
iter = len;
|
|
|
|
|
} else {
|
2020-10-29 08:15:32 +01:00
|
|
|
iter = xfer_size >> 1; // two tx / bit
|
2020-05-31 15:57:21 +02:00
|
|
|
iter = (iter / 8) * 8;
|
2020-03-07 11:43:18 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-31 15:57:21 +02:00
|
|
|
uint8_t *rx_ptr = rx;
|
|
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
if (rx)
|
2020-07-25 04:55:41 +02:00
|
|
|
memset(rx, 0, len/8);
|
2020-05-31 15:57:21 +02:00
|
|
|
|
2020-11-26 09:26:08 +01:00
|
|
|
/* quick fix: use an empty buffer */
|
|
|
|
|
if (_num != 0)
|
|
|
|
|
flush();
|
|
|
|
|
|
2020-05-31 15:57:21 +02:00
|
|
|
for (uint32_t i = 0, pos = 0; i < len; i++) {
|
|
|
|
|
/* keep tms or
|
|
|
|
|
* set tms high if it's last bit and end true */
|
|
|
|
|
if (end && (i == len -1))
|
|
|
|
|
_curr_tms = _tms_pin;
|
|
|
|
|
uint8_t val = _curr_tms;
|
|
|
|
|
|
|
|
|
|
if (tx)
|
|
|
|
|
val |= ((tx[i >> 3] & (1 << (i & 0x07)))? _tdi_pin : 0);
|
2020-10-29 07:39:47 +01:00
|
|
|
_buffer[_num ] = val;
|
|
|
|
|
_buffer[_num + 1] = val | _tck_pin;
|
2020-05-31 15:57:21 +02:00
|
|
|
|
2020-10-29 07:39:47 +01:00
|
|
|
_num += 2;
|
2020-05-31 15:57:21 +02:00
|
|
|
|
|
|
|
|
pos++;
|
|
|
|
|
/* flush buffer */
|
|
|
|
|
if (pos == iter) {
|
|
|
|
|
pos = 0;
|
|
|
|
|
write((rx) ? rx_ptr : NULL, iter);
|
|
|
|
|
if (rx)
|
|
|
|
|
rx_ptr += (iter/8);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* security check: try to flush buffer */
|
2020-10-29 07:39:47 +01:00
|
|
|
if (_num != 0) {
|
|
|
|
|
write((rx && _num > 1) ? rx_ptr : NULL, _num / 2);
|
2020-03-07 11:43:18 +01:00
|
|
|
}
|
2020-05-31 15:57:21 +02:00
|
|
|
|
|
|
|
|
return len;
|
2020-03-07 11:43:18 +01:00
|
|
|
}
|
|
|
|
|
|
2020-06-14 15:05:47 +02:00
|
|
|
int FtdiJtagBitBang::toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len)
|
2020-03-07 11:43:18 +01:00
|
|
|
{
|
2020-06-14 15:05:47 +02:00
|
|
|
int xfer_len = clk_len;
|
|
|
|
|
|
|
|
|
|
int val = ((tms) ? _tms_pin : 0) | ((tdi) ? _tdi_pin : 0);
|
|
|
|
|
while (xfer_len > 0) {
|
2020-10-29 07:39:47 +01:00
|
|
|
if (_num + 2 > _buffer_size)
|
2020-06-14 15:05:47 +02:00
|
|
|
if (write(NULL, 0) < 0)
|
|
|
|
|
return -EXIT_FAILURE;
|
2020-10-29 07:39:47 +01:00
|
|
|
_buffer[_num++] = val | _tck_pin;
|
|
|
|
|
_buffer[_num++] = val;
|
2020-06-14 15:05:47 +02:00
|
|
|
|
|
|
|
|
xfer_len--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* flush */
|
|
|
|
|
write(NULL, 0);
|
|
|
|
|
|
|
|
|
|
return clk_len;
|
2020-03-07 11:43:18 +01:00
|
|
|
}
|
|
|
|
|
|
2020-05-31 15:57:21 +02:00
|
|
|
int FtdiJtagBitBang::flush()
|
|
|
|
|
{
|
|
|
|
|
return write(NULL, 0);
|
|
|
|
|
}
|
2020-03-07 11:43:18 +01:00
|
|
|
|
2020-05-19 08:32:43 +02:00
|
|
|
int FtdiJtagBitBang::write(uint8_t *tdo, int nb_bit)
|
2020-03-07 11:43:18 +01:00
|
|
|
{
|
|
|
|
|
int ret = 0;
|
2020-10-29 07:39:47 +01:00
|
|
|
if (_num == 0)
|
2020-03-07 11:43:18 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
setBitmode((tdo) ? BITMODE_SYNCBB : BITMODE_BITBANG);
|
|
|
|
|
|
2020-10-29 07:39:47 +01:00
|
|
|
ret = ftdi_write_data(_ftdi, _buffer, _num);
|
|
|
|
|
if (ret != _num) {
|
2020-03-07 11:43:18 +01:00
|
|
|
printf("problem %d written\n", ret);
|
2020-05-31 15:57:21 +02:00
|
|
|
return ret;
|
|
|
|
|
}
|
2020-03-07 11:43:18 +01:00
|
|
|
|
|
|
|
|
if (tdo) {
|
2020-10-29 07:39:47 +01:00
|
|
|
ret = ftdi_read_data(_ftdi, _buffer, _num);
|
|
|
|
|
if (ret != _num) {
|
2020-03-07 11:43:18 +01:00
|
|
|
printf("problem %d read\n", ret);
|
2020-05-31 15:57:21 +02:00
|
|
|
return ret;
|
|
|
|
|
}
|
2020-03-07 11:43:18 +01:00
|
|
|
/* need to reconstruct received word
|
|
|
|
|
* even bit are discarded since JTAG read in rising edge
|
|
|
|
|
* since jtag is LSB first we need to shift right content by 1
|
|
|
|
|
* and add 0x80 (1 << 7) or 0
|
2020-05-19 08:32:43 +02:00
|
|
|
* the buffer may contains some tms bit, so start with i
|
|
|
|
|
* equal to fill exactly nb_bit bits
|
2020-03-07 11:43:18 +01:00
|
|
|
* */
|
2020-10-29 07:39:47 +01:00
|
|
|
for (int i = (_num-(nb_bit *2) + 1), offset=0; i < _num; i+=2, offset++) {
|
|
|
|
|
tdo[offset >> 3] = (((_buffer[i] & _tdo_pin) ? 0x80 : 0x00) |
|
2020-03-07 11:43:18 +01:00
|
|
|
(tdo[offset >> 3] >> 1));
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-10-29 07:39:47 +01:00
|
|
|
_num = 0;
|
2020-03-07 11:43:18 +01:00
|
|
|
return ret;
|
|
|
|
|
}
|