diff --git a/spiOverJtag/Makefile b/spiOverJtag/Makefile index 7ac1da4..1734100 100644 --- a/spiOverJtag/Makefile +++ b/spiOverJtag/Makefile @@ -15,7 +15,7 @@ XILINX_PARTS := xc3s500evq100 \ xcku040-ffva1156 xcku060-ffva1156 \ xcku5p-ffvb676 \ xcvu9p-flga2104 xcvu37p-fsvh2892 \ - xcau10p-ffvb676 \ + xcau7p-sbvc484 xcau10p-ffvb676 \ xcau15p-ffvb676 XILINX_BIT_FILES := $(addsuffix .bit.gz,$(addprefix spiOverJtag_, $(XILINX_PARTS))) diff --git a/spiOverJtag/build.py b/spiOverJtag/build.py index a1d1163..42f9ccd 100755 --- a/spiOverJtag/build.py +++ b/spiOverJtag/build.py @@ -166,6 +166,7 @@ if tool in ["ise", "vivado"]: "xcku3p-ffva676" : "xcku3p_ffva676", "xcku3p-ffvb676" : "xcku3p_ffvb676", "xcku5p-ffvb676" : "xcku5p_ffvb676", + "xcau7p-sbvc484" : "xcau7p_sbvc484", "xcau10p-ffvb676" : "xcau10p_ffvb676", "xcau15p-ffvb676" : "xcau15p_ffvb676", }.get(part, pkg_name) @@ -233,7 +234,7 @@ if tool in ["ise", "vivado"]: "description" : "secondary flash", "default" : 1, } - elif part == "xcau10p-ffvb676": + elif part in ["xcau10p-ffvb676", "xcau7p-sbvc484"]: tool_options = {"part": part + "-1-e"} elif part == "xcau15p-ffvb676": tool_options = {"part": part + "-2-e"} diff --git a/spiOverJtag/constr_xcau7p_sbvc484.xdc b/spiOverJtag/constr_xcau7p_sbvc484.xdc new file mode 100644 index 0000000..bc4bb4a --- /dev/null +++ b/spiOverJtag/constr_xcau7p_sbvc484.xdc @@ -0,0 +1,7 @@ +set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design] +set_property CONFIG_VOLTAGE 1.8 [current_design] +# Table 1-2 from UG570 +set_property CFGBVS GND [current_design] + +# Primary QSPI flash +# Connection done through the STARTUPE3 block diff --git a/spiOverJtag/xilinx_spiOverJtag.v b/spiOverJtag/xilinx_spiOverJtag.v index a3e0dd8..6d212ab 100644 --- a/spiOverJtag/xilinx_spiOverJtag.v +++ b/spiOverJtag/xilinx_spiOverJtag.v @@ -32,6 +32,13 @@ module spiOverJtag wire capture, drck, sel, update, shift; wire tdi, tdo; +`ifdef xilinxultrascale + /* For ultrascale these signals are internal wires (not module ports); + declare them here so they are visible to spiOverJtag_core_prim below. */ + wire csn; + wire sdi_dq0, sdo_dq1, wpn_dq2, hldn_dq3; +`endif + `ifndef spartan3e `ifndef virtex6 /* Version Interface. */ @@ -75,7 +82,6 @@ module spiOverJtag `else // !spartan6 && !spartan3e `ifdef xilinxultrascale - assign sck = drck; wire [3:0] di; assign sdo_dq1 = di[1]; diff --git a/src/main.cpp b/src/main.cpp index 44de606..4acfec1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -804,14 +804,14 @@ int spi_comm(struct arguments args, const cable_t &cable, bit = new RawParser(args.bit_file, false); printSuccess("DONE"); } catch (std::exception &e) { - printError("FAIL"); + printError("FAIL: unable to open '" + args.bit_file + "': " + std::string(e.what())); delete spi; return EXIT_FAILURE; } printInfo("Parse file ", false); if (bit->parse() == EXIT_FAILURE) { - printError("FAIL"); + printError("FAIL: unable to parse '" + args.bit_file + "'"); delete bit; delete spi; return EXIT_FAILURE; diff --git a/src/part.hpp b/src/part.hpp index 71f4564..1a96129 100644 --- a/src/part.hpp +++ b/src/part.hpp @@ -131,6 +131,7 @@ static std::map fpga_list = { {0x03842093, {"xilinx", "virtexus", "xcvu095", 6}}, /* Xilinx Ultrascale+ / Artix */ + {0x04AF6093, {"xilinx", "artixusp", "xcau7p", 6}}, {0x04AC4033, {"xilinx", "artixusp", "xcau10p", 6}}, {0x04AC4093, {"xilinx", "artixusp", "xcau10p", 6}}, {0x04AC2093, {"xilinx", "artixusp", "xcau15p", 6}}, diff --git a/src/spiFlashdb.hpp b/src/spiFlashdb.hpp index 0fdebec..fcab329 100644 --- a/src/spiFlashdb.hpp +++ b/src/spiFlashdb.hpp @@ -651,6 +651,23 @@ static std::map flash_list = { .quad_mask = (1 << 6), .global_lock = false, }}, + {0xc86019, { + /* https://www.gigadevice.com/product/flash/spi-nor-flash/gd25lq256h */ + .manufacturer = "GigaDevice", + .model = "GD25LQ256H", + .nr_sector = 512, + .sector_erase = true, + .subsector_erase = true, + .has_extended = false, + .tb_otp = false, + .tb_offset = (1 << 6), // BP4 + .tb_register = STATR, + .bp_len = 4, + .bp_offset = {(1 << 2), (1 << 3), (1 << 4), (1 << 5)}, + .quad_register = CONFR, + .quad_mask = (1 << 1), // QE = SR2 S9 = bit1 of byte read by RDSR-2 (0x35) + .global_lock = false, + }}, {0xc22817, { /* https://www.macronix.com/Lists/Datasheet/Attachments/8868/MX25R6435F,%20Wide%20Range,%2064Mb,%20v1.6.pdf */ .manufacturer = "Macronix", @@ -766,6 +783,40 @@ static std::map flash_list = { .quad_mask = 0, .global_lock = false, }}, + {0xef6019, { + /* Winbond W25Q25PW (1.8V), 256 Mbit / 32 MiB. Requires 4-byte addressing. */ + .manufacturer = "Winbond", + .model = "W25Q25PW", + .nr_sector = 512, + .sector_erase = true, + .subsector_erase = true, + .has_extended = false, + .tb_otp = false, + .tb_offset = (1 << 6), // TB (SR1 S6) + .tb_register = STATR, + .bp_len = 4, + .bp_offset = {(1 << 2), (1 << 3), (1 << 4), (1 << 5)}, + .quad_register = CONFR, + .quad_mask = (1 << 1), // QE = SR2 S9 = bit1 of byte read by RDSR-2 (0x35) + .global_lock = false, + }}, + {0xef8019, { + /* Winbond W25Q25PW newer-gen die that reports memory-type 0x80. */ + .manufacturer = "Winbond", + .model = "W25Q25PW", + .nr_sector = 512, + .sector_erase = true, + .subsector_erase = true, + .has_extended = false, + .tb_otp = false, + .tb_offset = (1 << 6), // TB (SR1 S6) + .tb_register = STATR, + .bp_len = 4, + .bp_offset = {(1 << 2), (1 << 3), (1 << 4), (1 << 5)}, + .quad_register = CONFR, + .quad_mask = (1 << 1), // QE = SR2 S9 = bit1 of byte read by RDSR-2 (0x35) + .global_lock = false, + }}, {0x6bbb14, { .manufacturer = "Everspin", .model = "EM008LX", diff --git a/src/xilinx.cpp b/src/xilinx.cpp index aa53aa5..238df43 100644 --- a/src/xilinx.cpp +++ b/src/xilinx.cpp @@ -207,20 +207,24 @@ static void open_bitfile( const std::string &filename, const std::string &extension, ConfigBitstreamParser **parser, bool reverse, bool verbose) { - printInfo("Open file ", false); - if (extension == "bit") { - *parser = new BitParser(filename, reverse, verbose); - } else if (extension == "mcs") { - *parser = new McsParser(filename, reverse, verbose); - } else { - *parser = new RawParser(filename, reverse); + printInfo("Open file " + filename + " ", false); + try { + if (extension == "bit") { + *parser = new BitParser(filename, reverse, verbose); + } else if (extension == "mcs") { + *parser = new McsParser(filename, reverse, verbose); + } else { + *parser = new RawParser(filename, reverse); + } + } catch (const std::exception &e) { + throw std::runtime_error("Unable to open '" + filename + "': " + e.what()); } printSuccess("DONE"); printInfo("Parse file ", false); if ((*parser)->parse() == EXIT_FAILURE) { - throw std::runtime_error("Failed to parse bitstream"); + throw std::runtime_error("Failed to parse bitstream '" + filename + "'"); } printSuccess("DONE"); @@ -662,12 +666,11 @@ void Xilinx::program(unsigned int offset, bool unprotect_flash) &secondary_bit, reverse, _verbose); } } catch (std::exception &e) { - printError("FAIL"); if (bit) delete bit; if (secondary_bit) delete secondary_bit; - return; + throw std::runtime_error(e.what()); } if (_verbose) { @@ -899,11 +902,13 @@ void Xilinx::program_spi(ConfigBitstreamParser * bit, std::string extention, throw std::runtime_error("called with null bitstream"); if (extention == "mcs") { McsParser *parser = (McsParser *)bit; - FlashInterface::write(parser->getRecords(), unprotect_flash, true); + if (!FlashInterface::write(parser->getRecords(), unprotect_flash, true)) + throw std::runtime_error("SPI flash write failed"); } else { const uint8_t *data = bit->getData(); int length = bit->getLength() / 8; - FlashInterface::write(offset, data, length, unprotect_flash); + if (!FlashInterface::write(offset, data, length, unprotect_flash)) + throw std::runtime_error("SPI flash write failed"); } }