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", diff --git a/src/dfu.cpp b/src/dfu.cpp index d94e410..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), @@ -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 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( 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"); 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"); 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; } 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", diff --git a/src/xvc_client.cpp b/src/xvc_client.cpp index d095049..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; @@ -242,6 +245,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 +269,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; }