Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
23cbdbf0eThis file is pinned to the selected release. Download the original to open it in your design tool.
// SPDX-License-Identifier: Apache-2.0
/*
* 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>
#include "display.hpp"
#include "ch552_jtag.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
CH552_jtag::CH552_jtag(const cable_t &cable,
const string &dev, const string &serial, uint32_t clkHZ,
int8_t verbose):
FTDIpp_MPSSE(cable, dev, serial, clkHZ, verbose), _to_read(0)
{
init_internal(cable.config);
}
CH552_jtag::~CH552_jtag()
{
int read;
/* Before shutdown, we must wait until everything is shifted out
* Do this by temporary enabling loopback mode, write something
* and wait until we can read it back
*/
static unsigned char tbuf[16] = { SET_BITS_LOW, 0xff, 0x00,
SET_BITS_HIGH, 0xff, 0x00,
LOOPBACK_START,
static_cast<unsigned char>(MPSSE_DO_READ |
MPSSE_DO_WRITE | MPSSE_WRITE_NEG | MPSSE_LSB),
0x04, 0x00,
0xaa, 0x55, 0x00, 0xff, 0xaa,
LOOPBACK_END
};
mpsse_store(tbuf, 16);
read = mpsse_read(tbuf, 5);
if (read != 5)
fprintf(stderr,
"Loopback failed, expect problems on later runs %d\n", read);
}
void CH552_jtag::init_internal(const mpsse_bit_config &cable)
{
display("iProduct : %s\n", _iproduct);
display("%x\n", cable.bit_low_val);
display("%x\n", cable.bit_low_dir);
display("%x\n", cable.bit_high_val);
display("%x\n", cable.bit_high_dir);
init(5, 0xfb, BITMODE_MPSSE);
ftdi_set_event_char(_ftdi, 0, 0);
ftdi_set_error_char(_ftdi, 0, 0);
ftdi_set_latency_timer(_ftdi, 5);
#if (FTDI_VERSION < 105)
ftdi_usb_purge_rx_buffer(_ftdi);
ftdi_usb_purge_tx_buffer(_ftdi);
#else
ftdi_tciflush(_ftdi);
ftdi_tcoflush(_ftdi);
#endif
}
int CH552_jtag::setClkFreq(uint32_t clkHZ) {
int ret = FTDIpp_MPSSE::setClkFreq(clkHZ);
return ret;
}
int CH552_jtag::writeTMS(const uint8_t *tms, uint32_t len, bool flush_buffer,
__attribute__((unused)) const uint8_t tdi)
{
(void) flush_buffer;
display("%s %d %d\n", __func__, len, (len/8)+1);
if (len == 0)
return 0;
uint32_t xfer = len;
uint32_t iter = (_buffer_size -8) / 4;
iter = (_buffer_size / 3);
uint32_t offset = 0, pos = 0;
flush_buffer = true;
uint8_t buf[3]= {static_cast<unsigned char>(MPSSE_WRITE_TMS | MPSSE_LSB |
MPSSE_BITMODE | MPSSE_WRITE_NEG|
MPSSE_DO_READ),
0, 0};
while (xfer > 0) {
int bit_to_send = (xfer > 6) ? 6 : xfer;
buf[1] = bit_to_send-1;
buf[2] = 0x80;
for (int i = 0; i < bit_to_send; i++, offset++) {
buf[2] |=
(((tms[offset >> 3] & (1 << (offset & 0x07))) ? 1 : 0) << i);
}
pos+=3;
_to_read++;
mpsse_store(buf, 3);
if (pos >= iter) {
uint8_t tmp[_to_read];
pos = 0;
if (-1 == mpsse_read(tmp, _to_read))
printError("writeTMS: Fail to read/write");
_to_read = 0;
}
xfer -= bit_to_send;
}
if (flush_buffer) {
if (_to_read > 0) {
uint8_t tmp[_to_read];
if (mpsse_read(tmp, _to_read) == -1)
printError("writeTMS: fail to flush");
_to_read = 0;
}
if (_num > 0)
if (mpsse_write() == -1)
printError("writeTMS: fail to flush in write mode");
}
return len;
}
int CH552_jtag::toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len)
{
(void) tdi;
int byteLen = (clk_len+7)/8;
uint8_t buf_tms[byteLen];
memset(buf_tms, (tms) ? 0xff : 0x00, byteLen);
return writeTMS(buf_tms, clk_len, false);
}
int CH552_jtag::flush()
{
int ret;
if (_to_read == 0) {
ret = mpsse_write();
if (ret == -1)
printError("flush: fails to write");
} else {
uint8_t tmp[_to_read];
ret = mpsse_read(tmp, _to_read);
if (ret == -1)
printError("flush: fails to read/write");
_to_read = 0;
}
return ret;
}
int CH552_jtag::writeTDI(const uint8_t *tdi, uint8_t *tdo, uint32_t len, bool last)
{
bool rd_mode = (tdo) ? true : false;
/* 3 possible case :
* - n * 8bits to send -> use byte command
* - less than 8bits -> use bit command
* - last bit to send -> sent in conjunction with TMS
*/
int tx_buff_size = mpsse_get_buffer_size();
int real_len = (last) ? len - 1 : len; // if its a buffer in a big send send len
// else suppress last bit -> with TMS
int nb_byte = real_len >> 3; // number of byte to send
int nb_bit = (real_len & 0x07); // residual bits
int xfer = tx_buff_size - 7; // 2 byte for opcode and size 2 time
unsigned char *rx_ptr = (unsigned char *)tdo;
unsigned char *tx_ptr = (unsigned char *)tdi;
unsigned char tx_buf[3] = {(unsigned char)(MPSSE_LSB |
((tdi) ? (MPSSE_DO_WRITE | MPSSE_WRITE_NEG) : 0) |
((rd_mode) ? (MPSSE_DO_READ) : 0)),
static_cast<unsigned char>((xfer - 1) & 0xff), // low
static_cast<unsigned char>((((xfer - 1) >> 8) & 0xff))}; // high
unsigned char def_cmd = tx_buf[0];
unsigned char rd_cmd = def_cmd | (MPSSE_DO_READ);
/* read (and write) 1Byte */
uint8_t oneshot_buf[3] = {rd_cmd, 0, 0};
if (_to_read != 0) {
uint8_t tmp_[_to_read];
if (mpsse_read(tmp_, _to_read) == -1)
printError("writeTDI: fails to flush read");
_to_read = 0;
}
display("%s len : %d %d %d %d\n", __func__, len, real_len, nb_byte,
nb_bit);
if (_num != 0 && ((nb_byte + _num + 3) > _buffer_size))
if (mpsse_write() == -1)
printError("writeTDI: fails to flush write");
if ((nb_byte * 8) + nb_bit != real_len) {
printf("pas cool\n");
throw std::exception();
}
/* first case: 1 full byte (and maybe up to 7bit) to send
* direct write (and read)
*/
if (nb_byte == 1) {
uint8_t tmp_;
mpsse_store(oneshot_buf, 3);
if (tdi) {
mpsse_store(tx_ptr, 1);
tx_ptr++;
}
if (mpsse_read(&tmp_, 1) == -1)
printError("writeTDI: fails to read/write with nb_byte == 1");
if (rd_mode) {
*rx_ptr = tmp_;
rx_ptr++;
}
nb_byte--;
}
while (nb_byte != 0) {
uint8_t tmp_;
int xfer_len = (nb_byte > xfer) ? xfer : nb_byte;
if (!rd_mode) {
xfer_len--;
}
if (xfer_len != 0) {
tx_buf[0] = def_cmd;
tx_buf[1] = (((xfer_len - 1) ) & 0xff); // low
tx_buf[2] = (((xfer_len - 1) >> 8) & 0xff); // high
mpsse_store(tx_buf, 3);
if (tdi) {
mpsse_store(tx_ptr, xfer_len);
tx_ptr += xfer_len;
}
if (rd_mode) {
if (mpsse_read(rx_ptr, xfer_len) == -1)
printError("writeTDI: fails to read with nb_byte > 1");
rx_ptr += xfer_len;
} else {
mpsse_store(oneshot_buf, 3);
if (tdi) {
mpsse_store(tx_ptr, 1);
tx_ptr++;
}
if (mpsse_read(&tmp_, 1) == -1)
printError("writeTDI: fails to read/write with nb_byte > 1");
}
} else {
tx_buf[0] = rd_cmd;
tx_buf[1] = 0;
tx_buf[2] = 0;
mpsse_store(tx_buf, 3);
if (tdi) {
mpsse_store(tx_ptr, 1);
tx_ptr++;
}
if (mpsse_read(&tmp_, 1) == -1)
printError("writeTDI: fails to read/write with nb_byte == 0");
if (rd_mode) {
*rx_ptr = tmp_;
rx_ptr++;
}
}
if (!rd_mode)
xfer_len++;
nb_byte -= xfer_len;
}
unsigned char last_bit = (tdi) ? *tx_ptr : 0;
/* next: serie of bit to send: unconditionally write AND read
*/
if (nb_bit != 0) {
display("%s read/write %d bit\n", __func__, nb_bit);
tx_buf[0] = rd_cmd | MPSSE_BITMODE;
tx_buf[1] = nb_bit - 1;
mpsse_store(tx_buf, 2);
if (tdi) {
display("%s last_bit %x size %d\n", __func__, last_bit, nb_bit-1);
mpsse_store(last_bit);
}
uint8_t tmp_;
if (mpsse_read(&tmp_, 1) == -1)
printError("writeTDI: fails to read/write serie of bits");
if (rd_mode) {
*rx_ptr = tmp_;
/* realign we have read nb_bit
* since LSB add bit by the left and shift
* we need to complete shift
*/
*rx_ptr >>= (8 - nb_bit);
display("%s %x\n", __func__, *rx_ptr);
}
}
/* display : must be dropped */
if (_verbose && tdo) {
display("\n");
for (int i = (len / 8) - 1; i >= 0; i--)
display("%x ", (unsigned char)tdo[i]);
display("\n");
}
if (last == 1) {
last_bit = (tdi)? (*tx_ptr & (1 << nb_bit)) : 0;
display("%s move to EXIT1_xx and send last bit %x\n", __func__, (last_bit?0x81:0x01));
/* write the last bit in conjunction with TMS */
tx_buf[0] = MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG |
(MPSSE_DO_READ);
tx_buf[1] = 0x0; // send 1bit
tx_buf[2] = ((last_bit) ? 0x81 : 0x01); // we know in TMS tdi is bit 7
// and to move to EXIT_XR TMS = 1
mpsse_store(tx_buf, 3);
uint8_t c;
if (mpsse_read(&c, 1) == -1)
printError("writeTDI: fails to read/write last transaction");
if (rd_mode) {
/* in this case for 1 one it's always bit 7 */
*rx_ptr |= ((c & 0x80) << (7 - nb_bit));
}
}
return 0;
}