diff --git a/src/device.hpp b/src/device.hpp index 7295772..c913402 100644 --- a/src/device.hpp +++ b/src/device.hpp @@ -52,6 +52,8 @@ class Device { virtual int idCode() = 0; virtual void reset(); + virtual bool connectJtagToMCU() {return false;} + protected: Jtag *_jtag; std::string _filename; diff --git a/src/gowin.cpp b/src/gowin.cpp index 604ff7d..1637146 100644 --- a/src/gowin.cpp +++ b/src/gowin.cpp @@ -58,6 +58,7 @@ using namespace std; # define STATUS_FLASH_LOCK (1 << 17) #define EF_PROGRAM 0x71 #define EFLASH_ERASE 0x75 +#define SWITCH_TO_MCU_JTAG 0x7a /* BSCAN spi (external flash) (see below for details) */ /* most common pins def */ @@ -73,7 +74,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), @@ -82,7 +83,9 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, _spi_msk(BSCAN_SPI_MSK) { _fs = NULL; - uint32_t idcode = _jtag->get_target_device_id();; + _mcufw = NULL; + + uint32_t idcode = _jtag->get_target_device_id(); if (prg_type == Device::WR_FLASH) _mode = Device::FLASH_MODE; @@ -153,12 +156,29 @@ 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"); + + _mcufw = new RawParser(mcufw, false); + + if (_mcufw->parse() == EXIT_FAILURE) { + printError("FAIL"); + delete _mcufw; + throw std::runtime_error("can't parse file"); + } else { + printSuccess("DONE"); + } + } } Gowin::~Gowin() { if (_fs) delete _fs; + if (_mcufw) + delete _mcufw; } void Gowin::reset() @@ -170,11 +190,17 @@ void Gowin::reset() void Gowin::programFlash() { int status; - uint8_t *data; - int length; - data = _fs->getData(); - length = _fs->getLength(); + uint8_t *data = _fs->getData(); + int length = _fs->getLength(); + + uint8_t *mcu_data = nullptr; + int mcu_length = 0; + + if (_mcufw) { + mcu_data = _mcufw->getData(); + mcu_length = _mcufw->getLength(); + } /* erase SRAM */ if (!EnableCfg()) @@ -192,8 +218,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 +252,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 +463,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 +541,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 +564,13 @@ bool Gowin::flashFLASH(uint8_t *data, int length) _jtag->set_state(Jtag::RUN_TEST_IDLE); progress.done(); + delete[] buffer; + return true; +} + +bool Gowin::connectJtagToMCU() +{ + wr_rd(SWITCH_TO_MCU_JTAG, NULL, 0, NULL, 0); return true; } diff --git a/src/gowin.hpp b/src/gowin.hpp index d26889e..c628505 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(); @@ -26,6 +26,7 @@ class Gowin: public Device, SPIInterface { void reset() override; void program(unsigned int offset, bool unprotect_flash) override; void programFlash(); + bool connectJtagToMCU() override; /* spi interface */ virtual bool protect_flash(uint32_t len) override { @@ -48,7 +49,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 +62,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 */ + ConfigBitstreamParser *_mcufw; }; #endif // GOWIN_HPP_ diff --git a/src/main.cpp b/src/main.cpp index 29e070a..6ed5699 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -78,6 +78,8 @@ struct arguments { bool xvc; int port; string interface; + string mcufw; + bool conmcu; }; int run_xvc_server(const struct arguments &args, const cable_t &cable, @@ -506,7 +508,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, @@ -537,6 +539,10 @@ int main(int argc, char **argv) } } + if (args.conmcu == true) { + fpga->connectJtagToMCU(); + } + /* unprotect SPI flash */ if (args.unprotect_flash && args.bit_file.empty()) { fpga->unprotect_flash(); @@ -721,6 +727,10 @@ 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)) + ("conmcu", "Connect JTAG to MCU", + cxxopts::value(args->conmcu)) ("V,Version", "Print program version"); options.parse_positional({"bitstream"}); @@ -845,7 +855,8 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p !args->protect_flash && !args->unprotect_flash && !args->xvc && - !args->reset) { + !args->reset && + !args->conmcu) { printError("Error: bitfile not specified"); cout << options.help() << endl; throw std::exception();