From fc58ffed38de2de5918548064013d71715cf030a Mon Sep 17 00:00:00 2001 From: sigmaeo <36727521+sigmaeo@users.noreply.github.com> Date: Thu, 1 Feb 2024 19:48:21 +0100 Subject: [PATCH 1/9] Update spiFlashdb.hpp for Macronix MX25L3233F used on Cmod A7-35T Digilent changed from Micron N25Q032A to Macronix MX25L3233F in 2020/2021, so this flash is needed in openfpgaloader to load to Cmod A7-35T --- src/spiFlashdb.hpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/spiFlashdb.hpp b/src/spiFlashdb.hpp index 6404302..89a7320 100644 --- a/src/spiFlashdb.hpp +++ b/src/spiFlashdb.hpp @@ -286,6 +286,20 @@ static std::map flash_list = { .bp_len = 4, .bp_offset = {(1 << 2), (1 << 3), (1 << 4), (1 << 5)}} }, + {0xc22016, { + /* https://www.macronix.com/Lists/Datasheet/Attachments/8933/MX25L3233F,%203V,%2032Mb,%20v1.7.pdf */ + .manufacturer = "Macronix", + .model = "MX25L3233F", + .nr_sector = 256, + .sector_erase = true, + .subsector_erase = true, + .has_extended = false, + .tb_otp = true, + .tb_offset = (1 << 3), + .tb_register = CONFR, + .bp_len = 5, + .bp_offset = {(1 << 2), (1 << 3), (1 << 4), (1 << 5)}} + }, {0xc22018, { /* https://www.macronix.com/Lists/Datasheet/Attachments/8934/MX25L12833F,%203V,%20128Mb,%20v1.0.pdf */ .manufacturer = "Macronix", From eba9c37027c7a913beaf0835b2233078ca7e8011 Mon Sep 17 00:00:00 2001 From: jgroman Date: Fri, 2 Feb 2024 12:54:17 +0100 Subject: [PATCH 2/9] Fix SRAM loading on invalid flash --- src/gowin.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/gowin.cpp b/src/gowin.cpp index 1f7cbc0..fef7724 100644 --- a/src/gowin.cpp +++ b/src/gowin.cpp @@ -883,8 +883,19 @@ void Gowin::sendClkUs(unsigned us) bool Gowin::eraseSRAM() { printInfo("Erase SRAM ", false); + uint32_t status = readStatusReg(); if (_verbose) - displayReadReg("before erase sram", readStatusReg()); + displayReadReg("before erase sram", status); + + // If flash is invalid, send extra cmd 0x3F before SRAM erase + // This is required on GW5A-25 + bool auto_boot_2nd_fail = (status & 0x8) >> 3; + if ((_idcode == 0x0001281B) && auto_boot_2nd_fail) + { + disableCfg(); + send_command(0x3F); + send_command(NOOP); + } if (!enableCfg()) { printError("FAIL"); From 4c737b2b961bd403f755c1deca3a17c0753d03ec Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 11 Feb 2024 14:10:01 -0800 Subject: [PATCH 3/9] xvc client ensure send() entire buffer --- src/xvc_client.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/xvc_client.cpp b/src/xvc_client.cpp index d095049..6edb167 100644 --- a/src/xvc_client.cpp +++ b/src/xvc_client.cpp @@ -242,6 +242,23 @@ bool XVC_client::open_connection(const string &ip_addr) return true; } +static +int sendall(int sock, const void* raw, size_t cnt, int flags) +{ + const char *buf = (const char*)raw; + size_t remaining = cnt; + while (remaining) { + ssize_t ret = send(sock, buf, remaining, flags); + if (ret==0) // should not happen on Linux for a TCP socket + throw std::logic_error("platform TCP send() returns zero?!?"); + if (ret < 0) + return ret; + buf += ret; + remaining -= ret; + } + return cnt; // success +} + ssize_t XVC_client::xfer_pkt(const string &instr, const uint8_t *tx, uint32_t tx_size, uint8_t *rx, uint32_t rx_size) @@ -249,13 +266,13 @@ ssize_t XVC_client::xfer_pkt(const string &instr, ssize_t len = tx_size; /* 1. instruction */ - if (send(_sock, instr.c_str(), instr.size(), 0) == -1) { + if (sendall(_sock, instr.c_str(), instr.size(), 0) == -1) { printError("Send instruction failed"); return -1; } if (tx) { - if (send(_sock, tx, tx_size, 0) == -1) { + if (sendall(_sock, tx, tx_size, 0) == -1) { printError("Send error"); return -1; } From daa1e38799bddc457e8060cda6249756f058514a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 11 Feb 2024 14:14:08 -0800 Subject: [PATCH 4/9] xvc client: handle failed ll_write() Avoids "Send instruction failed" in a tight loop... --- src/xvc_client.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/xvc_client.cpp b/src/xvc_client.cpp index 6edb167..a8549df 100644 --- a/src/xvc_client.cpp +++ b/src/xvc_client.cpp @@ -99,7 +99,8 @@ int XVC_client::writeTMS(const uint8_t *tms, uint32_t len, bool flush_buffer, // buffer full -> write if (_num_bits == _buffer_size * 8) { // write - ll_write(NULL); + if(!ll_write(NULL)) + throw std::runtime_error("xvc ll_write fails"); _num_bits = 0; } @@ -147,7 +148,8 @@ int XVC_client::writeTDI(const uint8_t *tx, uint8_t *rx, uint32_t len, bool end) uint16_t idx = _num_bits - 1; _tms[(idx >> 3)] |= (1 << (idx & 0x07)); } - ll_write((rx) ? rx_ptr : NULL); // write + if(!ll_write((rx) ? rx_ptr : NULL)) // write + throw std::runtime_error("xvc ll_write fails"); tx_ptr += tt; if (rx) @@ -184,7 +186,8 @@ int XVC_client::toggleClk(uint8_t tms, uint8_t tdi, uint32_t clk_len) if (len < _num_bits) _num_bits = len; len -= _num_bits; - ll_write(NULL); + if(!ll_write(NULL)) + throw std::runtime_error("xvc ll_write fails"); } while (len > 0); return clk_len; From 0f9422f09a3e7ecc6b7108a651e9f979cbfbed2f Mon Sep 17 00:00:00 2001 From: Giovanni Bruni Date: Tue, 13 Feb 2024 09:20:35 +0100 Subject: [PATCH 5/9] latticeBitParser: add support for loading Lattice (Nexus) encrypted bitstreams, by adding key and preamble of encrypted bitstreams to if statements. --- src/latticeBitParser.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/latticeBitParser.cpp b/src/latticeBitParser.cpp index beb15ec..4c7ad92 100644 --- a/src/latticeBitParser.cpp +++ b/src/latticeBitParser.cpp @@ -68,7 +68,8 @@ int LatticeBitParser::parseHeader() printError("Preamble key not found"); return EXIT_FAILURE; } - if ((uint8_t)_raw_data[pos-1] != 0xbd && (uint8_t)_raw_data[pos-1] != 0xbf) { + //0xbe is the key for encrypted bitstreams in Nexus fpgas + if ((uint8_t)_raw_data[pos-1] != 0xbd && (uint8_t)_raw_data[pos-1] != 0xbf && (uint8_t)_raw_data[pos-1] != 0xbe) { printError("Wrong preamble key"); return EXIT_FAILURE; } @@ -98,7 +99,8 @@ int LatticeBitParser::parse() /* check preamble */ uint32_t preamble = (*(uint32_t *)&_raw_data[_endHeader+1]); - if ((preamble != 0xb3bdffff) && (preamble != 0xb3bfffff)) { + //0xb3beffff is the preamble for encrypted bitstreams in Nexus fpgas + if ((preamble != 0xb3bdffff) && (preamble != 0xb3bfffff) && (preamble != 0xb3beffff)) { printError("Error: missing preamble\n"); return EXIT_FAILURE; } From e923ef4059cfb4bb98e33d145cb8e99f8b15e07e Mon Sep 17 00:00:00 2001 From: Giovanni Bruni Date: Tue, 13 Feb 2024 09:24:47 +0100 Subject: [PATCH 6/9] lattice nexus boards: change from CABLE_DEFAULT (i.e. 6MHz) to CABLE_MHZ(1) (i.e. 1MHz) as at 6MHz the download of bitstreams is not stable. With "not stable" we mean that: - when dealing with Certus/Crosslink, most of the times it works - when dealing with CertusPro devices, most of the times it doesn't work We think this is due to the size of the bitstream and the way that the transmission/storing is handled on the receiving side (i.e. the FPGA). --- src/board.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/board.hpp b/src/board.hpp index 54fa83d..98ff6c5 100644 --- a/src/board.hpp +++ b/src/board.hpp @@ -131,10 +131,10 @@ static std::map board_list = { JTAG_BOARD("colorlight-i5", "", "cmsisdap", 0, 0, CABLE_DEFAULT), JTAG_BOARD("colorlight-i9", "", "cmsisdap", 0, 0, CABLE_DEFAULT), JTAG_BOARD("colorlight-i9+", "xc7a50tfgg484", "", 0, 0, CABLE_DEFAULT), - JTAG_BOARD("crosslinknx_evn", "", "ft2232", 0, 0, CABLE_DEFAULT), - JTAG_BOARD("certusnx_versa_evn", "", "ft2232", 0, 0, CABLE_DEFAULT), - JTAG_BOARD("certuspronx_evn", "", "ft2232", 0, 0, CABLE_DEFAULT), - JTAG_BOARD("certuspronx_versa_evn", "", "ft2232", 0, 0, CABLE_DEFAULT), + JTAG_BOARD("crosslinknx_evn", "", "ft2232", 0, 0, CABLE_MHZ(1)), + JTAG_BOARD("certusnx_versa_evn", "", "ft2232", 0, 0, CABLE_MHZ(1)), + JTAG_BOARD("certuspronx_evn", "", "ft2232", 0, 0, CABLE_MHZ(1)), + JTAG_BOARD("certuspronx_versa_evn", "", "ft2232", 0, 0, CABLE_MHZ(1)), JTAG_BOARD("cyc1000", "10cl025256", "ft2232", 0, 0, CABLE_DEFAULT), JTAG_BOARD("c10lp-refkit", "10cl055484", "ft2232", 0, 0, CABLE_DEFAULT), JTAG_BOARD("de0", "", "usb-blaster",0, 0, CABLE_DEFAULT), @@ -160,7 +160,7 @@ static std::map board_list = { SPI_BOARD("gatemate_evb_spi", "colognechip", "gatemate_evb_spi", DBUS4, DBUS5, CBUS0, DBUS3, DBUS0, DBUS1, DBUS2, 0, 0, CABLE_DEFAULT), JTAG_BOARD("genesys2", "xc7k325tffg900", "digilent_b", 0, 0, CABLE_DEFAULT), - JTAG_BOARD("gr740-mini", "", "ft4232hp_b", 0, 0, CABLE_DEFAULT), + JTAG_BOARD("gr740-mini", "", "ft4232hp_b", 0, 0, CABLE_MHZ(1)), JTAG_BOARD("hseda-xc6slx16", "xc6slx16ftg256", "", 0, 0, CABLE_DEFAULT), /* most ice40 boards uses the same pinout */ SPI_BOARD("ice40_generic", "lattice", "ft2232", From ffc519c0e2a74117d7d8ecd6988a0441ad684ead Mon Sep 17 00:00:00 2001 From: Giovanni Bruni Date: Tue, 13 Feb 2024 09:32:30 +0100 Subject: [PATCH 7/9] lattice: improve info about "BSE Error Code" from Device Status Register --- src/lattice.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/lattice.cpp b/src/lattice.cpp index 695b4af..5ca516e 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -1080,7 +1080,8 @@ void Lattice::displayReadReg(uint64_t dev) err = (dev >> 23)&0x07; } - printf("\t"); + printf("\tBSE Error Code\n"); + printf("\t\t"); switch (err) { case 0: printf("No err\n"); @@ -1106,8 +1107,17 @@ void Lattice::displayReadReg(uint64_t dev) case 7: printf("SDM EOF\n"); break; + case 8: + printf("Authentication ERR\n"); + break; + case 9: + printf("Authentication Setup ERR\n"); + break; + case 10: + printf("Bitstream Engine Timeout ERR\n"); + break; default: - printf("unknown %x\n", err); + printf("unknown error: %x\n", err); } if (_fpga_family == NEXUS_FAMILY) { @@ -1164,7 +1174,7 @@ void Lattice::displayReadReg(uint64_t dev) printf("Bitstream Engine Timeout ERR\n"); break; default: - printf("unknown %x\n", err); + printf("unknown error: %x\n", err); } if ((dev >> 38) & 0x01) printf("\tBypass Mode\n"); if ((dev >> 39) & 0x01) printf("\tFlow Through Mode\n"); From 3165552994fe16fb75e529996a2d3b91df1eb509 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 15 Feb 2024 06:45:13 +0100 Subject: [PATCH 8/9] DFU: fix code to accept tinyDFU implementation (where not altsettings have an DFU descriptor) --- src/dfu.cpp | 48 +++++++++++++++++++++++++++++++++++++++--------- src/dfu.hpp | 4 ++-- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/dfu.cpp b/src/dfu.cpp index d94e410..7a0cf35 100644 --- a/src/dfu.cpp +++ b/src/dfu.cpp @@ -358,23 +358,35 @@ int DFU::searchIfDFU(struct libusb_device_handle *handle, /* configuration interface iteration */ for (int if_idx=0; if_idx < cfg->bNumInterfaces; if_idx++) { const struct libusb_interface *uif = &cfg->interface[if_idx]; + std::vector dfu_dev_tmp; + struct dfu_desc *dfu_desc; + bool dfu_found = false; /* altsettings interation */ for (int intf_idx = 0; intf_idx < uif->num_altsetting; intf_idx++) { const struct libusb_interface_descriptor *intf = &uif->altsetting[intf_idx]; uint8_t intfClass = intf->bInterfaceClass; uint8_t intfSubClass = intf->bInterfaceSubClass; - if (_altsetting != -1 && _altsetting != intf_idx) - continue; if (intfClass == 0xfe && intfSubClass == 0x01) { struct dfu_dev my_dev; if (_verbose) printInfo("DFU found"); /* dfu functional descriptor */ + /* not all DFU implementations provides a descriptor per altsettings + * so don't stop directly. + */ if (parseDFUDescriptor(intf, reinterpret_cast(&my_dev.dfu_desc), - sizeof(my_dev.dfu_desc)) != 0) - continue; // not compatible + sizeof(my_dev.dfu_desc))) { + dfu_desc = &my_dev.dfu_desc; + dfu_found = true; + } + /* this altsetting is a DFU interface: + * - if user has selected one altsetting current is only stored if it match + * - otherwise all are stored + */ + if (_altsetting != -1 && _altsetting != intf_idx) + continue; my_dev.vid = desc->idVendor; my_dev.pid = desc->idProduct; my_dev.altsettings = intf_idx; @@ -397,9 +409,22 @@ int DFU::searchIfDFU(struct libusb_device_handle *handle, int r = libusb_get_port_numbers(dev, my_dev.path, sizeof(my_dev.path)); my_dev.path[r] = '\0'; - dfu_dev.push_back(my_dev); + dfu_dev_tmp.push_back(my_dev); } } + + /* At least one altsetting has a DFU descriptor */ + if (dfu_found) { + /* with tinyDFU only one (the first) altsetting contains a descriptor + * fill others with this information + */ + for (struct dfu_dev &d: dfu_dev_tmp) { + if (d.dfu_desc.bDescriptorType == 0) + memcpy(&d.dfu_desc, dfu_desc, sizeof(struct dfu_desc)); + } + std::move(dfu_dev_tmp.begin(), dfu_dev_tmp.end(), std::back_inserter(dfu_dev)); + + } } libusb_free_config_descriptor(cfg); @@ -413,24 +438,29 @@ int DFU::searchIfDFU(struct libusb_device_handle *handle, * Since libusb has no support for those structure * fill a custom structure */ -int DFU::parseDFUDescriptor(const struct libusb_interface_descriptor *intf, +bool DFU::parseDFUDescriptor(const struct libusb_interface_descriptor *intf, uint8_t *dfu_desc, int dfu_desc_size) { const uint8_t *extra = intf->extra; int extra_len = intf->extra_length; + /* not all altsettings for a DFU device have a DFU descriptor + * set to 0 to be able to detect a missing descriptor + */ + memset(dfu_desc, 0, 9); + if (extra_len < 9) - return -1; + return false; /* map memory to structure */ for (int j = 0; j + 1 < extra_len; j++) { if (extra[j+1] == 0x21) { memcpy(dfu_desc, (const void *)&extra[j], dfu_desc_size); - break; + return true; } } - return 0; + return false; } /* abstraction to send/receive to control */ diff --git a/src/dfu.hpp b/src/dfu.hpp index 1501dc2..437c6c5 100644 --- a/src/dfu.hpp +++ b/src/dfu.hpp @@ -206,9 +206,9 @@ class DFU { * \param[in] intf: interface descriptor with extra area * \param[out] dfu_desc: DFU descriptor * \param[in] dfu_desc_size: DFU descriptor structure size - * \return -1 if extra len is too small, 0 otherwise + * \return false if extra len is too small, true otherwise * */ - int parseDFUDescriptor(const struct libusb_interface_descriptor *intf, + bool parseDFUDescriptor(const struct libusb_interface_descriptor *intf, uint8_t *dfu_desc, int dfu_desc_size); /*! * \brief try to open device specified by vid and pid. If found From 0182d592befc780aed9d2e044e9cc65e1b95f9f9 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec Date: Tue, 20 Feb 2024 20:59:13 +0100 Subject: [PATCH 9/9] dfu,ftdipp_mpsse: sprintf -> snprintf --- src/dfu.cpp | 2 +- src/ftdipp_mpsse.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dfu.cpp b/src/dfu.cpp index 7a0cf35..76b682d 100644 --- a/src/dfu.cpp +++ b/src/dfu.cpp @@ -326,7 +326,7 @@ int DFU::searchDFUDevices() } } else if (_debug) { char mess[256]; - sprintf(mess,"Unable to open device: " + snprintf(mess, 256, "Unable to open device: " "%04x:%04x (bus %d, device %2d) Error: %s -> skip\n", desc.idVendor, desc.idProduct, libusb_get_bus_number(usb_dev), diff --git a/src/ftdipp_mpsse.cpp b/src/ftdipp_mpsse.cpp index 10bcef1..084fb40 100644 --- a/src/ftdipp_mpsse.cpp +++ b/src/ftdipp_mpsse.cpp @@ -878,7 +878,7 @@ bool FTDIpp_MPSSE::search_with_dev(const string &device) usbdeviceparent, "busnum"), 10)); _addr = static_cast(udevstufftoint(udev_device_get_sysattr_value( usbdeviceparent, "devnum"), 10)); - sprintf(_product, "%s", udev_device_get_sysattr_value(usbdeviceparent, "product")); + snprintf(_product, 64, "%s", udev_device_get_sysattr_value(usbdeviceparent, "product")); _vid = udevstufftoint( udev_device_get_sysattr_value(usbdeviceparent, "idVendor"), 16); _pid = udevstufftoint(udev_device_get_sysattr_value(