diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fc312f..e5386fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,9 @@ set(OPENFPGALOADER_SOURCE src/svf_jtag.cpp src/jedParser.cpp src/display.cpp - src/ftdijtag.cpp + src/jtag.cpp + src/ftdiJtagBitbang.cpp + src/ftdiJtagMPSSE.cpp src/configBitstreamParser.cpp src/ftdipp_mpsse.cpp src/xilinx.cpp @@ -46,7 +48,10 @@ set(OPENFPGALOADER_HEADERS src/altera.hpp src/progressBar.hpp src/bitparser.hpp - src/ftdijtag.hpp + src/ftdiJtagBitbang.hpp + src/ftdiJtagMPSSE.hpp + src/jtag.hpp + src/jtagInterface.hpp src/fsparser.hpp src/part.hpp src/board.hpp diff --git a/src/altera.cpp b/src/altera.cpp index 1cea967..438c54d 100644 --- a/src/altera.cpp +++ b/src/altera.cpp @@ -1,5 +1,6 @@ +#include #include "altera.hpp" -#include "ftdijtag.hpp" +#include "jtag.hpp" #include "device.hpp" #include "epcq.hpp" @@ -8,7 +9,7 @@ // DATA_DIR is defined at compile time. #define BIT_FOR_FLASH (DATA_DIR "/openFPGALoader/test_sfl.svf") -Altera::Altera(FtdiJtag *jtag, std::string filename, bool verbose): +Altera::Altera(Jtag *jtag, std::string filename, bool verbose): Device(jtag, filename, verbose), _svf(_jtag, _verbose) { if (_filename != "") { @@ -24,10 +25,10 @@ void Altera::reset() { /* PULSE_NCONFIG */ unsigned char tx_buff[2] = {0x01, 0x00}; - _jtag->set_state(FtdiJtag::TEST_LOGIC_RESET); + _jtag->set_state(Jtag::TEST_LOGIC_RESET); _jtag->shiftIR(tx_buff, NULL, IRLENGTH); _jtag->toggleClk(1); - _jtag->set_state(FtdiJtag::TEST_LOGIC_RESET); + _jtag->set_state(Jtag::TEST_LOGIC_RESET); } void Altera::program(unsigned int offset) @@ -45,7 +46,7 @@ void Altera::program(unsigned int offset) _svf.parse(_filename); } else if (_mode == Device::SPI_MODE) { /* GGM: TODO: fix this issue */ - EPCQ epcq(_jtag->vid(), _jtag->pid(), 2, 6000000); + EPCQ epcq(0x403, 0x6010/*_jtag->vid(), _jtag->pid()*/, 2, 6000000); _svf.parse(BIT_FOR_FLASH); epcq.program(offset, _filename, (_file_extension == "rpd")? true:false); reset(); @@ -53,11 +54,12 @@ void Altera::program(unsigned int offset) } int Altera::idCode() { - unsigned char tx_data = IDCODE; + unsigned char tx_data[4] = {IDCODE}; unsigned char rx_data[4]; _jtag->go_test_logic_reset(); - _jtag->shiftIR(&tx_data, NULL, IRLENGTH); - _jtag->shiftDR(NULL, rx_data, 32); + _jtag->shiftIR(tx_data, NULL, IRLENGTH); + bzero(tx_data, 4); + _jtag->shiftDR(tx_data, rx_data, 32); return ((rx_data[0] & 0x000000ff) | ((rx_data[1] << 8) & 0x0000ff00) | ((rx_data[2] << 16) & 0x00ff0000) | diff --git a/src/altera.hpp b/src/altera.hpp index 22127a8..0cfa913 100644 --- a/src/altera.hpp +++ b/src/altera.hpp @@ -3,12 +3,12 @@ #include "bitparser.hpp" #include "device.hpp" -#include "ftdijtag.hpp" +#include "jtag.hpp" #include "svf_jtag.hpp" class Altera: public Device { public: - Altera(FtdiJtag *jtag, std::string filename, bool verbose); + Altera(Jtag *jtag, std::string filename, bool verbose); ~Altera(); void program(unsigned int offset = 0); diff --git a/src/board.hpp b/src/board.hpp index 186d89c..492e93f 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -3,16 +3,51 @@ #include -static std::map board_list = { - {"arty", "digilent"}, - {"colorlight", ""}, - {"cyc1000", "ft2232"}, - {"de0nano", "usbblaster"}, - {"ecp5_evn", "ft2232"}, - {"machXO3SK", "ft2232"}, - {"littleBee", "ft2232"}, - {"spartanEdgeAccelBoard", ""}, - {"tangnano", "ft2232"} +#include "cable.hpp" + +/* AN_232R-01_Bit_Bang_Mode_Available_For_FT232R_and_Ft245R */ +enum { + FT232RL_TXD = 0, + FT232RL_RXD = 1, + FT232RL_RTS = 2, + FT232RL_CTS = 3, + FT232RL_DTR = 4, + FT232RL_DSR = 5, + FT232RL_DCD = 6, + FT232RL_RI = 7 +}; + +/*! + * \brief for bitbang mode this structure provide offset for each JTAG signals + */ +typedef struct { + uint8_t tms_pin; /*! TMS pin offset */ + uint8_t tck_pin; /*! TCK pin offset */ + uint8_t tdi_pin; /*! TDI pin offset */ + uint8_t tdo_pin; /*! TDO pin offset */ +} jtag_pins_conf_t; + +/*! + * \brief a board has a target cable and optionnally a pin configuration + * (bitbang mode) + */ +typedef struct { + std::string cable_name; /*! provide name of one entry in cable_list */ + jtag_pins_conf_t pins_config; /*! for bitbang, provide struct with pins offset */ +} target_cable_t; + +static std::map board_list = { + {"arty", {"digilent", {}}}, + {"colorlight", {"", {}}}, + {"cyc1000", {"ft2232", {}}}, + {"de0nano", {"usbblaster", {}}}, + {"ecp5_evn", {"ft2232", {}}}, + {"machXO3SK", {"ft2232", {}}}, + {"littleBee", {"ft2232", {}}}, + {"spartanEdgeAccelBoard", {"",{}}}, + {"tangnano", {"ft2232", {}}}, + {"ulx2s", {"ft232RL", {FT232RL_RI, FT232RL_DSR, FT232RL_CTS, FT232RL_DCD}}}, + {"ulx3s", {"ft231X", {FT232RL_DCD, FT232RL_DSR, FT232RL_RI, FT232RL_CTS}}} }; #endif diff --git a/src/cable.hpp b/src/cable.hpp index 11f96b4..4d16d4a 100644 --- a/src/cable.hpp +++ b/src/cable.hpp @@ -2,16 +2,32 @@ #define CABLE_HPP #include +#include #include "ftdipp_mpsse.hpp" -static std::map cable_list = { - {"digilent", {0x0403, 0x6010, 0xe8, 0xeb, 0x00, 0x60}}, - {"digilent_hs2", {0x0403, 0x6014, 0xe8, 0xeb, 0x00, 0x60}}, - {"digilent_hs3", {0x0403, 0x6014, 0x88, 0x8B, 0x20, 0x30}}, - {"ft232", {0x0403, 0x6014, 0x08, 0x0B, 0x08, 0x0B}}, - {"ft2232", {0x0403, 0x6010, 0x08, 0x0B, 0x08, 0x0B}}, - {"ft4232", {0x0403, 0x6011, 0x08, 0x0B, 0x08, 0x0B}}, +/*! + * \brief define type of communication + */ +enum { + MODE_FTDI_BITBANG = 0, /*! used with ft232RL/ft231x */ + MODE_FTDI_SERIAL = 1 /*! ft2232, ft232H */ +} communication_type_t; + +typedef struct { + int type; + FTDIpp_MPSSE::mpsse_bit_config config; +} cable_t; + +static std::map cable_list = { + {"digilent", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_A, 0xe8, 0xeb, 0x00, 0x60}}}, + {"digilent_hs2", {MODE_FTDI_SERIAL, {0x0403, 0x6014, INTERFACE_A, 0xe8, 0xeb, 0x00, 0x60}}}, + {"digilent_hs3", {MODE_FTDI_SERIAL, {0x0403, 0x6014, INTERFACE_A, 0x88, 0x8B, 0x20, 0x30}}}, + {"ft2232", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_A, 0x08, 0x0B, 0x08, 0x0B}}}, + {"ft231X", {MODE_FTDI_BITBANG, {0x0403, 0x6015, INTERFACE_A, 0x00, 0x00, 0x00, 0x00}}}, + {"ft232", {MODE_FTDI_SERIAL, {0x0403, 0x6014, INTERFACE_A, 0x08, 0x0B, 0x08, 0x0B}}}, + {"ft232RL", {MODE_FTDI_BITBANG, {0x0403, 0x6001, INTERFACE_A, 0x08, 0x0B, 0x08, 0x0B}}}, + {"ft4232", {MODE_FTDI_SERIAL, {0x0403, 0x6011, INTERFACE_A, 0x08, 0x0B, 0x08, 0x0B}}} }; #endif diff --git a/src/device.cpp b/src/device.cpp index 709b1f4..599c2d8 100644 --- a/src/device.cpp +++ b/src/device.cpp @@ -5,7 +5,7 @@ using namespace std; -Device::Device(FtdiJtag *jtag, string filename, bool verbose): +Device::Device(Jtag *jtag, string filename, bool verbose): _filename(filename), _file_extension(filename.substr(filename.find_last_of(".") +1)), _mode(NONE_MODE), _verbose(verbose) diff --git a/src/device.hpp b/src/device.hpp index c425e03..b76b474 100644 --- a/src/device.hpp +++ b/src/device.hpp @@ -3,7 +3,7 @@ #include -#include "ftdijtag.hpp" +#include "jtag.hpp" /* GGM: TODO: program must have an optional * offset @@ -18,13 +18,13 @@ class Device { FLASH_MODE = 1, MEM_MODE = 2 }; - Device(FtdiJtag *jtag, std::string filename, bool verbose = false); + Device(Jtag *jtag, std::string filename, bool verbose = false); virtual ~Device(); virtual void program(unsigned int offset = 0) = 0; virtual int idCode() = 0; virtual void reset(); protected: - FtdiJtag *_jtag; + Jtag *_jtag; std::string _filename; std::string _file_extension; enum prog_mode _mode; diff --git a/src/ftdiJtagBitbang.cpp b/src/ftdiJtagBitbang.cpp new file mode 100644 index 0000000..03c55ef --- /dev/null +++ b/src/ftdiJtagBitbang.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2020 Gwenhael Goavec-Merou + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include +#include +#include + +#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, + const jtag_pins_conf_t *pin_conf, string dev, uint32_t clkHZ, bool verbose): + FTDIpp_MPSSE(cable, dev, clkHZ, verbose), _bitmode(0), _nb_bit(0) +{ + init_internal(cable, pin_conf); +} + +FtdiJtagBitBang::FtdiJtagBitBang(const FTDIpp_MPSSE::mpsse_bit_config &cable, + const jtag_pins_conf_t *pin_conf, uint32_t clkHZ, bool verbose): + FTDIpp_MPSSE(cable, clkHZ, verbose), + _bitmode(0), _nb_bit(0) +{ + init_internal(cable, pin_conf); +} + +FtdiJtagBitBang::~FtdiJtagBitBang() +{ + free(_in_buf); +} + +void FtdiJtagBitBang::init_internal(const FTDIpp_MPSSE::mpsse_bit_config &cable, + const jtag_pins_conf_t *pin_conf) +{ + _tck_pin = (1 << pin_conf->tck_pin); + _tms_pin = (1 << pin_conf->tms_pin); + _tdi_pin = (1 << pin_conf->tdi_pin); + _tdo_pin = (1 << pin_conf->tdo_pin); + + _buffer_size = 128; // TX Fifo size + + _in_buf = (unsigned char *)malloc(sizeof(unsigned char) * _buffer_size); + bzero(_in_buf, _buffer_size); + init(1, _tck_pin | _tms_pin | _tdi_pin, BITMODE_BITBANG, + (FTDIpp_MPSSE::mpsse_bit_config &)cable); + setBitmode(BITMODE_BITBANG); + +} + +int FtdiJtagBitBang::setBitmode(uint8_t mode) +{ + if (_bitmode == mode) + return 0; + _bitmode = mode; + + int ret = ftdi_set_bitmode(_ftdi, _tck_pin | _tms_pin | _tdi_pin, _bitmode); + ftdi_usb_purge_rx_buffer(_ftdi); + ftdi_usb_purge_tx_buffer(_ftdi); + return ret; +} + +/** + * store tms in + * internal buffer + */ +int FtdiJtagBitBang::storeTMS(uint8_t *tms, int nb_bit, uint8_t tdi, bool read) +{ + (void) read; + int xfer_len = nb_bit; + /* need to check for available space in buffer */ + if (nb_bit == 0) + return 0; + + while (xfer_len > 0) { + int xfer = xfer_len; + if ((_nb_bit + 2*xfer) > _buffer_size) + xfer = (_buffer_size - _nb_bit) >> 1; + + for (int i = 0; i < xfer; i++, _nb_bit += 2) { + _in_buf[_nb_bit] = ((tdi)?_tdi_pin:0) | + (((tms[i >> 3] >> (i & 0x7)) & 0x01)? _tms_pin:0); + _in_buf[_nb_bit + 1] = _in_buf[_nb_bit] | _tck_pin; + } + + xfer_len -= xfer; + if (xfer_len != 0) + write(NULL); + } + return nb_bit; +} + +int FtdiJtagBitBang::writeTMS(uint8_t *tdo, int len) +{ + (void) len; + return write(tdo); +} + +/** + * store tdi in + * internal buffer with tms + * size must be <= 8 + */ +int FtdiJtagBitBang::storeTDI(uint8_t tdi, int nb_bit, bool read) +{ + for (int i = 0; i < nb_bit; i++, _nb_bit += 2) { + _in_buf[_nb_bit] = + ((tdi & (1 << (i & 0x7)))?_tdi_pin:0); + _in_buf[_nb_bit + 1] = _in_buf[_nb_bit] | _tck_pin; + } + return nb_bit; +} + +/** + * store tdi in + * internal buffer + * since TDI is used in shiftDR and shiftIR, tms is always set to 0 + */ +int FtdiJtagBitBang::storeTDI(uint8_t *tdi, int nb_byte, bool read) +{ + /* need to check for available space in buffer */ + for (int i = 0; i < nb_byte * 8; i++, _nb_bit += 2) { + _in_buf[_nb_bit] = + ((tdi[i >> 3] & (1 << (i & 0x7)))?_tdi_pin:0); + _in_buf[_nb_bit + 1] = _in_buf[_nb_bit] | _tck_pin; + } + return nb_byte; +} + +int FtdiJtagBitBang::writeTDI(uint8_t *tdo, int nb_bit) +{ + (void) nb_bit; + return write(tdo); +} + + +int FtdiJtagBitBang::write(uint8_t *tdo) +{ + int ret = 0; + if (_nb_bit == 0) + return 0; + + setBitmode((tdo) ? BITMODE_SYNCBB : BITMODE_BITBANG); + + ret = ftdi_write_data(_ftdi, _in_buf, _nb_bit); + if (ret != _nb_bit) + printf("problem %d written\n", ret); + + if (tdo) { + ret = ftdi_read_data(_ftdi, _in_buf, _nb_bit); + if (ret != _nb_bit) + printf("problem %d read\n", ret); + /* 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 + * */ + for (int i = 1, offset=0; i < _nb_bit; i+=2, offset++) { + tdo[offset >> 3] = (((_in_buf[i] & _tdo_pin) ? 0x80 : 0x00) | + (tdo[offset >> 3] >> 1)); + } + } + _nb_bit = 0; + return ret; +} diff --git a/src/ftdiJtagBitbang.hpp b/src/ftdiJtagBitbang.hpp new file mode 100644 index 0000000..41ff9d2 --- /dev/null +++ b/src/ftdiJtagBitbang.hpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020 Gwenhael Goavec-Merou + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FTDIJTAGBITBANG_H +#define FTDIJTAGBITBANG_H +#include +#include +#include +#include + +#include "board.hpp" +#include "jtagInterface.hpp" +#include "ftdipp_mpsse.hpp" + +/*! + * \file FtdiJtagBitBang.hpp + * \class FtdiJtagBitBang + * \brief concrete class between jtag implementation and FTDI capable bitbang mode + * \author Gwenhael Goavec-Merou + */ + +class FtdiJtagBitBang : public JtagInterface, private FTDIpp_MPSSE { + public: + FtdiJtagBitBang(const FTDIpp_MPSSE::mpsse_bit_config &cable, + const jtag_pins_conf_t *pin_conf, std::string dev, + uint32_t clkHZ, bool verbose = false); + FtdiJtagBitBang(const FTDIpp_MPSSE::mpsse_bit_config &cable, + const jtag_pins_conf_t *pin_conf, uint32_t clkHZ, bool verbose); + virtual ~FtdiJtagBitBang(); + + int setClkFreq(uint32_t clkHZ) override { + return FTDIpp_MPSSE::setClkFreq(clkHZ); + } + int setClkFreq(uint32_t clkHZ, char use_divide_by_5) override { + return FTDIpp_MPSSE::setClkFreq(clkHZ, use_divide_by_5);} + + /* TMS */ + int storeTMS(uint8_t *tms, int _bit_len, uint8_t tdi = 1, + bool read = false) override; + int writeTMS(uint8_t *tdo, int len = 0) override; + + /* TDI */ + int storeTDI(uint8_t tdi, int nb_bit, bool read) override; + int storeTDI(uint8_t *tdi, int nb_byte, bool read) override; + int writeTDI(uint8_t *tdo, int nb_bit) override; + + /*! + * \brief return internal buffer size (in byte). + * \return _buffer_size divided by 2 (two byte for clk) and divided by 8 (one + * state == one byte) + */ + int get_buffer_size() override { return _buffer_size/8/2; } + + bool isFull() override { return _nb_bit == 8*get_buffer_size();} + + private: + void init_internal(const FTDIpp_MPSSE::mpsse_bit_config &cable, + const jtag_pins_conf_t *pin_conf); + int write(uint8_t *tdo); + int setBitmode(uint8_t mode); + uint8_t *_in_buf; + + uint8_t _bitmode; + uint8_t _tck_pin; /*!< tck pin: 1 << pin id */ + uint8_t _tms_pin; /*!< tms pin: 1 << pin id */ + uint8_t _tdo_pin; /*!< tdo pin: 1 << pin id */ + uint8_t _tdi_pin; /*!< tdi pin: 1 << pin id */ + int _nb_bit; +}; +#endif diff --git a/src/ftdiJtagMPSSE.cpp b/src/ftdiJtagMPSSE.cpp new file mode 100644 index 0000000..b2e0427 --- /dev/null +++ b/src/ftdiJtagMPSSE.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2020 Gwenhael Goavec-Merou + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include "ftdiJtagMPSSE.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 + +FtdiJtagMPSSE::FtdiJtagMPSSE(const FTDIpp_MPSSE::mpsse_bit_config &cable, + string dev, uint32_t clkHZ, bool verbose): + FTDIpp_MPSSE(cable, dev, clkHZ, verbose), _ch552WA(false) +{ + init_internal(cable); +} + +FtdiJtagMPSSE::FtdiJtagMPSSE(const FTDIpp_MPSSE::mpsse_bit_config &cable, + uint32_t clkHZ, bool verbose): + FTDIpp_MPSSE(cable, clkHZ, verbose), + _ch552WA(false) +{ + init_internal(cable); +} + +FtdiJtagMPSSE::~FtdiJtagMPSSE() +{ + 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, + 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); + + free(_in_buf); +} + +void FtdiJtagMPSSE::init_internal(const FTDIpp_MPSSE::mpsse_bit_config &cable) +{ + /* search for iProduct -> need to have + * ftdi->usb_dev (libusb_device_handler) -> libusb_device -> + * libusb_device_descriptor + */ + struct libusb_device * usb_dev = libusb_get_device(_ftdi->usb_dev); + struct libusb_device_descriptor usb_desc; + unsigned char iProduct[200]; + libusb_get_device_descriptor(usb_dev, &usb_desc); + libusb_get_string_descriptor_ascii(_ftdi->usb_dev, usb_desc.iProduct, + iProduct, 200); + + display("iProduct : %s\n", iProduct); + + if (!strncmp((const char *)iProduct, "Sipeed-Debug", 12)) { + _ch552WA = true; + } + + 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); + + _in_buf = (unsigned char *)malloc(sizeof(unsigned char) * _buffer_size); + bzero(_in_buf, _buffer_size); + init(5, 0xfb, BITMODE_MPSSE, (FTDIpp_MPSSE::mpsse_bit_config &)cable); +} + +/** + * store tms in + * internal buffer + * size must be <= 8 + */ +int FtdiJtagMPSSE::storeTMS(uint8_t *tms, int nb_bit, uint8_t tdi, bool read) +{ + int xfer, pos = 0, tx = nb_bit; + unsigned char buf[3]= {static_cast(MPSSE_WRITE_TMS | MPSSE_LSB | + MPSSE_BITMODE | MPSSE_WRITE_NEG | ((read) ? MPSSE_DO_READ : 0)), + static_cast(0), + static_cast(0)}; + + if (nb_bit == 0) + return 0; + + display("%s: %d %s %d %d %x\n", __func__, tdi, (read) ? "true" : "false", + nb_bit, (nb_bit / 6) * 3, tms[0]); + int plop = 0; + + while (nb_bit != 0) { + xfer = (nb_bit > 6) ? 6 : nb_bit; + buf[1] = xfer - 1; + buf[2] = (tdi)?0x80 : 0x00; + for (int i = 0; i < xfer; i++, pos++) { + buf[2] |= + (((tms[pos >> 3] & (1 << (pos & 0x07))) ? 1 : 0) << i); + } + nb_bit -= xfer; + mpsse_store(buf, 3); + plop += 3; + } + + return tx; +} + +int FtdiJtagMPSSE::writeTMS(uint8_t *tdo, int len) +{ + display("%s %s %d %d\n", __func__, (tdo)?"true":"false", len, (len/8)+1); + + if (tdo) { + return mpsse_read(tdo, (len/8)+1); + } else { + int ret = mpsse_write(); + if (_ch552WA) { + uint8_t c[len/8+1]; + ftdi_read_data(_ftdi, c, len/8+1); + } + return ret; + } +} + +/** + * store tdi in internal buffer + * size must be <= 8 + */ +int FtdiJtagMPSSE::storeTDI(uint8_t tdi, int nb_bit, bool read) +{ + unsigned char tx_buf[3] = {(unsigned char)(MPSSE_LSB | MPSSE_WRITE_NEG | + MPSSE_DO_WRITE | MPSSE_BITMODE | ((read) ? MPSSE_DO_READ : 0)), + static_cast(nb_bit - 1), + tdi}; + mpsse_store(tx_buf, 3); + + return nb_bit; +} + +/** + * store tdi in internal buffer + */ +int FtdiJtagMPSSE::storeTDI(uint8_t *tdi, int nb_byte, bool read) +{ + unsigned char tx_buf[3] = {(unsigned char)(MPSSE_LSB | MPSSE_WRITE_NEG | + MPSSE_DO_WRITE | + ((read) ? MPSSE_DO_READ : 0)), + static_cast((nb_byte - 1) & 0xff), + static_cast(((nb_byte - 1) >> 8) & 0xff)}; + mpsse_store(tx_buf, 3); + mpsse_store(tdi, nb_byte); + + return nb_byte; +} + +/* flush buffer + * if tdo is not null read nb_bit + */ +int FtdiJtagMPSSE::writeTDI(uint8_t *tdo, int nb_bit) +{ + int nb_byte = (nb_bit < 8)? 1: (nb_bit >> 3); + + if (tdo) { + return mpsse_read(tdo, nb_byte); + } else { + int ret = mpsse_write(); + if (_ch552WA) { + uint8_t c[nb_byte]; + ftdi_read_data(_ftdi, c, nb_byte); + } + return ret; + } +} diff --git a/src/ftdiJtagMPSSE.hpp b/src/ftdiJtagMPSSE.hpp new file mode 100644 index 0000000..3b03721 --- /dev/null +++ b/src/ftdiJtagMPSSE.hpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2020 Gwenhael Goavec-Merou + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FTDIJTAGMPSSE_H +#define FTDIJTAGMPSSE_H +#include +#include +#include +#include + +#include "jtagInterface.hpp" +#include "ftdipp_mpsse.hpp" + +/*! + * \file FtdiJtagMPSSE.hpp + * \class FtdiJtagMPSSE + * \brief concrete class between jtag implementation and FTDI capable bitbang mode + * \author Gwenhael Goavec-Merou + */ + +class FtdiJtagMPSSE : public JtagInterface, private FTDIpp_MPSSE { + public: + FtdiJtagMPSSE(const FTDIpp_MPSSE::mpsse_bit_config &cable, std::string dev, + uint32_t clkHZ, bool verbose = false); + FtdiJtagMPSSE(const FTDIpp_MPSSE::mpsse_bit_config &cable, + uint32_t clkHZ, bool verbose); + virtual ~FtdiJtagMPSSE(); + + int setClkFreq(uint32_t clkHZ) override { + return FTDIpp_MPSSE::setClkFreq(clkHZ); + } + int setClkFreq(uint32_t clkHZ, char use_divide_by_5) override { + return FTDIpp_MPSSE::setClkFreq(clkHZ, use_divide_by_5);} + + /* TMS */ + int storeTMS(uint8_t *tms, int nb_bit, uint8_t tdi = 1, + bool read = false) override; + int writeTMS(uint8_t *tdo, int len = 0) override; + /* TDI */ + int storeTDI(uint8_t tdi, int nb_bit, bool read) override; + int storeTDI(uint8_t *tdi, int nb_byte, bool read) override; + int writeTDI(uint8_t *tdo, int nb_bit) override; + + /*! + * \brief return internal buffer size (in byte). + * \return _buffer_size -3 for mpsse cmd + size, -1 for potential SEND_IMMEDIATE + */ + int get_buffer_size() override { return _buffer_size-3; } + + bool isFull() override { return false;} + + private: + void init_internal(const FTDIpp_MPSSE::mpsse_bit_config &cable); + uint8_t *_in_buf; + bool _ch552WA; /* avoid errors with SiPeed tangNano */ +}; +#endif diff --git a/src/ftdijtag.hpp b/src/ftdijtag.hpp deleted file mode 100644 index c7fa615..0000000 --- a/src/ftdijtag.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef FTDIJTAG_H -#define FTDIJTAG_H -#include -#include -#include - -#include "ftdipp_mpsse.hpp" - -class FtdiJtag : public FTDIpp_MPSSE { - public: - //FtdiJtag(std::string board_name, int vid, int pid, unsigned char interface, uint32_t clkHZ); - FtdiJtag(FTDIpp_MPSSE::mpsse_bit_config &cable, std::string dev, - unsigned char interface, uint32_t clkHZ, bool verbose = false); - FtdiJtag(FTDIpp_MPSSE::mpsse_bit_config &cable, unsigned char interface, uint32_t clkHZ, - bool verbose); - ~FtdiJtag(); - - int detectChain(std::vector &devices, int max_dev); - - int shiftIR(unsigned char *tdi, unsigned char *tdo, int irlen, int end_state = RUN_TEST_IDLE); - int shiftIR(unsigned char tdi, int irlen, int end_state = RUN_TEST_IDLE); - int shiftDR(unsigned char *tdi, unsigned char *tdo, int drlen, int end_state = RUN_TEST_IDLE); - int read_write(unsigned char *tdi, unsigned char *tdo, int len, char last); - - void toggleClk(int nb); - void go_test_logic_reset(); - void set_state(int newState); - int flushTMS(bool flush_buffer = false); - void flush() {mpsse_write();} - void setTMS(unsigned char tms); - - enum tapState_t { - TEST_LOGIC_RESET = 0, - RUN_TEST_IDLE = 1, - SELECT_DR_SCAN = 2, - CAPTURE_DR = 3, - SHIFT_DR = 4, - EXIT1_DR = 5, - PAUSE_DR = 6, - EXIT2_DR = 7, - UPDATE_DR = 8, - SELECT_IR_SCAN = 9, - CAPTURE_IR = 10, - SHIFT_IR = 11, - EXIT1_IR = 12, - PAUSE_IR = 13, - EXIT2_IR = 14, - UPDATE_IR = 15, - UNKNOWN = 999 - }; - const char *getStateName(tapState_t s); - - /* utilities */ - void setVerbose(bool verbose){_verbose=verbose;} - - private: - void init_internal(FTDIpp_MPSSE::mpsse_bit_config &cable); - int _state; - int _tms_buffer_size; - int _num_tms; - unsigned char *_tms_buffer; - std::string _board_name; - bool _ch552WA; -}; -#endif diff --git a/src/ftdipp_mpsse.cpp b/src/ftdipp_mpsse.cpp index 2c2b610..85c49d6 100644 --- a/src/ftdipp_mpsse.cpp +++ b/src/ftdipp_mpsse.cpp @@ -18,14 +18,20 @@ using namespace std; #define display(...) \ do { if (_verbose) fprintf(stdout, __VA_ARGS__);}while(0) -FTDIpp_MPSSE::FTDIpp_MPSSE(const string &dev, unsigned char interface, +FTDIpp_MPSSE::FTDIpp_MPSSE(const mpsse_bit_config &cable, const string &dev, uint32_t clkHZ, bool verbose):_verbose(verbose), _vid(0), - _pid(0), _bus(-1), _addr(-1), _product(""), _interface(interface), + _pid(0), _bus(-1), _addr(-1), _product(""), + _interface(cable.interface), _clkHZ(clkHZ), _buffer_size(2*32768), _num(0) { - if (!search_with_dev(dev)) { - cerr << "No cable found" << endl; - throw std::exception(); + if (!dev.empty()) { + if (!search_with_dev(dev)) { + cerr << "No cable found" << endl; + throw std::exception(); + } + } else { + _vid = cable.vid; + _pid = cable.pid; } open_device(115200); @@ -38,10 +44,10 @@ FTDIpp_MPSSE::FTDIpp_MPSSE(const string &dev, unsigned char interface, } } -FTDIpp_MPSSE::FTDIpp_MPSSE(int vid, int pid, unsigned char interface, - uint32_t clkHZ, bool verbose):_verbose(verbose), _vid(vid), - _pid(pid), _bus(-1), - _addr(-1), _product(""), _interface(interface), +FTDIpp_MPSSE::FTDIpp_MPSSE(const mpsse_bit_config &cable, + uint32_t clkHZ, bool verbose):_verbose(verbose), + _vid(cable.vid), _pid(cable.pid), _bus(-1), + _addr(-1), _product(""), _interface(cable.interface), _clkHZ(clkHZ), _buffer_size(2*32768), _num(0) { open_device(115200); @@ -138,6 +144,7 @@ int FTDIpp_MPSSE::close_device() int FTDIpp_MPSSE::init(unsigned char latency, unsigned char bitmask_mode, + unsigned char mode, mpsse_bit_config & bit_conf) { unsigned char buf_cmd[6] = { SET_BITS_LOW, 0, 0, @@ -153,6 +160,7 @@ int FTDIpp_MPSSE::init(unsigned char latency, unsigned char bitmask_mode, cout << "bitmode_reset error" << endl; return -1; } + if (ftdi_usb_purge_buffers(_ftdi) != 0) { cout << "reset error" << endl; return -1; @@ -161,25 +169,30 @@ int FTDIpp_MPSSE::init(unsigned char latency, unsigned char bitmask_mode, cout << "reset error" << endl; return -1; } - /* enable MPSSE mode */ - if (ftdi_set_bitmode(_ftdi, bitmask_mode, BITMODE_MPSSE) < 0) { + /* enable mode */ + if (ftdi_set_bitmode(_ftdi, bitmask_mode, mode) < 0) { cout << "bitmode_mpsse error" << endl; return -1; } + if (mode == BITMODE_MPSSE) { - unsigned char buf1[5]; - ftdi_read_data(_ftdi, buf1, 5); + unsigned char buf1[5]; + ftdi_read_data(_ftdi, buf1, 5); - if (setClkFreq(_clkHZ, 0) < 0) - return -1; + if (setClkFreq(_clkHZ, 0) < 0) + return -1; - buf_cmd[1] = bit_conf.bit_low_val; // 0xe8; - buf_cmd[2] = bit_conf.bit_low_dir; // 0xeb; + buf_cmd[1] = bit_conf.bit_low_val; // 0xe8; + buf_cmd[2] = bit_conf.bit_low_dir; // 0xeb; - buf_cmd[4] = bit_conf.bit_high_val; // 0x00; - buf_cmd[5] = bit_conf.bit_high_dir; // 0x60; - mpsse_store(buf_cmd, 6); - mpsse_write(); + buf_cmd[4] = bit_conf.bit_high_val; // 0x00; + buf_cmd[5] = bit_conf.bit_high_dir; // 0x60; + mpsse_store(buf_cmd, 6); + mpsse_write(); + } + + ftdi_read_data_set_chunksize(_ftdi, _buffer_size); + ftdi_write_data_set_chunksize(_ftdi, _buffer_size); return 0; } @@ -237,6 +250,7 @@ int FTDIpp_MPSSE::setClkFreq(uint32_t clkHZ, char use_divide_by_5) return -1; } ret = ftdi_read_data(_ftdi, buffer, 4); + ftdi_usb_purge_buffers(_ftdi); return real_freq; } diff --git a/src/ftdipp_mpsse.hpp b/src/ftdipp_mpsse.hpp index d76b2d9..247ba25 100644 --- a/src/ftdipp_mpsse.hpp +++ b/src/ftdipp_mpsse.hpp @@ -5,22 +5,24 @@ class FTDIpp_MPSSE { public: - FTDIpp_MPSSE(const std::string &dev, unsigned char interface, - uint32_t clkHZ, bool verbose = false); - FTDIpp_MPSSE(int vid, int pid, unsigned char interface, - uint32_t clkHZ, bool verbose = false); - ~FTDIpp_MPSSE(); - typedef struct { int vid; int pid; + int interface; int bit_low_val; int bit_low_dir; int bit_high_val; int bit_high_dir; } mpsse_bit_config; - int init(unsigned char latency, unsigned char bitmask_mode, mpsse_bit_config &bit_conf); + FTDIpp_MPSSE(const mpsse_bit_config &cable, const std::string &dev, + uint32_t clkHZ, bool verbose = false); + FTDIpp_MPSSE(const mpsse_bit_config &cablen, + uint32_t clkHZ, bool verbose = false); + ~FTDIpp_MPSSE(); + + int init(unsigned char latency, unsigned char bitmask_mode, unsigned char mode, + mpsse_bit_config &bit_conf); int setClkFreq(uint32_t clkHZ); int setClkFreq(uint32_t clkHZ, char use_divide_by_5); @@ -39,8 +41,6 @@ class FTDIpp_MPSSE { unsigned int udevstufftoint(const char *udevstring, int base); bool search_with_dev(const std::string &device); bool _verbose; - struct ftdi_context *_ftdi; - private: int _vid; int _pid; @@ -49,7 +49,10 @@ class FTDIpp_MPSSE { char _product[64]; unsigned char _interface; int _clkHZ; + protected: + struct ftdi_context *_ftdi; int _buffer_size; + private: int _num; unsigned char *_buffer; }; diff --git a/src/ftdispi.cpp b/src/ftdispi.cpp index dfceb61..913defe 100644 --- a/src/ftdispi.cpp +++ b/src/ftdispi.cpp @@ -62,16 +62,16 @@ void FtdiSpi::setMode(uint8_t mode) } static FTDIpp_MPSSE::mpsse_bit_config bit_conf = - {0x08, 0x0B, 0x08, 0x0B}; + {0x403, 0x6010, INTERFACE_B, 0x08, 0x0B, 0x08, 0x0B}; FtdiSpi::FtdiSpi(int vid, int pid, unsigned char interface, uint32_t clkHZ, bool verbose): - FTDIpp_MPSSE(vid, pid, interface, clkHZ, verbose) + FTDIpp_MPSSE(bit_conf, clkHZ, verbose) { setCSmode(SPI_CS_AUTO); setEndianness(SPI_MSB_FIRST); - init(1, 0x00, bit_conf); + init(1, 0x00, BITMODE_MPSSE, bit_conf); } FtdiSpi::~FtdiSpi() { diff --git a/src/gowin.cpp b/src/gowin.cpp index a0e2974..cf133d3 100644 --- a/src/gowin.cpp +++ b/src/gowin.cpp @@ -24,7 +24,7 @@ #include -#include "ftdijtag.hpp" +#include "jtag.hpp" #include "gowin.hpp" #include "progressBar.hpp" #include "display.hpp" @@ -63,7 +63,7 @@ using namespace std; #define EF_PROGRAM 0x71 #define EFLASH_ERASE 0x75 -Gowin::Gowin(FtdiJtag *jtag, const string filename, bool flash_wr, bool sram_wr, +Gowin::Gowin(Jtag *jtag, const string filename, bool flash_wr, bool sram_wr, bool verbose): Device(jtag, filename, verbose) { _fs = NULL; @@ -372,7 +372,7 @@ bool Gowin::flashFLASH(uint8_t *data, int length) progress.display(i); } /* 2.2.6.6 */ - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); progress.done(); return true; @@ -390,25 +390,28 @@ bool Gowin::flashSRAM(uint8_t *data, int length) wr_rd(XFER_WRITE, NULL, 0, NULL, 0); /* 2.2.6.5 */ - _jtag->set_state(FtdiJtag::SHIFT_DR); + _jtag->set_state(Jtag::SHIFT_DR); - for (int i=0; i < byte_length; i+=256) { - if (i + 256 > byte_length) { // last packet with some size + int xfer_len = 256; + + for (int i=0; i < byte_length; i+=xfer_len) { + if (i + xfer_len > byte_length) { // last packet with some size tx_len = (byte_length - i) * 8; tx_end = 1; // to move in EXIT1_DR } else { - tx_len = 256 * 8; + tx_len = xfer_len * 8; tx_end = 0; } _jtag->read_write(data+i, NULL, tx_len, tx_end); - _jtag->flush(); + //_jtag->flush(); progress.display(i); } /* 2.2.6.6 */ - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); /* p.15 fig 2.11 */ wr_rd(XFER_DONE, NULL, 0, NULL, 0); + if (pollFlag(STATUS_DONE_FINAL, STATUS_DONE_FINAL)) { progress.done(); return true; @@ -426,7 +429,7 @@ bool Gowin::eraseFLASH() unsigned char tx[4] = {0, 0, 0, 0}; printInfo("erase Flash ", false); wr_rd(EFLASH_ERASE, NULL, 0, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->shiftDR(tx, NULL, 32); /* TN653 specifies to wait for 120ms with * there are no bit in status register to specify diff --git a/src/gowin.hpp b/src/gowin.hpp index a5a33ac..454f620 100644 --- a/src/gowin.hpp +++ b/src/gowin.hpp @@ -25,12 +25,12 @@ #include "device.hpp" #include "fsparser.hpp" -#include "ftdijtag.hpp" +#include "jtag.hpp" #include "jedParser.hpp" class Gowin: public Device { public: - Gowin(FtdiJtag *jtag, std::string filename, bool flash_wr, bool sram_wr, + Gowin(Jtag *jtag, std::string filename, bool flash_wr, bool sram_wr, bool verbose); ~Gowin(); int idCode() override; diff --git a/src/ftdijtag.cpp b/src/jtag.cpp similarity index 63% rename from src/ftdijtag.cpp rename to src/jtag.cpp index 509360c..97e5372 100644 --- a/src/ftdijtag.cpp +++ b/src/jtag.cpp @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2020 Gwenhael Goavec-Merou + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + #include #include @@ -7,8 +24,11 @@ #include #include -#include "ftdijtag.hpp" +#include "display.hpp" +#include "jtag.hpp" #include "ftdipp_mpsse.hpp" +#include "ftdiJtagBitbang.hpp" +#include "ftdiJtagMPSSE.hpp" using namespace std; @@ -43,81 +63,48 @@ using namespace std; * - envoyer le dernier avec 0x4B ou 0x6B */ -FtdiJtag::FtdiJtag(FTDIpp_MPSSE::mpsse_bit_config &cable, string dev, - unsigned char interface, uint32_t clkHZ, bool verbose): - FTDIpp_MPSSE(dev, interface, clkHZ, verbose), +Jtag::Jtag(cable_t &cable, const jtag_pins_conf_t *pin_conf, string dev, + uint32_t clkHZ, bool verbose): + _verbose(verbose), _state(RUN_TEST_IDLE), _tms_buffer_size(128), _num_tms(0), - _board_name("nope"), _ch552WA(false) + _board_name("nope") { - init_internal(cable); + init_internal(cable, dev, pin_conf, clkHZ); } -FtdiJtag::FtdiJtag(FTDIpp_MPSSE::mpsse_bit_config &cable, - unsigned char interface, uint32_t clkHZ, bool verbose): - FTDIpp_MPSSE(cable.vid, cable.pid, interface, clkHZ, verbose), +Jtag::Jtag(cable_t &cable, const jtag_pins_conf_t *pin_conf, + uint32_t clkHZ, bool verbose): + _verbose(verbose), _state(RUN_TEST_IDLE), _tms_buffer_size(128), _num_tms(0), - _board_name("nope"), _ch552WA(false) + _board_name("nope") { - init_internal(cable); + init_internal(cable, "", pin_conf, clkHZ); } -FtdiJtag::~FtdiJtag() +Jtag::~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, - 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); - free(_tms_buffer); + delete _jtag; } -void FtdiJtag::init_internal(FTDIpp_MPSSE::mpsse_bit_config &cable) +void Jtag::init_internal(cable_t &cable, const string &dev, + const jtag_pins_conf_t *pin_conf, uint32_t clkHZ) { - /* search for iProduct -> need to have - * ftdi->usb_dev (libusb_device_handler) -> libusb_device -> - * libusb_device_descriptor - */ - struct libusb_device * usb_dev = libusb_get_device(_ftdi->usb_dev); - struct libusb_device_descriptor usb_desc; - unsigned char iProduct[200]; - libusb_get_device_descriptor(usb_dev, &usb_desc); - libusb_get_string_descriptor_ascii(_ftdi->usb_dev, usb_desc.iProduct, - iProduct, 200); - - display("iProduct : %s\n", iProduct); - if (!strncmp((const char *)iProduct, "Sipeed-Debug", 12)) { - _ch552WA = true; + if (cable.type == MODE_FTDI_BITBANG) { + if (pin_conf == NULL) + throw std::exception(); + _jtag = new FtdiJtagBitBang(cable.config, pin_conf, dev, clkHZ, _verbose); + } else { + _jtag = new FtdiJtagMPSSE(cable.config, dev, clkHZ, _verbose); } - display("board_name %s\n", _board_name.c_str()); - 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); - _tms_buffer = (unsigned char *)malloc(sizeof(unsigned char) * _tms_buffer_size); bzero(_tms_buffer, _tms_buffer_size); - init(5, 0xfb, cable); } -int FtdiJtag::detectChain(vector &devices, int max_dev) +int Jtag::detectChain(vector &devices, int max_dev) { unsigned char rx_buff[4]; /* WA for CH552/tangNano: write is always mandatory */ @@ -140,9 +127,9 @@ int FtdiJtag::detectChain(vector &devices, int max_dev) return devices.size(); } -void FtdiJtag::setTMS(unsigned char tms) +void Jtag::setTMS(unsigned char tms) { - display("%s %d %d\n", __func__, _num_tms, (_num_tms >> 3)); + display("%s %x %d %d\n", __func__, tms, _num_tms, (_num_tms >> 3)); if (_num_tms+1 == _tms_buffer_size * 8) flushTMS(); if (tms != 0) @@ -158,38 +145,23 @@ void FtdiJtag::setTMS(unsigned char tms) * -bit 7 is TDI state for each clk cycles */ -int FtdiJtag::flushTMS(bool flush_buffer) +int Jtag::flushTMS(bool flush_buffer) { - int xfer, pos = 0; - unsigned char buf[3]= {MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | - MPSSE_WRITE_NEG, 0, 0}; + if (_num_tms != 0) { + display("%s: %d %x\n", __func__, _num_tms, _tms_buffer[0]); - if (_num_tms == 0) - return 0; + _jtag->storeTMS(_tms_buffer, _num_tms); - display("%s: %d %x\n", __func__, _num_tms, _tms_buffer[0]); - - while (_num_tms != 0) { - xfer = (_num_tms > 6) ? 6 : _num_tms; - buf[1] = xfer - 1; - buf[2] = 0x80; - for (int i = 0; i < xfer; i++, pos++) { - buf[2] |= - (((_tms_buffer[pos >> 3] & (1 << (pos & 0x07))) ? 1 : 0) << i); - } - _num_tms -= xfer; - mpsse_store(buf, 3); + /* reset buffer and number of bits */ + bzero(_tms_buffer, _tms_buffer_size); + _num_tms = 0; } - - /* reset buffer and number of bits */ - bzero(_tms_buffer, _tms_buffer_size); - _num_tms = 0; if (flush_buffer) - return mpsse_write(); + return _jtag->writeTMS(NULL); return 0; } -void FtdiJtag::go_test_logic_reset() +void Jtag::go_test_logic_reset() { /* idenpendly to current state 5 clk with TMS high is enough */ for (int i = 0; i < 6; i++) @@ -201,44 +173,42 @@ void FtdiJtag::go_test_logic_reset() /* GGM: faut tenir plus compte de la taille de la fifo interne * du FT2232 pour maximiser l'envoi au lieu de faire de petits envoies */ -int FtdiJtag::read_write(unsigned char *tdi, unsigned char *tdo, int len, char last) +int Jtag::read_write(unsigned char *tdi, unsigned char *tdo, int len, char last) { /* 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 tx_buff_size = _jtag->get_buffer_size(); int real_len = (last) ? len - 1 : len; // if its a buffer in a big send send len // else supress 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 - 3; - unsigned char c[len]; + int xfer = tx_buff_size; + unsigned char *rx_ptr = (unsigned char *)tdo; unsigned char *tx_ptr = (unsigned char *)tdi; - unsigned char tx_buf[3] = {(unsigned char)(MPSSE_LSB | MPSSE_WRITE_NEG | - ((tdi) ? MPSSE_DO_WRITE : 0) | - ((tdo) ? MPSSE_DO_READ : 0)), - static_cast((xfer - 1) & 0xff), // low - static_cast((((xfer - 1) >> 8) & 0xff))}; // high flushTMS(true); - display("%s len : %d %d %d %d\n", __func__, len, real_len, nb_byte, - nb_bit); + display("%s len : %d %d %d %d %d\n", __func__, len, real_len, nb_byte, + nb_bit, tx_buff_size); while (nb_byte > xfer) { - mpsse_store(tx_buf, 3); - if (tdi) { - mpsse_store(tx_ptr, xfer); + display("%s %d %d\n", __func__, nb_byte, xfer); + + if (xfer != _jtag->storeTDI(tx_ptr, xfer, tdo != NULL)) { + printError("%s: Fail to store tdi\n", __func__); + return -1; + } + if (0 > _jtag->writeTDI(rx_ptr, xfer * 8)) { + printError("%s: Write errror\n", __func__); + return -1; + } + if (tdi) tx_ptr += xfer; - } - if (tdo) { - mpsse_read(rx_ptr, xfer); + if (tdo) rx_ptr += xfer; - } else if (_ch552WA) { - ftdi_read_data(_ftdi, c, xfer); - } nb_byte -= xfer; } @@ -246,43 +216,40 @@ int FtdiJtag::read_write(unsigned char *tdi, unsigned char *tdo, int len, char l /* 1/ send serie of byte */ if (nb_byte > 0) { display("%s read/write %d byte\n", __func__, nb_byte); - tx_buf[1] = ((nb_byte - 1) & 0xff); // low - tx_buf[2] = (((nb_byte - 1) >> 8) & 0xff); // high - mpsse_store(tx_buf, 3); - if (tdi) { - mpsse_store(tx_ptr, nb_byte); + if (nb_byte != _jtag->storeTDI(tx_ptr, nb_byte, tdo != NULL)) { + printError("%s: Fail to store tdi\n", __func__); + return -1; + } + if (0 > _jtag->writeTDI(((tdo)?rx_ptr:NULL), nb_byte * 8)) { + printError("%s: Write errror\n", __func__); + return -1; + } + if (tdi) tx_ptr += nb_byte; - } - if (tdo) { - mpsse_read(rx_ptr, nb_byte); + if (tdo) rx_ptr += nb_byte; - } else if (_ch552WA) { - ftdi_read_data(_ftdi, c, nb_byte); - } } unsigned char last_bit = (tdi) ? *tx_ptr : 0; if (nb_bit != 0) { display("%s read/write %d bit\n", __func__, nb_bit); - tx_buf[0] |= 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); + if (nb_bit != _jtag->storeTDI(last_bit, nb_bit, tdo != NULL)) { + printError("%s: Fail to store tdi\n", __func__); + return -1; } - mpsse_write(); + if (0 > _jtag->writeTDI((tdo)?rx_ptr:NULL, nb_bit)) { + printError("%s: Write errror\n", __func__); + return -1; + } + if (tdo) { - mpsse_read(rx_ptr, 1); /* 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); - } else if (_ch552WA) { - ftdi_read_data(_ftdi, c, nb_bit); } } @@ -295,25 +262,18 @@ int FtdiJtag::read_write(unsigned char *tdi, unsigned char *tdo, int len, char l } if (last == 1) { + uint8_t c; 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 | - ((tdo) ? MPSSE_DO_READ : 0); - 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); - mpsse_write(); + + c=1; + _jtag->storeTMS(&c, 1, (last_bit)?1:0, tdo != NULL); + _jtag->writeTMS((tdo)?&c:NULL, 1); if (tdo) { - unsigned char c; - mpsse_read(&c, 1); /* in this case for 1 one it's always bit 7 */ *rx_ptr |= ((c & 0x80) << (7 - nb_bit)); display("%s %x\n", __func__, c); - } else if (_ch552WA) { - ftdi_read_data(_ftdi, c, 1); } _state = (_state == SHIFT_DR) ? EXIT1_DR : EXIT1_IR; } @@ -321,7 +281,7 @@ int FtdiJtag::read_write(unsigned char *tdi, unsigned char *tdo, int len, char l return 0; } -void FtdiJtag::toggleClk(int nb) +void Jtag::toggleClk(int nb) { unsigned char c = (TEST_LOGIC_RESET == _state) ? 1 : 0; for (int i = 0; i < nb; i++) @@ -329,7 +289,7 @@ void FtdiJtag::toggleClk(int nb) flushTMS(true); } -int FtdiJtag::shiftDR(unsigned char *tdi, unsigned char *tdo, int drlen, int end_state) +int Jtag::shiftDR(unsigned char *tdi, unsigned char *tdo, int drlen, int end_state) { set_state(SHIFT_DR); // force transmit tms state @@ -341,7 +301,7 @@ int FtdiJtag::shiftDR(unsigned char *tdi, unsigned char *tdo, int drlen, int end return 0; } -int FtdiJtag::shiftIR(unsigned char tdi, int irlen, int end_state) +int Jtag::shiftIR(unsigned char tdi, int irlen, int end_state) { if (irlen > 8) { cerr << "Error: this method this direct char don't support more than 1 byte" << endl; @@ -350,7 +310,7 @@ int FtdiJtag::shiftIR(unsigned char tdi, int irlen, int end_state) return shiftIR(&tdi, NULL, irlen, end_state); } -int FtdiJtag::shiftIR(unsigned char *tdi, unsigned char *tdo, int irlen, int end_state) +int Jtag::shiftIR(unsigned char *tdi, unsigned char *tdo, int irlen, int end_state) { display("%s: avant shiftIR\n", __func__); set_state(SHIFT_IR); @@ -358,13 +318,13 @@ int FtdiJtag::shiftIR(unsigned char *tdi, unsigned char *tdo, int irlen, int end // currently don't care about multiple device in the chain display("%s: envoi ircode\n", __func__); - read_write(tdi, tdo, irlen, 1);// 1 since only one device + read_write(tdi, tdo, irlen, 1); // 1 since only one device set_state(end_state); return 0; } -void FtdiJtag::set_state(int newState) +void Jtag::set_state(int newState) { unsigned char tms; while (newState != _state) { @@ -548,13 +508,14 @@ void FtdiJtag::set_state(int newState) } setTMS(tms); - display("%d %d %d %x\n", tms, _num_tms-1, _state, _tms_buffer[(_num_tms-1) / 8]); + display("%d %d %d %x\n", tms, _num_tms-1, _state, + _tms_buffer[(_num_tms-1) / 8]); } /* force write buffer */ flushTMS(); } -const char *FtdiJtag::getStateName(tapState_t s) +const char *Jtag::getStateName(tapState_t s) { switch (s) { case TEST_LOGIC_RESET: diff --git a/src/jtag.hpp b/src/jtag.hpp new file mode 100644 index 0000000..8469d49 --- /dev/null +++ b/src/jtag.hpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2020 Gwenhael Goavec-Merou + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef JTAG_H +#define JTAG_H +#include +#include +#include +#include + +#include "board.hpp" +#include "cable.hpp" +#include "ftdipp_mpsse.hpp" +#include "jtagInterface.hpp" + +class Jtag { + public: + Jtag(cable_t &cable, const jtag_pins_conf_t *pin_conf, std::string dev, + uint32_t clkHZ, bool verbose = false); + Jtag(cable_t &cable, const jtag_pins_conf_t *pin_conf, + uint32_t clkHZ, bool verbose); + ~Jtag(); + + /* maybe to update */ + int setClkFreq(uint32_t clkHZ) { return _jtag->setClkFreq(clkHZ);} + int setClkFreq(uint32_t clkHZ, char use_divide_by_5) { + return _jtag->setClkFreq(clkHZ, use_divide_by_5);} + + int detectChain(std::vector &devices, int max_dev); + + int shiftIR(unsigned char *tdi, unsigned char *tdo, int irlen, + int end_state = RUN_TEST_IDLE); + int shiftIR(unsigned char tdi, int irlen, + int end_state = RUN_TEST_IDLE); + int shiftDR(unsigned char *tdi, unsigned char *tdo, int drlen, + int end_state = RUN_TEST_IDLE); + int read_write(unsigned char *tdi, unsigned char *tdo, int len, char last); + + void toggleClk(int nb); + void go_test_logic_reset(); + void set_state(int newState); + int flushTMS(bool flush_buffer = false); + void flush() {_jtag->writeTMS(NULL, 0); _jtag->writeTDI(NULL, 0);} + void setTMS(unsigned char tms); + + enum tapState_t { + TEST_LOGIC_RESET = 0, + RUN_TEST_IDLE = 1, + SELECT_DR_SCAN = 2, + CAPTURE_DR = 3, + SHIFT_DR = 4, + EXIT1_DR = 5, + PAUSE_DR = 6, + EXIT2_DR = 7, + UPDATE_DR = 8, + SELECT_IR_SCAN = 9, + CAPTURE_IR = 10, + SHIFT_IR = 11, + EXIT1_IR = 12, + PAUSE_IR = 13, + EXIT2_IR = 14, + UPDATE_IR = 15, + UNKNOWN = 999 + }; + const char *getStateName(tapState_t s); + + /* utilities */ + void setVerbose(bool verbose){_verbose = verbose;} + + private: + void init_internal(cable_t &cable, const std::string &dev, + const jtag_pins_conf_t *pin_conf, uint32_t clkHZ); + bool _verbose; + int _state; + int _tms_buffer_size; + int _num_tms; + unsigned char *_tms_buffer; + std::string _board_name; + JtagInterface *_jtag; +}; +#endif diff --git a/src/jtagInterface.hpp b/src/jtagInterface.hpp new file mode 100644 index 0000000..6438528 --- /dev/null +++ b/src/jtagInterface.hpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2020 Gwenhael Goavec-Merou + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _JTAGINTERFACE_H_ +#define _JTAGINTERFACE_H_ + +#include +#include + +/*! + * \file JtagInterface.hpp + * \class JtagInterface + * \brief abstract class between jtag implementation and converters + * \author Gwenhael Goavec-Merou + */ + +class JtagInterface { + public: + virtual ~JtagInterface() {} + + virtual int setClkFreq(uint32_t clkHZ) = 0; + virtual int setClkFreq(uint32_t clkHZ, char use_divide_by_5) = 0; + + /*! + * \brief store TMS states in internal buffer. Not limited to 8 states + * \param tms: array of TMS values + * \param nb_bit: number of TMS states to store + * \param tdi: state of TDI for all TMS to store + * \return number of states stored + */ + virtual int storeTMS(uint8_t *tms, int nb_bit, uint8_t tdi = 1, + bool read = false) = 0; + /*! + * \brief flush TMS internal buffer (ie. transmit to converter) + * \param tdo: pointer for read operation. May be NULL + * \param len: number of bit to send + * \return number of bit send/received + */ + virtual int writeTMS(uint8_t *tdo, int len = 0) = 0; + /*! + * \brief store up to 8 TDI state(s) in internal buffer + * \param tdi: TDI value(s) + * \param tms: state of TMS for all TDI to store + * \param nb_bit: number of TMS states to store + * \return number of states stored + */ + virtual int storeTDI(uint8_t tdi, int nb_bit, bool read) = 0; + /*! + * \brief store TDI multiple of 8 states in internal buffer. + * \param tdi: array of TDI values + * \param tms: state of TMS for all TDI to store + * \param nb_byte: number of TDI states to store + * \return number of states stored + */ + virtual int storeTDI(uint8_t *tdi, int nb_byte, bool read) = 0; + /*! + * \brief flush TDI internal buffer (ie. transmit to converter) + * \param tdo: pointer for read operation. May be NULL + * \return number of bit send/received + */ + virtual int writeTDI(uint8_t *tdo, int nb_bit) = 0; + + /*! + * \brief return internal buffer size (in byte) + * \return internal buffer size + */ + virtual int get_buffer_size() = 0; + + /*! + * \brief return status of internal buffer + * \return true when internal buffer is full + */ + virtual bool isFull() = 0; +}; +#endif // _JTAGINTERFACE_H_ diff --git a/src/lattice.cpp b/src/lattice.cpp index 1fd184f..f5702c5 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -24,7 +24,7 @@ #include -#include "ftdijtag.hpp" +#include "jtag.hpp" #include "lattice.hpp" #include "progressBar.hpp" #include "display.hpp" @@ -61,7 +61,7 @@ using namespace std; # define REG_STATUS_CNF_CHK_MASK (0x7 << 23) # define REG_STATUS_EXEC_ERR (1 << 26) -Lattice::Lattice(FtdiJtag *jtag, const string filename, bool verbose): +Lattice::Lattice(Jtag *jtag, const string filename, bool verbose): Device(jtag, filename, verbose) { if (_filename != "") { @@ -182,13 +182,13 @@ bool Lattice::program_mem() /* LSC_INIT_ADDRESS */ wr_rd(0x46, NULL, 0, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); uint8_t *data = _bit.getData(); int length = _bit.getLength()/8; wr_rd(0x7A, NULL, 0, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(2); uint8_t tmp[1024]; @@ -205,10 +205,10 @@ bool Lattice::program_mem() for (int ii = 0; ii < size; ii++) tmp[ii] = ConfigBitstreamParser::reverseByte(data[i+ii]); - _jtag->shiftDR(tmp, NULL, size*8, FtdiJtag::SHIFT_DR); + _jtag->shiftDR(tmp, NULL, size*8, Jtag::SHIFT_DR); } - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); if (checkStatus(0, REG_STATUS_CNF_CHK_MASK)) progress.done(); @@ -341,7 +341,7 @@ bool Lattice::program_flash() /* LSC_INIT_ADDRESS */ wr_rd(0x46, NULL, 0, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); /* flash UFM */ @@ -354,7 +354,7 @@ bool Lattice::program_flash() /* LSC_INIT_ADDRESS */ wr_rd(0x46, NULL, 0, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); if ((eraseMode & FLASH_ERASE_FEATURE) != 0) { @@ -425,7 +425,7 @@ bool Lattice::EnableISC(uint8_t flash_mode) { wr_rd(ISC_ENABLE, &flash_mode, 1, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); if (!pollBusyFlag()) return false; @@ -437,7 +437,7 @@ bool Lattice::EnableISC(uint8_t flash_mode) bool Lattice::DisableISC() { wr_rd(ISC_DISABLE, NULL, 0, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); if (!pollBusyFlag()) return false; @@ -450,7 +450,7 @@ bool Lattice::EnableCfgIf() { uint8_t tx_buf = 0x08; wr_rd(0x74, &tx_buf, 1, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); return pollBusyFlag(); } @@ -459,7 +459,7 @@ bool Lattice::DisableCfg() { uint8_t tx_buf, rx_buf; wr_rd(0x26, &tx_buf, 1, &rx_buf, 1); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); return true; } @@ -490,7 +490,7 @@ bool Lattice::checkID() printf("check ID\n"); uint8_t tx[4]; wr_rd(0xE2, tx, 4, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); uint32_t reg = readStatusReg(); @@ -501,7 +501,7 @@ bool Lattice::checkID() tx[1] = 0xd0; tx[0] = 0x43; wr_rd(0xE2, tx, 4, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); reg = readStatusReg(); displayReadReg(reg); @@ -519,7 +519,7 @@ uint32_t Lattice::readStatusReg() uint32_t reg; uint8_t rx[4], tx[4]; wr_rd(0x3C, tx, 4, rx, 4); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); reg = rx[3] << 24 | rx[2] << 16 | rx[1] << 8 | rx[0]; return reg; @@ -543,10 +543,10 @@ bool Lattice::wr_rd(uint8_t cmd, xfer_tx[i] = tx[i]; } - _jtag->shiftIR(&cmd, NULL, 8, FtdiJtag::PAUSE_IR); + _jtag->shiftIR(&cmd, NULL, 8, Jtag::PAUSE_IR); if (rx || tx) { _jtag->shiftDR(xfer_tx, (rx) ? xfer_rx : NULL, 8 * xfer_len, - FtdiJtag::PAUSE_DR); + Jtag::PAUSE_DR); } if (rx) { if (verbose) { @@ -652,7 +652,7 @@ bool Lattice::pollBusyFlag(bool verbose) int timeout = 0; do { wr_rd(CHECK_BUSY_FLAG, NULL, 0, &rx, 1); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); if (verbose) printf("pollBusyFlag :%02x\n", rx); @@ -676,7 +676,7 @@ bool Lattice::flashErase(uint8_t mask) { uint8_t tx[1] = {mask}; wr_rd(FLASH_ERASE, tx, 1, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); if (!pollBusyFlag()) return false; @@ -692,7 +692,7 @@ bool Lattice::flashProg(uint32_t start_addr, std::vector data) for (uint32_t line = 0; line < data.size(); line++) { wr_rd(PROG_CFG_FLASH, (uint8_t *)data[line].c_str(), 16, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); progress.display(line); if (pollBusyFlag() == false) @@ -709,20 +709,20 @@ bool Lattice::Verify(JedParser &_jed, bool unlock) EnableISC(0x08); wr_rd(0x46, NULL, 0, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); tx_buf[0] = 0x73; - _jtag->shiftIR(tx_buf, NULL, 8, FtdiJtag::PAUSE_IR); + _jtag->shiftIR(tx_buf, NULL, 8, Jtag::PAUSE_IR); bzero(tx_buf, 16); bool failure = false; vector data = _jed.data_for_section(0); ProgressBar progress("Verifying", data.size(), 50); for (size_t line = 0; line< data.size(); line++) { - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(2); - _jtag->shiftDR(tx_buf, rx_buf, 16*8, FtdiJtag::PAUSE_DR); + _jtag->shiftDR(tx_buf, rx_buf, 16*8, Jtag::PAUSE_DR); for (size_t i = 0; i < data[i].size(); i++) { if (rx_buf[i] != (unsigned char)data[line][i]) { printf("%3ld %3ld %02x -> %02x\n", line, i, @@ -760,7 +760,7 @@ uint16_t Lattice::readFeabits() { uint8_t rx_buf[2]; wr_rd(READ_FEABITS, NULL, 0, rx_buf, 2); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); return rx_buf[0] | (((uint16_t)rx_buf[1]) << 8); @@ -772,7 +772,7 @@ bool Lattice::writeFeaturesRow(uint64_t features, bool verify) for (int i=0; i < 8; i++) tx_buf[i] = ((features >> (i*8)) & 0x00ff); wr_rd(PROG_FEATURE_ROW, tx_buf, 8, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); if (!pollBusyFlag()) return false; @@ -787,7 +787,7 @@ bool Lattice::writeFeabits(uint16_t feabits, bool verify) (uint8_t)(0x00ff & (feabits>>8))}; wr_rd(PROG_FEABITS, tx_buf, 2, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); if (!pollBusyFlag()) return false; @@ -799,7 +799,7 @@ bool Lattice::writeFeabits(uint16_t feabits, bool verify) bool Lattice::writeProgramDone() { wr_rd(PROG_DONE, NULL, 0, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); if (!pollBusyFlag()) return false; @@ -811,7 +811,7 @@ bool Lattice::writeProgramDone() bool Lattice::loadConfiguration() { wr_rd(REFRESH, NULL, 0, NULL, 0); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(1000); if (!pollBusyFlag()) return false; diff --git a/src/lattice.hpp b/src/lattice.hpp index fc81155..cb024ff 100644 --- a/src/lattice.hpp +++ b/src/lattice.hpp @@ -23,14 +23,14 @@ #include #include -#include "ftdijtag.hpp" +#include "jtag.hpp" #include "device.hpp" #include "jedParser.hpp" #include "latticeBitParser.hpp" class Lattice: public Device { public: - Lattice(FtdiJtag *jtag, std::string filename, bool verbose); + Lattice(Jtag *jtag, std::string filename, bool verbose); int idCode() override; int userCode(); void reset() override {} diff --git a/src/main.cpp b/src/main.cpp index 4a35abb..122d520 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,7 +31,7 @@ #include "display.hpp" #include "gowin.hpp" #include "lattice.hpp" -#include "ftdijtag.hpp" +#include "jtag.hpp" #include "part.hpp" #include "xilinx.hpp" @@ -85,7 +85,8 @@ void displaySupported(const struct arguments &args); int main(int argc, char **argv) { - FTDIpp_MPSSE::mpsse_bit_config cable; + cable_t cable; + jtag_pins_conf_t *pins_config = NULL; /* command line args. */ struct arguments args = {false, false, false, 0, "", "-", "-", "-", @@ -100,7 +101,10 @@ int main(int argc, char **argv) /* if a board name is specified try to use this to determine cable */ if (args.board[0] != '-' && board_list.find(args.board) != board_list.end()) { - auto t = cable_list.find(board_list[args.board]); + /* set pins config */ + pins_config = &board_list[args.board].pins_config; + /* search for cable */ + auto t = cable_list.find(board_list[args.board].cable_name); if (t == cable_list.end()) { args.cable = "-"; cout << "Board " << args.board << " has not default cable" << endl; @@ -122,11 +126,11 @@ int main(int argc, char **argv) cable = select_cable->second; /* jtag base */ - FtdiJtag *jtag; + Jtag *jtag; if (args.device == "-") - jtag = new FtdiJtag(cable, 1, 6000000, false); + jtag = new Jtag(cable, pins_config, 6000000, false); else - jtag = new FtdiJtag(cable, args.device, 1, 6000000, false); + jtag = new Jtag(cable, pins_config, args.device, 6000000, false); /* chain detection */ vector listDev; @@ -267,7 +271,7 @@ void displaySupported(const struct arguments &args) t << setw(15) << left << "cable name:" << "vid:pid"; printSuccess(t.str()); for (auto b = cable_list.begin(); b != cable_list.end(); b++) { - FTDIpp_MPSSE::mpsse_bit_config c = (*b).second; + FTDIpp_MPSSE::mpsse_bit_config c = (*b).second.config; stringstream ss; ss << setw(15) << left << (*b).first; ss << "0x" << hex << c.vid << ":" << c.pid; @@ -282,7 +286,8 @@ void displaySupported(const struct arguments &args) printSuccess(t.str()); for (auto b = board_list.begin(); b != board_list.end(); b++) { stringstream ss; - ss << setw(15) << left << (*b).first << " " << (*b).second; + target_cable_t c = (*b).second; + ss << setw(15) << left << (*b).first << " " << c.cable_name; printInfo(ss.str()); } cout << endl; diff --git a/src/part.hpp b/src/part.hpp index b0ebe92..53a38b2 100644 --- a/src/part.hpp +++ b/src/part.hpp @@ -38,6 +38,8 @@ static std::map fpga_list = { {0x81112043, {"lattice", "ECP5", "LFE5UM5G-45"}}, {0x81113043, {"lattice", "ECP5", "LFE5UM5G-85"}}, + {0x0129a043, {"lattice", "XP2", "LFXP2-8E"}}, + {0x1100581b, {"Gowin", "GW1N", "GW1NR-9"}}, {0x0900281B, {"Gowin", "GW1N", "GW1N-1"}}, {0x0100381B, {"Gowin", "GW1N", "GW1N-4"}}, diff --git a/src/spiFlash.cpp b/src/spiFlash.cpp index 0051f56..a5016d1 100644 --- a/src/spiFlash.cpp +++ b/src/spiFlash.cpp @@ -20,7 +20,7 @@ #include #include -#include "ftdijtag.hpp" +#include "jtag.hpp" #include "ftdipp_mpsse.hpp" #include "progressBar.hpp" #include "spiFlash.hpp" @@ -72,7 +72,7 @@ static uint8_t reverseByte(uint8_t src) #define FLASH_WRVECR 0x61 #define FLASH_RDVECR 0x65 -SPIFlash::SPIFlash(FtdiJtag *jtag, bool verbose):_jtag(jtag), _verbose(verbose) +SPIFlash::SPIFlash(Jtag *jtag, bool verbose):_jtag(jtag), _verbose(verbose) { } @@ -116,8 +116,8 @@ int SPIFlash::wait(uint8_t mask, uint8_t cond, uint32_t timeout, bool verbose) uint8_t tx = reverseByte(FLASH_RDSR); uint32_t count = 0; - _jtag->shiftIR(USER1, 6, FtdiJtag::UPDATE_IR); - _jtag->set_state(FtdiJtag::SHIFT_DR); + _jtag->shiftIR(USER1, 6, Jtag::UPDATE_IR); + _jtag->set_state(Jtag::SHIFT_DR); _jtag->read_write(&tx, NULL, 8, 0); do { diff --git a/src/spiFlash.hpp b/src/spiFlash.hpp index d4c303a..ffe19b0 100644 --- a/src/spiFlash.hpp +++ b/src/spiFlash.hpp @@ -18,11 +18,11 @@ #ifndef SPIFLASH_HPP #define SPIFLASH_HPP -#include "ftdijtag.hpp" +#include "jtag.hpp" class SPIFlash { public: - SPIFlash(FtdiJtag *jtag, bool verbose); + SPIFlash(Jtag *jtag, bool verbose); /* power */ void power_up(); void power_down(); @@ -46,7 +46,7 @@ class SPIFlash { void jtag_write_read(uint8_t cmd, uint8_t *tx, uint8_t *rx, uint16_t len = 0); int wait(uint8_t mask, uint8_t cond, uint32_t timeout, bool verbose=false); - FtdiJtag *_jtag; + Jtag *_jtag; bool _verbose; }; diff --git a/src/svf_jtag.cpp b/src/svf_jtag.cpp index 999abcb..ced4dfe 100644 --- a/src/svf_jtag.cpp +++ b/src/svf_jtag.cpp @@ -4,7 +4,7 @@ #include #include -#include "ftdijtag.hpp" +#include "jtag.hpp" #include "svf_jtag.hpp" @@ -231,7 +231,7 @@ void SVF_jtag::handle_instruction(vector const &vstr) } } -SVF_jtag::SVF_jtag(FtdiJtag *jtag, bool verbose):_verbose(verbose), _freq_hz(0), +SVF_jtag::SVF_jtag(Jtag *jtag, bool verbose):_verbose(verbose), _freq_hz(0), _enddr(fsm_state["IDLE"]), _endir(fsm_state["IDLE"]), _run_state(fsm_state["IDLE"]), _end_state(fsm_state["IDLE"]) diff --git a/src/svf_jtag.hpp b/src/svf_jtag.hpp index a7ad930..d1805de 100644 --- a/src/svf_jtag.hpp +++ b/src/svf_jtag.hpp @@ -3,11 +3,13 @@ #include #include #include + +#include "jtag.hpp" using namespace std; class SVF_jtag { public: - SVF_jtag(FtdiJtag *jtag, bool verbose); + SVF_jtag(Jtag *jtag, bool verbose); ~SVF_jtag(); void parse(string filename); void setVerbose(bool verbose) {_verbose = verbose;} @@ -46,7 +48,7 @@ class SVF_jtag { {"IRUPDATE", 15} }; - FtdiJtag *_jtag; + Jtag *_jtag; bool _verbose; uint32_t _freq_hz; diff --git a/src/xilinx.cpp b/src/xilinx.cpp index 99521e5..1ebf45a 100644 --- a/src/xilinx.cpp +++ b/src/xilinx.cpp @@ -1,7 +1,7 @@ #include #include -#include "ftdijtag.hpp" +#include "jtag.hpp" #include "bitparser.hpp" #include "mcsParser.hpp" #include "spiFlash.hpp" @@ -10,7 +10,7 @@ #include "part.hpp" #include "progressBar.hpp" -Xilinx::Xilinx(FtdiJtag *jtag, std::string filename, bool verbose): +Xilinx::Xilinx(Jtag *jtag, std::string filename, bool verbose): Device(jtag, filename, verbose) { if (_filename != ""){ @@ -36,23 +36,24 @@ void Xilinx::reset() { _jtag->shiftIR(JSHUTDOWN, 6); _jtag->shiftIR(JPROGRAM, 6); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(10000*12); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(2000); _jtag->shiftIR(BYPASS, 6); - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(2000); } int Xilinx::idCode() { + unsigned char tx_data[4]= {0x00, 0x00, 0x00, 0x00}; unsigned char rx_data[4]; _jtag->go_test_logic_reset(); _jtag->shiftIR(IDCODE, 6); - _jtag->shiftDR(NULL, rx_data, 32); + _jtag->shiftDR(tx_data, rx_data, 32); return ((rx_data[0] & 0x000000ff) | ((rx_data[1] << 8) & 0x0000ff00) | ((rx_data[2] << 16) & 0x00ff0000) | @@ -128,7 +129,7 @@ void Xilinx::program_mem(BitParser &bitfile) /* * 8: Move into the RTI state. X 0 10,000(1) */ - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(10000*12); /* * 9: Start loading the CFG_IN instruction, @@ -141,11 +142,11 @@ void Xilinx::program_mem(BitParser &bitfile) /* * 11: Enter the SELECT-DR state. X 1 2 */ - _jtag->set_state(FtdiJtag::SELECT_DR_SCAN); + _jtag->set_state(Jtag::SELECT_DR_SCAN); /* * 12: Enter the SHIFT-DR state. X 0 2 */ - _jtag->set_state(FtdiJtag::SHIFT_DR); + _jtag->set_state(Jtag::SHIFT_DR); /* * 13: Shift in the FPGA bitstream. Bitn (MSB) * is the first bit in the bitstream(2). bit1...bitn 0 (bits in bitstream)-1 @@ -177,11 +178,11 @@ void Xilinx::program_mem(BitParser &bitfile) /* * 15: Enter UPDATE-DR state. X 1 1 */ - _jtag->set_state(FtdiJtag::UPDATE_DR); + _jtag->set_state(Jtag::UPDATE_DR); /* * 16: Move into RTI state. X 0 1 */ - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); /* * 17: Enter the SELECT-IR state. X 1 2 * 18: Move to the SHIFT-IR state. X 0 2 @@ -191,13 +192,13 @@ void Xilinx::program_mem(BitParser &bitfile) * 20: Load the last bit of the JSTART instruction. 0 1 1 * 21: Move to the UPDATE-IR state. X 1 1 */ - _jtag->shiftIR(JSTART, 6, FtdiJtag::UPDATE_IR); + _jtag->shiftIR(JSTART, 6, Jtag::UPDATE_IR); /* * 22: Move to the RTI state and clock the * startup sequence by applying a minimum X 0 2000 * of 2000 clock cycles to the TCK. */ - _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->set_state(Jtag::RUN_TEST_IDLE); _jtag->toggleClk(2000); /* * 23: Move to the TLR state. The device is diff --git a/src/xilinx.hpp b/src/xilinx.hpp index e7d91ae..1e6b80c 100644 --- a/src/xilinx.hpp +++ b/src/xilinx.hpp @@ -3,11 +3,11 @@ #include "bitparser.hpp" #include "device.hpp" -#include "ftdijtag.hpp" +#include "jtag.hpp" class Xilinx: public Device { public: - Xilinx(FtdiJtag *jtag, std::string filename, bool verbose); + Xilinx(Jtag *jtag, std::string filename, bool verbose); ~Xilinx(); void program(unsigned int offset = 0) override;