diff --git a/README.md b/README.md index fa530c2..749ee28 100644 --- a/README.md +++ b/README.md @@ -49,9 +49,13 @@ openFPGALoader -- a program to flash cyclone10 LP FPGA -b, --board=BOARD board name, may be used instead of cable -c, --cable=CABLE jtag interface -d, --device=DEVICE device to use (/dev/ttyUSBx) + -f, --write-flash write bitstream in flash (default: false, only for + Gowin devices) --list-boards list all supported boards --list-cables list all supported cables --list-fpga list all supported FPGA + -m, --write-sram write bitstream in SRAM (default: true, only for + Gowin devices) -o, --offset=OFFSET start offset in EEPROM -r, --reset reset FPGA after operations -v, --verbose Produce verbose output @@ -194,12 +198,26 @@ openFPGALoader -b machXO3SK impl1/*.bit ### Trenz GOWIN LittleBee (TEC0117) -#### Flash SRAM: - *.fs* file is the default format generated by *Gowin IDE*, so nothing special must be done to generates this file. +Since the same file is used for SRAM and Flash a CLI argument is used to +specify the destination. + +#### Flash SRAM: + +with **-m** + __file load__: ```bash -openFPGALoader -b littleBee impl/pnr/*.fs +openFPGALoader -m -b littleBee impl/pnr/*.fs +``` + +#### Flash: + +with **-f** + +__file load__: +```bash +openFPGALoader -f -b littleBee impl/pnr/*.fs ``` diff --git a/gowin.cpp b/gowin.cpp index e512a81..0165317 100644 --- a/gowin.cpp +++ b/gowin.cpp @@ -60,15 +60,21 @@ 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 -Gowin::Gowin(FtdiJtag *jtag, const string filename, bool verbose): - Device(jtag, filename, verbose) +Gowin::Gowin(FtdiJtag *jtag, const string filename, bool flash_wr, bool sram_wr, + bool verbose): Device(jtag, filename, verbose) { if (_filename != "") { if (_file_extension == "fs") { - _mode = Device::FLASH_MODE; - _fs = new FsParser(_filename, true, _verbose); + if (flash_wr && sram_wr) + throw std::runtime_error("both write-flash and write-sram can't be set"); + if (flash_wr) + _mode = Device::FLASH_MODE; + else + _mode = Device::MEM_MODE; + _fs = new FsParser(_filename, _mode == Device::MEM_MODE, _verbose); _fs->parse(); } else { throw std::runtime_error("incompatible file format"); @@ -83,6 +89,41 @@ Gowin::~Gowin() delete _fs; } +void Gowin::programFlash() +{ + 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; + wr_rd(RELOAD, NULL, 0, NULL, 0); + wr_rd(NOOP, NULL, 0, NULL, 0); + /* test status a faire */ + if (!flashFLASH(data, length)) + return; + if (!DisableCfg()) + return; + wr_rd(RELOAD, NULL, 0, NULL, 0); + wr_rd(NOOP, NULL, 0, NULL, 0); + printf("%08x\n", readUserCode()); +} + void Gowin::program(unsigned int offset) { (void) offset; @@ -94,6 +135,11 @@ void Gowin::program(unsigned int offset) if (_filename == "" || !_fs) return; + if (_mode == FLASH_MODE) { + programFlash(); + return; + } + if (_verbose) { displayReadReg(readStatusReg()); } @@ -257,6 +303,73 @@ bool Gowin::pollFlag(uint32_t mask, uint32_t 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]; + bzero(tt, 39); + + ProgressBar progress("Flash SRAM", byte_length, 50); + _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 buffer[byte_length+(6*4)] = { + 0x47, 0x57, 0x31, 0x4E, + 0xff, 0xff , 0xff, 0xff, + 0xff, 0xff , 0xff, 0xff, + 0xff, 0xff , 0xff, 0xff, + 0xff, 0xff , 0xff, 0xff, + 0xff, 0xff , 0xff, 0xff}; + memcpy(buffer+6*4, data, byte_length); + + int nb_xpage = buffer_length/256; + if (nb_xpage * 256 != buffer_length) + nb_xpage++; + + 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); + _jtag->read_write(tt, NULL, 312, 0); + 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->read_write(tt, NULL, 312, 0); + + 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); + _jtag->read_write(tt, NULL, 40, 0); + } + progress.display(i); + } + /* 2.2.6.6 */ + _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + + progress.done(); + return true; +} + /* TN653 p. 9 */ bool Gowin::flashSRAM(uint8_t *data, int length) { @@ -297,12 +410,31 @@ bool Gowin::flashSRAM(uint8_t *data, int length) } } +/* Erase SRAM: + * TN653 p.14-17 + */ +bool Gowin::eraseFLASH() +{ + unsigned char tx[4] = {0, 0, 0, 0}; + printInfo("erase Flash ", false); + wr_rd(EFLASH_ERASE, NULL, 0, NULL, 0); + _jtag->set_state(FtdiJtag::RUN_TEST_IDLE); + _jtag->shiftDR(tx, NULL, 32); + /* TN653 specifies to wait for 120ms with + * there are no bit in status register to specify + * when this operation is done so we need to wait + */ + usleep(120000); + printSuccess("Done"); + return true; +} + /* Erase SRAM: * TN653 p.9-10, 14 and 31 */ bool Gowin::eraseSRAM() { - printInfo("erase Flash ", false); + printInfo("erase SRAM ", false); wr_rd(ERASE_SRAM, NULL, 0, NULL, 0); wr_rd(NOOP, NULL, 0, NULL, 0); diff --git a/gowin.hpp b/gowin.hpp index 6dd9b41..e281bd3 100644 --- a/gowin.hpp +++ b/gowin.hpp @@ -30,11 +30,13 @@ class Gowin: public Device { public: - Gowin(FtdiJtag *jtag, std::string filename, bool verbose); + Gowin(FtdiJtag *jtag, std::string filename, bool flash_wr, bool sram_wr, + bool verbose); ~Gowin(); int idCode() override; void reset() override {} void program(unsigned int offset) override; + void programFlash(); private: bool wr_rd(uint8_t cmd, uint8_t *tx, int tx_len, @@ -43,7 +45,9 @@ class Gowin: public Device { bool DisableCfg(); bool pollFlag(uint32_t mask, uint32_t value); bool eraseSRAM(); + bool eraseFLASH(); bool flashSRAM(uint8_t *data, int length); + bool flashFLASH(uint8_t *data, int length); void displayReadReg(uint32_t dev); uint32_t readStatusReg(); uint32_t readUserCode(); diff --git a/main.cpp b/main.cpp index 16bb717..e7ddc1e 100644 --- a/main.cpp +++ b/main.cpp @@ -47,6 +47,8 @@ struct arguments { bool list_cables; bool list_boards; bool list_fpga; + bool write_flash; + bool write_sram; }; #define LIST_CABLE 1 @@ -65,6 +67,10 @@ static struct argp_option options[] = { {"list-boards", LIST_BOARD, 0, 0, "list all supported boards"}, {"device", 'd', "DEVICE", 0, "device to use (/dev/ttyUSBx)"}, {"list-fpga", LIST_FPGA, 0, 0, "list all supported FPGA"}, + {"write-flash", 'f', 0, 0, + "write bitstream in flash (default: false, only for Gowin devices)"}, + {"write-sram", 'm', 0, 0, + "write bitstream in SRAM (default: true, only for Gowin devices)"}, {"offset", 'o', "OFFSET", 0, "start offset in EEPROM"}, {"verbose", 'v', 0, 0, "Produce verbose output"}, {"reset", 'r', 0, 0, "reset FPGA after operations"}, @@ -80,7 +86,7 @@ int main(int argc, char **argv) /* command line args. */ struct arguments args = {false, false, 0, "", "-", "-", "-", - false, false, false}; + false, false, false, false, true}; /* parse arguments */ argp_parse(&argp, argc, argv, 0, 0, &args); @@ -152,7 +158,8 @@ int main(int argc, char **argv) } else if (fab == "altera") { fpga = new Altera(jtag, args.bit_file, args.verbose); } else if (fab == "Gowin") { - fpga = new Gowin(jtag, args.bit_file, args.verbose); + fpga = new Gowin(jtag, args.bit_file, args.write_flash, args.write_sram, + args.verbose); } else if (fab == "lattice") { fpga = new Lattice(jtag, args.bit_file, args.verbose); } else { @@ -176,6 +183,13 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) struct arguments *arguments = (struct arguments *)state->input; switch (key) { + case 'f': + arguments->write_flash = true; + arguments->write_sram = false; + break; + case 'm': + arguments->write_sram = true; + break; case 'r': arguments->reset = true; break;