gowin: support write bitstream in internal Flash. Choise between write in flash and load in SRAM is determined by an command line option

This commit is contained in:
Gwenhael Goavec-Merou 2020-01-04 17:37:16 +01:00
parent cc2eacc533
commit 5053fa0127
4 changed files with 179 additions and 11 deletions

View File

@ -49,9 +49,13 @@ openFPGALoader -- a program to flash cyclone10 LP FPGA
-b, --board=BOARD board name, may be used instead of cable -b, --board=BOARD board name, may be used instead of cable
-c, --cable=CABLE jtag interface -c, --cable=CABLE jtag interface
-d, --device=DEVICE device to use (/dev/ttyUSBx) -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-boards list all supported boards
--list-cables list all supported cables --list-cables list all supported cables
--list-fpga list all supported FPGA --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 -o, --offset=OFFSET start offset in EEPROM
-r, --reset reset FPGA after operations -r, --reset reset FPGA after operations
-v, --verbose Produce verbose output -v, --verbose Produce verbose output
@ -194,12 +198,26 @@ openFPGALoader -b machXO3SK impl1/*.bit
### Trenz GOWIN LittleBee (TEC0117) ### Trenz GOWIN LittleBee (TEC0117)
#### Flash SRAM:
*.fs* file is the default format generated by *Gowin IDE*, so nothing *.fs* file is the default format generated by *Gowin IDE*, so nothing
special must be done to generates this file. 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__: __file load__:
```bash ```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
``` ```

142
gowin.cpp
View File

@ -60,15 +60,21 @@ using namespace std;
# define STATUS_READY (1 << 15) # define STATUS_READY (1 << 15)
# define STATUS_POR (1 << 16) # define STATUS_POR (1 << 16)
# define STATUS_FLASH_LOCK (1 << 17) # define STATUS_FLASH_LOCK (1 << 17)
#define EF_PROGRAM 0x71
#define EFLASH_ERASE 0x75 #define EFLASH_ERASE 0x75
Gowin::Gowin(FtdiJtag *jtag, const string filename, bool verbose): Gowin::Gowin(FtdiJtag *jtag, const string filename, bool flash_wr, bool sram_wr,
Device(jtag, filename, verbose) bool verbose): Device(jtag, filename, verbose)
{ {
if (_filename != "") { if (_filename != "") {
if (_file_extension == "fs") { if (_file_extension == "fs") {
_mode = Device::FLASH_MODE; if (flash_wr && sram_wr)
_fs = new FsParser(_filename, true, _verbose); 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(); _fs->parse();
} else { } else {
throw std::runtime_error("incompatible file format"); throw std::runtime_error("incompatible file format");
@ -83,6 +89,41 @@ Gowin::~Gowin()
delete _fs; 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 Gowin::program(unsigned int offset)
{ {
(void) offset; (void) offset;
@ -94,6 +135,11 @@ void Gowin::program(unsigned int offset)
if (_filename == "" || !_fs) if (_filename == "" || !_fs)
return; return;
if (_mode == FLASH_MODE) {
programFlash();
return;
}
if (_verbose) { if (_verbose) {
displayReadReg(readStatusReg()); displayReadReg(readStatusReg());
} }
@ -257,6 +303,73 @@ bool Gowin::pollFlag(uint32_t mask, uint32_t value)
return true; 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 */ /* TN653 p. 9 */
bool Gowin::flashSRAM(uint8_t *data, int length) 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: /* Erase SRAM:
* TN653 p.9-10, 14 and 31 * TN653 p.9-10, 14 and 31
*/ */
bool Gowin::eraseSRAM() bool Gowin::eraseSRAM()
{ {
printInfo("erase Flash ", false); printInfo("erase SRAM ", false);
wr_rd(ERASE_SRAM, NULL, 0, NULL, 0); wr_rd(ERASE_SRAM, NULL, 0, NULL, 0);
wr_rd(NOOP, NULL, 0, NULL, 0); wr_rd(NOOP, NULL, 0, NULL, 0);

View File

@ -30,11 +30,13 @@
class Gowin: public Device { class Gowin: public Device {
public: public:
Gowin(FtdiJtag *jtag, std::string filename, bool verbose); Gowin(FtdiJtag *jtag, std::string filename, bool flash_wr, bool sram_wr,
bool verbose);
~Gowin(); ~Gowin();
int idCode() override; int idCode() override;
void reset() override {} void reset() override {}
void program(unsigned int offset) override; void program(unsigned int offset) override;
void programFlash();
private: private:
bool wr_rd(uint8_t cmd, uint8_t *tx, int tx_len, bool wr_rd(uint8_t cmd, uint8_t *tx, int tx_len,
@ -43,7 +45,9 @@ class Gowin: public Device {
bool DisableCfg(); bool DisableCfg();
bool pollFlag(uint32_t mask, uint32_t value); bool pollFlag(uint32_t mask, uint32_t value);
bool eraseSRAM(); bool eraseSRAM();
bool eraseFLASH();
bool flashSRAM(uint8_t *data, int length); bool flashSRAM(uint8_t *data, int length);
bool flashFLASH(uint8_t *data, int length);
void displayReadReg(uint32_t dev); void displayReadReg(uint32_t dev);
uint32_t readStatusReg(); uint32_t readStatusReg();
uint32_t readUserCode(); uint32_t readUserCode();

View File

@ -47,6 +47,8 @@ struct arguments {
bool list_cables; bool list_cables;
bool list_boards; bool list_boards;
bool list_fpga; bool list_fpga;
bool write_flash;
bool write_sram;
}; };
#define LIST_CABLE 1 #define LIST_CABLE 1
@ -65,6 +67,10 @@ static struct argp_option options[] = {
{"list-boards", LIST_BOARD, 0, 0, "list all supported boards"}, {"list-boards", LIST_BOARD, 0, 0, "list all supported boards"},
{"device", 'd', "DEVICE", 0, "device to use (/dev/ttyUSBx)"}, {"device", 'd', "DEVICE", 0, "device to use (/dev/ttyUSBx)"},
{"list-fpga", LIST_FPGA, 0, 0, "list all supported FPGA"}, {"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"}, {"offset", 'o', "OFFSET", 0, "start offset in EEPROM"},
{"verbose", 'v', 0, 0, "Produce verbose output"}, {"verbose", 'v', 0, 0, "Produce verbose output"},
{"reset", 'r', 0, 0, "reset FPGA after operations"}, {"reset", 'r', 0, 0, "reset FPGA after operations"},
@ -80,7 +86,7 @@ int main(int argc, char **argv)
/* command line args. */ /* command line args. */
struct arguments args = {false, false, 0, "", "-", "-", "-", struct arguments args = {false, false, 0, "", "-", "-", "-",
false, false, false}; false, false, false, false, true};
/* parse arguments */ /* parse arguments */
argp_parse(&argp, argc, argv, 0, 0, &args); argp_parse(&argp, argc, argv, 0, 0, &args);
@ -152,7 +158,8 @@ int main(int argc, char **argv)
} else if (fab == "altera") { } else if (fab == "altera") {
fpga = new Altera(jtag, args.bit_file, args.verbose); fpga = new Altera(jtag, args.bit_file, args.verbose);
} else if (fab == "Gowin") { } 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") { } else if (fab == "lattice") {
fpga = new Lattice(jtag, args.bit_file, args.verbose); fpga = new Lattice(jtag, args.bit_file, args.verbose);
} else { } 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; struct arguments *arguments = (struct arguments *)state->input;
switch (key) { switch (key) {
case 'f':
arguments->write_flash = true;
arguments->write_sram = false;
break;
case 'm':
arguments->write_sram = true;
break;
case 'r': case 'r':
arguments->reset = true; arguments->reset = true;
break; break;