Merge pull request #242 from niklasekstrom/libgpiod_bitbang
Add JTAG driver for libgpiod bitbanging
This commit is contained in:
commit
eeb1be0aeb
|
|
@ -11,6 +11,11 @@ else()
|
||||||
option(ENABLE_UDEV "use udev to search JTAG adapter from /dev/xx" ON)
|
option(ENABLE_UDEV "use udev to search JTAG adapter from /dev/xx" ON)
|
||||||
endif()
|
endif()
|
||||||
option(ENABLE_CMSISDAP "enable cmsis DAP interface (requires hidapi)" ON)
|
option(ENABLE_CMSISDAP "enable cmsis DAP interface (requires hidapi)" ON)
|
||||||
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
|
option(ENABLE_LIBGPIOD "enable libgpiod bitbang driver (requires libgpiod)" ON)
|
||||||
|
else()
|
||||||
|
set(ENABLE_LIBGPIOD OFF)
|
||||||
|
endif()
|
||||||
option(USE_PKGCONFIG "Use pkgconfig to find libraries" ON)
|
option(USE_PKGCONFIG "Use pkgconfig to find libraries" ON)
|
||||||
option(LINK_CMAKE_THREADS "Use CMake find_package to link the threading library" OFF)
|
option(LINK_CMAKE_THREADS "Use CMake find_package to link the threading library" OFF)
|
||||||
set(ISE_PATH "/opt/Xilinx/14.7" CACHE STRING "ise root directory (default: /opt/Xilinx/14.7)")
|
set(ISE_PATH "/opt/Xilinx/14.7" CACHE STRING "ise root directory (default: /opt/Xilinx/14.7)")
|
||||||
|
|
@ -61,6 +66,14 @@ if (USE_PKGCONFIG)
|
||||||
set(ENABLE_UDEV OFF)
|
set(ENABLE_UDEV OFF)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (ENABLE_LIBGPIOD)
|
||||||
|
pkg_check_modules(LIBGPIOD libgpiod)
|
||||||
|
if (NOT LIBGPIOD_FOUND)
|
||||||
|
message("libgpiod not found, disabling gpiod support")
|
||||||
|
set(ENABLE_LIBGPIOD OFF)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(OPENFPGALOADER_SOURCE
|
set(OPENFPGALOADER_SOURCE
|
||||||
|
|
@ -193,6 +206,16 @@ if (ENABLE_UDEV)
|
||||||
target_link_libraries(openFPGALoader ${LIBUDEV_LIBRARIES})
|
target_link_libraries(openFPGALoader ${LIBUDEV_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (ENABLE_LIBGPIOD)
|
||||||
|
link_directories(${LIBGPIOD_LIBRARY_DIRS})
|
||||||
|
include_directories(${LIBGPIOD_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(openFPGALoader ${LIBGPIOD_LIBRARIES})
|
||||||
|
add_definitions(-DENABLE_LIBGPIOD=1)
|
||||||
|
target_sources(openFPGALoader PRIVATE src/libgpiodJtagBitbang.cpp)
|
||||||
|
list (APPEND OPENFPGALOADER_HEADERS src/libgpiodJtagBitbang.hpp)
|
||||||
|
message("libgpiod support enabled")
|
||||||
|
endif(ENABLE_LIBGPIOD)
|
||||||
|
|
||||||
if (BUILD_STATIC)
|
if (BUILD_STATIC)
|
||||||
set_target_properties(openFPGALoader PROPERTIES LINK_SEARCH_END_STATIC 1)
|
set_target_properties(openFPGALoader PROPERTIES LINK_SEARCH_END_STATIC 1)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -236,3 +236,10 @@ xvc-server:
|
||||||
- Name: Xilinx Virtual Cable (server side)
|
- Name: Xilinx Virtual Cable (server side)
|
||||||
Description: Xilinx Virtual Cable (XVC) is a TCP/IP-based protocol that acts like a JTAG cable.
|
Description: Xilinx Virtual Cable (XVC) is a TCP/IP-based protocol that acts like a JTAG cable.
|
||||||
URL: https://github.com/Xilinx/XilinxVirtualCable
|
URL: https://github.com/Xilinx/XilinxVirtualCable
|
||||||
|
|
||||||
|
|
||||||
|
libgpiod:
|
||||||
|
|
||||||
|
- Name: Bitbang GPIO
|
||||||
|
Description: Bitbang GPIO pins on Linux host.
|
||||||
|
URL: https://github.com/brgl/libgpiod
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ enum communication_type {
|
||||||
MODE_CMSISDAP, /*! CMSIS-DAP JTAG probe */
|
MODE_CMSISDAP, /*! CMSIS-DAP JTAG probe */
|
||||||
MODE_DFU, /*! DFU based probe */
|
MODE_DFU, /*! DFU based probe */
|
||||||
MODE_XVC_CLIENT, /*! Xilinx Virtual Cable client */
|
MODE_XVC_CLIENT, /*! Xilinx Virtual Cable client */
|
||||||
|
MODE_LIBGPIOD_BITBANG, /*! Bitbang gpio pins */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -69,6 +70,9 @@ static std::map <std::string, cable_t> cable_list = {
|
||||||
{"usb-blaster", {MODE_USBBLASTER, {0x09Fb, 0x6001, 0, 0, 0, 0, 0, 0}}},
|
{"usb-blaster", {MODE_USBBLASTER, {0x09Fb, 0x6001, 0, 0, 0, 0, 0, 0}}},
|
||||||
{"usb-blasterII", {MODE_USBBLASTER, {0x09Fb, 0x6810, 0, 0, 0, 0, 0, 0}}},
|
{"usb-blasterII", {MODE_USBBLASTER, {0x09Fb, 0x6810, 0, 0, 0, 0, 0, 0}}},
|
||||||
{"xvc-client", {MODE_XVC_CLIENT, {}}},
|
{"xvc-client", {MODE_XVC_CLIENT, {}}},
|
||||||
|
#ifdef ENABLE_LIBGPIOD
|
||||||
|
{"libgpiod", {MODE_LIBGPIOD_BITBANG, {}}},
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,19 @@ FtdiJtagBitBang::FtdiJtagBitBang(const FTDIpp_MPSSE::mpsse_bit_config &cable,
|
||||||
{
|
{
|
||||||
unsigned char *ptr;
|
unsigned char *ptr;
|
||||||
|
|
||||||
_tck_pin = pin_conf->tck_pin;
|
_tck_pin = 1 << pin_conf->tck_pin;
|
||||||
_tms_pin = pin_conf->tms_pin;
|
_tms_pin = 1 << pin_conf->tms_pin;
|
||||||
_tdi_pin = pin_conf->tdi_pin;
|
_tdi_pin = 1 << pin_conf->tdi_pin;
|
||||||
_tdo_pin = pin_conf->tdo_pin;
|
_tdo_pin = 1 << pin_conf->tdo_pin;
|
||||||
|
|
||||||
|
/* Validate pins */
|
||||||
|
uint8_t pins[] = {_tck_pin, _tms_pin, _tdi_pin, _tdo_pin};
|
||||||
|
for (int i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) {
|
||||||
|
if (pins[i] > FT232RL_RI || pins[i] < FT232RL_TXD) {
|
||||||
|
printError("Invalid pin ID");
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* store FTDI TX Fifo size */
|
/* store FTDI TX Fifo size */
|
||||||
if (_pid == 0x6001) // FT232R
|
if (_pid == 0x6001) // FT232R
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,9 @@
|
||||||
#include "ftdipp_mpsse.hpp"
|
#include "ftdipp_mpsse.hpp"
|
||||||
#include "ftdiJtagBitbang.hpp"
|
#include "ftdiJtagBitbang.hpp"
|
||||||
#include "ftdiJtagMPSSE.hpp"
|
#include "ftdiJtagMPSSE.hpp"
|
||||||
|
#ifdef ENABLE_LIBGPIOD
|
||||||
|
#include "libgpiodJtagBitbang.hpp"
|
||||||
|
#endif
|
||||||
#include "jlink.hpp"
|
#include "jlink.hpp"
|
||||||
#ifdef ENABLE_CMSISDAP
|
#ifdef ENABLE_CMSISDAP
|
||||||
#include "cmsisDAP.hpp"
|
#include "cmsisDAP.hpp"
|
||||||
|
|
@ -130,6 +133,11 @@ void Jtag::init_internal(cable_t &cable, const string &dev, const string &serial
|
||||||
#else
|
#else
|
||||||
std::cerr << "Jtag: support for xvc-client was not enabled at compile time" << std::endl;
|
std::cerr << "Jtag: support for xvc-client was not enabled at compile time" << std::endl;
|
||||||
throw std::exception();
|
throw std::exception();
|
||||||
|
#endif
|
||||||
|
#ifdef ENABLE_LIBGPIOD
|
||||||
|
case MODE_LIBGPIOD_BITBANG:
|
||||||
|
_jtag = new LibgpiodJtagBitbang(pin_conf, dev, clkHZ, _verbose);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
std::cerr << "Jtag: unknown cable type" << std::endl;
|
std::cerr << "Jtag: unknown cable type" << std::endl;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,225 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||||
|
*
|
||||||
|
* libgpiod bitbang driver added by Niklas Ekström <mail@niklasekstrom.nu> in 2022
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <gpiod.h>
|
||||||
|
|
||||||
|
#include "display.hpp"
|
||||||
|
#include "libgpiodJtagBitbang.hpp"
|
||||||
|
|
||||||
|
#define DEBUG 1
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define display(...) \
|
||||||
|
do { \
|
||||||
|
if (_verbose) fprintf(stdout, __VA_ARGS__); \
|
||||||
|
}while(0)
|
||||||
|
#else
|
||||||
|
#define display(...) do {}while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LibgpiodJtagBitbang::LibgpiodJtagBitbang(
|
||||||
|
const jtag_pins_conf_t *pin_conf,
|
||||||
|
const std::string &dev, uint32_t clkHZ, uint8_t verbose)
|
||||||
|
{
|
||||||
|
_verbose = verbose;
|
||||||
|
|
||||||
|
_tck_pin = pin_conf->tck_pin;
|
||||||
|
_tms_pin = pin_conf->tms_pin;
|
||||||
|
_tdi_pin = pin_conf->tdi_pin;
|
||||||
|
_tdo_pin = pin_conf->tdo_pin;
|
||||||
|
|
||||||
|
std::string chip_dev = dev;
|
||||||
|
if (chip_dev.empty())
|
||||||
|
chip_dev = "/dev/gpiochip0";
|
||||||
|
|
||||||
|
display("libgpiod jtag bitbang driver, dev=%s, tck_pin=%d, tms_pin=%d, tdi_pin=%d, tdo_pin=%d\n",
|
||||||
|
chip_dev.c_str(), _tck_pin, _tms_pin, _tdi_pin, _tdo_pin);
|
||||||
|
|
||||||
|
if (chip_dev.length() < 14 || chip_dev.substr(0, 13) != "/dev/gpiochip") {
|
||||||
|
display("Invalid gpio chip %s, should be /dev/gpiochipX\n", chip_dev.c_str());
|
||||||
|
throw std::runtime_error("Invalid gpio chip\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate pins */
|
||||||
|
int pins[] = {_tck_pin, _tms_pin, _tdi_pin, _tdo_pin};
|
||||||
|
for (int i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) {
|
||||||
|
if (pins[i] < 0 || pins[i] >= 1000) {
|
||||||
|
display("Pin %d is outside of valid range\n", pins[i]);
|
||||||
|
throw std::runtime_error("A pin is outside of valid range\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = i + 1; j < sizeof(pins) / sizeof(pins[0]); j++) {
|
||||||
|
if (pins[i] == pins[j]) {
|
||||||
|
display("Two or more pins are assigned to the same pin number %d\n", pins[i]);
|
||||||
|
throw std::runtime_error("Two or more pins are assigned to the same pin number\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_chip = gpiod_chip_open(chip_dev.c_str());
|
||||||
|
if (!_chip) {
|
||||||
|
display("Unable to open gpio chip %s\n", chip_dev.c_str());
|
||||||
|
throw std::runtime_error("Unable to open gpio chip\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
_tdo_line = get_line(_tdo_pin, 0, GPIOD_LINE_REQUEST_DIRECTION_INPUT);
|
||||||
|
_tdi_line = get_line(_tdi_pin, 0, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT);
|
||||||
|
_tck_line = get_line(_tck_pin, 0, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT);
|
||||||
|
_tms_line = get_line(_tms_pin, 1, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT);
|
||||||
|
|
||||||
|
_curr_tdi = 0;
|
||||||
|
_curr_tck = 0;
|
||||||
|
_curr_tms = 1;
|
||||||
|
|
||||||
|
// FIXME: I'm unsure how this value should be set.
|
||||||
|
// Maybe experiment, or think through what it should be.
|
||||||
|
_clkHZ = 5000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
LibgpiodJtagBitbang::~LibgpiodJtagBitbang()
|
||||||
|
{
|
||||||
|
if (_tms_line)
|
||||||
|
gpiod_line_release(_tms_line);
|
||||||
|
|
||||||
|
if (_tck_line)
|
||||||
|
gpiod_line_release(_tck_line);
|
||||||
|
|
||||||
|
if (_tdi_line)
|
||||||
|
gpiod_line_release(_tdi_line);
|
||||||
|
|
||||||
|
if (_tdo_line)
|
||||||
|
gpiod_line_release(_tdo_line);
|
||||||
|
|
||||||
|
if (_chip)
|
||||||
|
gpiod_chip_close(_chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpiod_line *LibgpiodJtagBitbang::get_line(unsigned int offset, int val, int dir)
|
||||||
|
{
|
||||||
|
gpiod_line *line = gpiod_chip_get_line(_chip, offset);
|
||||||
|
if (!line) {
|
||||||
|
display("Unable to get gpio line %d\n", offset);
|
||||||
|
throw std::runtime_error("Unable to get gpio line\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
gpiod_line_request_config config = {
|
||||||
|
.consumer = "openFPGALoader",
|
||||||
|
.request_type = dir,
|
||||||
|
.flags = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
int ret = gpiod_line_request(line, &config, val);
|
||||||
|
if (ret < 0) {
|
||||||
|
display("Error requesting gpio line %d\n", offset);
|
||||||
|
throw std::runtime_error("Error requesting gpio line\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LibgpiodJtagBitbang::update_pins(int tck, int tms, int tdi)
|
||||||
|
{
|
||||||
|
if (tdi != _curr_tdi) {
|
||||||
|
if (gpiod_line_set_value(_tdi_line, tdi) < 0)
|
||||||
|
display("Unable to set gpio pin tdi\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tms != _curr_tms) {
|
||||||
|
if (gpiod_line_set_value(_tms_line, tms) < 0)
|
||||||
|
display("Unable to set gpio pin tms\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tck != _curr_tck) {
|
||||||
|
if (gpiod_line_set_value(_tck_line, tck) < 0)
|
||||||
|
display("Unable to set gpio pin tck\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
_curr_tdi = tdi;
|
||||||
|
_curr_tms = tms;
|
||||||
|
_curr_tck = tck;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LibgpiodJtagBitbang::read_tdo()
|
||||||
|
{
|
||||||
|
return gpiod_line_get_value(_tdo_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
int LibgpiodJtagBitbang::setClkFreq(uint32_t clkHZ)
|
||||||
|
{
|
||||||
|
// FIXME: The assumption is that calling the gpiod_line_set_value
|
||||||
|
// routine will limit the clock frequency to lower than what is specified.
|
||||||
|
// This needs to be verified, and possibly artificial delays should be added.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LibgpiodJtagBitbang::writeTMS(uint8_t *tms_buf, uint32_t len, bool flush_buffer)
|
||||||
|
{
|
||||||
|
int tms;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < len; i++) {
|
||||||
|
tms = ((tms_buf[i >> 3] & (1 << (i & 7))) ? 1 : 0);
|
||||||
|
|
||||||
|
update_pins(0, tms, 0);
|
||||||
|
update_pins(1, tms, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_pins(0, tms, 0);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LibgpiodJtagBitbang::writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end)
|
||||||
|
{
|
||||||
|
int tms = _curr_tms;
|
||||||
|
int tdi = _curr_tdi;
|
||||||
|
|
||||||
|
if (rx)
|
||||||
|
memset(rx, 0, len / 8);
|
||||||
|
|
||||||
|
for (uint32_t i = 0, pos = 0; i < len; i++) {
|
||||||
|
if (end && (i == len - 1))
|
||||||
|
tms = 1;
|
||||||
|
|
||||||
|
if (tx)
|
||||||
|
tdi = (tx[i >> 3] & (1 << (i & 7))) ? 1 : 0;
|
||||||
|
|
||||||
|
update_pins(0, tms, tdi);
|
||||||
|
update_pins(1, tms, tdi);
|
||||||
|
|
||||||
|
if (rx) {
|
||||||
|
if (read_tdo() > 0)
|
||||||
|
rx[i >> 3] |= 1 << (i & 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update_pins(0, tms, tdi);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LibgpiodJtagBitbang::toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < clk_len; i++) {
|
||||||
|
update_pins(0, tms, tdi);
|
||||||
|
update_pins(1, tms, tdi);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_pins(0, tms, tdi);
|
||||||
|
|
||||||
|
return clk_len;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
||||||
|
*
|
||||||
|
* libgpiod bitbang driver added by Niklas Ekström <mail@niklasekstrom.nu> in 2022
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBGPIODBITBANG_H
|
||||||
|
#define LIBGPIODBITBANG_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "board.hpp"
|
||||||
|
#include "jtagInterface.hpp"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \file LibgpiodJtagBitbang.hpp
|
||||||
|
* \class LibgpiodJtagBitbang
|
||||||
|
* \brief concrete class between jtag implementation and gpio bitbang
|
||||||
|
* \author Niklas Ekström
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct gpiod_chip;
|
||||||
|
struct gpiod_line;
|
||||||
|
|
||||||
|
class LibgpiodJtagBitbang : public JtagInterface {
|
||||||
|
public:
|
||||||
|
LibgpiodJtagBitbang(const jtag_pins_conf_t *pin_conf,
|
||||||
|
const std::string &dev, uint32_t clkHZ, uint8_t verbose);
|
||||||
|
virtual ~LibgpiodJtagBitbang();
|
||||||
|
|
||||||
|
int setClkFreq(uint32_t clkHZ) override;
|
||||||
|
int writeTMS(uint8_t *tms_buf, uint32_t len, bool flush_buffer) override;
|
||||||
|
int writeTDI(uint8_t *tx, uint8_t *rx, uint32_t len, bool end) override;
|
||||||
|
int toggleClk(uint8_t tms, uint8_t tdo, uint32_t clk_len) override;
|
||||||
|
|
||||||
|
int get_buffer_size() override { return 0; }
|
||||||
|
bool isFull() override { return false; }
|
||||||
|
int flush() override { return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
gpiod_line *get_line(unsigned int offset, int val, int dir);
|
||||||
|
int update_pins(int tck, int tms, int tdi);
|
||||||
|
int read_tdo();
|
||||||
|
|
||||||
|
bool _verbose;
|
||||||
|
|
||||||
|
int _tck_pin;
|
||||||
|
int _tms_pin;
|
||||||
|
int _tdo_pin;
|
||||||
|
int _tdi_pin;
|
||||||
|
|
||||||
|
gpiod_chip *_chip;
|
||||||
|
|
||||||
|
gpiod_line *_tck_line;
|
||||||
|
gpiod_line *_tms_line;
|
||||||
|
gpiod_line *_tdo_line;
|
||||||
|
gpiod_line *_tdi_line;
|
||||||
|
|
||||||
|
int _curr_tms;
|
||||||
|
int _curr_tdi;
|
||||||
|
int _curr_tck;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
36
src/main.cpp
36
src/main.cpp
|
|
@ -617,6 +617,14 @@ static int parse_eng(string arg, double *dst) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_bit_index(int mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
if (mask & (1 << i))
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* arguments parser */
|
/* arguments parser */
|
||||||
int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *pins_config)
|
int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *pins_config)
|
||||||
{
|
{
|
||||||
|
|
@ -649,7 +657,7 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p
|
||||||
|
|
||||||
("ftdi-serial", "FTDI chip serial number", cxxopts::value<string>(args->ftdi_serial))
|
("ftdi-serial", "FTDI chip serial number", cxxopts::value<string>(args->ftdi_serial))
|
||||||
("ftdi-channel", "FTDI chip channel number (channels 0-3 map to A-D)", cxxopts::value<int>(args->ftdi_channel))
|
("ftdi-channel", "FTDI chip channel number (channels 0-3 map to A-D)", cxxopts::value<int>(args->ftdi_channel))
|
||||||
#ifdef USE_UDEV
|
#if defined(USE_UDEV) || defined(ENABLE_LIBGPIOD)
|
||||||
("d,device", "device to use (/dev/ttyUSBx)",
|
("d,device", "device to use (/dev/ttyUSBx)",
|
||||||
cxxopts::value<string>(args->device))
|
cxxopts::value<string>(args->device))
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -683,7 +691,7 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p
|
||||||
"write bitstream in SRAM (default: true)")
|
"write bitstream in SRAM (default: true)")
|
||||||
("o,offset", "start offset in EEPROM",
|
("o,offset", "start offset in EEPROM",
|
||||||
cxxopts::value<unsigned int>(args->offset))
|
cxxopts::value<unsigned int>(args->offset))
|
||||||
("pins", "pin config (only for ft232R) TDI:TDO:TCK:TMS",
|
("pins", "pin config TDI:TDO:TCK:TMS",
|
||||||
cxxopts::value<vector<string>>(pins))
|
cxxopts::value<vector<string>>(pins))
|
||||||
("probe-firmware", "firmware for JTAG probe (usbBlasterII)",
|
("probe-firmware", "firmware for JTAG probe (usbBlasterII)",
|
||||||
cxxopts::value<string>(args->probe_firmware))
|
cxxopts::value<string>(args->probe_firmware))
|
||||||
|
|
@ -788,20 +796,19 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::map <std::string, int> pins_list = {
|
static std::map <std::string, int> pins_list = {
|
||||||
{"TXD", FT232RL_TXD},
|
{"TXD", get_bit_index(FT232RL_TXD)},
|
||||||
{"RXD", FT232RL_RXD},
|
{"RXD", get_bit_index(FT232RL_RXD)},
|
||||||
{"RTS", FT232RL_RTS},
|
{"RTS", get_bit_index(FT232RL_RTS)},
|
||||||
{"CTS", FT232RL_CTS},
|
{"CTS", get_bit_index(FT232RL_CTS)},
|
||||||
{"DTR", FT232RL_DTR},
|
{"DTR", get_bit_index(FT232RL_DTR)},
|
||||||
{"DSR", FT232RL_DSR},
|
{"DSR", get_bit_index(FT232RL_DSR)},
|
||||||
{"DCD", FT232RL_DCD},
|
{"DCD", get_bit_index(FT232RL_DCD)},
|
||||||
{"RI" , FT232RL_RI }};
|
{"RI" , get_bit_index(FT232RL_RI) }};
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
int pin_num;
|
int pin_num;
|
||||||
try {
|
try {
|
||||||
pin_num = 1 << std::stoi(pins[i], nullptr, 0);
|
pin_num = std::stoi(pins[i], nullptr, 0);
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
if (pins_list.find(pins[i]) == pins_list.end()) {
|
if (pins_list.find(pins[i]) == pins_list.end()) {
|
||||||
printError("Invalid pin name");
|
printError("Invalid pin name");
|
||||||
|
|
@ -810,11 +817,6 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p
|
||||||
pin_num = pins_list[pins[i]];
|
pin_num = pins_list[pins[i]];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pin_num > FT232RL_RI || pin_num < FT232RL_TXD) {
|
|
||||||
printError("Invalid pin ID");
|
|
||||||
throw std::exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0:
|
case 0:
|
||||||
pins_config->tdi_pin = pin_num;
|
pins_config->tdi_pin = pin_num;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue