diff --git a/src/gowin.cpp b/src/gowin.cpp index b435e5cb7c..9b501d25ac 100644 --- a/src/gowin.cpp +++ b/src/gowin.cpp @@ -56,6 +56,7 @@ using namespace std; # define STATUS_READY (1 << 15) # define STATUS_POR (1 << 16) # define STATUS_FLASH_LOCK (1 << 17) + #define EF_PROGRAM 0x71 #define EFLASH_ERASE 0x75 #define SWITCH_TO_MCU_JTAG 0x7a @@ -66,19 +67,18 @@ using namespace std; #define BSCAN_SPI_CS (1 << 3) #define BSCAN_SPI_DI (1 << 5) #define BSCAN_SPI_DO (1 << 7) -#define BSCAN_SPI_MSK ((0x01 << 6)) +#define BSCAN_SPI_MSK (1 << 6) /* GW1NSR-4C pins def */ #define BSCAN_GW1NSR_4C_SPI_SCK (1 << 7) #define BSCAN_GW1NSR_4C_SPI_CS (1 << 5) #define BSCAN_GW1NSR_4C_SPI_DI (1 << 3) #define BSCAN_GW1NSR_4C_SPI_DO (1 << 1) -#define BSCAN_GW1NSR_4C_SPI_MSK ((0x01 << 0)) +#define BSCAN_GW1NSR_4C_SPI_MSK (1 << 0) Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::string mcufw, Device::prog_type_t prg_type, bool external_flash, bool verify, int8_t verbose): Device(jtag, filename, file_type, - verify, verbose), is_gw1n1(false), is_gw2a(false), - is_gw5a(false), + verify, verbose), is_gw1n1(false), is_gw2a(false), is_gw1n4(false), is_gw5a(false), _external_flash(external_flash), _spi_sck(BSCAN_SPI_SCK), _spi_cs(BSCAN_SPI_CS), _spi_di(BSCAN_SPI_DI), _spi_do(BSCAN_SPI_DO), @@ -130,17 +130,20 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st uint32_t fs_idcode = std::stoul(idcode_str.c_str(), NULL, 16); if ((fs_idcode & 0x0fffffff) != idcode) { char mess[256]; - sprintf(mess, "mismatch between target's idcode and bitstream idcode\n" + snprintf(mess, 256, "mismatch between target's idcode and bitstream idcode\n" "\tbitstream has 0x%08X hardware requires 0x%08x", fs_idcode, idcode); throw std::runtime_error(mess); } } } - _jtag->setClkFreq(2500000); /* erase and program flash differ for GW1N1 */ if (idcode == 0x0900281B) is_gw1n1 = true; + /* erase and program flash differ for GW1N4 */ + if (idcode == 0x0100381B) + is_gw1n4 = true; + /* bscan spi external flash differ for GW1NSR-4C */ if (idcode == 0x0100981b) { _spi_sck = BSCAN_GW1NSR_4C_SPI_SCK; @@ -196,10 +199,42 @@ Gowin::~Gowin() delete _mcufw; } +bool Gowin::send_command(uint8_t cmd) +{ + _jtag->shiftIR(&cmd, nullptr, 8); + _jtag->toggleClk(5); + return true; +} + +#ifdef __APPLE__ +#include +#define le32toh(x) OSSwapLittleToHostInt32(x) +#define htole32(x) OSSwapHostToLittleInt32(x) +#elif (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) || defined(__WINDOWS__) + #if BYTE_ORDER == LITTLE_ENDIAN + #if defined(_MSC_VER) + #include + #define htole32(x) (x) + #define le32toh(x) (x) + #elif defined(__GNUC__) || defined(__clang__) + #define htole32(x) (x) + #define le32toh(x) (x) + #endif + #endif +#endif + +uint32_t Gowin::readReg32(uint8_t cmd) +{ + uint32_t reg = 0, tmp = 0xffffffffU; + send_command(cmd); + _jtag->shiftDR((uint8_t *)&tmp, (uint8_t *)®, 32); + return le32toh(reg); +} + void Gowin::reset() { - wr_rd(RELOAD, NULL, 0, NULL, 0); - wr_rd(NOOP, NULL, 0, NULL, 0); + send_command(RELOAD); + send_command(NOOP); } void Gowin::programFlash() @@ -207,113 +242,81 @@ void Gowin::programFlash() const uint8_t *data = _fs->getData(); int length = _fs->getLength(); - const uint8_t *mcu_data = nullptr; - int mcu_length = 0; + _jtag->setClkFreq(2500000); // default for GOWIN, should use LoadingRate from file header - if (_mcufw) { - mcu_data = _mcufw->getData(); - mcu_length = _mcufw->getLength(); - } - - /* erase SRAM */ - if (!EnableCfg()) - return; - eraseSRAM(); - wr_rd(XFER_DONE, NULL, 0, NULL, 0); - wr_rd(NOOP, NULL, 0, NULL, 0); - if (!DisableCfg()) - return; - - if (!EnableCfg()) + send_command(CONFIG_DISABLE); + send_command(0); + _jtag->set_state(Jtag::TEST_LOGIC_RESET); + uint32_t state = readStatusReg(); + if ((state & (STATUS_GOWIN_VLD | STATUS_POR)) == 0) { + displayReadReg("Either GOWIN_VLD or POR should be set, aborting", state); return; + } if (!eraseFLASH()) return; - if (!DisableCfg()) - return; /* test status a faire */ - if (!flashFLASH(0, data, length)) + if (!writeFLASH(0, data, length)) return; - if (mcu_data) { - if (!flashFLASH(0x380, mcu_data, mcu_length)) + if (_mcufw) { + const uint8_t *mcu_data = _mcufw->getData(); + int mcu_length = _mcufw->getLength(); + if (!writeFLASH(0x380, mcu_data, mcu_length)) return; } if (_verify) printWarn("writing verification not supported"); - if (!DisableCfg()) - return; - wr_rd(RELOAD, NULL, 0, NULL, 0); - wr_rd(NOOP, NULL, 0, NULL, 0); - - /* wait for reload */ - usleep(2*150*1000); /* check if file checksum == checksum in FPGA */ - checkCRC(); + if (!skip_checksum) + checkCRC(); if (_verbose) - displayReadReg(readStatusReg()); + displayReadReg("after program flash", readStatusReg()); } -void Gowin::program(unsigned int offset, bool unprotect_flash) -{ - const uint8_t *data; - int length; - - if (_mode == NONE_MODE || !_fs) - return; +void Gowin::programExtFlash(unsigned int offset, bool unprotect_flash) { + _jtag->setClkFreq(10000000); - data = _fs->getData(); - length = _fs->getLength(); + if (!enableCfg()) + throw std::runtime_error("Error: fail to enable configuration"); - if (_mode == FLASH_MODE) { - if (is_gw5a) - throw std::runtime_error("Error: write to flash on GW5A is not yet supported"); - if (!_external_flash) { /* write into internal flash */ - programFlash(); - } else { /* write bitstream into external flash */ - _jtag->setClkFreq(10000000); - - if (!EnableCfg()) - throw std::runtime_error("Error: fail to enable configuration"); + eraseSRAM(); + send_command(XFER_DONE); + send_command(NOOP); - eraseSRAM(); - wr_rd(XFER_DONE, NULL, 0, NULL, 0); - wr_rd(NOOP, NULL, 0, NULL, 0); + if (!is_gw2a) { + send_command(0x3D); + } else { + disableCfg(); + send_command(NOOP); + } - if (!is_gw2a) { - wr_rd(0x3D, NULL, 0, NULL, 0); - } else { - DisableCfg(); - wr_rd(NOOP, NULL, 0, NULL, 0); - } + SPIFlash spiFlash(this, unprotect_flash, + (_verbose ? 1 : (_quiet ? -1 : 0))); + spiFlash.reset(); + spiFlash.read_id(); + spiFlash.display_status_reg(spiFlash.read_status_reg()); + const uint8_t *data = _fs->getData(); + int length = _fs->getLength(); - SPIFlash spiFlash(this, unprotect_flash, - (_verbose ? 1 : (_quiet ? -1 : 0))); - spiFlash.reset(); - spiFlash.read_id(); - spiFlash.display_status_reg(spiFlash.read_status_reg()); - if (spiFlash.erase_and_prog(offset, data, length / 8) != 0) - throw std::runtime_error("Error: write to flash failed"); - if (_verify) - if (!spiFlash.verify(offset, data, length / 8, 256)) - throw std::runtime_error("Error: flash vefication failed"); - if (!is_gw2a) { - if (!DisableCfg()) - throw std::runtime_error("Error: fail to disable configuration"); - } + if (spiFlash.erase_and_prog(offset, data, length / 8) != 0) + throw std::runtime_error("Error: write to flash failed"); + if (_verify) + if (!spiFlash.verify(offset, data, length / 8, 256)) + throw std::runtime_error("Error: flash vefication failed"); + if (!is_gw2a) { + if (!disableCfg()) + throw std::runtime_error("Error: fail to disable configuration"); + } - reset(); - } + reset(); - return; - } +} +void Gowin::programSRAM() { if (_verbose) { - displayReadReg(readStatusReg()); + displayReadReg("before program sram", readStatusReg()); } - - wr_rd(READ_IDCODE, NULL, 0, NULL, 0); - /* Work around FPGA stuck in Bad Command status */ if (is_gw5a) { reset(); @@ -321,182 +324,108 @@ void Gowin::program(unsigned int offset, bool unprotect_flash) _jtag->toggleClk(1000000); } - /* erase SRAM */ - if (!EnableCfg()) - return; - eraseSRAM(); - if (!DisableCfg()) + if (!eraseSRAM()) return; - /* load bitstream in SRAM */ - if (!EnableCfg()) - return; - if (!flashSRAM(data, length)) - return; - if (!DisableCfg()) + if (!writeSRAM(_fs->getData(), _fs->getLength())) return; /* ocheck if file checksum == checksum in FPGA */ - checkCRC(); + if (!skip_checksum) + checkCRC(); if (_verbose) - displayReadReg(readStatusReg()); + displayReadReg("after program sram", readStatusReg()); } -void Gowin::checkCRC() +void Gowin::program(unsigned int offset, bool unprotect_flash) { - if (skip_checksum) + if (!_fs) return; - bool is_match = true; - char mess[256]; - uint32_t status = readUserCode(); + if (_mode == FLASH_MODE) { + if (is_gw5a) + throw std::runtime_error("Error: write to flash on GW5A is not yet supported"); + if (_external_flash) + programExtFlash(offset, unprotect_flash); + else + programFlash(); + } else if (_mode == MEM_MODE) + programSRAM(); + + return; +} + +void Gowin::checkCRC() +{ + uint32_t ucode = readUserCode(); uint16_t checksum = static_cast(_fs)->checksum(); - string hdr = ""; + if (static_cast(0xffff & ucode) == checksum) + goto success; + /* no match: + * user code register contains checksum or + * user_code when set_option -user_code + * is used, try to compare with this value + */ try { - hdr = _fs->getHeaderVal("checkSum"); - } catch (std::exception &e) { - if (_verbose) - printError(e.what()); - } - if (static_cast(0xffff & status) != checksum) { - /* no match: - * user code register contains checksum or - * user_code when: - * set_option -user_code - * is used: try to compare with this value - */ - if (hdr.empty()) { - is_match = false; - snprintf(mess, 256, "Read: 0x%08x checksum: 0x%04x\n", - status, checksum); - } else { - uint32_t user_code = strtol(hdr.c_str(), NULL, 16); - if (status != user_code) { - is_match = false; - snprintf(mess, 256, - "Read 0x%08x (checksum: 0x%08x, user_code: 0x%08x)\n", - status, checksum, user_code); - } + string hdr = _fs->getHeaderVal("checkSum"); + if (!hdr.empty()) { + if (ucode == strtol(hdr.c_str(), NULL, 16)) + goto success; } - } - if (is_match) { - printSuccess("CRC check: Success"); - } else { - printError("CRC check : FAIL"); - printError(mess); - } + } catch (std::exception &e) {} + char mess[256]; + snprintf(mess, 256, "Read: 0x%08x checksum: 0x%04x\n", ucode, checksum); + printError("CRC check : FAIL"); + printError(mess); + return; +success: + printSuccess("CRC check: Success"); + return; } -bool Gowin::EnableCfg() +bool Gowin::enableCfg() { - wr_rd(CONFIG_ENABLE, NULL, 0, NULL, 0); + send_command(CONFIG_ENABLE); return pollFlag(STATUS_SYSTEM_EDIT_MODE, STATUS_SYSTEM_EDIT_MODE); } -bool Gowin::DisableCfg() +bool Gowin::disableCfg() { - wr_rd(CONFIG_DISABLE, NULL, 0, NULL, 0); - wr_rd(NOOP, NULL, 0, NULL, 0); + send_command(CONFIG_DISABLE); + send_command(NOOP); return pollFlag(STATUS_SYSTEM_EDIT_MODE, 0); } uint32_t Gowin::idCode() { - uint8_t device_id[4]; - wr_rd(READ_IDCODE, NULL, 0, device_id, 4); - return device_id[3] << 24 | - device_id[2] << 16 | - device_id[1] << 8 | - device_id[0]; + return readReg32(READ_IDCODE); } uint32_t Gowin::readStatusReg() { - uint32_t reg; - uint8_t rx[4]; - wr_rd(STATUS_REGISTER, NULL, 0, rx, 4); - reg = rx[3] << 24 | rx[2] << 16 | rx[1] << 8 | rx[0]; - return reg; + return readReg32(STATUS_REGISTER); } uint32_t Gowin::readUserCode() { - uint8_t rx[4]; - wr_rd(READ_USERCODE, NULL, 0, rx, 4); - return rx[3] << 24 | rx[2] << 16 | rx[1] << 8 | rx[0]; + return readReg32(READ_USERCODE); } -bool Gowin::wr_rd(uint8_t cmd, - uint8_t *tx, int tx_len, - uint8_t *rx, int rx_len, - bool verbose) +void Gowin::displayReadReg(const char *prefix, uint32_t reg) { - int xfer_len = rx_len; - if (tx_len > rx_len) - xfer_len = tx_len; - - uint8_t xfer_tx[xfer_len], xfer_rx[xfer_len]; - memset(xfer_tx, 0, xfer_len); - int i; - if (tx != NULL) { - for (i = 0; i < tx_len; i++) - xfer_tx[i] = tx[i]; - } - - _jtag->shiftIR(&cmd, NULL, 8); - _jtag->toggleClk(6); - if (rx || tx) { - _jtag->shiftDR(xfer_tx, (rx) ? xfer_rx : NULL, 8 * xfer_len); - _jtag->toggleClk(6); - _jtag->flush(); - } - if (rx) { - if (verbose) { - for (i=xfer_len-1; i >= 0; i--) - printf("%02x ", xfer_rx[i]); - printf("\n"); + static const char *desc[19] = { + "CRC Error", "Bad Command", "ID Verify Failed", "Timeout", + "Reserved4", "Memory Erase", "Preamble", "System Edit Mode", + "Program SPI FLASH directly", "Reserved9", "Non-JTAG configuration is active", "Bypass", + "Gowin VLD", "Done Final", "Security Final", "Ready", + "POR", "FLASH lock", "FLASH2 lock", + }; + printf("%s: displayReadReg %08x\n", prefix, reg); + for (unsigned i = 0, bm = 1; i < 19; ++i, bm <<= 1) { + if (reg & bm) { + printf("\t%s\n", desc[i]); } - for (i = 0; i < rx_len; i++) - rx[i] = (xfer_rx[i]); } - return true; -} - -void Gowin::displayReadReg(uint32_t dev) -{ - printf("displayReadReg %08x\n", dev); - if (dev & STATUS_CRC_ERROR) - printf("\tCRC Error\n"); - if (dev & STATUS_BAD_COMMAND) - printf("\tBad Command\n"); - if (dev & STATUS_ID_VERIFY_FAILED) - printf("\tID Verify Failed\n"); - if (dev & STATUS_TIMEOUT) - printf("\tTimeout\n"); - if (dev & STATUS_MEMORY_ERASE) - printf("\tMemory Erase\n"); - if (dev & STATUS_PREAMBLE) - printf("\tPreamble\n"); - if (dev & STATUS_SYSTEM_EDIT_MODE) - printf("\tSystem Edit Mode\n"); - if (dev & STATUS_PRG_SPIFLASH_DIRECT) - printf("\tProgram spi flash directly\n"); - if (dev & STATUS_NON_JTAG_CNF_ACTIVE) - printf("\tNon-jtag is active\n"); - if (dev & STATUS_BYPASS) - printf("\tBypass\n"); - if (dev & STATUS_GOWIN_VLD) - printf("\tGowin VLD\n"); - if (dev & STATUS_DONE_FINAL) - printf("\tDone Final\n"); - if (dev & STATUS_SECURITY_FINAL) - printf("\tSecurity Final\n"); - if (dev & STATUS_READY) - printf("\tReady\n"); - if (dev & STATUS_POR) - printf("\tPOR\n"); - if (dev & STATUS_FLASH_LOCK) - printf("\tFlash Lock\n"); } bool Gowin::pollFlag(uint32_t mask, uint32_t value) @@ -506,7 +435,7 @@ bool Gowin::pollFlag(uint32_t mask, uint32_t value) do { status = readStatusReg(); if (_verbose) - printf("pollFlag: %x\n", status); + printf("pollFlag: %x (%x)\n", status, status & mask); if (timeout == 100000000){ printError("timeout"); return false; @@ -517,220 +446,226 @@ bool Gowin::pollFlag(uint32_t mask, uint32_t value) return true; } -/* TN653 p. 17-21 */ -bool Gowin::flashFLASH(uint32_t page, const uint8_t *data, int length) +inline uint32_t bswap_32(uint32_t x) { - uint8_t tx[4] = {0x4E, 0x31, 0x57, 0x47}; - uint8_t tmp[4]; - uint32_t addr; - int nb_iter; - int byte_length = length / 8; - int buffer_length; - uint8_t *buffer; - int nb_xpage; - uint8_t tt[39]; - memset(tt, 0, 39); - - _jtag->go_test_logic_reset(); - - if (page == 0) { - /* we have to send - * bootcode a X=0, Y=0 (4Bytes) - * 5 x 32 dummy bits - * full bitstream - */ - buffer_length = byte_length+(6*4); - unsigned char bufvalues[]={ - 0x47, 0x57, 0x31, 0x4E, - 0xff, 0xff , 0xff, 0xff, - 0xff, 0xff , 0xff, 0xff, - 0xff, 0xff , 0xff, 0xff, - 0xff, 0xff , 0xff, 0xff, - 0xff, 0xff , 0xff, 0xff}; - nb_xpage = buffer_length/256; - if (nb_xpage * 256 != buffer_length) { - nb_xpage++; - buffer_length = nb_xpage * 256; - } + return ((x << 24) & 0xff000000 ) | + ((x << 8) & 0x00ff0000 ) | + ((x >> 8) & 0x0000ff00 ) | + ((x >> 24) & 0x000000ff ); +} - buffer = new uint8_t[buffer_length]; - /* fill theorical size with 0xff */ - memset(buffer, 0xff, buffer_length); - /* fill first page with code */ - memcpy(buffer, bufvalues, 6*4); - /* bitstream just after opcode */ - memcpy(buffer+6*4, data, byte_length); - } else { - buffer_length = byte_length; - nb_xpage = buffer_length/256; - if (nb_xpage * 256 != buffer_length) { - nb_xpage++; - buffer_length = nb_xpage * 256; +bool Gowin::writeFLASH(uint32_t page, const uint8_t *data, int length) +{ + printInfo("Write FLASH ", false); + if (_verbose) + displayReadReg("before write flash",readStatusReg()); + uint8_t xpage[256]; + length /= 8; + ProgressBar progress("Writing to FLASH", length, 50, _verbose); + for (int off = 0; off < length; off += 256) { + int l = 256; + if (length - off < l) { + memset(xpage, 0xff, sizeof(xpage)); + l = length - off; } - buffer = new uint8_t[buffer_length]; - memset(buffer, 0xff, buffer_length); - memcpy(buffer, data, byte_length); - } - - - ProgressBar progress("write Flash", buffer_length, 50, _quiet); - - for (int i=0, xpage = 0; xpage < nb_xpage; i += (nb_iter * 4), xpage++) { - wr_rd(CONFIG_ENABLE, NULL, 0, NULL, 0); - wr_rd(EF_PROGRAM, NULL, 0, NULL, 0); - if ((page + xpage) != 0) - _jtag->toggleClk(312); - addr = (page + xpage) << 6; - tmp[3] = 0xff&(addr >> 24); - tmp[2] = 0xff&(addr >> 16); - tmp[1] = 0xff&(addr >> 8); - tmp[0] = addr&0xff; - _jtag->shiftDR(tmp, NULL, 32); - _jtag->toggleClk(312); - - int xoffset = xpage * 256; // each page containt 256Bytes - if (xoffset + 256 > buffer_length) - nb_iter = (buffer_length-xoffset) / 4; - else - nb_iter = 64; - - for (int ypage = 0; ypage < nb_iter; ypage++) { - unsigned char *t = buffer+xoffset + 4*ypage; - for (int x=0; x < 4; x++) { - if (page == 0) - tx[3-x] = t[x]; - else - tx[x] = t[x]; - } - _jtag->shiftDR(tx, NULL, 32); - - if (!is_gw1n1) - _jtag->toggleClk(40); + memcpy(xpage, &data[off], l); + unsigned addr = off / 4 + page; + if (addr) { + sendClkUs(16); + } else { + // autoboot pattern + static const uint8_t pat[4] = {'G', 'W', '1', 'N'}; + memcpy(xpage, pat, 4); } - if (is_gw1n1) { - //usleep(10*2400*2); - uint8_t tt2[6008/8]; - memset(tt2, 0, 6008/8); - _jtag->toggleClk(6008); + + send_command(CONFIG_ENABLE); + send_command(NOOP); + send_command(EF_PROGRAM); + + unsigned w = htole32(addr); + _jtag->shiftDR((uint8_t *)&w, nullptr, 32); + sendClkUs(16); + for (int y = 0; y < 64; ++y) { + memcpy(&w, &xpage[y * 4], 4); + w = bswap_32(w); + _jtag->shiftDR((uint8_t *)&w, nullptr, 32); + sendClkUs((is_gw1n1) ? 32 : 16); } - progress.display(i); + sendClkUs((is_gw1n1) ? 2400 : 6); + progress.display(off); } - /* 2.2.6.6 */ - _jtag->set_state(Jtag::RUN_TEST_IDLE); + sendClkUs(400); + send_command(CONFIG_DISABLE); + send_command(NOOP); + if (_verbose) + displayReadReg("after write flash #1", readStatusReg()); + send_command(RELOAD); + send_command(NOOP); + if (_verbose) + displayReadReg("after write flash #2", readStatusReg()); + _jtag->flush(); + usleep(500*1000); + progress.done(); - delete[] buffer; - return true; + if (_verbose) + displayReadReg("after write flash", readStatusReg()); + if (readStatusReg() & STATUS_DONE_FINAL) { + printSuccess("DONE"); + return true; + } else { + printSuccess("FAIL"); + return false; + } } bool Gowin::connectJtagToMCU() { - wr_rd(SWITCH_TO_MCU_JTAG, NULL, 0, NULL, 0); + send_command(SWITCH_TO_MCU_JTAG); return true; } -/* TN653 p. 9 */ -bool Gowin::flashSRAM(const uint8_t *data, int length) +bool Gowin::writeSRAM(const uint8_t *data, int length) { - int tx_len; - Jtag::tapState_t tx_end; - int byte_length = length / 8; - - ProgressBar progress("Flash SRAM", byte_length, 50, _quiet); - - /* UG704 3.4.3 */ - if (is_gw5a) { - wr_rd(INIT_ADDR, NULL, 0, NULL, 0); - } - - /* 2.2.6.4 */ - wr_rd(XFER_WRITE, NULL, 0, NULL, 0); - - int xfer_len = 256; - - for (int i=0; i < byte_length; i+=xfer_len) { - if (i + xfer_len > byte_length) { // last packet with some size - tx_len = (byte_length - i) * 8; - tx_end = Jtag::EXIT1_DR; // to move in EXIT1_DR - } else { - tx_len = xfer_len * 8; - /* 2.2.6.5 */ - tx_end = Jtag::SHIFT_DR; + printInfo("Write SRAM ", false); + if (_verbose) + displayReadReg("before write sram", readStatusReg()); + ProgressBar progress("Writing to SRAM", length, 50, _verbose); + send_command(CONFIG_ENABLE); // config enable + send_command(INIT_ADDR); // address initialize + send_command(XFER_WRITE); // transfer configuration data + int remains = length; + const uint8_t *ptr = data; + const static unsigned pstep = 524288; // 0x80000, about 0.2 sec of bitstream at 2.5MHz + while (remains) { + int chunk = pstep; + Jtag::tapState_t next = Jtag::SHIFT_DR; + if (remains < chunk) { + chunk = remains; + next = Jtag::RUN_TEST_IDLE; } - _jtag->shiftDR(data+i, NULL, tx_len, tx_end); - //_jtag->flush(); - progress.display(i); + _jtag->shiftDR(ptr, NULL, chunk, next); + ptr += chunk >> 3; // in bytes + remains -= chunk; + progress.display(ptr - data); } - /* 2.2.6.6 */ - _jtag->set_state(Jtag::RUN_TEST_IDLE); - - /* p.15 fig 2.11 */ - wr_rd(XFER_DONE, NULL, 0, NULL, 0); - - if (pollFlag(STATUS_DONE_FINAL, STATUS_DONE_FINAL)) { - progress.done(); + progress.done(); + send_command(0x0a); + uint32_t checksum = static_cast(_fs)->checksum(); + checksum = htole32(checksum); + _jtag->shiftDR((uint8_t *)&checksum, NULL, 32); + send_command(0x08); + + send_command(CONFIG_DISABLE); // config disable + send_command(NOOP); // noop + + if (_verbose) + displayReadReg("after write sram", readStatusReg()); + if (readStatusReg() & STATUS_DONE_FINAL) { + printSuccess("DONE"); return true; } else { - progress.fail(); + printSuccess("FAIL"); return false; } } /* Erase SRAM: - * TN653 p.14-17 + * UG290-2.7.1E p.53 */ bool Gowin::eraseFLASH() { - uint8_t tt[37500 * 8]; - memset(tt, 0, 37500 * 8); - unsigned char tx[4] = {0, 0, 0, 0}; - printInfo("erase Flash ", false); - wr_rd(EFLASH_ERASE, NULL, 0, NULL, 0); - _jtag->set_state(Jtag::RUN_TEST_IDLE); - - /* GW1N1 need 65 x 32bits - * others 1 x 32bits - */ - int nb_iter = (is_gw1n1)?65:1; - for (int i = 0; i < nb_iter; i++) { - _jtag->shiftDR(tx, NULL, 32); - _jtag->toggleClk(6); + if (readStatusReg() & STATUS_GOWIN_VLD) { + if (!eraseSRAM()) { + return false; + } + } + printInfo("Erase FLASH ", false); + for (unsigned i = 0; i < 100; ++i) { // 100 attempts? + if (_verbose) + displayReadReg("before erase flash", readStatusReg()); + send_command(CONFIG_ENABLE); + send_command(EFLASH_ERASE); + if (is_gw1n4) { + // keep following sequence as-is. it is _not_ _jtag->shiftDR(). + _jtag->set_state(Jtag::SHIFT_DR); + _jtag->toggleClk(32); + _jtag->set_state(Jtag::RUN_TEST_IDLE); + } + if (is_gw1n1) { + for (unsigned i = 0; i < 65; ++i) { + _jtag->set_state(Jtag::SHIFT_DR); + _jtag->toggleClk(32); + _jtag->set_state(Jtag::RUN_TEST_IDLE); + } + } + sendClkUs(150 * 1000); + send_command(CONFIG_DISABLE); + send_command(NOOP); + + send_command(RELOAD); + send_command(NOOP); + _jtag->flush(); + usleep(500 * 1000); + uint32_t state = readStatusReg(); + if (_verbose) + displayReadReg("after erase flash", state); + + if (!(state & STATUS_DONE_FINAL)) { + break; + } + } + if (readStatusReg() & STATUS_DONE_FINAL) { + printError("FAIL"); + return false; + } else { + printSuccess("DONE"); + return true; } - /* TN653 specifies to wait for 160ms with - * there are no bit in status register to specify - * when this operation is done so we need to wait - */ - //usleep(2*120000); - //uint8_t tt[37500]; - _jtag->toggleClk(37500*8); - printSuccess("Done"); - return true; } -/* Erase SRAM: - * TN653 p.9-10, 14 and 31 - */ +void Gowin::sendClkUs(unsigned us) +{ + uint64_t clocks = _jtag->getClkFreq(); + clocks *= us; + clocks /= 1000000; + _jtag->toggleClk(clocks); +} + bool Gowin::eraseSRAM() { - printInfo("erase SRAM ", false); - wr_rd(ERASE_SRAM, NULL, 0, NULL, 0); - wr_rd(NOOP, NULL, 0, NULL, 0); - - /* TN653 specifies to wait for 4ms with - * clock generated but - * status register bit MEMORY_ERASE goes low when ERASE_SRAM - * is send and goes high after erase - * this check seems enough - */ - if (pollFlag(STATUS_MEMORY_ERASE, STATUS_MEMORY_ERASE)) { - printSuccess("Done"); - return true; - } else { + printInfo("Erase SRAM ", false); + if (_verbose) + displayReadReg("before erase sram", readStatusReg()); + + send_command(CONFIG_ENABLE); + send_command(ERASE_SRAM); + send_command(NOOP); + + sendClkUs(10 * 1000); // depends on chip type: 1-10ms + send_command(XFER_DONE); + send_command(NOOP); + + send_command(CONFIG_DISABLE); + send_command(NOOP); + sendClkUs(500); + + if (_verbose) + displayReadReg("after erase sram", readStatusReg()); + if (readStatusReg() & STATUS_DONE_FINAL) { printError("FAIL"); return false; + } else { + printSuccess("DONE"); + return true; } } +inline void Gowin::spi_gowin_write(const uint8_t *wr, uint8_t *rd, unsigned len) { + _jtag->shiftDR(wr, rd, len); + _jtag->toggleClk(6); +} + /* SPI wrapper * extflash access may be done using specific mode or * boundary scan. But former is only available with mode=[11] @@ -745,10 +680,6 @@ bool Gowin::eraseSRAM() * but all byte must be bit reversal... */ -#define spi_gowin_write(_wr, _rd, _len) do { \ - _jtag->shiftDR(_wr, _rd, _len); \ - _jtag->toggleClk(6); } while (0) - int Gowin::spi_put(uint8_t cmd, const uint8_t *tx, uint8_t *rx, uint32_t len) { uint8_t jrx[len+1], jtx[len+1]; @@ -774,11 +705,11 @@ int Gowin::spi_put(const uint8_t *tx, uint8_t *rx, uint32_t len) for (uint32_t i = 0; i < len; i++) jtx[i] = FsParser::reverseByte(tx[i]); } - bool ret = wr_rd(0x16, NULL, 0, NULL, 0, false); + bool ret = send_command(0x16); if (!ret) return -1; _jtag->set_state(Jtag::EXIT2_DR); - ret = _jtag->shiftDR(jtx, (rx)? jrx:NULL, 8*len); + _jtag->shiftDR(jtx, (rx)? jrx:NULL, 8*len); if (rx) { for (uint32_t i=0; i < len; i++) { rx[i] = FsParser::reverseByte(jrx[i]>>1) | @@ -793,21 +724,21 @@ int Gowin::spi_put(const uint8_t *tx, uint8_t *rx, uint32_t len) _jtag->flush(); /* send bit/bit full tx content (or set di to 0 when NULL) */ - for (uint32_t i = 0; i < len * 8; i++) { - uint8_t r; - t = _spi_msk | _spi_do; - if (tx != NULL && tx[i>>3] & (1 << (7-(i&0x07)))) - t |= _spi_di; - spi_gowin_write(&t, NULL, 8); - t |= _spi_sck; - spi_gowin_write(&t, (rx) ? &r : NULL, 8); - _jtag->flush(); - /* if read reconstruct bytes */ - if (rx) { - if (r & _spi_do) - rx[i >> 3] |= 1 << (7-(i & 0x07)); - else - rx[i >> 3] &= ~(1 << (7-(i & 0x07))); + for (unsigned l = 0; l < len; ++l) { + if (rx) + rx[l] = 0; + for (uint8_t b = 0, bm = 0x80; b < 8; ++b, bm >>= 1) { + uint8_t r; + t = _spi_msk | _spi_do; + if (tx != NULL && tx[l] & bm) + t |= _spi_di; + spi_gowin_write(&t, NULL, 8); + t |= _spi_sck; + spi_gowin_write(&t, (rx) ? &r : NULL, 8); + _jtag->flush(); + /* if read reconstruct bytes */ + if (rx && (r & _spi_do)) + rx[l] |= bm; } } /* set CS and unset SCK (next xfer) */ @@ -831,11 +762,11 @@ int Gowin::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, tx[0] = FsParser::reverseByte(cmd); do { - bool ret = wr_rd(0x16, NULL, 0, NULL, 0, false); + bool ret = send_command(0x16); if (!ret) return -1; _jtag->set_state(Jtag::EXIT2_DR); - ret = _jtag->shiftDR(tx, rx, 8 * 3); + _jtag->shiftDR(tx, rx, 8 * 3); tmp = (FsParser::reverseByte(rx[1]>>1)) | (0x01 & rx[2]); count ++; @@ -855,9 +786,9 @@ int Gowin::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, spi_gowin_write(&t, NULL, 8); /* send command bit/bit */ - for (int i = 0; i < 8; i++) { + for (uint8_t i = 0, bm = 0x80; i < 8; ++i, bm >>= 1) { t = _spi_msk | _spi_do; - if ((cmd & (1 << (7-i))) != 0) + if ((cmd & bm) != 0) t |= _spi_di; spi_gowin_write(&t, NULL, 8); t |= _spi_sck; @@ -869,7 +800,7 @@ int Gowin::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, do { tmp = 0; /* read status register bit/bit with di == 0 */ - for (int i = 0; i < 8; i++) { + for (uint8_t i = 0, bm = 0x80; i < 8; ++i, bm >>= 1) { uint8_t r; t &= ~_spi_sck; spi_gowin_write(&t, NULL, 8); @@ -877,7 +808,7 @@ int Gowin::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, spi_gowin_write(&t, &r, 8); _jtag->flush(); if ((r & _spi_do) != 0) - tmp |= 1 << (7-i); + tmp |= bm; } count++; diff --git a/src/gowin.hpp b/src/gowin.hpp index 24b701a600..f45744d98c 100644 --- a/src/gowin.hpp +++ b/src/gowin.hpp @@ -25,7 +25,6 @@ class Gowin: public Device, SPIInterface { uint32_t idCode() override; void reset() override; void program(unsigned int offset, bool unprotect_flash) override; - void programFlash(); bool connectJtagToMCU() override; /* spi interface */ @@ -43,16 +42,21 @@ class Gowin: public Device, SPIInterface { uint32_t timeout, bool verbose) override; private: - bool wr_rd(uint8_t cmd, uint8_t *tx, int tx_len, - uint8_t *rx, int rx_len, bool verbose = false); - bool EnableCfg(); - bool DisableCfg(); + bool send_command(uint8_t cmd); + void spi_gowin_write(const uint8_t *wr, uint8_t *rd, unsigned len); + uint32_t readReg32(uint8_t cmd); + void sendClkUs(unsigned us); + bool enableCfg(); + bool disableCfg(); bool pollFlag(uint32_t mask, uint32_t value); bool eraseSRAM(); bool eraseFLASH(); - bool flashSRAM(const uint8_t *data, int length); - bool flashFLASH(uint32_t page, const uint8_t *data, int length); - void displayReadReg(uint32_t dev); + void programFlash(); + void programExtFlash(unsigned int offset, bool unprotect_flash); + void programSRAM(); + bool writeSRAM(const uint8_t *data, int length); + bool writeFLASH(uint32_t page, const uint8_t *data, int length); + void displayReadReg(const char *, uint32_t dev); uint32_t readStatusReg(); uint32_t readUserCode(); /*! @@ -63,6 +67,7 @@ class Gowin: public Device, SPIInterface { ConfigBitstreamParser *_fs; bool is_gw1n1; bool is_gw2a; + bool is_gw1n4; bool is_gw5a; bool skip_checksum; /**< bypass checksum verification (GW2A) */ bool _external_flash; /**< select between int or ext flash */