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:
parent
cc2eacc533
commit
5053fa0127
24
README.md
24
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
|
-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
142
gowin.cpp
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
18
main.cpp
18
main.cpp
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue