// SPDX-License-Identifier: Apache-2.0 /* * Copyright (C) 2019 Gwenhael Goavec-Merou */ #include #include #include #include #include #include #include #include #include "jtag.hpp" #include "gowin.hpp" #include "progressBar.hpp" #include "display.hpp" #include "fsparser.hpp" using namespace std; #ifdef STATUS_TIMEOUT // defined in the Windows headers included by libftdi.h #undef STATUS_TIMEOUT #endif #define NOOP 0x02 #define ERASE_SRAM 0x05 #define READ_SRAM 0x03 #define XFER_DONE 0x09 #define READ_IDCODE 0x11 #define INIT_ADDR 0x12 #define READ_USERCODE 0x13 #define CONFIG_ENABLE 0x15 #define XFER_WRITE 0x17 #define CONFIG_DISABLE 0x3A #define RELOAD 0x3C #define STATUS_REGISTER 0x41 # define STATUS_CRC_ERROR (1 << 0) # define STATUS_BAD_COMMAND (1 << 1) # define STATUS_ID_VERIFY_FAILED (1 << 2) # define STATUS_TIMEOUT (1 << 3) # define STATUS_MEMORY_ERASE (1 << 5) # define STATUS_PREAMBLE (1 << 6) # define STATUS_SYSTEM_EDIT_MODE (1 << 7) # define STATUS_PRG_SPIFLASH_DIRECT (1 << 8) # define STATUS_NON_JTAG_CNF_ACTIVE (1 << 10) # define STATUS_BYPASS (1 << 11) # define STATUS_GOWIN_VLD (1 << 12) # define STATUS_DONE_FINAL (1 << 13) # define STATUS_SECURITY_FINAL (1 << 14) # define STATUS_READY (1 << 15) # define STATUS_POR (1 << 16) # define STATUS_FLASH_LOCK (1 << 17) #define EF_PROGRAM 0x71 #define EFLASH_ERASE 0x75 Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, Device::prog_type_t prg_type, bool verify, int8_t verbose): Device(jtag, filename, file_type, verify, verbose), is_gw1n1(false) { _fs = NULL; uint32_t idcode = idCode(); if (!_file_extension.empty()) { if (_file_extension == "fs") { if (prg_type == Device::WR_FLASH) _mode = Device::FLASH_MODE; else _mode = Device::MEM_MODE; try { _fs = new FsParser(_filename, _mode == Device::MEM_MODE, _verbose); } catch (std::exception &e) { throw std::runtime_error(e.what()); } printInfo("Parse file ", false); if (_fs->parse() == EXIT_FAILURE) { printError("FAIL"); delete _fs; throw std::runtime_error("can't parse file"); } else { printSuccess("DONE"); } if (_verbose) _fs->displayHeader(); string idcode_str = _fs->getHeaderVal("idcode"); uint32_t fs_idcode = std::stoul(idcode_str.c_str(), NULL, 16); if (fs_idcode != idcode) { throw std::runtime_error("mismatch between target's idcode and fs idcode"); } } else { throw std::runtime_error("incompatible file format"); } } _jtag->setClkFreq(2500000); /* erase and program flash differ for GW1N1 */ if (idcode == 0x0900281B) is_gw1n1 = true; } Gowin::~Gowin() { if (_fs) delete _fs; } void Gowin::reset() { wr_rd(RELOAD, NULL, 0, NULL, 0); wr_rd(NOOP, NULL, 0, NULL, 0); } void Gowin::programFlash() { int status; uint8_t *data; int length; data = _fs->getData(); length = _fs->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()) return; if (!eraseFLASH()) return; if (!DisableCfg()) return; /* test status a faire */ if (!flashFLASH(data, 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 */ status = readUserCode(); if (_fs->checksum() != status) { printError("CRC check : FAIL"); printf("%04x %04x\n", _fs->checksum(), status); } else printSuccess("CRC check: Success"); if (_verbose) displayReadReg(readStatusReg()); } void Gowin::program(unsigned int offset) { (void) offset; uint8_t *data; uint32_t status; int length; if (_mode == NONE_MODE || !_fs) return; if (_mode == FLASH_MODE) { programFlash(); return; } if (_verbose) { displayReadReg(readStatusReg()); } data = _fs->getData(); length = _fs->getLength(); wr_rd(READ_IDCODE, NULL, 0, NULL, 0); /* erase SRAM */ if (!EnableCfg()) return; eraseSRAM(); if (!DisableCfg()) return; /* load bitstream in SRAM */ if (!EnableCfg()) return; if (!flashSRAM(data, length)) return; if (!DisableCfg()) return; /* check if file checksum == checksum in FPGA */ status = readUserCode(); if (_fs->checksum() != status) { printError("SRAM Flash: FAIL"); printf("%04x %04x\n", _fs->checksum(), status); } else printSuccess("SRAM Flash: Success"); if (_verbose) displayReadReg(readStatusReg()); } bool Gowin::EnableCfg() { wr_rd(CONFIG_ENABLE, NULL, 0, NULL, 0); return pollFlag(STATUS_SYSTEM_EDIT_MODE, STATUS_SYSTEM_EDIT_MODE); } bool Gowin::DisableCfg() { wr_rd(CONFIG_DISABLE, NULL, 0, NULL, 0); wr_rd(NOOP, NULL, 0, NULL, 0); return pollFlag(STATUS_SYSTEM_EDIT_MODE, 0); } int 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]; } 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; } 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]; } bool Gowin::wr_rd(uint8_t cmd, uint8_t *tx, int tx_len, uint8_t *rx, int rx_len, bool verbose) { 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"); } 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) { uint32_t status; int timeout = 0; do { status = readStatusReg(); if (_verbose) printf("pollFlag: %x\n", status); if (timeout == 100000000){ printError("timeout"); return false; } timeout++; } while ((status & mask) != value); return true; } /* TN653 p. 17-21 */ bool Gowin::flashFLASH(uint8_t *data, int length) { uint8_t tx[4] = {0x4E, 0x31, 0x57, 0x47}; uint8_t tmp[4]; uint32_t addr; int nb_iter; int byte_length = length / 8; uint8_t tt[39]; memset(tt, 0, 39); _jtag->go_test_logic_reset(); /* we have to send * bootcode a X=0, Y=0 (4Bytes) * 5 x 32 dummy bits * full bitstream */ int 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}; int nb_xpage = buffer_length/256; if (nb_xpage * 256 != buffer_length) { nb_xpage++; buffer_length = nb_xpage * 256; } unsigned char buffer[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); 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 (xpage != 0) _jtag->toggleClk(312); addr = 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++) tx[3-x] = t[x]; _jtag->shiftDR(tx, NULL, 32); if (!is_gw1n1) _jtag->toggleClk(40); } if (is_gw1n1) { //usleep(10*2400*2); uint8_t tt2[6008/8]; memset(tt2, 0, 6008/8); _jtag->toggleClk(6008); } progress.display(i); } /* 2.2.6.6 */ _jtag->set_state(Jtag::RUN_TEST_IDLE); progress.done(); return true; } /* TN653 p. 9 */ bool Gowin::flashSRAM(uint8_t *data, int length) { int tx_len, tx_end; int byte_length = length / 8; ProgressBar progress("Flash SRAM", byte_length, 50, _quiet); /* 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; } _jtag->shiftDR(data+i, NULL, tx_len, tx_end); //_jtag->flush(); progress.display(i); } /* 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(); return true; } else { progress.fail(); return false; } } /* Erase SRAM: * TN653 p.14-17 */ 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); } /* 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 */ 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 { printError("FAIL"); return false; } }