2021-06-26 15:24:07 +02:00
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
2019-09-26 18:29:20 +02:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2019 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
|
|
|
|
*/
|
2022-11-12 22:58:17 +01:00
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
2019-09-26 18:29:20 +02:00
|
|
|
#include <fstream>
|
2019-12-07 06:40:29 +01:00
|
|
|
#include <iomanip>
|
2019-09-26 18:29:20 +02:00
|
|
|
#include <iostream>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
2019-09-28 15:46:12 +02:00
|
|
|
#include "altera.hpp"
|
2020-08-20 16:58:20 +02:00
|
|
|
#include "anlogic.hpp"
|
2019-09-26 18:29:20 +02:00
|
|
|
#include "board.hpp"
|
|
|
|
|
#include "cable.hpp"
|
2021-12-10 12:12:32 +01:00
|
|
|
#include "colognechip.hpp"
|
2022-11-12 22:58:17 +01:00
|
|
|
#include "cxxopts.hpp"
|
2019-09-26 18:29:20 +02:00
|
|
|
#include "device.hpp"
|
2021-06-20 10:25:49 +02:00
|
|
|
#include "dfu.hpp"
|
2019-12-07 06:40:29 +01:00
|
|
|
#include "display.hpp"
|
2020-10-31 10:41:44 +01:00
|
|
|
#include "efinix.hpp"
|
2020-10-06 08:38:24 +02:00
|
|
|
#include "ftdispi.hpp"
|
2019-12-06 07:29:28 +01:00
|
|
|
#include "gowin.hpp"
|
2020-10-31 15:02:54 +01:00
|
|
|
#include "ice40.hpp"
|
2019-11-18 16:04:50 +01:00
|
|
|
#include "lattice.hpp"
|
2022-10-15 22:28:06 +02:00
|
|
|
#include "libusb_ll.hpp"
|
2020-03-06 09:05:57 +01:00
|
|
|
#include "jtag.hpp"
|
2019-09-28 15:46:12 +02:00
|
|
|
#include "part.hpp"
|
2020-10-06 08:38:24 +02:00
|
|
|
#include "spiFlash.hpp"
|
2020-10-07 07:47:46 +02:00
|
|
|
#include "rawParser.hpp"
|
2019-09-26 18:29:20 +02:00
|
|
|
#include "xilinx.hpp"
|
2022-11-11 00:01:21 +01:00
|
|
|
#include "svf_jtag.hpp"
|
2022-07-06 21:14:25 +02:00
|
|
|
#ifdef ENABLE_XVC
|
2022-07-06 20:58:34 +02:00
|
|
|
#include "xvc_server.hpp"
|
2022-07-06 21:14:25 +02:00
|
|
|
#endif
|
2019-09-26 18:29:20 +02:00
|
|
|
|
2021-07-11 16:27:46 +02:00
|
|
|
#define DEFAULT_FREQ 6000000
|
|
|
|
|
|
2019-09-26 18:29:20 +02:00
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
struct arguments {
|
2021-01-30 07:57:49 +01:00
|
|
|
int8_t verbose;
|
2024-06-09 09:28:52 +02:00
|
|
|
bool reset, detect, detect_flash, verify, scan_usb;
|
2019-09-26 18:29:20 +02:00
|
|
|
unsigned int offset;
|
|
|
|
|
string bit_file;
|
2023-01-21 14:20:49 +01:00
|
|
|
string secondary_bit_file;
|
2019-11-19 09:02:24 +01:00
|
|
|
string device;
|
2019-09-26 18:29:20 +02:00
|
|
|
string cable;
|
2020-09-29 14:16:30 +02:00
|
|
|
string ftdi_serial;
|
2020-09-22 10:45:44 +02:00
|
|
|
int ftdi_channel;
|
2023-04-10 17:59:07 +02:00
|
|
|
int status_pin;
|
2020-05-25 10:31:37 +02:00
|
|
|
uint32_t freq;
|
2022-03-11 07:45:48 +01:00
|
|
|
bool invert_read_edge;
|
2019-09-26 18:29:20 +02:00
|
|
|
string board;
|
2020-08-04 17:36:33 +02:00
|
|
|
bool pin_config;
|
2019-12-07 06:40:29 +01:00
|
|
|
bool list_cables;
|
|
|
|
|
bool list_boards;
|
|
|
|
|
bool list_fpga;
|
2021-02-18 21:09:34 +01:00
|
|
|
Device::prog_type_t prg_type;
|
2020-02-16 10:13:09 +01:00
|
|
|
bool is_list_command;
|
2020-10-06 08:38:24 +02:00
|
|
|
bool spi;
|
2021-06-20 10:25:49 +02:00
|
|
|
bool dfu;
|
2021-02-21 18:30:13 +01:00
|
|
|
string file_type;
|
2021-04-19 21:17:08 +02:00
|
|
|
string fpga_part;
|
2022-12-10 22:05:37 +01:00
|
|
|
string bridge_path;
|
2021-05-13 16:07:40 +02:00
|
|
|
string probe_firmware;
|
2021-05-15 15:26:09 +02:00
|
|
|
int index_chain;
|
2021-06-24 18:19:09 +02:00
|
|
|
unsigned int file_size;
|
2023-01-21 14:20:49 +01:00
|
|
|
string target_flash;
|
2021-09-15 20:18:49 +02:00
|
|
|
bool external_flash;
|
2021-10-03 18:33:55 +02:00
|
|
|
int16_t altsetting;
|
|
|
|
|
uint16_t vid;
|
|
|
|
|
uint16_t pid;
|
2022-08-29 20:58:51 +02:00
|
|
|
int16_t cable_index;
|
2023-02-25 17:10:01 +01:00
|
|
|
uint8_t bus_addr;
|
|
|
|
|
uint8_t device_addr;
|
2022-04-11 06:53:22 +02:00
|
|
|
string ip_adr;
|
2021-12-22 19:12:33 +01:00
|
|
|
uint32_t protect_flash;
|
|
|
|
|
bool unprotect_flash;
|
2024-08-23 09:19:11 +02:00
|
|
|
bool enable_quad;
|
|
|
|
|
bool disable_quad;
|
2022-03-10 08:51:54 +01:00
|
|
|
bool bulk_erase_flash;
|
2021-12-22 19:12:33 +01:00
|
|
|
string flash_sector;
|
2022-05-11 14:29:08 +02:00
|
|
|
bool skip_load_bridge;
|
2022-05-24 07:29:35 +02:00
|
|
|
bool skip_reset;
|
2022-07-06 20:58:34 +02:00
|
|
|
/* xvc server */
|
|
|
|
|
bool xvc;
|
|
|
|
|
int port;
|
|
|
|
|
string interface;
|
2022-07-20 23:25:53 +02:00
|
|
|
string mcufw;
|
2022-07-20 23:27:32 +02:00
|
|
|
bool conmcu;
|
2023-11-10 22:00:13 +01:00
|
|
|
std::map<uint32_t, misc_device> user_misc_devs;
|
2023-11-25 08:47:24 +01:00
|
|
|
bool read_dna;
|
|
|
|
|
bool read_xadc;
|
2024-04-21 14:35:23 +02:00
|
|
|
string read_register;
|
2019-09-26 18:29:20 +02:00
|
|
|
};
|
|
|
|
|
|
2022-07-06 20:58:34 +02:00
|
|
|
int run_xvc_server(const struct arguments &args, const cable_t &cable,
|
|
|
|
|
const jtag_pins_conf_t *pins_config);
|
|
|
|
|
|
2022-11-12 22:58:17 +01:00
|
|
|
int parse_opt(int argc, char **argv, struct arguments *args,
|
|
|
|
|
jtag_pins_conf_t *pins_config);
|
2019-12-07 06:40:29 +01:00
|
|
|
|
|
|
|
|
void displaySupported(const struct arguments &args);
|
2019-09-26 18:29:20 +02:00
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
|
{
|
2020-03-07 10:56:34 +01:00
|
|
|
cable_t cable;
|
2021-04-19 21:17:08 +02:00
|
|
|
target_board_t *board = NULL;
|
2020-08-04 17:36:33 +02:00
|
|
|
jtag_pins_conf_t pins_config = {0, 0, 0, 0};
|
2019-09-26 18:29:20 +02:00
|
|
|
|
|
|
|
|
/* command line args. */
|
2024-06-09 09:28:52 +02:00
|
|
|
struct arguments args = {0,
|
|
|
|
|
//reset, detect, detect_flash, verify, scan_usb
|
|
|
|
|
false, false, false, false, false,
|
|
|
|
|
0, "", "", "", "-", "", -1,
|
2023-04-10 17:59:07 +02:00
|
|
|
-1, 0, false, "-", false, false, false, false, Device::PRG_NONE, false,
|
2022-12-10 22:05:37 +01:00
|
|
|
/* spi dfu file_type fpga_part bridge_path probe_firmware */
|
|
|
|
|
false, false, "", "", "", "",
|
2023-01-21 14:20:49 +01:00
|
|
|
/* index_chain file_size target_flash external_flash altsetting */
|
|
|
|
|
-1, 0, "primary", false, -1,
|
2022-10-15 17:41:30 +02:00
|
|
|
/* vid, pid, index bus_addr, device_addr */
|
2023-08-10 12:50:26 +02:00
|
|
|
0, 0, -1, 0, 0,
|
2024-08-23 09:19:11 +02:00
|
|
|
"127.0.0.1", 0, false, false, false, false, "", false, false,
|
2022-07-06 20:58:34 +02:00
|
|
|
/* xvc server */
|
|
|
|
|
false, 3721, "-",
|
2023-11-25 08:47:24 +01:00
|
|
|
"", false, {}, // mcufw conmcu, user_misc_dev_list
|
2024-04-21 14:35:23 +02:00
|
|
|
false, false, "" // read_dna, read_xadc, read_register
|
2022-07-06 20:58:34 +02:00
|
|
|
};
|
2019-09-26 18:29:20 +02:00
|
|
|
/* parse arguments */
|
2020-07-23 18:32:18 +02:00
|
|
|
try {
|
2020-08-04 17:36:33 +02:00
|
|
|
if (parse_opt(argc, argv, &args, &pins_config))
|
2020-07-23 18:32:18 +02:00
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
printError("Error in parse arg step");
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
2019-09-26 18:29:20 +02:00
|
|
|
|
2020-02-16 10:13:09 +01:00
|
|
|
if (args.is_list_command) {
|
2019-12-07 06:40:29 +01:00
|
|
|
displaySupported(args);
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-18 21:09:34 +01:00
|
|
|
if (args.prg_type == Device::WR_SRAM)
|
|
|
|
|
cout << "write to ram" << endl;
|
|
|
|
|
if (args.prg_type == Device::WR_FLASH)
|
|
|
|
|
cout << "write to flash" << endl;
|
|
|
|
|
|
2021-11-11 17:20:51 +01:00
|
|
|
if (args.board[0] != '-') {
|
|
|
|
|
if (board_list.find(args.board) != board_list.end()) {
|
|
|
|
|
board = &(board_list[args.board]);
|
|
|
|
|
} else {
|
|
|
|
|
printError("Error: cannot find board \'" +args.board + "\'");
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
2020-10-31 08:40:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if a board name is specified try to use this to determine cable */
|
|
|
|
|
if (board) {
|
2020-08-04 17:36:33 +02:00
|
|
|
/* set pins config (only when user has not already provided
|
|
|
|
|
* configuration
|
|
|
|
|
*/
|
|
|
|
|
if (!args.pin_config) {
|
2020-10-31 08:40:18 +01:00
|
|
|
pins_config.tdi_pin = board->jtag_pins_config.tdi_pin;
|
|
|
|
|
pins_config.tdo_pin = board->jtag_pins_config.tdo_pin;
|
|
|
|
|
pins_config.tms_pin = board->jtag_pins_config.tms_pin;
|
|
|
|
|
pins_config.tck_pin = board->jtag_pins_config.tck_pin;
|
2020-08-04 17:36:33 +02:00
|
|
|
}
|
2020-03-07 11:44:17 +01:00
|
|
|
/* search for cable */
|
2020-10-31 08:40:18 +01:00
|
|
|
auto t = cable_list.find(board->cable_name);
|
2023-03-09 21:19:35 +01:00
|
|
|
if (t != cable_list.end()) {
|
|
|
|
|
if (args.cable[0] == '-') { // no user selection
|
2022-11-12 22:58:17 +01:00
|
|
|
args.cable = (*t).first; // use board default cable
|
2020-10-21 13:41:26 +02:00
|
|
|
} else {
|
|
|
|
|
cout << "Board default cable overridden with " << args.cable << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-04-19 21:17:08 +02:00
|
|
|
|
|
|
|
|
/* Xilinx only: to write flash exact fpga model must be provided */
|
|
|
|
|
if (!board->fpga_part.empty() && !args.fpga_part.empty())
|
|
|
|
|
printInfo("Board default fpga part overridden with " + args.fpga_part);
|
|
|
|
|
else if (!board->fpga_part.empty() && args.fpga_part.empty())
|
|
|
|
|
args.fpga_part = board->fpga_part;
|
2021-07-11 16:20:15 +02:00
|
|
|
|
2021-07-14 08:04:43 +02:00
|
|
|
/* Some boards can override the default clock speed
|
|
|
|
|
* if args.freq == 0: the `--freq` arg has not been used
|
|
|
|
|
* => apply board->default_freq with a value of
|
|
|
|
|
* 0 (no default frequency) or > 0 (board has a default frequency)
|
|
|
|
|
*/
|
|
|
|
|
if (args.freq == 0)
|
|
|
|
|
args.freq = board->default_freq;
|
2020-02-01 18:07:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (args.cable[0] == '-') { /* if no board and no cable */
|
2023-03-09 21:19:35 +01:00
|
|
|
printWarn("No cable or board specified: using direct ft2232 interface");
|
2019-09-26 18:29:20 +02:00
|
|
|
args.cable = "ft2232";
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-14 08:04:43 +02:00
|
|
|
/* if args.freq == 0: no user requirement nor board default
|
|
|
|
|
* clock speed => set default frequency
|
|
|
|
|
*/
|
|
|
|
|
if (args.freq == 0)
|
|
|
|
|
args.freq = DEFAULT_FREQ;
|
|
|
|
|
|
2019-09-26 18:29:20 +02:00
|
|
|
auto select_cable = cable_list.find(args.cable);
|
|
|
|
|
if (select_cable == cable_list.end()) {
|
2020-07-11 07:47:27 +02:00
|
|
|
printError("error : " + args.cable + " not found");
|
2019-09-26 18:29:20 +02:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
cable = select_cable->second;
|
|
|
|
|
|
2020-09-22 10:45:44 +02:00
|
|
|
if (args.ftdi_channel != -1) {
|
2020-09-22 18:22:51 +02:00
|
|
|
if (cable.type != MODE_FTDI_SERIAL && cable.type != MODE_FTDI_BITBANG){
|
|
|
|
|
printError("Error: FTDI channel param is for FTDI cables.");
|
2020-09-22 10:45:44 +02:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-12 22:58:17 +01:00
|
|
|
const int mapping[] = {INTERFACE_A, INTERFACE_B, INTERFACE_C,
|
|
|
|
|
INTERFACE_D};
|
2020-09-22 18:22:51 +02:00
|
|
|
cable.config.interface = mapping[args.ftdi_channel];
|
2020-09-22 10:45:44 +02:00
|
|
|
}
|
|
|
|
|
|
2020-10-07 07:37:40 +02:00
|
|
|
if (!args.ftdi_serial.empty()) {
|
2020-09-29 14:16:30 +02:00
|
|
|
if (cable.type != MODE_FTDI_SERIAL && cable.type != MODE_FTDI_BITBANG){
|
|
|
|
|
printError("Error: FTDI serial param is for FTDI cables.");
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 17:59:07 +02:00
|
|
|
if (args.status_pin != -1) {
|
|
|
|
|
if (cable.type != MODE_FTDI_SERIAL){
|
|
|
|
|
printError("Error: FTDI status pin is for FTDI MPSSE cables.");
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-13 06:51:22 +02:00
|
|
|
if (args.vid != 0) {
|
|
|
|
|
printInfo("Cable VID overridden");
|
2022-10-15 16:17:32 +02:00
|
|
|
cable.vid = args.vid;
|
2021-10-13 06:51:22 +02:00
|
|
|
}
|
|
|
|
|
if (args.pid != 0) {
|
|
|
|
|
printInfo("Cable PID overridden");
|
2022-10-15 16:17:32 +02:00
|
|
|
cable.pid = args.pid;
|
2021-10-13 06:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
2022-10-15 17:41:30 +02:00
|
|
|
cable.bus_addr = args.bus_addr;
|
|
|
|
|
cable.device_addr = args.device_addr;
|
|
|
|
|
|
2023-04-10 17:59:07 +02:00
|
|
|
// always set these
|
2022-06-01 16:17:38 +02:00
|
|
|
cable.config.index = args.cable_index;
|
2023-04-10 17:59:07 +02:00
|
|
|
cable.config.status_pin = args.status_pin;
|
2022-06-01 16:17:38 +02:00
|
|
|
|
2020-10-07 07:47:46 +02:00
|
|
|
/* FLASH direct access */
|
2020-10-31 08:40:18 +01:00
|
|
|
if (args.spi || (board && board->mode == COMM_SPI)) {
|
2022-01-18 08:09:54 +01:00
|
|
|
/* if no instruction from user -> select flash mode */
|
|
|
|
|
if (args.prg_type == Device::PRG_NONE)
|
|
|
|
|
args.prg_type = Device::WR_FLASH;
|
|
|
|
|
|
2020-10-07 07:47:46 +02:00
|
|
|
FtdiSpi *spi = NULL;
|
2021-12-22 19:12:33 +01:00
|
|
|
spi_pins_conf_t pins_config;
|
|
|
|
|
if (board)
|
|
|
|
|
pins_config = board->spi_pins_config;
|
2020-10-07 07:47:46 +02:00
|
|
|
|
|
|
|
|
try {
|
2023-07-30 07:19:17 +02:00
|
|
|
spi = new FtdiSpi(cable, pins_config, args.freq, args.verbose);
|
2020-10-07 07:47:46 +02:00
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
printError("Error: Failed to claim cable");
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-22 19:12:33 +01:00
|
|
|
int spi_ret = EXIT_SUCCESS;
|
|
|
|
|
|
|
|
|
|
if (board && board->manufacturer != "none") {
|
|
|
|
|
Device *target;
|
|
|
|
|
if (board->manufacturer == "efinix") {
|
|
|
|
|
target = new Efinix(spi, args.bit_file, args.file_type,
|
|
|
|
|
board->reset_pin, board->done_pin, board->oe_pin,
|
|
|
|
|
args.verify, args.verbose);
|
|
|
|
|
} else if (board->manufacturer == "lattice") {
|
|
|
|
|
target = new Ice40(spi, args.bit_file, args.file_type,
|
2022-01-18 08:09:54 +01:00
|
|
|
args.prg_type,
|
2021-12-22 19:12:33 +01:00
|
|
|
board->reset_pin, board->done_pin, args.verify, args.verbose);
|
|
|
|
|
} else if (board->manufacturer == "colognechip") {
|
2021-12-23 08:54:48 +01:00
|
|
|
target = new CologneChip(spi, args.bit_file, args.file_type, args.prg_type,
|
2021-12-22 19:12:33 +01:00
|
|
|
board->reset_pin, board->done_pin, DBUS6, board->oe_pin,
|
|
|
|
|
args.verify, args.verbose);
|
2023-07-27 07:15:49 +02:00
|
|
|
} else {
|
|
|
|
|
printError("Error (SPI mode): " + board->manufacturer +
|
|
|
|
|
" is an unsupported/unknown target");
|
|
|
|
|
return EXIT_FAILURE;
|
2021-06-26 08:34:12 +02:00
|
|
|
}
|
2021-06-26 08:43:02 +02:00
|
|
|
if (args.prg_type == Device::RD_FLASH) {
|
|
|
|
|
if (args.file_size == 0) {
|
|
|
|
|
printError("Error: 0 size for dump");
|
|
|
|
|
} else {
|
2021-12-22 19:12:33 +01:00
|
|
|
target->dumpFlash(args.offset, args.file_size);
|
2021-06-26 08:43:02 +02:00
|
|
|
}
|
2022-01-18 08:09:54 +01:00
|
|
|
} else if ((args.prg_type == Device::WR_FLASH ||
|
|
|
|
|
args.prg_type == Device::WR_SRAM) ||
|
2021-12-24 11:19:30 +01:00
|
|
|
!args.bit_file.empty() || !args.file_type.empty()) {
|
2021-12-22 19:12:33 +01:00
|
|
|
target->program(args.offset, args.unprotect_flash);
|
2021-12-10 12:12:32 +01:00
|
|
|
}
|
2021-12-22 19:12:33 +01:00
|
|
|
if (args.unprotect_flash && args.bit_file.empty())
|
|
|
|
|
if (!target->unprotect_flash())
|
|
|
|
|
spi_ret = EXIT_FAILURE;
|
2022-03-10 08:51:54 +01:00
|
|
|
if (args.bulk_erase_flash && args.bit_file.empty())
|
|
|
|
|
if (!target->bulk_erase_flash())
|
|
|
|
|
spi_ret = EXIT_FAILURE;
|
2021-12-22 19:12:33 +01:00
|
|
|
if (args.protect_flash)
|
|
|
|
|
if (!target->protect_flash(args.protect_flash))
|
|
|
|
|
spi_ret = EXIT_FAILURE;
|
2020-10-31 10:41:44 +01:00
|
|
|
} else {
|
|
|
|
|
RawParser *bit = NULL;
|
2022-05-28 17:20:53 +02:00
|
|
|
if (board && board->reset_pin) {
|
2020-10-31 10:41:44 +01:00
|
|
|
spi->gpio_set_output(board->reset_pin, true);
|
|
|
|
|
spi->gpio_clear(board->reset_pin, true);
|
2020-10-07 07:47:46 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-22 19:12:33 +01:00
|
|
|
SPIFlash flash((SPIInterface *)spi, args.unprotect_flash, args.verbose);
|
|
|
|
|
flash.display_status_reg();
|
2020-10-31 10:41:44 +01:00
|
|
|
|
2021-07-11 11:34:14 +02:00
|
|
|
if (args.prg_type != Device::RD_FLASH &&
|
|
|
|
|
(!args.bit_file.empty() || !args.file_type.empty())) {
|
2020-10-31 10:41:44 +01:00
|
|
|
printInfo("Open file " + args.bit_file + " ", false);
|
|
|
|
|
try {
|
|
|
|
|
bit = new RawParser(args.bit_file, false);
|
|
|
|
|
printSuccess("DONE");
|
|
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
printError("FAIL");
|
|
|
|
|
delete spi;
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printInfo("Parse file ", false);
|
|
|
|
|
if (bit->parse() == EXIT_FAILURE) {
|
|
|
|
|
printError("FAIL");
|
|
|
|
|
delete spi;
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
} else {
|
|
|
|
|
printSuccess("DONE");
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-22 19:12:33 +01:00
|
|
|
try {
|
|
|
|
|
flash.erase_and_prog(args.offset, bit->getData(), bit->getLength()/8);
|
|
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
printError("FAIL: " + string(e.what()));
|
|
|
|
|
}
|
2020-10-31 10:41:44 +01:00
|
|
|
|
2021-06-25 08:58:45 +02:00
|
|
|
if (args.verify)
|
2021-07-11 11:34:14 +02:00
|
|
|
flash.verify(args.offset, bit->getData(), bit->getLength() / 8);
|
2021-06-25 08:58:45 +02:00
|
|
|
|
2020-10-31 10:41:44 +01:00
|
|
|
delete bit;
|
2021-07-11 11:34:14 +02:00
|
|
|
} else if (args.prg_type == Device::RD_FLASH) {
|
|
|
|
|
flash.dump(args.bit_file, args.offset, args.file_size);
|
2020-10-07 07:47:46 +02:00
|
|
|
}
|
2021-07-11 11:34:14 +02:00
|
|
|
|
2021-12-22 19:12:33 +01:00
|
|
|
if (args.unprotect_flash && args.bit_file.empty())
|
|
|
|
|
if (!flash.disable_protection())
|
|
|
|
|
spi_ret = EXIT_FAILURE;
|
2022-03-10 08:51:54 +01:00
|
|
|
if (args.bulk_erase_flash && args.bit_file.empty())
|
|
|
|
|
if (!flash.bulk_erase())
|
|
|
|
|
spi_ret = EXIT_FAILURE;
|
2021-12-22 19:12:33 +01:00
|
|
|
if (args.protect_flash)
|
|
|
|
|
if (!flash.enable_protection(args.protect_flash))
|
|
|
|
|
spi_ret = EXIT_FAILURE;
|
|
|
|
|
|
2022-05-28 17:20:53 +02:00
|
|
|
if (board && board->reset_pin)
|
2020-10-31 10:41:44 +01:00
|
|
|
spi->gpio_set(board->reset_pin, true);
|
2020-10-07 07:47:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete spi;
|
|
|
|
|
|
2021-12-22 19:12:33 +01:00
|
|
|
return spi_ret;
|
2020-10-07 07:47:46 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-20 10:25:49 +02:00
|
|
|
/* ------------------- */
|
|
|
|
|
/* DFU access */
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
if (args.dfu || (board && board->mode == COMM_DFU)) {
|
|
|
|
|
/* try to init DFU probe */
|
|
|
|
|
DFU *dfu = NULL;
|
2021-07-17 08:36:32 +02:00
|
|
|
uint16_t vid = 0, pid = 0;
|
2021-10-03 12:39:06 +02:00
|
|
|
int altsetting = -1;
|
2021-07-17 08:36:32 +02:00
|
|
|
if (board) {
|
|
|
|
|
vid = board->vid;
|
|
|
|
|
pid = board->pid;
|
2021-10-03 12:39:06 +02:00
|
|
|
altsetting = board->altsetting;
|
|
|
|
|
}
|
|
|
|
|
if (args.altsetting != -1) {
|
|
|
|
|
if (altsetting != -1)
|
|
|
|
|
printInfo("Board altsetting overridden");
|
|
|
|
|
altsetting = args.altsetting;
|
2021-07-17 08:36:32 +02:00
|
|
|
}
|
2021-10-03 18:33:55 +02:00
|
|
|
|
|
|
|
|
if (args.vid != 0) {
|
|
|
|
|
if (vid != 0)
|
|
|
|
|
printInfo("Board VID overridden");
|
|
|
|
|
vid = args.vid;
|
|
|
|
|
}
|
|
|
|
|
if (args.pid != 0) {
|
|
|
|
|
if (pid != 0)
|
|
|
|
|
printInfo("Board PID overridden");
|
|
|
|
|
pid = args.pid;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-20 10:25:49 +02:00
|
|
|
try {
|
2022-06-18 18:39:58 +02:00
|
|
|
dfu = new DFU(args.bit_file, args.detect, vid, pid, altsetting,
|
|
|
|
|
args.verbose);
|
2021-06-20 10:25:49 +02:00
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
printError("DFU init failed with: " + string(e.what()));
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
/* if verbose or detect: display device */
|
|
|
|
|
if (args.verbose > 0 || args.detect)
|
|
|
|
|
dfu->displayDFU();
|
|
|
|
|
|
|
|
|
|
/* if detect: stop */
|
|
|
|
|
if (args.detect)
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
dfu->download();
|
|
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
printError("DFU download failed with: " + string(e.what()));
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-06 21:14:25 +02:00
|
|
|
#ifdef ENABLE_XVC
|
2022-07-06 20:58:34 +02:00
|
|
|
/* ------------------- */
|
|
|
|
|
/* XVC server */
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
if (args.xvc) {
|
2023-01-02 18:02:43 +01:00
|
|
|
try {
|
|
|
|
|
return run_xvc_server(args, cable, &pins_config);
|
|
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
2022-07-06 20:58:34 +02:00
|
|
|
}
|
2022-07-06 21:14:25 +02:00
|
|
|
#endif
|
2022-07-06 20:58:34 +02:00
|
|
|
|
2019-09-26 18:29:20 +02:00
|
|
|
/* jtag base */
|
2022-01-18 08:09:54 +01:00
|
|
|
|
2022-07-06 20:58:34 +02:00
|
|
|
|
2022-01-18 08:09:54 +01:00
|
|
|
/* if no instruction from user -> select load */
|
|
|
|
|
if (args.prg_type == Device::PRG_NONE)
|
|
|
|
|
args.prg_type = Device::WR_SRAM;
|
|
|
|
|
|
2020-03-06 09:05:57 +01:00
|
|
|
Jtag *jtag;
|
2020-07-11 07:23:24 +02:00
|
|
|
try {
|
2021-05-13 16:07:40 +02:00
|
|
|
jtag = new Jtag(cable, &pins_config, args.device, args.ftdi_serial,
|
2022-10-06 07:07:17 +02:00
|
|
|
args.freq, args.verbose, args.ip_adr, args.port,
|
2023-11-10 22:00:13 +01:00
|
|
|
args.invert_read_edge, args.probe_firmware,
|
|
|
|
|
args.user_misc_devs);
|
2020-07-11 07:23:24 +02:00
|
|
|
} catch (std::exception &e) {
|
2021-05-15 15:08:27 +02:00
|
|
|
printError("JTAG init failed with: " + string(e.what()));
|
2020-07-11 07:23:24 +02:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
2019-09-26 18:29:20 +02:00
|
|
|
|
2019-09-28 15:46:12 +02:00
|
|
|
/* chain detection */
|
2024-03-09 10:21:21 +01:00
|
|
|
vector<uint32_t> listDev = jtag->get_devices_list();
|
|
|
|
|
size_t found = listDev.size();
|
|
|
|
|
int idcode = -1;
|
|
|
|
|
size_t index = 0;
|
2019-09-28 15:46:12 +02:00
|
|
|
|
2021-01-30 07:57:49 +01:00
|
|
|
if (args.verbose > 0)
|
2019-11-21 08:39:27 +01:00
|
|
|
cout << "found " << std::to_string(found) << " devices" << endl;
|
2021-05-15 15:08:27 +02:00
|
|
|
|
|
|
|
|
/* in verbose mode or when detect
|
|
|
|
|
* display full chain with details
|
|
|
|
|
*/
|
|
|
|
|
if (args.verbose > 0 || args.detect) {
|
2024-03-09 10:21:21 +01:00
|
|
|
for (size_t i = 0; i < found; i++) {
|
|
|
|
|
uint32_t t = listDev[i];
|
|
|
|
|
printf("index %zu:\n", i);
|
2021-05-15 15:08:27 +02:00
|
|
|
if (fpga_list.find(t) != fpga_list.end()) {
|
2021-08-18 07:40:25 +02:00
|
|
|
printf("\tidcode 0x%x\n\tmanufacturer %s\n\tfamily %s\n\tmodel %s\n",
|
2021-05-15 15:08:27 +02:00
|
|
|
t,
|
|
|
|
|
fpga_list[t].manufacturer.c_str(),
|
2021-08-18 07:40:25 +02:00
|
|
|
fpga_list[t].family.c_str(),
|
|
|
|
|
fpga_list[t].model.c_str());
|
2021-05-15 15:08:27 +02:00
|
|
|
printf("\tirlength %d\n", fpga_list[t].irlength);
|
|
|
|
|
} else if (misc_dev_list.find(t) != misc_dev_list.end()) {
|
|
|
|
|
printf("\tidcode 0x%x\n\ttype %s\n\tirlength %d\n",
|
|
|
|
|
t,
|
|
|
|
|
misc_dev_list[t].name.c_str(),
|
|
|
|
|
misc_dev_list[t].irlength);
|
2023-11-10 22:00:13 +01:00
|
|
|
} else if (args.user_misc_devs.find(t) != args.user_misc_devs.end()) {
|
|
|
|
|
printf("\tidcode 0x%x\n\ttype %s\n\tirlength %d\n",
|
|
|
|
|
t,
|
|
|
|
|
args.user_misc_devs[t].name.c_str(),
|
|
|
|
|
args.user_misc_devs[t].irlength);
|
2021-05-15 15:08:27 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (args.detect == true) {
|
|
|
|
|
delete jtag;
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (found != 0) {
|
2021-05-15 15:26:09 +02:00
|
|
|
if (args.index_chain == -1) {
|
2024-03-09 10:21:21 +01:00
|
|
|
for (size_t i = 0; i < found; i++) {
|
2021-05-15 15:26:09 +02:00
|
|
|
if (fpga_list.find(listDev[i]) != fpga_list.end()) {
|
|
|
|
|
index = i;
|
|
|
|
|
if (idcode != -1) {
|
|
|
|
|
printError("Error: more than one FPGA found");
|
|
|
|
|
printError("Use --index-chain to force selection");
|
2024-03-09 10:21:21 +01:00
|
|
|
for (size_t i = 0; i < found; i++)
|
2021-05-15 15:26:09 +02:00
|
|
|
printf("0x%08x\n", listDev[i]);
|
|
|
|
|
delete(jtag);
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
} else {
|
|
|
|
|
idcode = listDev[i];
|
|
|
|
|
}
|
2021-05-15 15:08:27 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-05-15 15:26:09 +02:00
|
|
|
} else {
|
|
|
|
|
index = args.index_chain;
|
|
|
|
|
if (index > found || index < 0) {
|
|
|
|
|
printError("wrong index for device in JTAG chain");
|
|
|
|
|
delete(jtag);
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
idcode = listDev[index];
|
2021-05-15 15:08:27 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
2020-07-11 07:47:27 +02:00
|
|
|
printError("Error: no device found");
|
2020-08-19 15:15:37 +02:00
|
|
|
delete(jtag);
|
2019-09-26 18:29:20 +02:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
2019-09-28 15:46:12 +02:00
|
|
|
|
2021-05-15 15:08:27 +02:00
|
|
|
jtag->device_select(index);
|
2019-09-28 15:46:12 +02:00
|
|
|
|
2022-11-11 00:01:21 +01:00
|
|
|
/* detect svf file and program the device */
|
2022-11-12 22:58:17 +01:00
|
|
|
if (!args.file_type.compare("svf") ||
|
|
|
|
|
args.bit_file.find(".svf") != string::npos) {
|
2022-11-11 00:01:21 +01:00
|
|
|
SVF_jtag *svf = new SVF_jtag(jtag, args.verbose);
|
|
|
|
|
try {
|
|
|
|
|
svf->parse(args.bit_file);
|
|
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-10 12:50:26 +02:00
|
|
|
/* check if selected device is supported
|
2021-05-15 15:26:09 +02:00
|
|
|
* mainly used in conjunction with --index-chain
|
|
|
|
|
*/
|
2019-09-26 18:29:20 +02:00
|
|
|
if (fpga_list.find(idcode) == fpga_list.end()) {
|
2019-12-06 07:29:28 +01:00
|
|
|
cerr << "Error: device " << hex << idcode << " not supported" << endl;
|
2020-08-20 16:58:20 +02:00
|
|
|
delete(jtag);
|
2020-07-11 07:47:27 +02:00
|
|
|
return EXIT_FAILURE;
|
2020-02-22 20:55:51 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-06 19:59:35 +01:00
|
|
|
string fab = fpga_list[idcode].manufacturer;
|
2019-09-26 18:29:20 +02:00
|
|
|
|
2022-07-06 20:58:34 +02:00
|
|
|
|
2019-09-28 15:46:12 +02:00
|
|
|
Device *fpga;
|
2021-01-29 06:19:42 +01:00
|
|
|
try {
|
|
|
|
|
if (fab == "xilinx") {
|
2023-01-21 14:20:49 +01:00
|
|
|
fpga = new Xilinx(jtag, args.bit_file, args.secondary_bit_file,
|
|
|
|
|
args.file_type, args.prg_type, args.fpga_part, args.bridge_path,
|
2023-11-25 08:47:24 +01:00
|
|
|
args.target_flash, args.verify, args.verbose, args.skip_load_bridge, args.skip_reset,
|
|
|
|
|
args.read_dna, args.read_xadc);
|
2021-01-29 06:19:42 +01:00
|
|
|
} else if (fab == "altera") {
|
2021-02-21 18:30:13 +01:00
|
|
|
fpga = new Altera(jtag, args.bit_file, args.file_type,
|
2022-12-10 22:05:37 +01:00
|
|
|
args.prg_type, args.fpga_part, args.bridge_path, args.verify,
|
|
|
|
|
args.verbose, args.skip_load_bridge, args.skip_reset);
|
2021-02-21 18:30:13 +01:00
|
|
|
} else if (fab == "anlogic") {
|
|
|
|
|
fpga = new Anlogic(jtag, args.bit_file, args.file_type,
|
2021-06-25 08:58:45 +02:00
|
|
|
args.prg_type, args.verify, args.verbose);
|
2021-10-23 08:44:23 +02:00
|
|
|
} else if (fab == "efinix") {
|
|
|
|
|
fpga = new Efinix(jtag, args.bit_file, args.file_type,
|
2023-04-19 06:58:39 +02:00
|
|
|
args.prg_type, args.board, args.fpga_part, args.bridge_path,
|
|
|
|
|
args.verify, args.verbose);
|
2021-01-29 06:19:42 +01:00
|
|
|
} else if (fab == "Gowin") {
|
2022-07-20 23:25:53 +02:00
|
|
|
fpga = new Gowin(jtag, args.bit_file, args.file_type, args.mcufw,
|
2021-09-15 20:18:49 +02:00
|
|
|
args.prg_type, args.external_flash, args.verify, args.verbose);
|
2021-01-29 06:19:42 +01:00
|
|
|
} else if (fab == "lattice") {
|
2021-02-21 18:30:13 +01:00
|
|
|
fpga = new Lattice(jtag, args.bit_file, args.file_type,
|
2023-09-11 05:46:08 +02:00
|
|
|
args.prg_type, args.flash_sector, args.verify, args.verbose, args.skip_load_bridge, args.skip_reset);
|
2021-12-10 12:12:32 +01:00
|
|
|
} else if (fab == "colognechip") {
|
|
|
|
|
fpga = new CologneChip(jtag, args.bit_file, args.file_type,
|
|
|
|
|
args.prg_type, args.board, args.cable, args.verify, args.verbose);
|
2021-01-29 06:19:42 +01:00
|
|
|
} else {
|
|
|
|
|
printError("Error: manufacturer " + fab + " not supported");
|
|
|
|
|
delete(jtag);
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
} catch (std::exception &e) {
|
2021-02-21 18:30:13 +01:00
|
|
|
printError("Error: Failed to claim FPGA device: " + string(e.what()));
|
2019-12-27 14:00:30 +01:00
|
|
|
delete(jtag);
|
|
|
|
|
return EXIT_FAILURE;
|
2019-09-26 18:29:20 +02:00
|
|
|
}
|
|
|
|
|
|
2023-01-21 14:20:49 +01:00
|
|
|
if ((!args.bit_file.empty() ||
|
|
|
|
|
!args.secondary_bit_file.empty() ||
|
2023-12-14 13:13:48 +01:00
|
|
|
!args.file_type.empty() || !args.mcufw.empty())
|
2021-06-24 18:19:09 +02:00
|
|
|
&& args.prg_type != Device::RD_FLASH) {
|
2020-02-16 16:55:37 +01:00
|
|
|
try {
|
2021-12-22 19:12:33 +01:00
|
|
|
fpga->program(args.offset, args.unprotect_flash);
|
2020-02-16 16:55:37 +01:00
|
|
|
} catch (std::exception &e) {
|
2021-07-14 16:39:14 +02:00
|
|
|
printError("Error: Failed to program FPGA: " + string(e.what()));
|
2020-02-16 16:55:37 +01:00
|
|
|
delete(fpga);
|
|
|
|
|
delete(jtag);
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-28 15:46:12 +02:00
|
|
|
|
2022-07-20 23:27:32 +02:00
|
|
|
if (args.conmcu == true) {
|
|
|
|
|
fpga->connectJtagToMCU();
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-21 14:35:23 +02:00
|
|
|
/* read internal register */
|
|
|
|
|
if (!args.read_register.empty()) {
|
|
|
|
|
fpga->read_register(args.read_register);
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-22 19:12:33 +01:00
|
|
|
/* unprotect SPI flash */
|
|
|
|
|
if (args.unprotect_flash && args.bit_file.empty()) {
|
|
|
|
|
fpga->unprotect_flash();
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-10 08:51:54 +01:00
|
|
|
/* bulk erase SPI flash */
|
|
|
|
|
if (args.bulk_erase_flash && args.bit_file.empty()) {
|
|
|
|
|
fpga->bulk_erase_flash();
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-22 19:12:33 +01:00
|
|
|
/* protect SPI flash */
|
|
|
|
|
if (args.protect_flash != 0) {
|
|
|
|
|
fpga->protect_flash(args.protect_flash);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-23 09:19:11 +02:00
|
|
|
/* Enable/disable SPI Flash quad mode */
|
|
|
|
|
if (args.enable_quad || args.disable_quad) {
|
|
|
|
|
bool ret = true;
|
|
|
|
|
if (args.enable_quad && args.disable_quad) {
|
|
|
|
|
printError("Error: can't set enable and disable Quad mode at same time");
|
|
|
|
|
ret = false;
|
|
|
|
|
} else if (!fpga->set_quad_bit(args.enable_quad)) {
|
|
|
|
|
printError("Error: Failed to enable/disable Quad mode");
|
|
|
|
|
ret = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ret) {
|
|
|
|
|
delete(fpga);
|
|
|
|
|
delete(jtag);
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-09 09:28:52 +02:00
|
|
|
/* detect/display flash */
|
|
|
|
|
if (args.detect_flash != 0) {
|
|
|
|
|
fpga->detect_flash();
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 18:19:09 +02:00
|
|
|
if (args.prg_type == Device::RD_FLASH) {
|
|
|
|
|
if (args.file_size == 0) {
|
|
|
|
|
printError("Error: 0 size for dump");
|
|
|
|
|
} else {
|
2021-12-22 19:12:33 +01:00
|
|
|
fpga->dumpFlash(args.offset, args.file_size);
|
2021-06-24 18:19:09 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-28 15:46:12 +02:00
|
|
|
if (args.reset)
|
|
|
|
|
fpga->reset();
|
|
|
|
|
|
|
|
|
|
delete(fpga);
|
2019-11-19 09:03:09 +01:00
|
|
|
delete(jtag);
|
2019-09-26 18:29:20 +02:00
|
|
|
}
|
|
|
|
|
|
2022-07-06 21:14:25 +02:00
|
|
|
#ifdef ENABLE_XVC
|
2022-07-06 20:58:34 +02:00
|
|
|
int run_xvc_server(const struct arguments &args, const cable_t &cable,
|
|
|
|
|
const jtag_pins_conf_t *pins_config)
|
|
|
|
|
{
|
2022-11-12 22:58:17 +01:00
|
|
|
// create XVC instance
|
2022-07-06 20:58:34 +02:00
|
|
|
try {
|
|
|
|
|
XVC_server *xvc = NULL;
|
|
|
|
|
xvc = new XVC_server(args.port, cable, pins_config, args.device,
|
|
|
|
|
args.ftdi_serial, args.freq, args.verbose, args.ip_adr,
|
|
|
|
|
args.invert_read_edge, args.probe_firmware);
|
|
|
|
|
/* create connection */
|
|
|
|
|
xvc->open_connection();
|
|
|
|
|
/* start loop */
|
|
|
|
|
xvc->listen_loop();
|
|
|
|
|
/* close connection */
|
|
|
|
|
xvc->close_connection();
|
|
|
|
|
delete xvc;
|
|
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
printError("XVC_server failed with " + string(e.what()));
|
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
printInfo("Xilinx Virtual Cable Stopped! ");
|
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
}
|
2022-07-06 21:14:25 +02:00
|
|
|
#endif
|
2022-07-06 20:58:34 +02:00
|
|
|
|
2020-07-25 04:55:41 +02:00
|
|
|
// parse double from string in engineering notation
|
2020-05-25 10:31:37 +02:00
|
|
|
// can deal with postfixes k and m, add more when required
|
2020-07-25 04:55:41 +02:00
|
|
|
static int parse_eng(string arg, double *dst) {
|
2020-05-25 10:31:37 +02:00
|
|
|
try {
|
|
|
|
|
size_t end;
|
|
|
|
|
double base = stod(arg, &end);
|
|
|
|
|
if (end == arg.size()) {
|
|
|
|
|
*dst = base;
|
|
|
|
|
return 0;
|
|
|
|
|
} else if (end == (arg.size() - 1)) {
|
|
|
|
|
switch (arg.back()) {
|
|
|
|
|
case 'k': case 'K':
|
|
|
|
|
*dst = (uint32_t)(1e3 * base);
|
|
|
|
|
return 0;
|
|
|
|
|
case 'm': case 'M':
|
|
|
|
|
*dst = (uint32_t)(1e6 * base);
|
|
|
|
|
return 0;
|
|
|
|
|
default:
|
|
|
|
|
return EINVAL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return EINVAL;
|
|
|
|
|
}
|
|
|
|
|
} catch (...) {
|
2020-07-25 04:55:41 +02:00
|
|
|
cerr << "error : speed: invalid format" << endl;
|
2020-05-25 10:31:37 +02:00
|
|
|
return EINVAL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-26 18:29:20 +02:00
|
|
|
/* arguments parser */
|
2022-11-12 22:58:17 +01:00
|
|
|
int parse_opt(int argc, char **argv, struct arguments *args,
|
|
|
|
|
jtag_pins_conf_t *pins_config)
|
2019-09-26 18:29:20 +02:00
|
|
|
{
|
2024-04-21 14:35:23 +02:00
|
|
|
string freqo, rd_reg;
|
2022-10-15 17:41:30 +02:00
|
|
|
vector<string> pins, bus_dev_num;
|
2021-01-30 07:57:49 +01:00
|
|
|
bool verbose, quiet;
|
2021-10-03 08:22:35 +02:00
|
|
|
int8_t verbose_level = -2;
|
2020-07-23 18:32:18 +02:00
|
|
|
try {
|
|
|
|
|
cxxopts::Options options(argv[0], "openFPGALoader -- a program to flash FPGA",
|
|
|
|
|
"<gwenhael.goavec-merou@trabucayre.com>");
|
|
|
|
|
options
|
|
|
|
|
.positional_help("BIT_FILE")
|
|
|
|
|
.show_positional_help();
|
|
|
|
|
|
|
|
|
|
options
|
|
|
|
|
.add_options()
|
2021-10-03 12:39:06 +02:00
|
|
|
("altsetting", "DFU interface altsetting (only for DFU mode)",
|
2021-10-03 18:33:55 +02:00
|
|
|
cxxopts::value<int16_t>(args->altsetting))
|
2020-07-23 18:32:18 +02:00
|
|
|
("bitstream", "bitstream",
|
|
|
|
|
cxxopts::value<std::string>(args->bit_file))
|
2023-01-21 14:20:49 +01:00
|
|
|
("secondary-bitstream", "secondary bitstream (some Xilinx"
|
|
|
|
|
" UltraScale boards)",
|
|
|
|
|
cxxopts::value<std::string>(args->secondary_bit_file))
|
2020-07-23 18:32:18 +02:00
|
|
|
("b,board", "board name, may be used instead of cable",
|
|
|
|
|
cxxopts::value<string>(args->board))
|
2022-12-10 22:05:37 +01:00
|
|
|
("B,bridge", "disable spiOverJtag model detection by providing "
|
|
|
|
|
"bitstream(intel/xilinx)",
|
|
|
|
|
cxxopts::value<string>(args->bridge_path))
|
2020-07-23 18:32:18 +02:00
|
|
|
("c,cable", "jtag interface", cxxopts::value<string>(args->cable))
|
2023-04-10 17:59:07 +02:00
|
|
|
("status-pin",
|
|
|
|
|
"JTAG mode / FTDI: GPIO pin number to use as a status indicator (active low)",
|
|
|
|
|
cxxopts::value<int>(args->status_pin))
|
2022-11-12 22:58:17 +01:00
|
|
|
("invert-read-edge",
|
|
|
|
|
"JTAG mode / FTDI: read on negative edge instead of positive",
|
2022-03-11 07:45:48 +01:00
|
|
|
cxxopts::value<bool>(args->invert_read_edge))
|
2021-10-03 18:33:55 +02:00
|
|
|
("vid", "probe Vendor ID", cxxopts::value<uint16_t>(args->vid))
|
|
|
|
|
("pid", "probe Product ID", cxxopts::value<uint16_t>(args->pid))
|
2022-11-12 22:58:17 +01:00
|
|
|
("cable-index", "probe index (FTDI and cmsisDAP)",
|
|
|
|
|
cxxopts::value<int16_t>(args->cable_index))
|
|
|
|
|
("busdev-num",
|
|
|
|
|
"select a probe by it bus and device number (bus_num:device_addr)",
|
2022-10-15 17:41:30 +02:00
|
|
|
cxxopts::value<vector<string>>(bus_dev_num))
|
2022-11-12 22:58:17 +01:00
|
|
|
("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))
|
2022-09-17 17:33:25 +02:00
|
|
|
#if defined(USE_DEVICE_ARG)
|
2020-07-23 18:32:18 +02:00
|
|
|
("d,device", "device to use (/dev/ttyUSBx)",
|
|
|
|
|
cxxopts::value<string>(args->device))
|
2020-03-14 19:42:07 +01:00
|
|
|
#endif
|
2024-06-20 16:21:40 +02:00
|
|
|
("detect", "detect FPGA, add -f to show connected flash",
|
2020-07-23 18:32:18 +02:00
|
|
|
cxxopts::value<bool>(args->detect))
|
2021-06-20 10:25:49 +02:00
|
|
|
("dfu", "DFU mode", cxxopts::value<bool>(args->dfu))
|
2021-06-24 18:19:09 +02:00
|
|
|
("dump-flash", "Dump flash mode")
|
2022-03-10 08:51:54 +01:00
|
|
|
("bulk-erase", "Bulk erase flash",
|
|
|
|
|
cxxopts::value<bool>(args->bulk_erase_flash))
|
2024-08-23 09:19:11 +02:00
|
|
|
("enable-quad", "Enable quad mode for SPI Flash",
|
|
|
|
|
cxxopts::value<bool>(args->enable_quad))
|
|
|
|
|
("disable-quad", "Disable quad mode for SPI Flash",
|
|
|
|
|
cxxopts::value<bool>(args->disable_quad))
|
2023-01-21 14:20:49 +01:00
|
|
|
("target-flash",
|
|
|
|
|
"for boards with multiple flash chips (some Xilinx UltraScale"
|
|
|
|
|
" boards), select the target flash: primary (default), secondary or both",
|
|
|
|
|
cxxopts::value<string>(args->target_flash))
|
2021-09-15 20:18:49 +02:00
|
|
|
("external-flash",
|
2023-01-21 14:20:49 +01:00
|
|
|
"select ext flash for device with internal and external storage",
|
2021-09-15 20:18:49 +02:00
|
|
|
cxxopts::value<bool>(args->external_flash))
|
2022-11-12 22:58:17 +01:00
|
|
|
("file-size",
|
|
|
|
|
"provides size in Byte to dump, must be used with dump-flash",
|
2021-06-24 18:19:09 +02:00
|
|
|
cxxopts::value<unsigned int>(args->file_size))
|
2022-11-12 22:58:17 +01:00
|
|
|
("file-type",
|
|
|
|
|
"provides file type instead of let's deduced by using extension",
|
2021-02-21 18:30:13 +01:00
|
|
|
cxxopts::value<string>(args->file_type))
|
2022-11-12 22:58:17 +01:00
|
|
|
("flash-sector", "flash sector (Lattice parts only)",
|
|
|
|
|
cxxopts::value<string>(args->flash_sector))
|
|
|
|
|
("fpga-part", "fpga model flavor + package",
|
|
|
|
|
cxxopts::value<string>(args->fpga_part))
|
2020-07-23 18:32:18 +02:00
|
|
|
("freq", "jtag frequency (Hz)", cxxopts::value<string>(freqo))
|
|
|
|
|
("f,write-flash",
|
2021-09-13 14:10:42 +02:00
|
|
|
"write bitstream in flash (default: false)")
|
2021-05-15 15:26:09 +02:00
|
|
|
("index-chain", "device index in JTAG-chain",
|
|
|
|
|
cxxopts::value<int>(args->index_chain))
|
2023-11-10 22:00:13 +01:00
|
|
|
("misc-device", "add JTAG non-FPGA devices <idcode,irlen,name>",
|
|
|
|
|
cxxopts::value<vector<string>>())
|
2023-03-02 13:54:56 +01:00
|
|
|
("ip", "IP address (XVC and remote bitbang client)",
|
2022-04-11 06:53:22 +02:00
|
|
|
cxxopts::value<string>(args->ip_adr))
|
2020-07-23 18:32:18 +02:00
|
|
|
("list-boards", "list all supported boards",
|
|
|
|
|
cxxopts::value<bool>(args->list_boards))
|
|
|
|
|
("list-cables", "list all supported cables",
|
|
|
|
|
cxxopts::value<bool>(args->list_cables))
|
|
|
|
|
("list-fpga", "list all supported FPGA",
|
|
|
|
|
cxxopts::value<bool>(args->list_fpga))
|
|
|
|
|
("m,write-sram",
|
2021-09-13 14:10:42 +02:00
|
|
|
"write bitstream in SRAM (default: true)")
|
2023-02-27 21:15:34 +01:00
|
|
|
("o,offset", "Start address (in bytes) for read/write into non volatile memory (default: 0)",
|
2020-07-23 18:32:18 +02:00
|
|
|
cxxopts::value<unsigned int>(args->offset))
|
2022-05-23 20:16:48 +02:00
|
|
|
("pins", "pin config TDI:TDO:TCK:TMS",
|
2020-08-04 17:36:33 +02:00
|
|
|
cxxopts::value<vector<string>>(pins))
|
2021-05-13 16:07:40 +02:00
|
|
|
("probe-firmware", "firmware for JTAG probe (usbBlasterII)",
|
|
|
|
|
cxxopts::value<string>(args->probe_firmware))
|
2021-12-22 19:12:33 +01:00
|
|
|
("protect-flash", "protect SPI flash area",
|
|
|
|
|
cxxopts::value<uint32_t>(args->protect_flash))
|
2021-01-30 07:57:49 +01:00
|
|
|
("quiet", "Produce quiet output (no progress bar)",
|
|
|
|
|
cxxopts::value<bool>(quiet))
|
2020-07-23 18:32:18 +02:00
|
|
|
("r,reset", "reset FPGA after operations",
|
|
|
|
|
cxxopts::value<bool>(args->reset))
|
2022-10-15 22:28:06 +02:00
|
|
|
("scan-usb", "scan USB to display connected probes",
|
|
|
|
|
cxxopts::value<bool>(args->scan_usb))
|
2022-05-11 14:29:08 +02:00
|
|
|
("skip-load-bridge", "skip writing bridge to SRAM when in write-flash mode",
|
|
|
|
|
cxxopts::value<bool>(args->skip_load_bridge))
|
2022-05-24 07:29:35 +02:00
|
|
|
("skip-reset", "skip resetting the device when in write-flash mode",
|
2022-05-28 18:06:51 +02:00
|
|
|
cxxopts::value<bool>(args->skip_reset))
|
2020-10-06 08:38:24 +02:00
|
|
|
("spi", "SPI mode (only for FTDI in serial mode)",
|
|
|
|
|
cxxopts::value<bool>(args->spi))
|
2021-12-22 19:12:33 +01:00
|
|
|
("unprotect-flash", "Unprotect flash blocks",
|
|
|
|
|
cxxopts::value<bool>(args->unprotect_flash))
|
2021-01-30 07:57:49 +01:00
|
|
|
("v,verbose", "Produce verbose output", cxxopts::value<bool>(verbose))
|
2021-10-03 08:22:35 +02:00
|
|
|
("verbose-level", "verbose level -1: quiet, 0: normal, 1:verbose, 2:debug",
|
|
|
|
|
cxxopts::value<int8_t>(verbose_level))
|
2020-07-23 18:32:18 +02:00
|
|
|
("h,help", "Give this help list")
|
2021-06-24 18:06:48 +02:00
|
|
|
("verify", "Verify write operation (SPI Flash only)",
|
|
|
|
|
cxxopts::value<bool>(args->verify))
|
2022-07-06 21:14:25 +02:00
|
|
|
#ifdef ENABLE_XVC
|
2022-07-06 20:58:34 +02:00
|
|
|
("xvc", "Xilinx Virtual Cable Functions",
|
|
|
|
|
cxxopts::value<bool>(args->xvc))
|
2022-07-06 21:14:25 +02:00
|
|
|
#endif
|
2023-03-02 13:54:56 +01:00
|
|
|
("port", "Xilinx Virtual Cable and remote bitbang Port (default 3721)",
|
2022-07-06 20:58:34 +02:00
|
|
|
cxxopts::value<int>(args->port))
|
2022-07-20 23:25:53 +02:00
|
|
|
("mcufw", "Microcontroller firmware",
|
|
|
|
|
cxxopts::value<std::string>(args->mcufw))
|
2022-07-20 23:27:32 +02:00
|
|
|
("conmcu", "Connect JTAG to MCU",
|
|
|
|
|
cxxopts::value<bool>(args->conmcu))
|
2023-11-25 08:47:24 +01:00
|
|
|
("D,read_dna", "Read DNA (Xilinx FPGA only)",
|
|
|
|
|
cxxopts::value<bool>(args->read_dna))
|
|
|
|
|
("X,read_xadc", "Read XADC (Xilinx FPGA only)",
|
|
|
|
|
cxxopts::value<bool>(args->read_xadc))
|
2024-04-21 14:35:23 +02:00
|
|
|
("read-register", "Read Status Register(Xilinx FPGA only)",
|
|
|
|
|
cxxopts::value<string>(rd_reg))
|
2020-07-23 18:32:18 +02:00
|
|
|
("V,Version", "Print program version");
|
|
|
|
|
|
|
|
|
|
options.parse_positional({"bitstream"});
|
|
|
|
|
auto result = options.parse(argc, argv);
|
|
|
|
|
|
|
|
|
|
if (result.count("help")) {
|
|
|
|
|
cout << options.help() << endl;
|
|
|
|
|
return 1;
|
2020-05-25 10:31:37 +02:00
|
|
|
}
|
2020-07-23 18:32:18 +02:00
|
|
|
|
2021-01-30 07:57:49 +01:00
|
|
|
if (verbose && quiet) {
|
|
|
|
|
printError("Error: can't select quiet and verbose mode in same time");
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
|
|
|
|
if (verbose)
|
|
|
|
|
args->verbose = 1;
|
|
|
|
|
if (quiet)
|
|
|
|
|
args->verbose = -1;
|
2021-10-03 08:22:35 +02:00
|
|
|
if (verbose_level != -2) {
|
|
|
|
|
if ((verbose && verbose_level != 1) ||
|
|
|
|
|
(quiet && verbose_level != -1)) {
|
|
|
|
|
printError("Error: mismatch quiet/verbose and verbose-level\n");
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
args->verbose = verbose_level;
|
|
|
|
|
}
|
2021-01-30 07:57:49 +01:00
|
|
|
|
2020-07-23 18:32:18 +02:00
|
|
|
if (result.count("Version")) {
|
2020-12-17 13:58:30 +01:00
|
|
|
cout << "openFPGALoader " << VERSION << endl;
|
2020-07-23 18:32:18 +02:00
|
|
|
return 1;
|
2020-05-25 10:31:37 +02:00
|
|
|
}
|
2020-07-23 18:32:18 +02:00
|
|
|
|
2023-11-10 22:00:13 +01:00
|
|
|
if (result.count("misc-device")) {
|
|
|
|
|
auto misc_devices = result["misc-device"].as<std::vector<std::string>>();
|
|
|
|
|
for (auto &dev : misc_devices) {
|
|
|
|
|
uint32_t idcode;
|
|
|
|
|
int irlen;
|
2023-11-19 10:17:54 +01:00
|
|
|
std::string name;
|
2023-11-10 22:00:13 +01:00
|
|
|
std::stringstream ss(dev);
|
|
|
|
|
std::string item;
|
|
|
|
|
std::vector<std::string> tokens;
|
|
|
|
|
|
|
|
|
|
while (std::getline(ss, item, ',')) {
|
|
|
|
|
tokens.push_back(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tokens.size() != 3) {
|
|
|
|
|
printError("Error: invalid format for misc-device.");
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idcode = std::stoul(tokens[0], nullptr, 16);
|
|
|
|
|
irlen = std::stoi(tokens[1]);
|
|
|
|
|
name = tokens[2];
|
|
|
|
|
args->user_misc_devs[idcode] = {name, irlen};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-24 18:19:09 +02:00
|
|
|
if (result.count("write-flash") && result.count("write-sram") &&
|
|
|
|
|
result.count("dump-flash")) {
|
2020-07-23 18:32:18 +02:00
|
|
|
printError("Error: both write to flash and write to ram enabled");
|
|
|
|
|
throw std::exception();
|
2020-02-16 10:13:09 +01:00
|
|
|
}
|
2020-07-23 18:32:18 +02:00
|
|
|
|
2021-02-18 21:09:34 +01:00
|
|
|
if (result.count("write-flash"))
|
|
|
|
|
args->prg_type = Device::WR_FLASH;
|
|
|
|
|
else if (result.count("write-sram"))
|
|
|
|
|
args->prg_type = Device::WR_SRAM;
|
2021-06-24 18:19:09 +02:00
|
|
|
else if (result.count("dump-flash"))
|
|
|
|
|
args->prg_type = Device::RD_FLASH;
|
2021-09-15 20:18:49 +02:00
|
|
|
else if (result.count("external-flash"))
|
|
|
|
|
args->prg_type = Device::WR_FLASH;
|
2020-07-23 18:32:18 +02:00
|
|
|
|
|
|
|
|
if (result.count("freq")) {
|
|
|
|
|
double freq;
|
|
|
|
|
if (parse_eng(freqo, &freq)) {
|
|
|
|
|
printError("Error: invalid format for --freq");
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
|
|
|
|
if (freq < 1) {
|
|
|
|
|
printError("Error: --freq must be positive");
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
|
|
|
|
args->freq = static_cast<uint32_t>(freq);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 17:59:07 +02:00
|
|
|
if (result.count("status-pin")) {
|
|
|
|
|
if (args->status_pin < 4 || args->status_pin > 15) {
|
|
|
|
|
printError("Error: valid status pin numbers are 4-15.");
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-22 18:22:51 +02:00
|
|
|
if (result.count("ftdi-channel")) {
|
|
|
|
|
if (args->ftdi_channel < 0 || args->ftdi_channel > 3) {
|
|
|
|
|
printError("Error: valid FTDI channels are 0-3.");
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-15 17:41:30 +02:00
|
|
|
if (result.count("busdev-num")) {
|
|
|
|
|
if (bus_dev_num.size() != 2) {
|
|
|
|
|
printError("Error: busdev-num must be xx:yy");
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
|
|
|
|
try {
|
2022-11-12 22:58:17 +01:00
|
|
|
args->bus_addr = static_cast<uint8_t>(std::stoi(bus_dev_num[0],
|
2023-07-29 09:43:32 +02:00
|
|
|
nullptr, 10));
|
2022-11-12 22:58:17 +01:00
|
|
|
args->device_addr = static_cast<uint8_t>(
|
2023-07-29 09:43:32 +02:00
|
|
|
std::stoi(bus_dev_num[1], nullptr, 10));
|
2022-10-15 17:41:30 +02:00
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
printError("Error: busdev-num invalid format: must be numeric values");
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-04 17:36:33 +02:00
|
|
|
if (result.count("pins")) {
|
|
|
|
|
if (pins.size() != 4) {
|
|
|
|
|
printError("Error: pin_config need 4 pins");
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static std::map <std::string, int> pins_list = {
|
2022-08-23 18:37:43 +02:00
|
|
|
{"TXD", FT232RL_TXD},
|
|
|
|
|
{"RXD", FT232RL_RXD},
|
|
|
|
|
{"RTS", FT232RL_RTS},
|
|
|
|
|
{"CTS", FT232RL_CTS},
|
|
|
|
|
{"DTR", FT232RL_DTR},
|
|
|
|
|
{"DSR", FT232RL_DSR},
|
|
|
|
|
{"DCD", FT232RL_DCD},
|
|
|
|
|
{"RI" , FT232RL_RI}};
|
2020-08-04 17:36:33 +02:00
|
|
|
|
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
|
int pin_num;
|
|
|
|
|
try {
|
2022-05-23 20:16:48 +02:00
|
|
|
pin_num = std::stoi(pins[i], nullptr, 0);
|
2020-08-04 17:36:33 +02:00
|
|
|
} catch (std::exception &e) {
|
|
|
|
|
if (pins_list.find(pins[i]) == pins_list.end()) {
|
|
|
|
|
printError("Invalid pin name");
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
|
|
|
|
pin_num = pins_list[pins[i]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (i) {
|
|
|
|
|
case 0:
|
|
|
|
|
pins_config->tdi_pin = pin_num;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
pins_config->tdo_pin = pin_num;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
pins_config->tck_pin = pin_num;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
pins_config->tms_pin = pin_num;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
args->pin_config = true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-21 14:20:49 +01:00
|
|
|
if (args->target_flash == "both" || args->target_flash == "secondary") {
|
|
|
|
|
if ((args->prg_type == Device::WR_FLASH || args->prg_type == Device::RD_FLASH) &&
|
|
|
|
|
args->secondary_bit_file.empty() &&
|
|
|
|
|
!args->protect_flash &&
|
|
|
|
|
!args->unprotect_flash &&
|
|
|
|
|
!args->bulk_erase_flash
|
|
|
|
|
) {
|
|
|
|
|
printError("Error: secondary bitfile not specified");
|
|
|
|
|
cout << options.help() << endl;
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-15 22:28:06 +02:00
|
|
|
if (args->list_cables || args->list_boards || args->list_fpga ||
|
|
|
|
|
args->scan_usb)
|
2020-07-23 18:32:18 +02:00
|
|
|
args->is_list_command = true;
|
|
|
|
|
|
2023-12-14 13:13:48 +01:00
|
|
|
if (args->mcufw.empty()) {
|
|
|
|
|
printf("empty\n");
|
|
|
|
|
} else {
|
|
|
|
|
printf("pas empty\n");
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-21 14:35:23 +02:00
|
|
|
if (result.count("read-register")) {
|
|
|
|
|
args->read_register = rd_reg;
|
|
|
|
|
printf("read_register");
|
|
|
|
|
std::cout << args->read_register << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-23 18:32:18 +02:00
|
|
|
if (args->bit_file.empty() &&
|
2023-01-21 14:20:49 +01:00
|
|
|
args->secondary_bit_file.empty() &&
|
2021-02-21 18:30:13 +01:00
|
|
|
args->file_type.empty() &&
|
2023-12-14 13:13:48 +01:00
|
|
|
args->mcufw.empty() &&
|
2020-07-23 18:32:18 +02:00
|
|
|
!args->is_list_command &&
|
|
|
|
|
!args->detect &&
|
2021-12-22 19:12:33 +01:00
|
|
|
!args->protect_flash &&
|
|
|
|
|
!args->unprotect_flash &&
|
2024-08-23 09:19:11 +02:00
|
|
|
!args->enable_quad &&
|
|
|
|
|
!args->disable_quad &&
|
2022-03-10 08:51:54 +01:00
|
|
|
!args->bulk_erase_flash &&
|
2022-07-06 20:58:34 +02:00
|
|
|
!args->xvc &&
|
2022-07-20 23:27:32 +02:00
|
|
|
!args->reset &&
|
2023-11-25 08:47:24 +01:00
|
|
|
!args->conmcu &&
|
|
|
|
|
!args->read_dna &&
|
2024-04-21 14:35:23 +02:00
|
|
|
!args->read_xadc &&
|
|
|
|
|
args->read_register.empty()) {
|
2020-07-23 18:32:18 +02:00
|
|
|
printError("Error: bitfile not specified");
|
|
|
|
|
cout << options.help() << endl;
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
2024-06-09 09:28:52 +02:00
|
|
|
|
|
|
|
|
// user ask detect with flash set
|
|
|
|
|
// detect/display flash CHIP informations instead
|
|
|
|
|
// of FPGA details
|
|
|
|
|
if (args->detect && args->prg_type == Device::WR_FLASH) {
|
|
|
|
|
args->detect = false;
|
|
|
|
|
args->detect_flash = true;
|
|
|
|
|
}
|
2020-07-23 18:32:18 +02:00
|
|
|
} catch (const cxxopts::OptionException& e) {
|
|
|
|
|
cerr << "Error parsing options: " << e.what() << endl;
|
|
|
|
|
throw std::exception();
|
2019-09-26 18:29:20 +02:00
|
|
|
}
|
2020-07-23 18:32:18 +02:00
|
|
|
|
2019-09-26 18:29:20 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-07 06:40:29 +01:00
|
|
|
/* display list of cables, boards and devices supported */
|
|
|
|
|
void displaySupported(const struct arguments &args)
|
|
|
|
|
{
|
|
|
|
|
if (args.list_cables == true) {
|
|
|
|
|
stringstream t;
|
2022-02-08 19:31:37 +01:00
|
|
|
t << setw(25) << left << "cable name" << "vid:pid";
|
2019-12-07 06:40:29 +01:00
|
|
|
printSuccess(t.str());
|
|
|
|
|
for (auto b = cable_list.begin(); b != cable_list.end(); b++) {
|
2022-10-15 16:17:32 +02:00
|
|
|
cable_t c = (*b).second;
|
2019-12-07 06:40:29 +01:00
|
|
|
stringstream ss;
|
2022-02-08 19:31:37 +01:00
|
|
|
ss << setw(25) << left << (*b).first;
|
2022-11-12 22:58:17 +01:00
|
|
|
ss << "0x" << hex << right << setw(4) << setfill('0') << c.vid
|
|
|
|
|
<< ":" << setw(4) << c.pid;
|
2019-12-07 06:40:29 +01:00
|
|
|
printInfo(ss.str());
|
|
|
|
|
}
|
|
|
|
|
cout << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (args.list_boards) {
|
|
|
|
|
stringstream t;
|
2022-02-08 19:31:37 +01:00
|
|
|
t << setw(25) << left << "board name" << "cable_name";
|
2019-12-07 06:40:29 +01:00
|
|
|
printSuccess(t.str());
|
|
|
|
|
for (auto b = board_list.begin(); b != board_list.end(); b++) {
|
|
|
|
|
stringstream ss;
|
2021-04-19 21:17:08 +02:00
|
|
|
target_board_t c = (*b).second;
|
2022-02-08 19:31:37 +01:00
|
|
|
ss << setw(25) << left << (*b).first << c.cable_name;
|
2019-12-07 06:40:29 +01:00
|
|
|
printInfo(ss.str());
|
|
|
|
|
}
|
|
|
|
|
cout << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (args.list_fpga) {
|
|
|
|
|
stringstream t;
|
|
|
|
|
t << setw(12) << left << "IDCode" << setw(14) << "manufacturer";
|
2022-02-08 19:31:37 +01:00
|
|
|
t << setw(16) << "family" << setw(20) << "model";
|
2019-12-07 06:40:29 +01:00
|
|
|
printSuccess(t.str());
|
|
|
|
|
for (auto b = fpga_list.begin(); b != fpga_list.end(); b++) {
|
|
|
|
|
fpga_model fpga = (*b).second;
|
|
|
|
|
stringstream ss, idCode;
|
2022-02-08 19:31:37 +01:00
|
|
|
idCode << "0x" << hex << setw(8) << setfill('0') << (*b).first;
|
2019-12-07 06:40:29 +01:00
|
|
|
ss << setw(12) << left << idCode.str();
|
2022-02-08 19:31:37 +01:00
|
|
|
ss << setw(14) << fpga.manufacturer << setw(16) << fpga.family;
|
2019-12-07 06:40:29 +01:00
|
|
|
ss << setw(20) << fpga.model;
|
|
|
|
|
printInfo(ss.str());
|
|
|
|
|
}
|
|
|
|
|
cout << endl;
|
|
|
|
|
}
|
2022-10-15 22:28:06 +02:00
|
|
|
|
|
|
|
|
if (args.scan_usb) {
|
2024-05-20 16:18:50 +02:00
|
|
|
libusb_ll usb(0, 0, args.verbose);
|
2022-10-15 22:28:06 +02:00
|
|
|
usb.scan();
|
|
|
|
|
}
|
2019-12-07 06:40:29 +01:00
|
|
|
}
|
2020-02-16 10:13:09 +01:00
|
|
|
|