Support for the FX2 cable using libfpgalink
This commit is contained in:
parent
b5d18369bb
commit
dba31e77a2
|
|
@ -7,6 +7,7 @@ add_definitions(-DVERSION=\"v${PROJECT_VERSION}\")
|
|||
|
||||
option(BUILD_STATIC "Whether or not to build with static libraries" OFF)
|
||||
option(ENABLE_UDEV "use udev to search JTAG adapter from /dev/xx" ON)
|
||||
option(ENABLE_FPGALINK "enable fx2 cable support through libfpgalink" ON)
|
||||
option(USE_PKGCONFIG "Use pkgconfig to find libraries" ON)
|
||||
option(LINK_CMAKE_THREADS "Use CMake find_package to link the threading library" OFF)
|
||||
|
||||
|
|
@ -113,6 +114,9 @@ set(OPENFPGALOADER_HEADERS
|
|||
src/ftdispi.hpp
|
||||
src/lattice.hpp
|
||||
src/latticeBitParser.hpp
|
||||
src/fx2.hpp
|
||||
src/makestuff/common.h
|
||||
src/makestuff/libfpgalink.h
|
||||
)
|
||||
|
||||
add_executable(openFPGALoader
|
||||
|
|
@ -139,8 +143,21 @@ else()
|
|||
target_link_libraries(openFPGALoader
|
||||
${LIBUSB_LIBRARIES}
|
||||
${LIBFTDI_LIBRARIES}
|
||||
|
||||
)
|
||||
|
||||
if (ENABLE_FPGALINK)
|
||||
find_library(LIBFPGALINK libfpgalink.dll.a)
|
||||
if (${LIBFPGALINK} STREQUAL "LIBFPGALINK-NOTFOUND")
|
||||
message("libfpgalink not found, disabling fx2 support")
|
||||
set(ENABLE_FPGALINK OFF)
|
||||
else()
|
||||
add_definitions(-DENABLE_FX2)
|
||||
target_link_libraries(openFPGALoader ${LIBFPGALINK})
|
||||
target_sources(openFPGALoader PRIVATE src/fx2.cpp )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
# winsock provides ntohs
|
||||
target_link_libraries(openFPGALoader ws2_32)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* 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 "FX2.hpp"
|
||||
#include "makestuff/libfpgalink.h"
|
||||
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
#undef CHECK_STATUS
|
||||
|
||||
#define CHECK_STATUS(fStatus)\
|
||||
if (fStatus) \
|
||||
{ \
|
||||
cerr << error << endl;\
|
||||
flFreeError(error);\
|
||||
fStatus = progClose(handle, &error);\
|
||||
if (error)\
|
||||
flFreeError(error);\
|
||||
flClose(handle);\
|
||||
handle = NULL;\
|
||||
throw std::exception();\
|
||||
}
|
||||
|
||||
|
||||
FX2Cable::FX2Cable(bool verbose, const jtag_pins_conf_t *pin_conf, const char *ivp, const char *vp):
|
||||
_verbose(verbose)
|
||||
{
|
||||
FLStatus fStatus;
|
||||
const char *error = NULL;
|
||||
fStatus = flInitialise(0, &error);
|
||||
CHECK_STATUS(fStatus);
|
||||
char portConfig[10];
|
||||
|
||||
vp = "1D50:602B";
|
||||
|
||||
printf("Attempting to open connection to FPGALink device %s...\n", vp);
|
||||
fStatus = flOpen(vp, &handle, NULL);
|
||||
if ( fStatus ) {
|
||||
{
|
||||
int count = 60;
|
||||
uint8 flag;
|
||||
ivp = "04b4:8613";
|
||||
printf("Loading firmware into %s...\n", ivp);
|
||||
fStatus = flLoadStandardFirmware(ivp, vp, &error);
|
||||
CHECK_STATUS(fStatus);
|
||||
|
||||
printf("Awaiting renumeration");
|
||||
flSleep(1000);
|
||||
do {
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
fStatus = flIsDeviceAvailable(vp, &flag, &error);
|
||||
CHECK_STATUS(fStatus);
|
||||
flSleep(250);
|
||||
count--;
|
||||
} while ( !flag && count );
|
||||
printf("\n");
|
||||
if ( !flag ) {
|
||||
fprintf(stderr, "FPGALink device did not renumerate properly as %s\n", vp);
|
||||
flClose(handle);
|
||||
handle = NULL;
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
printf("Attempting to open connection to FPGLink device %s again...\n", vp);
|
||||
fStatus = flOpen(vp, &handle, &error);
|
||||
CHECK_STATUS(fStatus);
|
||||
}
|
||||
}
|
||||
|
||||
transcode_pin_config(pin_conf, portConfig);
|
||||
fStatus = progOpen(handle, portConfig, &error);
|
||||
CHECK_STATUS(fStatus);
|
||||
|
||||
}
|
||||
|
||||
void FX2Cable::transcode_pin_config(const jtag_pins_conf_t *pin_conf, char* buffer)
|
||||
{
|
||||
sprintf(buffer, "%X%X%X%X",pin_conf->tdo_pin, pin_conf->tdi_pin, pin_conf->tms_pin, pin_conf->tck_pin);
|
||||
}
|
||||
|
||||
FX2Cable::~FX2Cable()
|
||||
{
|
||||
const char *error = NULL;
|
||||
FLStatus fStatus;
|
||||
(void)fStatus;
|
||||
if (handle)
|
||||
{
|
||||
fStatus = progClose(handle, &error);
|
||||
flClose(handle);
|
||||
handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int FX2Cable::writeTMS(uint8_t *tms, int len, bool flush_buffer)
|
||||
{
|
||||
(void)flush_buffer;
|
||||
FLStatus fStatus;
|
||||
const char *error = NULL;
|
||||
uint32_t bitPattern = 0;
|
||||
int ulen = len;
|
||||
int i = 0;
|
||||
while (ulen > 0)
|
||||
{
|
||||
{bitPattern = tms[i++];}
|
||||
ulen-=8;
|
||||
if (ulen > 0) {bitPattern |= tms[i++] << 8;}
|
||||
ulen-=8;
|
||||
if (ulen > 0) {bitPattern |= tms[i++] << 16;}
|
||||
ulen-=8;
|
||||
if (ulen > 0) {bitPattern |= tms[i++] << 24;}
|
||||
ulen-=8;
|
||||
fStatus = jtagClockFSM(handle, bitPattern, (ulen > 0) ? 32 : 32 + ulen, &error);
|
||||
CHECK_STATUS(fStatus);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int FX2Cable::toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len)
|
||||
{
|
||||
(void)tms;
|
||||
(void)tdi;
|
||||
FLStatus fStatus;
|
||||
const char *error = NULL;
|
||||
fStatus = jtagClocks(handle, clk_len, &error);
|
||||
CHECK_STATUS(fStatus);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int FX2Cable::flush()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FX2Cable::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
|
||||
{
|
||||
FLStatus fStatus;
|
||||
const char *error = NULL;
|
||||
if (rx)
|
||||
fStatus = jtagShiftInOut(handle, len, tx, rx, end, &error);
|
||||
else
|
||||
{
|
||||
fStatus = jtagShiftInOnly(handle, len, tx, end, &error);
|
||||
}
|
||||
|
||||
CHECK_STATUS(fStatus);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ enum communication_type {
|
|||
MODE_FTDI_SERIAL = 2, /*! ft2232, ft232H */
|
||||
MODE_DIRTYJTAG = 3, /*! JTAG probe firmware for STM32F1 */
|
||||
MODE_USBBLASTER = 4, /*! JTAG probe firmware for USBBLASTER */
|
||||
MODE_FX2 = 5, /* FX2 support through libFPGAlink */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -41,6 +42,9 @@ static std::map <std::string, cable_t> cable_list = {
|
|||
{"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}}},
|
||||
{"usb-blaster", {MODE_USBBLASTER, {}}},
|
||||
#ifdef ENABLE_FX2
|
||||
{"fx2", {MODE_FX2, {}}},
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 SRC_FX2CABLE_HPP_
|
||||
#define SRC_FX2CABLE_HPP_
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
#include "jtagInterface.hpp"
|
||||
#include "board.hpp"
|
||||
|
||||
|
||||
/*!
|
||||
* \file FX2Cable.hpp
|
||||
* \class FX2Cable
|
||||
* \brief concrete class between jtag implementation and FX2 cable
|
||||
*/
|
||||
|
||||
class FX2Cable : public JtagInterface {
|
||||
public:
|
||||
FX2Cable(bool verbose, const jtag_pins_conf_t *pin_conf, const char *ivp = NULL, const char *vp = NULL);
|
||||
virtual ~FX2Cable();
|
||||
|
||||
int setClkFreq(uint32_t clkHZ) override{(void)clkHZ; return 0;}
|
||||
int setClkFreq(uint32_t clkHZ, char use_divide_by_5) override {(void)clkHZ; (void)use_divide_by_5;return 0;}
|
||||
|
||||
/* TMS */
|
||||
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;
|
||||
/* clk */
|
||||
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 0;}
|
||||
|
||||
bool isFull() override { return false;}
|
||||
|
||||
int flush() override;
|
||||
|
||||
private:
|
||||
bool _verbose;
|
||||
|
||||
int write(uint8_t *in_buf, uint8_t *out_buf, int len, int rd_len);
|
||||
void transcode_pin_config(const jtag_pins_conf_t *pin_conf, char* buffer);
|
||||
struct FLContext *handle = NULL;
|
||||
};
|
||||
#endif // SRC_FX2CABLE_HPP_
|
||||
|
|
@ -33,6 +33,10 @@
|
|||
#include "dirtyJtag.hpp"
|
||||
#include "usbBlaster.hpp"
|
||||
|
||||
#ifdef ENABLE_FX2
|
||||
#include "fx2.hpp"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define DEBUG 0
|
||||
|
|
@ -103,6 +107,11 @@ void Jtag::init_internal(cable_t &cable, const string &dev, const string &serial
|
|||
case MODE_USBBLASTER:
|
||||
_jtag = new UsbBlaster(_verbose);
|
||||
break;
|
||||
#ifdef ENABLE_FX2
|
||||
case MODE_FX2:
|
||||
_jtag = new FX2Cable(_verbose, pin_conf);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
std::cerr << "Jtag: unknown cable type" << std::endl;
|
||||
throw std::exception();
|
||||
|
|
|
|||
10
src/main.cpp
10
src/main.cpp
|
|
@ -383,7 +383,7 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p
|
|||
"write bitstream in SRAM (default: true, only for Gowin and ECP5 devices)")
|
||||
("o,offset", "start offset in EEPROM",
|
||||
cxxopts::value<unsigned int>(args->offset))
|
||||
("pins", "pin config (only for ft232R) TDI:TDO:TCK:TMS",
|
||||
("pins", "pin config (only for ft232R and fx2) TDI:TDO:TCK:TMS",
|
||||
cxxopts::value<vector<string>>(pins))
|
||||
("quiet", "Produce quiet output (no progress bar)",
|
||||
cxxopts::value<bool>(quiet))
|
||||
|
|
@ -467,7 +467,7 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p
|
|||
for (int i = 0; i < 4; i++) {
|
||||
int pin_num;
|
||||
try {
|
||||
pin_num = std::stoi(pins[i], nullptr, 0);
|
||||
pin_num = std::stoi(pins[i], nullptr, 16);
|
||||
} catch (std::exception &e) {
|
||||
if (pins_list.find(pins[i]) == pins_list.end()) {
|
||||
printError("Invalid pin name");
|
||||
|
|
@ -476,7 +476,11 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p
|
|||
pin_num = pins_list[pins[i]];
|
||||
}
|
||||
|
||||
if (pin_num > 7 || pin_num < 0) {
|
||||
if ((pin_num > 7 || pin_num < 0) &&
|
||||
(pin_num > 0xD7 || pin_num < 0xD0) &&
|
||||
(pin_num > 0xC7 || pin_num < 0xC0) &&
|
||||
(pin_num > 0xB7 || pin_num < 0xB0) &&
|
||||
(pin_num > 0xA7 || pin_num < 0xA0)) {
|
||||
printError("Invalid pin ID");
|
||||
throw std::exception();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2012 Chris McClelland
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MAKESTUFF_COMMON_H
|
||||
#define MAKESTUFF_COMMON_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef __cplusplus
|
||||
#ifdef _MSC_VER
|
||||
typedef char bool;
|
||||
enum {
|
||||
false = 0,
|
||||
true = 1
|
||||
};
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define WARN_UNUSED_RESULT
|
||||
#define DLLEXPORT(t) __declspec(dllexport) t __stdcall
|
||||
#define PFSZD "%Iu"
|
||||
#ifdef _WIN64
|
||||
#define PFSZH "%016IX"
|
||||
#define WORD_LENGTH 64
|
||||
#else
|
||||
#define PFSZH "%08IX"
|
||||
#define WORD_LENGTH 32
|
||||
#endif
|
||||
#else
|
||||
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#define DLLEXPORT(t) t
|
||||
#define PFSZD "%zu"
|
||||
#ifdef __LP64__
|
||||
#define PFSZH "%016zX"
|
||||
#define WORD_LENGTH 64
|
||||
#else
|
||||
#define PFSZH "%08zX"
|
||||
#define WORD_LENGTH 32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void*)0)
|
||||
#endif
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
#ifndef __cplusplus
|
||||
#ifndef SDCC
|
||||
typedef unsigned long long uint64;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef signed char int8;
|
||||
typedef signed short int16;
|
||||
|
||||
#if (defined __AVR__ && defined __GNUC__) || defined SDCC
|
||||
// The embedded platforms have sizeof(int) = 2, so use long
|
||||
typedef signed long int32;
|
||||
typedef unsigned long uint32;
|
||||
#else
|
||||
// The i686 & x86_64 have sizeof(int) = 4
|
||||
typedef signed int int32;
|
||||
typedef unsigned int uint32;
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus
|
||||
#ifndef SDCC
|
||||
typedef signed long long int64;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef unsigned int bitfield;
|
||||
|
||||
#if defined __GNUC__
|
||||
#define swap32(x) __builtin_bswap32(x)
|
||||
#elif defined WIN32
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
unsigned long __cdecl _byteswap_ulong(unsigned long);
|
||||
#define swap32(x) _byteswap_ulong(x)
|
||||
#ifndef __cplusplus
|
||||
#define inline __inline
|
||||
#endif
|
||||
#endif
|
||||
#define swap16(x) ((uint16)((((x) & 0x00FF) << 8) | (((x) >> 8) & 0x00FF)))
|
||||
|
||||
// The C standard requires this two-level indirection thing
|
||||
#undef CONCAT
|
||||
#define CONCAT_INTERNAL(x, y) x ## y
|
||||
#define CONCAT(x, y) CONCAT_INTERNAL(x, y)
|
||||
|
||||
#define STR_INTERNAL(x) #x
|
||||
#define STR(x) STR_INTERNAL(x)
|
||||
|
||||
// The VA_NARGS() macro - count the number of arguments in a C99 variadic macro
|
||||
#define VA_EXPAND(x) x
|
||||
#define VA_NARGS(...) VA_EXPAND(VA_NARGS_INTERNAL(__VA_ARGS__, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 3, 2, 1))
|
||||
#define VA_NARGS_INTERNAL(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, N, ...) N
|
||||
|
||||
#define FAIL_INTERNAL2(code, label) { retVal = code; goto label; }
|
||||
#define FAIL_INTERNAL3(code, label, prefix) LIBERROR_IS_REQUIRED
|
||||
#define FAIL_INTERNAL4(code, label, prefix, arg) FAIL_INTERNAL5(code, label, prefix, arg)
|
||||
#define FAIL_INTERNAL5(code, label, ...) LIBERROR_IS_REQUIRED
|
||||
#define FAIL_RET(...) VA_EXPAND(CONCAT(FAIL_INTERNAL, VA_NARGS(__VA_ARGS__))(__VA_ARGS__))
|
||||
|
||||
// The CHECK_STATUS() macro - if condition is true, set a returnCode and jump to a label (exit,
|
||||
// cleanup etc). If liberror is included you can also give an error message.
|
||||
#define CHECK_INTERNAL3(condition, code, label) if ( condition ) { FAIL_RET(code, label); }
|
||||
#define CHECK_INTERNAL4(condition, code, label, prefix) LIBERROR_IS_REQUIRED
|
||||
#define CHECK_INTERNAL5(condition, code, label, ...) LIBERROR_IS_REQUIRED
|
||||
#define CHECK_STATUS(...) VA_EXPAND(CONCAT(CHECK_INTERNAL, VA_NARGS(__VA_ARGS__))(__VA_ARGS__))
|
||||
|
||||
#ifdef BYTE_ORDER
|
||||
#if BYTE_ORDER == 1234
|
||||
// Little-endian machines
|
||||
static inline uint16 bigEndian16(uint16 x) {
|
||||
return swap16(x);
|
||||
}
|
||||
static inline uint32 bigEndian32(uint32 x) {
|
||||
return swap32(x);
|
||||
}
|
||||
static inline uint16 littleEndian16(uint16 x) {
|
||||
return x;
|
||||
}
|
||||
static inline uint32 littleEndian32(uint32 x) {
|
||||
return x;
|
||||
}
|
||||
#elif BYTE_ORDER == 4321
|
||||
// Big-endian machines
|
||||
static inline uint16 bigEndian16(uint16 x) {
|
||||
return x;
|
||||
}
|
||||
static inline uint32 bigEndian32(uint32 x) {
|
||||
return x;
|
||||
}
|
||||
static inline uint16 littleEndian16(uint16 x) {
|
||||
return swap16(x);
|
||||
}
|
||||
static inline uint32 littleEndian32(uint32 x) {
|
||||
return swap32(x);
|
||||
}
|
||||
#else
|
||||
#error Unsupported BYTE_ORDER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue