Merge pull request #499 from lambdaconcept/gowin-gw1n9-userflash
gowin: Implement User Flash programming for GW1N9
This commit is contained in:
commit
cdc4d32e32
|
|
@ -62,3 +62,17 @@ It's possible to flash external SPI Flash (connected to MSPI) in bscan mode by u
|
|||
|
||||
Gowin's FPGA may fails to be detected if **JTAGSEL_N** (pin 08 for *GW1N-4K*) is used as a GPIO.
|
||||
To recover you have to pull down this pin (before power up) to recover JTAG interface (*UG292 - JTAGSELL_N section*).
|
||||
|
||||
User Flash
|
||||
----------
|
||||
|
||||
.. ATTENTION::
|
||||
User Flash support is based on reverse engineering of the JTAG protocol. This functionality should be considered
|
||||
experimental as it hasn't been thoroughly tested, and may in some circumstances destroy your device.
|
||||
|
||||
Gowin FPGA come with extra flash space that can be read and written from the programmable logic ("User Flash"). This
|
||||
flash section can also be programmed via the JTAG interface:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
openFPGALoader --write-flash /path/to/bitstream.fs --user-flash /path/to/flash.bin
|
||||
|
|
|
|||
|
|
@ -77,15 +77,15 @@ using namespace std;
|
|||
|
||||
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),
|
||||
bool verify, int8_t verbose, const std::string& user_flash)
|
||||
: Device(jtag, filename, file_type, verify, verbose),
|
||||
SPIInterface(filename, verbose, 0, verify, false, false),
|
||||
_fs(NULL), _idcode(0), is_gw1n1(false), is_gw2a(false),
|
||||
is_gw1n4(false), is_gw5a(false), _external_flash(external_flash),
|
||||
_idcode(0), is_gw1n1(false), is_gw1n4(false), is_gw1n9(false),
|
||||
is_gw2a(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),
|
||||
_spi_msk(BSCAN_SPI_MSK),
|
||||
_mcufw(NULL)
|
||||
_spi_msk(BSCAN_SPI_MSK)
|
||||
{
|
||||
detectFamily();
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st
|
|||
if (!_file_extension.empty() && prg_type != Device::RD_FLASH) {
|
||||
if (_file_extension == "fs") {
|
||||
try {
|
||||
_fs = new FsParser(_filename, _mode == Device::MEM_MODE, _verbose);
|
||||
_fs = std::unique_ptr<ConfigBitstreamParser>(new FsParser(_filename, _mode == Device::MEM_MODE, _verbose));
|
||||
} catch (std::exception &e) {
|
||||
throw std::runtime_error(e.what());
|
||||
}
|
||||
|
|
@ -109,7 +109,7 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st
|
|||
if (!_external_flash)
|
||||
throw std::runtime_error("incompatible file format");
|
||||
try {
|
||||
_fs = new RawParser(_filename, false);
|
||||
_fs = std::unique_ptr<ConfigBitstreamParser>(new RawParser(_filename, false));
|
||||
} catch (std::exception &e) {
|
||||
throw std::runtime_error(e.what());
|
||||
}
|
||||
|
|
@ -118,7 +118,6 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st
|
|||
printInfo("Parse file ", false);
|
||||
if (_fs->parse() == EXIT_FAILURE) {
|
||||
printError("FAIL");
|
||||
delete _fs;
|
||||
throw std::runtime_error("can't parse file");
|
||||
} else {
|
||||
printSuccess("DONE");
|
||||
|
|
@ -144,11 +143,26 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st
|
|||
if (_idcode != 0x0100981b)
|
||||
throw std::runtime_error("Microcontroller firmware flashing only supported on GW1NSR-4C");
|
||||
|
||||
_mcufw = new RawParser(mcufw, false);
|
||||
_mcufw = std::unique_ptr<ConfigBitstreamParser>(new RawParser(mcufw, false));
|
||||
|
||||
if (_mcufw->parse() == EXIT_FAILURE) {
|
||||
printError("FAIL");
|
||||
delete _mcufw;
|
||||
throw std::runtime_error("can't parse file");
|
||||
} else {
|
||||
printSuccess("DONE");
|
||||
}
|
||||
}
|
||||
|
||||
if (user_flash.size() > 0) {
|
||||
if (!is_gw1n9)
|
||||
throw std::runtime_error("Unsupported FPGA model (only GW1N(R)-9(C) is supported at the moment)");
|
||||
if (mcufw.size() > 0)
|
||||
throw std::runtime_error("Microcontroller firmware and user flash can't be specified simultaneously");
|
||||
|
||||
_userflash = std::unique_ptr<ConfigBitstreamParser>(new RawParser(user_flash, false));
|
||||
|
||||
if (_userflash->parse() == EXIT_FAILURE) {
|
||||
printError("FAIL");
|
||||
throw std::runtime_error("can't parse file");
|
||||
} else {
|
||||
printSuccess("DONE");
|
||||
|
|
@ -167,25 +181,10 @@ Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::st
|
|||
}
|
||||
}
|
||||
|
||||
Gowin::~Gowin()
|
||||
{
|
||||
if (_fs)
|
||||
delete _fs;
|
||||
if (_mcufw)
|
||||
delete _mcufw;
|
||||
}
|
||||
|
||||
bool Gowin::detectFamily()
|
||||
{
|
||||
_idcode = _jtag->get_target_device_id();
|
||||
|
||||
/* erase and program flash differ for GW1N1 */
|
||||
if (_idcode == 0x0900281B)
|
||||
is_gw1n1 = true;
|
||||
/* erase and program flash differ for GW1N4, GW1N1Z-1 */
|
||||
if (_idcode == 0x0100381B || _idcode == 0x100681b)
|
||||
is_gw1n4 = true;
|
||||
|
||||
/* bscan spi external flash differ for GW1NSR-4C */
|
||||
if (_idcode == 0x0100981b) {
|
||||
_spi_sck = BSCAN_GW1NSR_4C_SPI_SCK;
|
||||
|
|
@ -200,6 +199,16 @@ bool Gowin::detectFamily()
|
|||
* algorithm that is not yet supported.
|
||||
*/
|
||||
switch (_idcode) {
|
||||
case 0x0900281B: /* GW1N-1 */
|
||||
is_gw1n1 = true;
|
||||
break;
|
||||
case 0x0100381B: /* GW1N-4B */
|
||||
case 0x0100681b: /* GW1NZ-1 */
|
||||
is_gw1n4 = true;
|
||||
break;
|
||||
case 0x0100481B: /* GW1N(R)-9, although documentation says otherwise */
|
||||
is_gw1n9 = true;
|
||||
break;
|
||||
case 0x0000081b: /* GW2A(R)-18(C) */
|
||||
case 0x0000281b: /* GW2A(R)-55(C) */
|
||||
_external_flash = true;
|
||||
|
|
@ -300,6 +309,13 @@ void Gowin::programFlash()
|
|||
return;
|
||||
}
|
||||
|
||||
if (_userflash) {
|
||||
const uint8_t *userflash_data = _userflash->getData();
|
||||
int userflash_length = _userflash->getLength();
|
||||
if (!writeFLASH(0x6D0, userflash_data, userflash_length, true))
|
||||
return;
|
||||
}
|
||||
|
||||
if (_verify)
|
||||
printWarn("writing verification not supported");
|
||||
|
||||
|
|
@ -415,7 +431,7 @@ void Gowin::program(unsigned int offset, bool unprotect_flash)
|
|||
void Gowin::checkCRC()
|
||||
{
|
||||
uint32_t ucode = readUserCode();
|
||||
uint16_t checksum = static_cast<FsParser *>(_fs)->checksum();
|
||||
uint16_t checksum = static_cast<FsParser *>(_fs.get())->checksum();
|
||||
if (static_cast<uint16_t>(0xffff & ucode) == checksum)
|
||||
goto success;
|
||||
/* no match:
|
||||
|
|
@ -574,7 +590,7 @@ inline uint32_t bswap_32(uint32_t x)
|
|||
}
|
||||
|
||||
/* TN653 p. 17-21 */
|
||||
bool Gowin::writeFLASH(uint32_t page, const uint8_t *data, int length)
|
||||
bool Gowin::writeFLASH(uint32_t page, const uint8_t *data, int length, bool invert_bits)
|
||||
{
|
||||
|
||||
#if 1
|
||||
|
|
@ -659,6 +675,13 @@ bool Gowin::writeFLASH(uint32_t page, const uint8_t *data, int length)
|
|||
else
|
||||
tx[x] = t[x];
|
||||
}
|
||||
|
||||
if (invert_bits) {
|
||||
for (int x = 0; x < 4; x++) {
|
||||
tx[x] ^= 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
_jtag->shiftDR(tx, NULL, 32);
|
||||
|
||||
if (!is_gw1n1)
|
||||
|
|
@ -788,7 +811,7 @@ bool Gowin::writeSRAM(const uint8_t *data, int length)
|
|||
}
|
||||
progress.done();
|
||||
send_command(0x0a);
|
||||
uint32_t checksum = static_cast<FsParser *>(_fs)->checksum();
|
||||
uint32_t checksum = static_cast<FsParser *>(_fs.get())->checksum();
|
||||
checksum = htole32(checksum);
|
||||
_jtag->shiftDR((uint8_t *)&checksum, NULL, 32);
|
||||
send_command(0x08);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "configBitstreamParser.hpp"
|
||||
#include "device.hpp"
|
||||
|
|
@ -21,8 +22,8 @@ class Gowin: public Device, SPIInterface {
|
|||
public:
|
||||
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();
|
||||
bool external_flash, bool verify, int8_t verbose,
|
||||
const std::string& user_flash);
|
||||
uint32_t idCode() override;
|
||||
void reset() override;
|
||||
void program(unsigned int offset, bool unprotect_flash) override;
|
||||
|
|
@ -104,7 +105,7 @@ class Gowin: public Device, SPIInterface {
|
|||
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);
|
||||
bool writeFLASH(uint32_t page, const uint8_t *data, int length, bool invert_bits = false);
|
||||
void displayReadReg(const char *, uint32_t dev);
|
||||
uint32_t readStatusReg();
|
||||
uint32_t readUserCode();
|
||||
|
|
@ -128,11 +129,14 @@ class Gowin: public Device, SPIInterface {
|
|||
*/
|
||||
bool gw5a_enable_spi();
|
||||
|
||||
ConfigBitstreamParser *_fs;
|
||||
std::unique_ptr<ConfigBitstreamParser> _fs;
|
||||
std::unique_ptr<ConfigBitstreamParser> _mcufw;
|
||||
std::unique_ptr<ConfigBitstreamParser> _userflash;
|
||||
uint32_t _idcode;
|
||||
bool is_gw1n1;
|
||||
bool is_gw2a;
|
||||
bool is_gw1n4;
|
||||
bool is_gw1n9;
|
||||
bool is_gw2a;
|
||||
bool is_gw5a;
|
||||
bool skip_checksum; /**< bypass checksum verification (GW2A) */
|
||||
bool _external_flash; /**< select between int or ext flash */
|
||||
|
|
@ -141,7 +145,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;
|
||||
JtagInterface::tck_edge_t _prev_rd_edge; /**< default probe rd edge cfg */
|
||||
JtagInterface::tck_edge_t _prev_wr_edge; /**< default probe wr edge cfg */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ struct arguments {
|
|||
bool read_dna;
|
||||
bool read_xadc;
|
||||
string read_register;
|
||||
string user_flash;
|
||||
};
|
||||
|
||||
int run_xvc_server(const struct arguments &args, const cable_t &cable,
|
||||
|
|
@ -582,7 +583,7 @@ int main(int argc, char **argv)
|
|||
args.verify, args.verbose);
|
||||
} else if (fab == "Gowin") {
|
||||
fpga = new Gowin(jtag, args.bit_file, args.file_type, args.mcufw,
|
||||
args.prg_type, args.external_flash, args.verify, args.verbose);
|
||||
args.prg_type, args.external_flash, args.verify, args.verbose, args.user_flash);
|
||||
} else if (fab == "lattice") {
|
||||
fpga = new Lattice(jtag, args.bit_file, args.file_type,
|
||||
args.prg_type, args.flash_sector, args.verify, args.verbose, args.skip_load_bridge, args.skip_reset);
|
||||
|
|
@ -871,6 +872,8 @@ int parse_opt(int argc, char **argv, struct arguments *args,
|
|||
cxxopts::value<bool>(args->read_xadc))
|
||||
("read-register", "Read Status Register(Xilinx FPGA only)",
|
||||
cxxopts::value<string>(rd_reg))
|
||||
("user-flash", "User flash file (Gowin LittleBee FPGA only)",
|
||||
cxxopts::value<string>(args->user_flash))
|
||||
("V,Version", "Print program version");
|
||||
|
||||
options.parse_positional({"bitstream"});
|
||||
|
|
|
|||
Loading…
Reference in New Issue