From 0581803def5d647386918ca9557d9974522ffcf9 Mon Sep 17 00:00:00 2001 From: balika011 Date: Wed, 20 Jul 2022 23:25:53 +0200 Subject: [PATCH] Add MCU Firmware flashing support for GW1NSR-4C --- src/gowin.cpp | 125 ++++++++++++++++++++++++++++++++++++-------------- src/gowin.hpp | 5 +- src/main.cpp | 5 +- 3 files changed, 97 insertions(+), 38 deletions(-) diff --git a/src/gowin.cpp b/src/gowin.cpp index 604ff7d..5b84762 100644 --- a/src/gowin.cpp +++ b/src/gowin.cpp @@ -73,7 +73,7 @@ using namespace std; #define BSCAN_GW1NSR_4C_SPI_DO (1 << 1) #define BSCAN_GW1NSR_4C_SPI_MSK ((0x01 << 0)) -Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, +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), _external_flash(external_flash), @@ -153,6 +153,30 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, /* FIXME: implement GW2 checksum calculation */ skip_checksum = true; }; + + if (mcufw.size() > 0) { + if (idcode != 0x0100981b) + throw std::runtime_error("Microcontroller firmware flashing only supported on GW1NSR-4C"); + + + FILE *fd = fopen(mcufw.c_str(), "rb"); + if (!fd) + throw std::runtime_error("Error: fail to open " + filename); + + fseek(fd, 0, SEEK_END); + int file_size = ftell(fd); + fseek(fd, 0, SEEK_SET); + + mcufwdata.resize(file_size); + + int ret = fread((char *) mcufwdata.data(), sizeof(char), file_size, fd); + fclose(fd); + if (ret != file_size) + throw std::runtime_error("Error: fail to read " + mcufw); + + /* FIXME: implement checksum calculation */ + skip_checksum = true; + } } Gowin::~Gowin() @@ -172,9 +196,19 @@ void Gowin::programFlash() int status; uint8_t *data; int length; + uint8_t *mcu_data; + int mcu_length; data = _fs->getData(); length = _fs->getLength(); + + if (mcufwdata.size() == 0) { + mcu_data = nullptr; + mcu_length = 0; + } else { + mcu_data = (uint8_t *) mcufwdata.data(); + mcu_length = mcufwdata.size() * 8; + } /* erase SRAM */ if (!EnableCfg()) @@ -192,8 +226,12 @@ void Gowin::programFlash() if (!DisableCfg()) return; /* test status a faire */ - if (!flashFLASH(data, length)) + if (!flashFLASH(0, data, length)) return; + if (mcu_data) { + if (!flashFLASH(0x380, mcu_data, mcu_length)) + return; + } if (_verify) printWarn("writing verification not supported"); if (!DisableCfg()) @@ -222,8 +260,6 @@ void Gowin::programFlash() void Gowin::program(unsigned int offset, bool unprotect_flash) { - (void) offset; - uint8_t *data; uint32_t status; int length; @@ -435,55 +471,69 @@ bool Gowin::pollFlag(uint32_t mask, uint32_t value) } /* TN653 p. 17-21 */ -bool Gowin::flashFLASH(uint8_t *data, int length) +bool Gowin::flashFLASH(uint32_t page, 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; + int buffer_length; + uint8_t *buffer; + int nb_xpage; 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}; + 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; + } - int nb_xpage = buffer_length/256; - if (nb_xpage * 256 != buffer_length) { - nb_xpage++; - buffer_length = nb_xpage * 256; + 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; + } + buffer = new uint8_t[buffer_length]; + memset(buffer, 0xff, buffer_length); + memcpy(buffer, data, byte_length); } - 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++) { + 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) + if ((page + xpage) != 0) _jtag->toggleClk(312); - addr = xpage << 6; + addr = (page + xpage) << 6; tmp[3] = 0xff&(addr >> 24); tmp[2] = 0xff&(addr >> 16); tmp[1] = 0xff&(addr >> 8); @@ -499,8 +549,12 @@ bool Gowin::flashFLASH(uint8_t *data, int length) 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]; + 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) @@ -518,6 +572,7 @@ bool Gowin::flashFLASH(uint8_t *data, int length) _jtag->set_state(Jtag::RUN_TEST_IDLE); progress.done(); + delete[] buffer; return true; } diff --git a/src/gowin.hpp b/src/gowin.hpp index d26889e..2ad9b32 100644 --- a/src/gowin.hpp +++ b/src/gowin.hpp @@ -18,7 +18,7 @@ class Gowin: public Device, SPIInterface { public: - Gowin(Jtag *jtag, std::string filename, const std::string &file_type, + Gowin(Jtag *jtag, std::string filename, const std::string &file_type, std::string mcufw, Device::prog_type_t prg_type, bool external_flash, bool verify, int8_t verbose); ~Gowin(); @@ -48,7 +48,7 @@ class Gowin: public Device, SPIInterface { bool eraseSRAM(); bool eraseFLASH(); bool flashSRAM(uint8_t *data, int length); - bool flashFLASH(uint8_t *data, int length); + bool flashFLASH(uint32_t page, uint8_t *data, int length); void displayReadReg(uint32_t dev); uint32_t readStatusReg(); uint32_t readUserCode(); @@ -61,5 +61,6 @@ class Gowin: public Device, SPIInterface { uint8_t _spi_di; /**< di signal (mosi) offset in bscan SPI */ uint8_t _spi_do; /**< do signal (miso) offset in bscan SPI */ uint8_t _spi_msk; /** default spi msk with only do out */ + std::string mcufwdata; }; #endif // GOWIN_HPP_ diff --git a/src/main.cpp b/src/main.cpp index 65f7d49..b4922a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -78,6 +78,7 @@ struct arguments { bool xvc; int port; string interface; + string mcufw; }; int run_xvc_server(const struct arguments &args, const cable_t &cable, @@ -506,7 +507,7 @@ int main(int argc, char **argv) fpga = new Efinix(jtag, args.bit_file, args.file_type, /*DBUS4 | DBUS7, DBUS5*/args.board, args.verify, args.verbose); } else if (fab == "Gowin") { - fpga = new Gowin(jtag, args.bit_file, args.file_type, + fpga = new Gowin(jtag, args.bit_file, args.file_type, args.mcufw, args.prg_type, args.external_flash, args.verify, args.verbose); } else if (fab == "lattice") { fpga = new Lattice(jtag, args.bit_file, args.file_type, @@ -713,6 +714,8 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p #endif ("port", "Xilinx Virtual Cable Port (default 3721)", cxxopts::value(args->port)) + ("mcufw", "Microcontroller firmware", + cxxopts::value(args->mcufw)) ("V,Version", "Print program version"); options.parse_positional({"bitstream"});