rework xilinx fpga spiOverJtag to respect model/package

This commit is contained in:
Gwenhael Goavec-Merou 2021-04-19 21:17:08 +02:00
parent 65a1e995ec
commit 7039465353
21 changed files with 123 additions and 63 deletions

View File

@ -179,10 +179,12 @@ add_definitions(-DFTDI_VERSION=${FTDI_VAL})
install(TARGETS openFPGALoader DESTINATION bin) install(TARGETS openFPGALoader DESTINATION bin)
install(FILES install(FILES
test_sfl.svf test_sfl.svf
spiOverJtag/spiOverJtag_xc7a35.bit spiOverJtag/spiOverJtag_xc7a100tfgg484.bit
spiOverJtag/spiOverJtag_xc7a50t.bit spiOverJtag/spiOverJtag_xc7a200tsbg484.bit
spiOverJtag/spiOverJtag_xc7a100.bit spiOverJtag/spiOverJtag_xc7a35tcsg324.bit
spiOverJtag/spiOverJtag_xc7a200.bit spiOverJtag/spiOverJtag_xc7a35tftg256.bit
spiOverJtag/spiOverJtag_xc7s50.bit spiOverJtag/spiOverJtag_xc7a50tcpg236.bit
spiOverJtag/spiOverJtag_xc7a75tfgg484.bit
spiOverJtag/spiOverJtag_xc7s50csga324.bit
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/openFPGALoader DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/openFPGALoader
) )

View File

@ -315,6 +315,9 @@ current directory.
1. Spartan Edge Accelerator Board has only pinheader, so the cable must be provided 1. Spartan Edge Accelerator Board has only pinheader, so the cable must be provided
2. a *JTAG* <-> *SPI* bridge (used to write bitstream in FLASH) is available for some device, see 2. a *JTAG* <-> *SPI* bridge (used to write bitstream in FLASH) is available for some device, see
[spiOverJtag](https://github.com/trabucayre/openFPGALoader/tree/master/spiOverJtag) to check if your model is supported [spiOverJtag](https://github.com/trabucayre/openFPGALoader/tree/master/spiOverJtag) to check if your model is supported
3. board provides the device/package model, but if the targeted board is not
officially supported but the FPGA yes, you can use --fpga-part to provides
model
<span style="color:red">**Warning** *.bin* may be loaded in memory or in flash, but this extension is a classic extension <span style="color:red">**Warning** *.bin* may be loaded in memory or in flash, but this extension is a classic extension
for CPU firmware and, by default, *openFPGALoader* load file in memory, double check for CPU firmware and, by default, *openFPGALoader* load file in memory, double check
@ -367,10 +370,15 @@ vivado -nolog -nojournal -mode batch -source script.tcl -tclargs myproject
__file load:__ __file load:__
```bash ```bash
openFPGALoader -f -b arty *.runs/impl_1/*.mcs (or .bit / .bin) openFPGALoader [--fpga-part xxxx] -f -b arty *.runs/impl_1/*.mcs (or .bit / .bin)
``` ```
**Note: *-f* is required to write bitstream (without them *.bit* and *.bin* are loaded in memory)** **Note: *-f* is required to write bitstream (without them *.bit* and *.bin* are loaded in memory)**
Note: "--fpga-part" is only required if this information is not provided at
board.hpp level or if the board is not officially supported. device/packagee
format is something like xc7a35tcsg324 (arty model). See src/board.hpp, or
spiOverJtag directory for examples.
### MachXO2/MachXO3 Starter Kit ### MachXO2/MachXO3 Starter Kit
#### Flash memory: #### Flash memory:

View File

@ -1,12 +1,12 @@
VIVADO := vivado -nolog -nojournal -mode batch -source VIVADO := vivado -nolog -nojournal -mode batch -source
MODELS := xc7a35 xc7a50t xc7a100 xc7s50 xc7a200 PARTS := xc7a35tcsg324 xc7a35tftg256 xc7a50tcpg236 xc7a75tfgg484 xc7a100tfgg484 xc7a200tsbg484 xc7s50csga324
BIT_FILES := $(addsuffix .bit,$(addprefix spiOverJtag_, $(MODELS))) BIT_FILES := $(addsuffix .bit,$(addprefix spiOverJtag_, $(PARTS)))
all: $(BIT_FILES) all: $(BIT_FILES)
$(BIT_FILES) : spiOverJtag_%.bit : tmp_%/spiOverJtag.runs/impl_1/xilinx_spiOverJtag.bit $(BIT_FILES) : spiOverJtag_%.bit : tmp_%/spiOverJtag.runs/impl_1/xilinx_spiOverJtag.bit
cp $< $@ cp $< $@
tmp_%/spiOverJtag.runs/impl_1/xilinx_spiOverJtag.bit : xilinx_spiOverJtag.vhd constr_%.xdc tmp_%/spiOverJtag.runs/impl_1/xilinx_spiOverJtag.bit : xilinx_spiOverJtag.vhd
$(VIVADO) xilinx_spiOverJtag.tcl -tclargs $* $(VIVADO) xilinx_spiOverJtag.tcl -tclargs $*
clean: clean:

View File

@ -0,0 +1,10 @@
set_property CFGBVS VCCO [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH {4} [current_design]
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
set_property -dict {PACKAGE_PIN L12 IOSTANDARD LVCMOS33} [get_ports {csn}];
set_property -dict {PACKAGE_PIN J13 IOSTANDARD LVCMOS33} [get_ports {sdi_dq0}];
set_property -dict {PACKAGE_PIN J14 IOSTANDARD LVCMOS33} [get_ports {sdo_dq1}];
set_property -dict {PACKAGE_PIN K15 IOSTANDARD LVCMOS33} [get_ports {wpn_dq2}];
set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {hldn_dq3}];

Binary file not shown.

Binary file not shown.

View File

@ -1,22 +1,39 @@
set model [lindex $argv 0] set parts [lindex $argv 0]
set project_name "spiOverJtag" set project_name "spiOverJtag"
set build_path tmp_${model} set build_path tmp_${parts}
file delete -force $build_path file delete -force $build_path
# Project creation # Project creation
set parts [dict create \ set grade [dict create \
xc7a35 xc7a35ticsg324-1L \ xc7a35tcsg324 -1 \
xc7a50t xc7a50tcpg236-2 \ xc7a35tftg256 -1 \
xc7s50 xc7s50csga324-1 \ xc7a50tcpg236 -2 \
xc7a100 xc7a100tfgg484-2 \ xc7a75tfgg484 -2 \
xc7a200 xc7a200tsbg484-1 \ xc7a100tfgg484 -2 \
xc7a200tsbg484 -1 \
xc7s50csga324 -1 \
] ]
create_project $project_name $build_path -part [dict get $parts $model]
set pkg_name [dict create \
xc7a35tcsg324 xc7a_csg324 \
xc7a35tftg256 xc7a_ftg256 \
xc7a50tcpg236 xc7a_cpg236 \
xc7a75tfgg484 xc7a_fgg484 \
xc7a100tfgg484 xc7a_fgg484 \
xc7a200tsbg484 xc7a_sbg484 \
xc7a200tfbg484 xc7a_fbg484 \
xc7s50csga324 xc7s_csga324 \
]
set curr_grade [dict get $grade $parts]
set curr_pins [dict get $pkg_name $parts]
create_project $project_name $build_path -part ${parts}${curr_grade}
add_files -norecurse xilinx_spiOverJtag.vhd add_files -norecurse xilinx_spiOverJtag.vhd
add_files -norecurse -fileset constrs_1 constr_${model}.xdc add_files -norecurse -fileset constrs_1 constr_${curr_pins}.xdc
set_property VERILOG_DEFINE {TOOL_VIVADO} [current_fileset] set_property VERILOG_DEFINE {TOOL_VIVADO} [current_fileset]

View File

@ -68,57 +68,58 @@ enum {
typedef struct { typedef struct {
std::string manufacturer; std::string manufacturer;
std::string cable_name; /*! provide name of one entry in cable_list */ std::string cable_name; /*! provide name of one entry in cable_list */
std::string fpga_part; /*! provide full fpga model name with package */
uint16_t reset_pin; /*! reset pin value */ uint16_t reset_pin; /*! reset pin value */
uint16_t done_pin; /*! done pin value */ uint16_t done_pin; /*! done pin value */
uint16_t mode; /*! communication type (JTAG or SPI) */ uint16_t mode; /*! communication type (JTAG or SPI) */
jtag_pins_conf_t jtag_pins_config; /*! for bitbang, provide struct with pins value */ jtag_pins_conf_t jtag_pins_config; /*! for bitbang, provide struct with pins value */
spi_pins_conf_t spi_pins_config; /*! for SPI, provide struct with pins value */ spi_pins_conf_t spi_pins_config; /*! for SPI, provide struct with pins value */
} target_cable_t; } target_board_t;
#define JTAG_BOARD(_name, _cable, _rst, _done) \ #define JTAG_BOARD(_name, _fpga_part, _cable, _rst, _done) \
{_name, {"", _cable, _rst, _done, COMM_JTAG, {}, {}}} {_name, {"", _cable, _fpga_part, _rst, _done, COMM_JTAG, {}, {}}}
#define JTAG_BITBANG_BOARD(_name, _cable, _rst, _done, _tms, _tck, _tdi, _tdo) \ #define JTAG_BITBANG_BOARD(_name, _fpga_part, _cable, _rst, _done, _tms, _tck, _tdi, _tdo) \
{_name, {"", _cable, _rst, _done, COMM_JTAG, { _tms, _tck, _tdi, _tdo }, {}}} {_name, {"", _cable, _fpga_part, _rst, _done, COMM_JTAG, { _tms, _tck, _tdi, _tdo }, {}}}
#define SPI_BOARD(_name, _manufacturer, _cable, _rst, _done, _cs, _sck, _si, _so, _holdn, _wpn) \ #define SPI_BOARD(_name, _manufacturer, _cable, _rst, _done, _cs, _sck, _si, _so, _holdn, _wpn) \
{_name, {_manufacturer, _cable, _rst, _done, COMM_SPI, {}, \ {_name, {_manufacturer, _cable, "", _rst, _done, COMM_SPI, {}, \
{_cs, _sck, _so, _si, _holdn, _wpn}}} {_cs, _sck, _so, _si, _holdn, _wpn}}}
static std::map <std::string, target_cable_t> board_list = { static std::map <std::string, target_board_t> board_list = {
JTAG_BOARD("acornCle215", "", 0, 0), JTAG_BOARD("acornCle215", "xc7a200tsbg484", "", 0, 0),
JTAG_BOARD("alchitry_au", "ft2232", 0, 0), JTAG_BOARD("alchitry_au", "xc7a35tftg256", "ft2232", 0, 0),
JTAG_BOARD("arty", "digilent", 0, 0), JTAG_BOARD("arty", "xc7a35tcsg324", "digilent", 0, 0),
JTAG_BOARD("nexysVideo", "digilent_b", 0, 0), JTAG_BOARD("nexysVideo", "xc7a200tsbg484", "digilent_b", 0, 0),
JTAG_BOARD("kc705", "digilent", 0, 0), JTAG_BOARD("kc705", "", "digilent", 0, 0),
JTAG_BOARD("colorlight", "", 0, 0), JTAG_BOARD("colorlight", "", "", 0, 0),
JTAG_BOARD("crosslinknx_evn", "ft2232", 0, 0), JTAG_BOARD("crosslinknx_evn", "", "ft2232", 0, 0),
JTAG_BOARD("cyc1000", "ft2232", 0, 0), JTAG_BOARD("cyc1000", "", "ft2232", 0, 0),
JTAG_BOARD("de0", "usb-blaster",0, 0), JTAG_BOARD("de0", "", "usb-blaster",0, 0),
JTAG_BOARD("de0nano", "usb-blaster",0, 0), JTAG_BOARD("de0nano", "", "usb-blaster",0, 0),
JTAG_BOARD("ecp5_evn", "ft2232", 0, 0), JTAG_BOARD("ecp5_evn", "", "ft2232", 0, 0),
SPI_BOARD("fireant", "efinix", "ft232", SPI_BOARD("fireant", "efinix", "ft232",
DBUS4, DBUS5, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0), DBUS4, DBUS5, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0),
/* most ice40 boards uses the same pinout */ /* most ice40 boards uses the same pinout */
SPI_BOARD("ice40_generic", "lattice", "ft2232", SPI_BOARD("ice40_generic", "lattice", "ft2232",
DBUS7, DBUS6, DBUS7, DBUS6,
DBUS4, DBUS0, DBUS1, DBUS2, DBUS4, DBUS0, DBUS1, DBUS2,
0, 0), 0, 0),
JTAG_BOARD("machXO2EVN", "ft2232", 0, 0), JTAG_BOARD("machXO2EVN", "", "ft2232", 0, 0),
JTAG_BOARD("machXO3SK", "ft2232", 0, 0), JTAG_BOARD("machXO3SK", "", "ft2232", 0, 0),
JTAG_BOARD("machXO3EVN", "ft2232", 0, 0), JTAG_BOARD("machXO3EVN", "", "ft2232", 0, 0),
JTAG_BOARD("licheeTang", "anlogicCable", 0, 0), JTAG_BOARD("licheeTang", "", "anlogicCable", 0, 0),
/* left for backward compatibility, use tec0117 instead */ /* left for backward compatibility, use tec0117 instead */
JTAG_BOARD("littleBee", "ft2232", 0, 0), JTAG_BOARD("littleBee", "", "ft2232", 0, 0),
JTAG_BOARD("spartanEdgeAccelBoard", "",0, 0), JTAG_BOARD("spartanEdgeAccelBoard", "", "",0, 0),
JTAG_BOARD("pipistrello", "ft2232", 0, 0), JTAG_BOARD("pipistrello", "", "ft2232", 0, 0),
JTAG_BOARD("qmtechCycloneV", "", 0, 0), JTAG_BOARD("qmtechCycloneV", "", "", 0, 0),
JTAG_BOARD("runber", "ft232", 0, 0), JTAG_BOARD("runber", "", "ft232", 0, 0),
JTAG_BOARD("tangnano", "ft2232", 0, 0), JTAG_BOARD("tangnano", "", "ft2232", 0, 0),
JTAG_BOARD("tec0117", "ft2232", 0, 0), JTAG_BOARD("tec0117", "", "ft2232", 0, 0),
JTAG_BITBANG_BOARD("ulx2s", "ft232RL", 0, 0, FT232RL_RI, FT232RL_DSR, FT232RL_CTS, FT232RL_DCD), JTAG_BITBANG_BOARD("ulx2s", "", "ft232RL", 0, 0, FT232RL_RI, FT232RL_DSR, FT232RL_CTS, FT232RL_DCD),
JTAG_BITBANG_BOARD("ulx3s", "ft231X", 0, 0, FT232RL_DCD, FT232RL_DSR, FT232RL_RI, FT232RL_CTS), JTAG_BITBANG_BOARD("ulx3s", "", "ft231X", 0, 0, FT232RL_DCD, FT232RL_DSR, FT232RL_RI, FT232RL_CTS),
JTAG_BOARD("ecpix5", "ecpix5-debug", 0, 0), JTAG_BOARD("ecpix5", "", "ecpix5-debug", 0, 0),
JTAG_BOARD("xtrx", "" , 0, 0), JTAG_BOARD("xtrx", "xc7a50tcpg236", "" , 0, 0),
SPI_BOARD("xyloni_spi", "efinix", "efinix_spi", SPI_BOARD("xyloni_spi", "efinix", "efinix_spi",
DBUS4 | DBUS7, DBUS5, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0), DBUS4 | DBUS7, DBUS5, DBUS3, DBUS0, DBUS1, DBUS2, DBUS6, 0),
}; };

View File

@ -62,6 +62,7 @@ struct arguments {
bool is_list_command; bool is_list_command;
bool spi; bool spi;
string file_type; string file_type;
string fpga_part;
}; };
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);
@ -71,12 +72,13 @@ void displaySupported(const struct arguments &args);
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
cable_t cable; cable_t cable;
target_cable_t *board = NULL; target_board_t *board = NULL;
jtag_pins_conf_t pins_config = {0, 0, 0, 0}; jtag_pins_conf_t pins_config = {0, 0, 0, 0};
/* command line args. */ /* command line args. */
struct arguments args = {0, false, false, 0, "", "", "-", "", -1, 6000000, "-", struct arguments args = {0, false, false, 0, "", "", "-", "", -1, 6000000, "-",
false, false, false, false, Device::WR_SRAM, false, false, ""}; false, false, false, false, Device::WR_SRAM, false, false, "",
""};
/* parse arguments */ /* parse arguments */
try { try {
if (parse_opt(argc, argv, &args, &pins_config)) if (parse_opt(argc, argv, &args, &pins_config))
@ -122,6 +124,12 @@ int main(int argc, char **argv)
cout << "Board default cable overridden with " << args.cable << endl; cout << "Board default cable overridden with " << args.cable << endl;
} }
} }
/* 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;
} }
if (args.cable[0] == '-') { /* if no board and no cable */ if (args.cable[0] == '-') { /* if no board and no cable */
@ -269,7 +277,7 @@ int main(int argc, char **argv)
try { try {
if (fab == "xilinx") { if (fab == "xilinx") {
fpga = new Xilinx(jtag, args.bit_file, args.file_type, fpga = new Xilinx(jtag, args.bit_file, args.file_type,
args.prg_type, args.verbose); args.prg_type, args.fpga_part, args.verbose);
} else if (fab == "altera") { } else if (fab == "altera") {
fpga = new Altera(jtag, args.bit_file, args.file_type, fpga = new Altera(jtag, args.bit_file, args.file_type,
args.verbose); args.verbose);
@ -370,6 +378,7 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p
cxxopts::value<bool>(args->detect)) cxxopts::value<bool>(args->detect))
("file-type", "provides file type instead of let's deduced by using extension", ("file-type", "provides file type instead of let's deduced by using extension",
cxxopts::value<string>(args->file_type)) cxxopts::value<string>(args->file_type))
("fpga-part", "fpga model flavor + package", cxxopts::value<string>(args->fpga_part))
("freq", "jtag frequency (Hz)", cxxopts::value<string>(freqo)) ("freq", "jtag frequency (Hz)", cxxopts::value<string>(freqo))
("f,write-flash", ("f,write-flash",
"write bitstream in flash (default: false, only for Gowin and ECP5 devices)") "write bitstream in flash (default: false, only for Gowin and ECP5 devices)")
@ -543,7 +552,7 @@ void displaySupported(const struct arguments &args)
printSuccess(t.str()); printSuccess(t.str());
for (auto b = board_list.begin(); b != board_list.end(); b++) { for (auto b = board_list.begin(); b != board_list.end(); b++) {
stringstream ss; stringstream ss;
target_cable_t c = (*b).second; target_board_t c = (*b).second;
ss << setw(15) << left << (*b).first << " " << c.cable_name; ss << setw(15) << left << (*b).first << " " << c.cable_name;
printInfo(ss.str()); printInfo(ss.str());
} }

View File

@ -1,5 +1,6 @@
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
#include <string>
#include "jtag.hpp" #include "jtag.hpp"
#include "bitparser.hpp" #include "bitparser.hpp"
@ -15,8 +16,9 @@
Xilinx::Xilinx(Jtag *jtag, const std::string &filename, Xilinx::Xilinx(Jtag *jtag, const std::string &filename,
const std::string &file_type, const std::string &file_type,
Device::prog_type_t prg_type, int8_t verbose): Device::prog_type_t prg_type,
Device(jtag, filename, file_type, verbose) std::string device_package, int8_t verbose):
Device(jtag, filename, file_type, verbose),_device_package(device_package)
{ {
if (!_file_extension.empty()) { if (!_file_extension.empty()) {
if (_file_extension == "mcs") { if (_file_extension == "mcs") {
@ -123,9 +125,16 @@ void Xilinx::program(unsigned int offset)
void Xilinx::program_spi(ConfigBitstreamParser * bit, unsigned int offset) void Xilinx::program_spi(ConfigBitstreamParser * bit, unsigned int offset)
{ {
if (_device_package.empty()) {
printError("Can't program SPI flash: missing device-package information");
return;
}
// DATA_DIR is defined at compile time. // DATA_DIR is defined at compile time.
std::string bitname = DATA_DIR "/openFPGALoader/spiOverJtag_"; std::string bitname = DATA_DIR "/openFPGALoader/spiOverJtag_";
bitname += fpga_list[idCode()].model + ".bit"; bitname += _device_package + ".bit";
std::cout << "use: " << bitname << std::endl;
/* first: load spi over jtag */ /* first: load spi over jtag */
try { try {

View File

@ -12,7 +12,8 @@ class Xilinx: public Device, SPIInterface {
public: public:
Xilinx(Jtag *jtag, const std::string &filename, Xilinx(Jtag *jtag, const std::string &filename,
const std::string &file_type, const std::string &file_type,
Device::prog_type_t prg_type, int8_t verbose); Device::prog_type_t prg_type,
std::string device_package, int8_t verbose);
~Xilinx(); ~Xilinx();
void program(unsigned int offset = 0) override; void program(unsigned int offset = 0) override;
@ -27,6 +28,9 @@ class Xilinx: public Device, SPIInterface {
int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) override; int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) override;
int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
uint32_t timeout, bool verbose = false) override; uint32_t timeout, bool verbose = false) override;
private:
std::string _device_package;
}; };
#endif #endif