introduce intel usb blaster cable and de0nano board
This commit is contained in:
parent
dcf4468206
commit
4a3d1b3009
|
|
@ -42,6 +42,7 @@ endif()
|
||||||
set(OPENFPGALOADER_SOURCE
|
set(OPENFPGALOADER_SOURCE
|
||||||
src/dirtyJtag.cpp
|
src/dirtyJtag.cpp
|
||||||
src/spiFlash.cpp
|
src/spiFlash.cpp
|
||||||
|
src/usbBlaster.cpp
|
||||||
src/epcq.cpp
|
src/epcq.cpp
|
||||||
src/svf_jtag.cpp
|
src/svf_jtag.cpp
|
||||||
src/jedParser.cpp
|
src/jedParser.cpp
|
||||||
|
|
@ -70,6 +71,7 @@ set(OPENFPGALOADER_HEADERS
|
||||||
src/cxxopts.hpp
|
src/cxxopts.hpp
|
||||||
src/dirtyJtag.hpp
|
src/dirtyJtag.hpp
|
||||||
src/progressBar.hpp
|
src/progressBar.hpp
|
||||||
|
src/usbBlaster.hpp
|
||||||
src/bitparser.hpp
|
src/bitparser.hpp
|
||||||
src/ftdiJtagBitbang.hpp
|
src/ftdiJtagBitbang.hpp
|
||||||
src/ftdiJtagMPSSE.hpp
|
src/ftdiJtagMPSSE.hpp
|
||||||
|
|
|
||||||
12
README.md
12
README.md
|
|
@ -14,6 +14,7 @@ __Current support kits:__
|
||||||
* [Saanlima Pipistrello LX45](http://pipistrello.saanlima.com/index.php?title=Welcome_to_Pipistrello) (memory)
|
* [Saanlima Pipistrello LX45](http://pipistrello.saanlima.com/index.php?title=Welcome_to_Pipistrello) (memory)
|
||||||
* [SeeedStudio Spartan Edge Accelerator Board](http://wiki.seeedstudio.com/Spartan-Edge-Accelerator-Board) (memory)
|
* [SeeedStudio Spartan Edge Accelerator Board](http://wiki.seeedstudio.com/Spartan-Edge-Accelerator-Board) (memory)
|
||||||
* [Sipeed Tang Nano](https://tangnano.sipeed.com/en/) (memory)
|
* [Sipeed Tang Nano](https://tangnano.sipeed.com/en/) (memory)
|
||||||
|
* [Terasic de0nano](https://www.terasic.com.tw/cgi-bin/page/archive.pl?No=593) (memory)
|
||||||
* LambdaConcept ECPIX-5 (memory and flash)
|
* LambdaConcept ECPIX-5 (memory and flash)
|
||||||
|
|
||||||
__Supported (tested) FPGA:__
|
__Supported (tested) FPGA:__
|
||||||
|
|
@ -25,12 +26,17 @@ __Supported (tested) FPGA:__
|
||||||
* Xilinx Artix 7 [xc7a35ti, xc7a100t](https://www.xilinx.com/products/silicon-devices/fpga/artix-7.html) (memory (all) and spi flash (xc7a35ti)
|
* Xilinx Artix 7 [xc7a35ti, xc7a100t](https://www.xilinx.com/products/silicon-devices/fpga/artix-7.html) (memory (all) and spi flash (xc7a35ti)
|
||||||
* Xilinx Spartan 6 [xc6slx45](https://www.xilinx.com/products/silicon-devices/fpga/spartan-6.html) (memory)
|
* Xilinx Spartan 6 [xc6slx45](https://www.xilinx.com/products/silicon-devices/fpga/spartan-6.html) (memory)
|
||||||
* Xilinx Spartan 7 [xc7s15, xc7s50](https://www.xilinx.com/products/silicon-devices/fpga/spartan-7.html) (memory (all) and spi flash (xc7s50))
|
* Xilinx Spartan 7 [xc7s15, xc7s50](https://www.xilinx.com/products/silicon-devices/fpga/spartan-7.html) (memory (all) and spi flash (xc7s50))
|
||||||
|
* Intel Cyclone IV CE [EP4CE22](https://www.intel.com/content/www/us/en/products/programmable/fpga/cyclone-iv/features.html) (memory. See note below)
|
||||||
* Intel Cyclone 10 LP [10CL025](https://www.intel.com/content/www/us/en/products/programmable/fpga/cyclone-10.html)
|
* Intel Cyclone 10 LP [10CL025](https://www.intel.com/content/www/us/en/products/programmable/fpga/cyclone-10.html)
|
||||||
|
|
||||||
|
**Note**: cyclone IV and cyclone 10 have same idcode. A WA is mandatory to
|
||||||
|
detect correct model for flash programming.
|
||||||
|
|
||||||
__Supported cables:__
|
__Supported cables:__
|
||||||
|
|
||||||
* [digilent_hs2](https://store.digilentinc.com/jtag-hs2-programming-cable/): jtag programmer cable from digilent
|
* [digilent_hs2](https://store.digilentinc.com/jtag-hs2-programming-cable/): jtag programmer cable from digilent
|
||||||
* [DirtyJTAG](https://github.com/jeanthom/DirtyJTAG): JTAG probe firmware for STM32F1
|
* [DirtyJTAG](https://github.com/jeanthom/DirtyJTAG): JTAG probe firmware for STM32F1
|
||||||
|
* Intel USB Blaster: jtag programmer cable from intel/altera
|
||||||
* JTAG-HS3: jtag programmer cable from digilent
|
* JTAG-HS3: jtag programmer cable from digilent
|
||||||
* FT2232: generic programmer cable based on Ftdi FT2232
|
* FT2232: generic programmer cable based on Ftdi FT2232
|
||||||
* FT232RL and FT231X: generic USB<->UART converters in bitbang mode
|
* FT232RL and FT231X: generic USB<->UART converters in bitbang mode
|
||||||
|
|
@ -187,7 +193,7 @@ allowed values are:
|
||||||
| RI | 7 |
|
| RI | 7 |
|
||||||
|
|
||||||
|
|
||||||
### CYC1000
|
### CYC1000 and de0nano
|
||||||
|
|
||||||
#### loading in memory:
|
#### loading in memory:
|
||||||
|
|
||||||
|
|
@ -200,6 +206,10 @@ file load:
|
||||||
openFPGALoader -b cyc1000 project_name.svf
|
openFPGALoader -b cyc1000 project_name.svf
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openFPGALoader -b de0nano -b project_name.svf
|
||||||
|
```
|
||||||
|
|
||||||
#### SPI flash:
|
#### SPI flash:
|
||||||
sof to rpd:
|
sof to rpd:
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ static std::map <std::string, target_cable_t> board_list = {
|
||||||
{"arty", {"digilent", {}}},
|
{"arty", {"digilent", {}}},
|
||||||
{"colorlight", {"", {}}},
|
{"colorlight", {"", {}}},
|
||||||
{"cyc1000", {"ft2232", {}}},
|
{"cyc1000", {"ft2232", {}}},
|
||||||
{"de0nano", {"usbblaster", {}}},
|
{"de0nano", {"usb-blaster",{}}},
|
||||||
{"ecp5_evn", {"ft2232", {}}},
|
{"ecp5_evn", {"ft2232", {}}},
|
||||||
{"machXO2EVN", {"ft2232", {}}},
|
{"machXO2EVN", {"ft2232", {}}},
|
||||||
{"machXO3SK", {"ft2232", {}}},
|
{"machXO3SK", {"ft2232", {}}},
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,8 @@
|
||||||
enum {
|
enum {
|
||||||
MODE_FTDI_BITBANG = 0, /*! used with ft232RL/ft231x */
|
MODE_FTDI_BITBANG = 0, /*! used with ft232RL/ft231x */
|
||||||
MODE_FTDI_SERIAL = 1, /*! ft2232, ft232H */
|
MODE_FTDI_SERIAL = 1, /*! ft2232, ft232H */
|
||||||
MODE_DIRTYJTAG = 2 /*! JTAG probe firmware for STM32F1 */
|
MODE_DIRTYJTAG = 2, /*! JTAG probe firmware for STM32F1 */
|
||||||
|
MODE_USBBLASTER = 3 /*! JTAG probe firmware for USBBLASTER */
|
||||||
} communication_type_t;
|
} communication_type_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -35,6 +36,7 @@ static std::map <std::string, cable_t> cable_list = {
|
||||||
{"ft232RL", {MODE_FTDI_BITBANG, {0x0403, 0x6001, 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}}},
|
{"ft4232", {MODE_FTDI_SERIAL, {0x0403, 0x6011, INTERFACE_A, 0x08, 0x0B, 0x08, 0x0B}}},
|
||||||
{"ecpix5-debug", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_A, 0xF8, 0xFB, 0xFF, 0xFF}}},
|
{"ecpix5-debug", {MODE_FTDI_SERIAL, {0x0403, 0x6010, INTERFACE_A, 0xF8, 0xFB, 0xFF, 0xFF}}},
|
||||||
|
{"usb-blaster", {MODE_USBBLASTER, {}}},
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include "ftdiJtagBitbang.hpp"
|
#include "ftdiJtagBitbang.hpp"
|
||||||
#include "ftdiJtagMPSSE.hpp"
|
#include "ftdiJtagMPSSE.hpp"
|
||||||
#include "dirtyJtag.hpp"
|
#include "dirtyJtag.hpp"
|
||||||
|
#include "usbBlaster.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
@ -105,6 +106,9 @@ void Jtag::init_internal(cable_t &cable, const string &dev,
|
||||||
case MODE_DIRTYJTAG:
|
case MODE_DIRTYJTAG:
|
||||||
_jtag = new DirtyJtag(clkHZ, _verbose);
|
_jtag = new DirtyJtag(clkHZ, _verbose);
|
||||||
break;
|
break;
|
||||||
|
case MODE_USBBLASTER:
|
||||||
|
_jtag = new UsbBlaster(_verbose);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
std::cerr << "Jtag: unknown cable type" << std::endl;
|
std::cerr << "Jtag: unknown cable type" << std::endl;
|
||||||
throw std::exception();
|
throw std::exception();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,378 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libusb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "display.hpp"
|
||||||
|
#include "usbBlaster.hpp"
|
||||||
|
#include "ftdipp_mpsse.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define DO_READ (1 << 6)
|
||||||
|
#define DO_WRITE (0 << 6)
|
||||||
|
#define DO_RDWR (1 << 6)
|
||||||
|
#define DO_SHIFT (1 << 7)
|
||||||
|
#define DO_BITBB (0 << 7)
|
||||||
|
#define DEFAULT ((1<<2) | (1<<3) | (1 << 5))
|
||||||
|
|
||||||
|
#define DEBUG 0
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define display(...) \
|
||||||
|
do { \
|
||||||
|
if (_verbose) fprintf(stdout, __VA_ARGS__); \
|
||||||
|
}while(0)
|
||||||
|
#else
|
||||||
|
#define display(...) do {}while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UsbBlaster::UsbBlaster(bool verbose):
|
||||||
|
_verbose(verbose), _nb_bit(0),
|
||||||
|
_curr_tms(0), _buffer_size(64)
|
||||||
|
{
|
||||||
|
init_internal();
|
||||||
|
}
|
||||||
|
|
||||||
|
UsbBlaster::~UsbBlaster()
|
||||||
|
{
|
||||||
|
_in_buf[_nb_bit++] = 0;
|
||||||
|
flush();
|
||||||
|
free(_in_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UsbBlaster::init_internal()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
_ftdi = ftdi_new();
|
||||||
|
if (_ftdi == NULL) {
|
||||||
|
cout << "open_device: failed to initialize ftdi" << endl;
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ftdi_usb_open(_ftdi, 0x09fb, 0x6001);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "unable to open ftdi device: %d (%s)\n",
|
||||||
|
ret, ftdi_get_error_string(_ftdi));
|
||||||
|
ftdi_free(_ftdi);
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ftdi_usb_reset(_ftdi);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error reset: %d (%s)\n",
|
||||||
|
ret, ftdi_get_error_string(_ftdi));
|
||||||
|
ftdi_free(_ftdi);
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ftdi_set_latency_timer(_ftdi, 2);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Error set latency timer: %d (%s)\n",
|
||||||
|
ret, ftdi_get_error_string(_ftdi));
|
||||||
|
ftdi_free(_ftdi);
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
_tck_pin = (1 << 0);
|
||||||
|
_tms_pin = (1 << 1);
|
||||||
|
_tdi_pin = (1 << 4);
|
||||||
|
|
||||||
|
_in_buf = (unsigned char *)malloc(sizeof(unsigned char) * _buffer_size);
|
||||||
|
memset(_in_buf, 0, _buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int UsbBlaster::setClkFreq(uint32_t clkHZ)
|
||||||
|
{
|
||||||
|
(void) clkHZ;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UsbBlaster::writeTMS(uint8_t *tms, int len, bool flush_buffer)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* nothing to send
|
||||||
|
* but maybe need to flush internal buffer
|
||||||
|
*/
|
||||||
|
if (len == 0) {
|
||||||
|
if (flush_buffer) {
|
||||||
|
ret = flush();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for at least one bit space in buffer */
|
||||||
|
if (_nb_bit+2 > _buffer_size) {
|
||||||
|
ret = flush();
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill buffer to reduce USB transaction */
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
_curr_tms = ((tms[i >> 3] & (1 << (i & 0x07)))? _tms_pin : 0);
|
||||||
|
uint8_t val = DEFAULT | DO_WRITE | DO_BITBB | _tdi_pin | _curr_tms;
|
||||||
|
_in_buf[_nb_bit++] = val;
|
||||||
|
_in_buf[_nb_bit++] = val | _tck_pin;
|
||||||
|
|
||||||
|
if (_nb_bit + 2 > _buffer_size) {
|
||||||
|
ret = flush();
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_in_buf[_nb_bit++] = DEFAULT | DO_WRITE | DO_BITBB | _curr_tms;
|
||||||
|
|
||||||
|
/* security check: try to flush buffer */
|
||||||
|
if (flush_buffer) {
|
||||||
|
ret = flush();
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
//printInfo("writeTMS: end");
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "configBitstreamParser.hpp"
|
||||||
|
|
||||||
|
int UsbBlaster::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint32_t real_len = (end) ? len -1 : len;
|
||||||
|
uint32_t nb_byte = real_len >> 3;
|
||||||
|
uint32_t nb_bit = (real_len & 0x03);
|
||||||
|
uint8_t mode = (rx != NULL)? DO_RDWR : DO_WRITE;
|
||||||
|
|
||||||
|
uint8_t *tx_ptr = tx;
|
||||||
|
uint8_t *rx_ptr = rx;
|
||||||
|
|
||||||
|
/* security: send residual
|
||||||
|
* it's possible since all functions do a flush at the end
|
||||||
|
* okay it's maybe less efficient
|
||||||
|
*/
|
||||||
|
_in_buf[_nb_bit++] = DEFAULT | DO_BITBB | DO_WRITE | _curr_tms;
|
||||||
|
flush();
|
||||||
|
|
||||||
|
if (_curr_tms == 0 && nb_byte != 0) {
|
||||||
|
uint8_t mask = DO_SHIFT | mode;
|
||||||
|
|
||||||
|
while (nb_byte != 0) {
|
||||||
|
uint32_t tx_len = nb_byte;
|
||||||
|
if (tx_len > 63)
|
||||||
|
tx_len = 63;
|
||||||
|
/* if not enough space flush */
|
||||||
|
if (_nb_bit + tx_len + 1 > 64) {
|
||||||
|
int num_read = _nb_bit -1;
|
||||||
|
if (writeByte((rx)? rx_ptr:NULL, num_read) < 0)
|
||||||
|
return -EXIT_FAILURE;
|
||||||
|
if (rx)
|
||||||
|
rx_ptr += num_read;
|
||||||
|
}
|
||||||
|
_in_buf[_nb_bit++] = mask | (tx_len & 0x3f);
|
||||||
|
if (tx) {
|
||||||
|
memcpy(&_in_buf[_nb_bit], tx_ptr, tx_len);
|
||||||
|
tx_ptr += tx_len;
|
||||||
|
} else {
|
||||||
|
memset(&_in_buf[_nb_bit], 0, tx_len);
|
||||||
|
}
|
||||||
|
_nb_bit += tx_len;
|
||||||
|
|
||||||
|
nb_byte -= tx_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_nb_bit != 0) {
|
||||||
|
int num_read = _nb_bit-1;
|
||||||
|
if (writeByte((rx)? rx_ptr:NULL, num_read) < 0)
|
||||||
|
return -EXIT_FAILURE;
|
||||||
|
if (rx)
|
||||||
|
rx_ptr += num_read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nb_bit != 0) {
|
||||||
|
uint8_t mask = DEFAULT | DO_BITBB;
|
||||||
|
if (_nb_bit + 2 > _buffer_size) {
|
||||||
|
int num_read = _nb_bit;
|
||||||
|
if (writeBit((rx)? rx_ptr:NULL, num_read/2) < 0)
|
||||||
|
return -EXIT_FAILURE;
|
||||||
|
if (rx)
|
||||||
|
rx_ptr += num_read;
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < nb_bit; i++) {
|
||||||
|
uint8_t val = 0;
|
||||||
|
if (tx)
|
||||||
|
val |= ((tx_ptr[i >> 3] & (1 << (i & 0x07)))? _tdi_pin : 0);
|
||||||
|
_in_buf[_nb_bit++] = mask | val;
|
||||||
|
_in_buf[_nb_bit++] = mask | mode | val | _tck_pin;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_read = _nb_bit;
|
||||||
|
if (writeBit((rx)? rx_ptr:NULL, num_read/2) < 0)
|
||||||
|
return -EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set TMS high */
|
||||||
|
if (end) {
|
||||||
|
//printf("end\n");
|
||||||
|
_curr_tms = _tms_pin;
|
||||||
|
uint8_t mask = DEFAULT | DO_BITBB | _curr_tms;
|
||||||
|
if (tx && *tx_ptr & (1 << nb_bit))
|
||||||
|
mask |= _tdi_pin;
|
||||||
|
_in_buf[_nb_bit++] = mask;
|
||||||
|
_in_buf[_nb_bit++] = mask | mode | _tck_pin;
|
||||||
|
uint8_t tmp;
|
||||||
|
if (writeBit((rx)? &tmp:NULL, 1) < 0)
|
||||||
|
return -EXIT_FAILURE;
|
||||||
|
if (rx)
|
||||||
|
*rx_ptr |= ((tmp & 0x80) << (7 - nb_bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UsbBlaster::toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len)
|
||||||
|
{
|
||||||
|
int xfer_len = clk_len;
|
||||||
|
|
||||||
|
int mask = DO_SHIFT | DO_WRITE;
|
||||||
|
|
||||||
|
/* try to use shift mode but only when
|
||||||
|
* xfer > 1Byte and tms is low
|
||||||
|
*/
|
||||||
|
if (tms == 0 && xfer_len >= 8) {
|
||||||
|
_in_buf[_nb_bit++] = DEFAULT | DO_WRITE | DO_BITBB;
|
||||||
|
flush();
|
||||||
|
/* fill a byte with all 1 or all 0 */
|
||||||
|
uint8_t content = (tdi)?0xff:0;
|
||||||
|
|
||||||
|
while (xfer_len >= 8) {
|
||||||
|
uint16_t tx_len = (xfer_len >> 3);
|
||||||
|
if (tx_len > 63)
|
||||||
|
tx_len = 63;
|
||||||
|
/* if not enough space flush */
|
||||||
|
if (_nb_bit + tx_len + 1 > 64)
|
||||||
|
if (flush() < 0)
|
||||||
|
return -EXIT_FAILURE;
|
||||||
|
_in_buf[_nb_bit++] = mask | static_cast<uint8_t>(tx_len);
|
||||||
|
for (int i = 0; i < tx_len; i++)
|
||||||
|
_in_buf[_nb_bit++] = content;
|
||||||
|
xfer_len -= (tx_len << 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mask = DEFAULT | DO_BITBB | DO_WRITE | ((tms) ? _tms_pin : 0) | ((tdi) ? _tdi_pin : 0);
|
||||||
|
while (xfer_len > 0) {
|
||||||
|
if (_nb_bit + 2 > _buffer_size)
|
||||||
|
if (flush() < 0)
|
||||||
|
return -EXIT_FAILURE;
|
||||||
|
_in_buf[_nb_bit++] = mask;
|
||||||
|
_in_buf[_nb_bit++] = mask | _tck_pin;
|
||||||
|
|
||||||
|
xfer_len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush */
|
||||||
|
_in_buf[_nb_bit++] = mask;
|
||||||
|
flush();
|
||||||
|
|
||||||
|
return clk_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UsbBlaster::flush()
|
||||||
|
{
|
||||||
|
return write(false, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* simply call write and return buffer
|
||||||
|
*/
|
||||||
|
int UsbBlaster::writeByte(uint8_t *tdo, int nb_byte)
|
||||||
|
{
|
||||||
|
int ret = write(tdo != NULL, nb_byte);
|
||||||
|
if (tdo && ret > 0)
|
||||||
|
memcpy(tdo, _in_buf, nb_byte);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call write with a temporary buffer
|
||||||
|
* if tdo reconstruct message
|
||||||
|
*/
|
||||||
|
int UsbBlaster::writeBit(uint8_t *tdo, int nb_bit)
|
||||||
|
{
|
||||||
|
int ret = write(tdo != NULL, nb_bit);
|
||||||
|
if (tdo && ret > 0) {
|
||||||
|
/* need to reconstruct received word
|
||||||
|
* since jtag is LSB first we need to shift right content by 1
|
||||||
|
* and add 0x80 (1 << 7) or 0
|
||||||
|
* the buffer may contains some tms bit, so start with i
|
||||||
|
* equal to fill exactly nb_bit bits
|
||||||
|
* */
|
||||||
|
for (int i = nb_bit, offset=0; i < rd_bit; i++, offset++) {
|
||||||
|
tdo[offset >> 3] = (((_in_buf[i] & (1<<0)) ? 0x80 : 0x00) |
|
||||||
|
(tdo[offset >> 3] >> 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UsbBlaster::write(bool read, int rd_len)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
if (_nb_bit == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = ftdi_write_data(_ftdi, _in_buf, _nb_bit);
|
||||||
|
if (ret != _nb_bit) {
|
||||||
|
printf("problem %d written %d\n", ret, _nb_bit);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read) {
|
||||||
|
int timeout = 100;
|
||||||
|
uint8_t byte_read = 0;
|
||||||
|
while (byte_read < rd_len && timeout != 0) {
|
||||||
|
timeout--;
|
||||||
|
ret = ftdi_read_data(_ftdi, _in_buf + byte_read, rd_len - byte_read);
|
||||||
|
if (ret < 0) {
|
||||||
|
printError("Write error: " + std::to_string(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
byte_read += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout == 0) {
|
||||||
|
printError("Error: timeout " + std::to_string(byte_read) +
|
||||||
|
" " + std::to_string(rd_len));
|
||||||
|
for (int i=0; i < byte_read; i++)
|
||||||
|
printf("%02x ", _in_buf[i]);
|
||||||
|
printf("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_nb_bit = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef USBBLASTER_H
|
||||||
|
#define USBBLASTER_H
|
||||||
|
#include <ftdi.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "board.hpp"
|
||||||
|
#include "jtagInterface.hpp"
|
||||||
|
#include "ftdipp_mpsse.hpp"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \file UsbBlaster.hpp
|
||||||
|
* \class UsbBlaster
|
||||||
|
* \brief altera/intel usb blaster implementation
|
||||||
|
* \author Gwenhael Goavec-Merou
|
||||||
|
*/
|
||||||
|
|
||||||
|
class UsbBlaster : public JtagInterface {
|
||||||
|
public:
|
||||||
|
UsbBlaster(bool verbose = false);
|
||||||
|
virtual ~UsbBlaster();
|
||||||
|
|
||||||
|
int setClkFreq(uint32_t clkHZ) override;
|
||||||
|
int setClkFreq(uint32_t clkHZ, char use_divide_by_5) override {
|
||||||
|
(void)clkHZ; (void) use_divide_by_5;
|
||||||
|
return 1;}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief drive TMS to move in JTAG state machine
|
||||||
|
* \param tms serie of TMS state
|
||||||
|
* \param len number of TMS state
|
||||||
|
* \param flush_buffer force flushing the buffer
|
||||||
|
* \return number of state written
|
||||||
|
* */
|
||||||
|
int writeTMS(uint8_t *tms, int len, bool flush_buffer) override;
|
||||||
|
|
||||||
|
/* TDI */
|
||||||
|
int writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end) override;
|
||||||
|
/*!
|
||||||
|
* \brief toggle clock with static tms and tdi
|
||||||
|
* \param tms TMS state
|
||||||
|
* \param tdi TDI state
|
||||||
|
* \param clk_len number of clock cycle
|
||||||
|
* \return number of clock cycle
|
||||||
|
* */
|
||||||
|
int toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len) 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 63/8/2; }
|
||||||
|
|
||||||
|
bool isFull() override { return _nb_bit == 8*get_buffer_size();}
|
||||||
|
|
||||||
|
int flush() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ftdi_context *_ftdi;
|
||||||
|
void init_internal();
|
||||||
|
int writeByte(uint8_t *tdo, int nb_byte);
|
||||||
|
int writeBit(uint8_t *tdo, int nb_bit);
|
||||||
|
int write(bool read, int rd_len);
|
||||||
|
int setBitmode(uint8_t mode);
|
||||||
|
uint8_t *_in_buf;
|
||||||
|
|
||||||
|
bool _verbose;
|
||||||
|
uint8_t _tck_pin; /*!< tck pin: 1 << pin id */
|
||||||
|
uint8_t _tms_pin; /*!< tms pin: 1 << pin id */
|
||||||
|
uint8_t _tdi_pin; /*!< tdi pin: 1 << pin id */
|
||||||
|
int _nb_bit;
|
||||||
|
uint8_t _curr_tms;
|
||||||
|
uint8_t _buffer_size;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue