Rewrite GOWIN algorithms

This commit is contained in:
Alexey Starikovskiy 2023-08-30 17:16:13 +03:00
parent 0f3afbcaea
commit ff755f9811
2 changed files with 260 additions and 389 deletions

View File

@ -15,12 +15,13 @@
#include "jtag.hpp" #include "jtag.hpp"
#include "gowin.hpp" #include "gowin.hpp"
#include "progressBar.hpp"
#include "display.hpp" #include "display.hpp"
#include "fsparser.hpp" #include "fsparser.hpp"
#include "rawParser.hpp" #include "rawParser.hpp"
#include "spiFlash.hpp" #include "spiFlash.hpp"
#include <byteswap.h>
using namespace std; using namespace std;
#ifdef STATUS_TIMEOUT #ifdef STATUS_TIMEOUT
@ -56,6 +57,7 @@ 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 EF_PROGRAM 0x71
#define EFLASH_ERASE 0x75 #define EFLASH_ERASE 0x75
#define SWITCH_TO_MCU_JTAG 0x7a #define SWITCH_TO_MCU_JTAG 0x7a
@ -66,19 +68,21 @@ using namespace std;
#define BSCAN_SPI_CS (1 << 3) #define BSCAN_SPI_CS (1 << 3)
#define BSCAN_SPI_DI (1 << 5) #define BSCAN_SPI_DI (1 << 5)
#define BSCAN_SPI_DO (1 << 7) #define BSCAN_SPI_DO (1 << 7)
#define BSCAN_SPI_MSK ((0x01 << 6)) #define BSCAN_SPI_MSK (1 << 6)
/* GW1NSR-4C pins def */ /* GW1NSR-4C pins def */
#define BSCAN_GW1NSR_4C_SPI_SCK (1 << 7) #define BSCAN_GW1NSR_4C_SPI_SCK (1 << 7)
#define BSCAN_GW1NSR_4C_SPI_CS (1 << 5) #define BSCAN_GW1NSR_4C_SPI_CS (1 << 5)
#define BSCAN_GW1NSR_4C_SPI_DI (1 << 3) #define BSCAN_GW1NSR_4C_SPI_DI (1 << 3)
#define BSCAN_GW1NSR_4C_SPI_DO (1 << 1) #define BSCAN_GW1NSR_4C_SPI_DO (1 << 1)
#define BSCAN_GW1NSR_4C_SPI_MSK ((0x01 << 0)) #define BSCAN_GW1NSR_4C_SPI_MSK (1 << 0)
#define HZ_TO_US (2)
#define HZ_TO_MS (HZ_TO_US * 1000)
Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::string mcufw, Gowin::Gowin(Jtag *jtag, const string filename, const string &file_type, std::string mcufw,
Device::prog_type_t prg_type, bool external_flash, Device::prog_type_t prg_type, bool external_flash,
bool verify, int8_t verbose): Device(jtag, filename, file_type, bool verify, int8_t verbose): Device(jtag, filename, file_type,
verify, verbose), is_gw1n1(false), is_gw2a(false), verify, verbose), is_gw1n1(false), is_gw2a(false), is_gw5a(false),
is_gw5a(false),
_external_flash(external_flash), _external_flash(external_flash),
_spi_sck(BSCAN_SPI_SCK), _spi_cs(BSCAN_SPI_CS), _spi_sck(BSCAN_SPI_SCK), _spi_cs(BSCAN_SPI_CS),
_spi_di(BSCAN_SPI_DI), _spi_do(BSCAN_SPI_DO), _spi_di(BSCAN_SPI_DI), _spi_do(BSCAN_SPI_DO),
@ -196,124 +200,104 @@ Gowin::~Gowin()
delete _mcufw; delete _mcufw;
} }
bool Gowin::send_command(uint8_t cmd)
{
_jtag->shiftIR(&cmd, nullptr, 8);
_jtag->toggleClk(8);
return true;
}
uint32_t Gowin::readReg32(uint8_t cmd)
{
uint32_t reg = 0, tmp = 0xff;
send_command(cmd);
_jtag->shiftDR((uint8_t *)&tmp, (uint8_t *)&reg, 32);
return le32toh(reg);
}
void Gowin::reset() void Gowin::reset()
{ {
wr_rd(RELOAD, NULL, 0, NULL, 0); send_command(RELOAD);
wr_rd(NOOP, NULL, 0, NULL, 0); send_command(NOOP);
} }
void Gowin::programFlash() void Gowin::programFlash()
{ {
const uint8_t *data = _fs->getData(); const uint8_t *data = _fs->getData();
int length = _fs->getLength(); int length = _fs->getLength();
const uint8_t *mcu_data = nullptr; send_command(0x3a);
int mcu_length = 0; send_command(0);
_jtag->go_test_logic_reset();
if (_mcufw) { usleep(500*1000);
mcu_data = _mcufw->getData();
mcu_length = _mcufw->getLength();
}
/* erase SRAM */
if (!EnableCfg())
return;
eraseSRAM(); eraseSRAM();
wr_rd(XFER_DONE, NULL, 0, NULL, 0);
wr_rd(NOOP, NULL, 0, NULL, 0);
if (!DisableCfg())
return;
if (!EnableCfg())
return;
if (!eraseFLASH()) if (!eraseFLASH())
return; return;
if (!DisableCfg())
return;
/* test status a faire */ /* test status a faire */
if (!flashFLASH(0, data, length)) if (!writeFLASH(0, data, length))
return; return;
if (mcu_data) { if (_mcufw) {
if (!flashFLASH(0x380, mcu_data, mcu_length)) const uint8_t *mcu_data = _mcufw->getData();
int mcu_length = _mcufw->getLength();
if (!writeFLASH(0x380, mcu_data, mcu_length))
return; return;
} }
if (_verify) if (_verify)
printWarn("writing verification not supported"); printWarn("writing verification not supported");
if (!DisableCfg())
return;
wr_rd(RELOAD, NULL, 0, NULL, 0);
wr_rd(NOOP, NULL, 0, NULL, 0);
/* wait for reload */
usleep(2*150*1000);
/* check if file checksum == checksum in FPGA */ /* check if file checksum == checksum in FPGA */
checkCRC(); if (!skip_checksum)
checkCRC();
if (_verbose) if (_verbose)
displayReadReg(readStatusReg()); displayReadReg(readStatusReg());
} }
void Gowin::program(unsigned int offset, bool unprotect_flash) void Gowin::programExtFlash(unsigned int offset, bool unprotect_flash) {
{ _jtag->setClkFreq(10000000);
const uint8_t *data;
int length;
if (_mode == NONE_MODE || !_fs) if (!enableCfg())
return; throw std::runtime_error("Error: fail to enable configuration");
data = _fs->getData(); eraseSRAM();
length = _fs->getLength(); send_command(XFER_DONE);
send_command(NOOP);
if (_mode == FLASH_MODE) { if (!is_gw2a) {
if (is_gw5a) send_command(0x3D);
throw std::runtime_error("Error: write to flash on GW5A is not yet supported"); } else {
if (!_external_flash) { /* write into internal flash */ disableCfg();
programFlash(); send_command(NOOP);
} else { /* write bitstream into external flash */
_jtag->setClkFreq(10000000);
if (!EnableCfg())
throw std::runtime_error("Error: fail to enable configuration");
eraseSRAM();
wr_rd(XFER_DONE, NULL, 0, NULL, 0);
wr_rd(NOOP, NULL, 0, NULL, 0);
if (!is_gw2a) {
wr_rd(0x3D, NULL, 0, NULL, 0);
} else {
DisableCfg();
wr_rd(NOOP, NULL, 0, NULL, 0);
}
SPIFlash spiFlash(this, unprotect_flash,
(_verbose ? 1 : (_quiet ? -1 : 0)));
spiFlash.reset();
spiFlash.read_id();
spiFlash.display_status_reg(spiFlash.read_status_reg());
if (spiFlash.erase_and_prog(offset, data, length / 8) != 0)
throw std::runtime_error("Error: write to flash failed");
if (_verify)
if (!spiFlash.verify(offset, data, length / 8, 256))
throw std::runtime_error("Error: flash vefication failed");
if (!is_gw2a) {
if (!DisableCfg())
throw std::runtime_error("Error: fail to disable configuration");
}
reset();
}
return;
} }
SPIFlash spiFlash(this, unprotect_flash,
(_verbose ? 1 : (_quiet ? -1 : 0)));
spiFlash.reset();
spiFlash.read_id();
spiFlash.display_status_reg(spiFlash.read_status_reg());
const uint8_t *data = _fs->getData();
int length = _fs->getLength();
if (spiFlash.erase_and_prog(offset, data, length / 8) != 0)
throw std::runtime_error("Error: write to flash failed");
if (_verify)
if (!spiFlash.verify(offset, data, length / 8, 256))
throw std::runtime_error("Error: flash vefication failed");
if (!is_gw2a) {
if (!disableCfg())
throw std::runtime_error("Error: fail to disable configuration");
}
reset();
}
void Gowin::programSRAM() {
if (_verbose) { if (_verbose) {
displayReadReg(readStatusReg()); displayReadReg(readStatusReg());
} }
wr_rd(READ_IDCODE, NULL, 0, NULL, 0);
/* Work around FPGA stuck in Bad Command status */ /* Work around FPGA stuck in Bad Command status */
if (is_gw5a) { if (is_gw5a) {
reset(); reset();
@ -321,145 +305,96 @@ void Gowin::program(unsigned int offset, bool unprotect_flash)
_jtag->toggleClk(1000000); _jtag->toggleClk(1000000);
} }
/* erase SRAM */
if (!EnableCfg())
return;
eraseSRAM(); eraseSRAM();
if (!DisableCfg())
return;
/* load bitstream in SRAM */ if (!writeSRAM(_fs->getData(), _fs->getLength()))
if (!EnableCfg())
return;
if (!flashSRAM(data, length))
return;
if (!DisableCfg())
return; return;
/* ocheck if file checksum == checksum in FPGA */ /* ocheck if file checksum == checksum in FPGA */
checkCRC(); if (!skip_checksum)
checkCRC();
if (_verbose) if (_verbose)
displayReadReg(readStatusReg()); displayReadReg(readStatusReg());
} }
void Gowin::checkCRC() void Gowin::program(unsigned int offset, bool unprotect_flash)
{ {
if (skip_checksum) if (!_fs)
return; return;
bool is_match = true; if (_mode == FLASH_MODE) {
char mess[256]; if (is_gw5a)
uint32_t status = readUserCode(); throw std::runtime_error("Error: write to flash on GW5A is not yet supported");
uint16_t checksum = static_cast<FsParser *>(_fs)->checksum(); if (_external_flash)
string hdr = ""; programExtFlash(offset, unprotect_flash);
try { else
hdr = _fs->getHeaderVal("checkSum"); programFlash();
} catch (std::exception &e) { } else if (_mode == MEM_MODE)
if (_verbose) programSRAM();
printError(e.what());
} return;
if (static_cast<uint16_t>(0xffff & status) != checksum) {
/* no match:
* user code register contains checksum or
* user_code when:
* set_option -user_code
* is used: try to compare with this value
*/
if (hdr.empty()) {
is_match = false;
snprintf(mess, 256, "Read: 0x%08x checksum: 0x%04x\n",
status, checksum);
} else {
uint32_t user_code = strtol(hdr.c_str(), NULL, 16);
if (status != user_code) {
is_match = false;
snprintf(mess, 256,
"Read 0x%08x (checksum: 0x%08x, user_code: 0x%08x)\n",
status, checksum, user_code);
}
}
}
if (is_match) {
printSuccess("CRC check: Success");
} else {
printError("CRC check : FAIL");
printError(mess);
}
} }
bool Gowin::EnableCfg() void Gowin::checkCRC()
{ {
wr_rd(CONFIG_ENABLE, NULL, 0, NULL, 0); uint32_t ucode = readUserCode();
uint16_t checksum = static_cast<FsParser *>(_fs)->checksum();
if (static_cast<uint16_t>(0xffff & ucode) == checksum) {
printSuccess("CRC check: Success");
return;
}
/* no match:
* user code register contains checksum or
* user_code when set_option -user_code
* is used, try to compare with this value
*/
string hdr = "";
char mess[256];
try {
hdr = _fs->getHeaderVal("checkSum");
if (!hdr.empty()) {
} else {
uint32_t user_code = strtol(hdr.c_str(), NULL, 16);
if (ucode != user_code) {
snprintf(mess, 256, "Read 0x%08x (checksum: 0x%08x, user_code: 0x%08x)\n",
ucode, checksum, user_code);
printError("CRC check : FAIL");
printError(mess);
}
printSuccess("CRC check: Success");
}
} catch (std::exception &e) {}
snprintf(mess, 256, "Read: 0x%08x checksum: 0x%04x\n", ucode, checksum);
printError("CRC check : FAIL");
printError(mess);
}
bool Gowin::enableCfg()
{
send_command(CONFIG_ENABLE);
return pollFlag(STATUS_SYSTEM_EDIT_MODE, STATUS_SYSTEM_EDIT_MODE); return pollFlag(STATUS_SYSTEM_EDIT_MODE, STATUS_SYSTEM_EDIT_MODE);
} }
bool Gowin::DisableCfg() bool Gowin::disableCfg()
{ {
wr_rd(CONFIG_DISABLE, NULL, 0, NULL, 0); send_command(CONFIG_DISABLE);
wr_rd(NOOP, NULL, 0, NULL, 0); send_command(NOOP);
return pollFlag(STATUS_SYSTEM_EDIT_MODE, 0); return pollFlag(STATUS_SYSTEM_EDIT_MODE, 0);
} }
uint32_t Gowin::idCode() uint32_t Gowin::idCode()
{ {
uint8_t device_id[4]; return readReg32(READ_IDCODE);
wr_rd(READ_IDCODE, NULL, 0, device_id, 4);
return device_id[3] << 24 |
device_id[2] << 16 |
device_id[1] << 8 |
device_id[0];
} }
uint32_t Gowin::readStatusReg() uint32_t Gowin::readStatusReg()
{ {
uint32_t reg; return readReg32(STATUS_REGISTER);
uint8_t rx[4];
wr_rd(STATUS_REGISTER, NULL, 0, rx, 4);
reg = rx[3] << 24 | rx[2] << 16 | rx[1] << 8 | rx[0];
return reg;
} }
uint32_t Gowin::readUserCode() uint32_t Gowin::readUserCode()
{ {
uint8_t rx[4]; return readReg32(READ_USERCODE);
wr_rd(READ_USERCODE, NULL, 0, rx, 4);
return rx[3] << 24 | rx[2] << 16 | rx[1] << 8 | rx[0];
}
bool Gowin::wr_rd(uint8_t cmd,
uint8_t *tx, int tx_len,
uint8_t *rx, int rx_len,
bool verbose)
{
int xfer_len = rx_len;
if (tx_len > rx_len)
xfer_len = tx_len;
uint8_t xfer_tx[xfer_len], xfer_rx[xfer_len];
memset(xfer_tx, 0, xfer_len);
int i;
if (tx != NULL) {
for (i = 0; i < tx_len; i++)
xfer_tx[i] = tx[i];
}
_jtag->shiftIR(&cmd, NULL, 8);
_jtag->toggleClk(6);
if (rx || tx) {
_jtag->shiftDR(xfer_tx, (rx) ? xfer_rx : NULL, 8 * xfer_len);
_jtag->toggleClk(6);
_jtag->flush();
}
if (rx) {
if (verbose) {
for (i=xfer_len-1; i >= 0; i--)
printf("%02x ", xfer_rx[i]);
printf("\n");
}
for (i = 0; i < rx_len; i++)
rx[i] = (xfer_rx[i]);
}
return true;
} }
void Gowin::displayReadReg(uint32_t dev) void Gowin::displayReadReg(uint32_t dev)
@ -506,7 +441,7 @@ bool Gowin::pollFlag(uint32_t mask, uint32_t value)
do { do {
status = readStatusReg(); status = readStatusReg();
if (_verbose) if (_verbose)
printf("pollFlag: %x\n", status); printf("pollFlag: %x (%x)\n", status, status & mask);
if (timeout == 100000000){ if (timeout == 100000000){
printError("timeout"); printError("timeout");
return false; return false;
@ -518,162 +453,79 @@ bool Gowin::pollFlag(uint32_t mask, uint32_t value)
} }
/* TN653 p. 17-21 */ /* TN653 p. 17-21 */
bool Gowin::flashFLASH(uint32_t page, const uint8_t *data, int length) bool Gowin::writeFLASH(uint32_t page, const uint8_t *data, int length)
{ {
uint8_t tx[4] = {0x4E, 0x31, 0x57, 0x47}; uint8_t xpage[256];
uint8_t tmp[4]; length /= 8;
uint32_t addr; for (int off = 0; off < length; off += 256) {
int nb_iter; int l = 256;
int byte_length = length / 8; if (length - off < l) {
int buffer_length; memset(xpage, 0xff, sizeof(xpage));
uint8_t *buffer; l = length - off;
int nb_xpage; }
uint8_t tt[39]; memcpy(xpage, &data[off], l);
memset(tt, 0, 39); unsigned addr = off / 4 + page;
if (addr) {
_jtag->go_test_logic_reset(); sendClkUs(120);
} else {
if (page == 0) { // autoboot pattern
/* we have to send static uint8_t pat[4] = {'G', 'W', '1', 'N'};
* bootcode a X=0, Y=0 (4Bytes) memcpy(xpage, pat, 4);
* 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;
} }
buffer = new uint8_t[buffer_length]; send_command(CONFIG_ENABLE);
/* fill theorical size with 0xff */ send_command(EF_PROGRAM);
memset(buffer, 0xff, buffer_length);
/* fill first page with code */ unsigned w = htole32(addr);
memcpy(buffer, bufvalues, 6*4); _jtag->shiftDR((uint8_t *)&w, nullptr, 32);
/* bitstream just after opcode */ sendClkUs(120);
memcpy(buffer+6*4, data, byte_length); for (int y = 0; y < 64; ++y) {
} else { memcpy(&w, &xpage[y * 4], 4);
buffer_length = byte_length; w = bswap_32(w);
nb_xpage = buffer_length/256; _jtag->shiftDR((uint8_t *)&w, nullptr, 32);
if (nb_xpage * 256 != buffer_length) { sendClkUs((is_gw1n1) ? 32 : 16);
nb_xpage++;
buffer_length = nb_xpage * 256;
} }
buffer = new uint8_t[buffer_length]; sendClkUs((is_gw1n1) ? 2400 : 6);
memset(buffer, 0xff, buffer_length); usleep(200);
memcpy(buffer, data, byte_length);
} }
send_command(CONFIG_DISABLE);
send_command(NOOP);
usleep(600*1000);
send_command(CONFIG_DISABLE);
send_command(NOOP);
ProgressBar progress("write Flash", buffer_length, 50, _quiet); send_command(RELOAD);
send_command(NOOP);
if (_verbose)
displayReadReg(readStatusReg());
sleep(1);
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 ((page + xpage) != 0)
_jtag->toggleClk(312);
addr = (page + 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->toggleClk(312);
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++) {
if (page == 0)
tx[3-x] = t[x];
else
tx[x] = t[x];
}
_jtag->shiftDR(tx, NULL, 32);
if (!is_gw1n1)
_jtag->toggleClk(40);
}
if (is_gw1n1) {
//usleep(10*2400*2);
uint8_t tt2[6008/8];
memset(tt2, 0, 6008/8);
_jtag->toggleClk(6008);
}
progress.display(i);
}
/* 2.2.6.6 */
_jtag->set_state(Jtag::RUN_TEST_IDLE);
progress.done();
delete[] buffer;
return true; return true;
} }
bool Gowin::connectJtagToMCU() bool Gowin::connectJtagToMCU()
{ {
wr_rd(SWITCH_TO_MCU_JTAG, NULL, 0, NULL, 0); send_command(SWITCH_TO_MCU_JTAG);
return true; return true;
} }
/* TN653 p. 9 */ /* TN653 p. 9 */
bool Gowin::flashSRAM(const uint8_t *data, int length) bool Gowin::writeSRAM(const uint8_t *data, int length)
{ {
int tx_len; send_command(CONFIG_ENABLE); // config enable
Jtag::tapState_t tx_end; send_command(INIT_ADDR); // address initialize
int byte_length = length / 8; send_command(XFER_WRITE); // transfer configuration data
_jtag->shiftDR(data, NULL, length);
send_command(CONFIG_DISABLE); // config disable
send_command(NOOP); // noop
ProgressBar progress("Flash SRAM", byte_length, 50, _quiet); sleep(1);
/* UG704 3.4.3 */ if (readStatusReg() & STATUS_DONE_FINAL)
if (is_gw5a) {
wr_rd(INIT_ADDR, NULL, 0, NULL, 0);
}
/* 2.2.6.4 */
wr_rd(XFER_WRITE, NULL, 0, NULL, 0);
int xfer_len = 256;
for (int i=0; i < byte_length; i+=xfer_len) {
if (i + xfer_len > byte_length) { // last packet with some size
tx_len = (byte_length - i) * 8;
tx_end = Jtag::EXIT1_DR; // to move in EXIT1_DR
} else {
tx_len = xfer_len * 8;
/* 2.2.6.5 */
tx_end = Jtag::SHIFT_DR;
}
_jtag->shiftDR(data+i, NULL, tx_len, tx_end);
//_jtag->flush();
progress.display(i);
}
/* 2.2.6.6 */
_jtag->set_state(Jtag::RUN_TEST_IDLE);
/* p.15 fig 2.11 */
wr_rd(XFER_DONE, NULL, 0, NULL, 0);
if (pollFlag(STATUS_DONE_FINAL, STATUS_DONE_FINAL)) {
progress.done();
return true; return true;
} else { else
progress.fail();
return false; return false;
}
} }
/* Erase SRAM: /* Erase SRAM:
@ -681,48 +533,58 @@ bool Gowin::flashSRAM(const uint8_t *data, int length)
*/ */
bool Gowin::eraseFLASH() bool Gowin::eraseFLASH()
{ {
uint8_t tt[37500 * 8]; printInfo("Erase Flash ", false);
memset(tt, 0, 37500 * 8); send_command(CONFIG_ENABLE);
unsigned char tx[4] = {0, 0, 0, 0}; send_command(EFLASH_ERASE);
printInfo("erase Flash ", false); uint32_t tx = 0;
wr_rd(EFLASH_ERASE, NULL, 0, NULL, 0); _jtag->shiftDR((uint8_t *)&tx, NULL, 32);
_jtag->set_state(Jtag::RUN_TEST_IDLE); if (is_gw1n1) {
for (unsigned i = 0; i < 64; ++i)
/* GW1N1 need 65 x 32bits _jtag->shiftDR((uint8_t *)&tx, NULL, 32);
* others 1 x 32bits
*/
int nb_iter = (is_gw1n1)?65:1;
for (int i = 0; i < nb_iter; i++) {
_jtag->shiftDR(tx, NULL, 32);
_jtag->toggleClk(6);
} }
/* TN653 specifies to wait for 160ms with sendClkUs(150*1000);
* there are no bit in status register to specify if (_verbose)
* when this operation is done so we need to wait displayReadReg(readStatusReg());
*/ send_command(CONFIG_DISABLE);
//usleep(2*120000); send_command(NOOP);
//uint8_t tt[37500]; send_command(CONFIG_DISABLE);
_jtag->toggleClk(37500*8); send_command(NOOP);
send_command(RELOAD);
send_command(NOOP);
if (_verbose)
displayReadReg(readStatusReg());
usleep(500*1000);
if (_verbose)
displayReadReg(readStatusReg());
printSuccess("Done"); printSuccess("Done");
return true; return true;
} }
void Gowin::sendClkUs(unsigned us)
{
//unsigned freq = _jtag->getClkFreq() / 1000000;
//freq = (freq) ? freq : 1;
unsigned clocks = us * 2; // at 2MHz 1us ~ 2 clocks
_jtag->toggleClk(clocks);
}
/* 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 SRAM ", false); printInfo("Erase SRAM ", false);
wr_rd(ERASE_SRAM, NULL, 0, NULL, 0); send_command(CONFIG_ENABLE);
wr_rd(NOOP, NULL, 0, NULL, 0); send_command(ERASE_SRAM);
send_command(NOOP);
sendClkUs(32*1000);
send_command(XFER_DONE);
send_command(NOOP);
/* TN653 specifies to wait for 4ms with //sendClkUs(500);
* clock generated but send_command(CONFIG_DISABLE);
* status register bit MEMORY_ERASE goes low when ERASE_SRAM send_command(NOOP);
* is send and goes high after erase if (readStatusReg() & STATUS_MEMORY_ERASE) {
* this check seems enough
*/
if (pollFlag(STATUS_MEMORY_ERASE, STATUS_MEMORY_ERASE)) {
printSuccess("Done"); printSuccess("Done");
return true; return true;
} else { } else {
@ -745,10 +607,6 @@ bool Gowin::eraseSRAM()
* but all byte must be bit reversal... * but all byte must be bit reversal...
*/ */
#define spi_gowin_write(_wr, _rd, _len) do { \
_jtag->shiftDR(_wr, _rd, _len); \
_jtag->toggleClk(6); } while (0)
int Gowin::spi_put(uint8_t cmd, const uint8_t *tx, uint8_t *rx, uint32_t len) int Gowin::spi_put(uint8_t cmd, const uint8_t *tx, uint8_t *rx, uint32_t len)
{ {
uint8_t jrx[len+1], jtx[len+1]; uint8_t jrx[len+1], jtx[len+1];
@ -774,11 +632,11 @@ int Gowin::spi_put(const uint8_t *tx, uint8_t *rx, uint32_t len)
for (uint32_t i = 0; i < len; i++) for (uint32_t i = 0; i < len; i++)
jtx[i] = FsParser::reverseByte(tx[i]); jtx[i] = FsParser::reverseByte(tx[i]);
} }
bool ret = wr_rd(0x16, NULL, 0, NULL, 0, false); bool ret = send_command(0x16);
if (!ret) if (!ret)
return -1; return -1;
_jtag->set_state(Jtag::EXIT2_DR); _jtag->set_state(Jtag::EXIT2_DR);
ret = _jtag->shiftDR(jtx, (rx)? jrx:NULL, 8*len); _jtag->shiftDR(jtx, (rx)? jrx:NULL, 8*len);
if (rx) { if (rx) {
for (uint32_t i=0; i < len; i++) { for (uint32_t i=0; i < len; i++) {
rx[i] = FsParser::reverseByte(jrx[i]>>1) | rx[i] = FsParser::reverseByte(jrx[i]>>1) |
@ -789,7 +647,8 @@ int Gowin::spi_put(const uint8_t *tx, uint8_t *rx, uint32_t len)
/* set CS/SCK/DI low */ /* set CS/SCK/DI low */
uint8_t t = _spi_msk | _spi_do; uint8_t t = _spi_msk | _spi_do;
t &= ~_spi_cs; t &= ~_spi_cs;
spi_gowin_write(&t, NULL, 8); _jtag->shiftDR(&t, NULL, 8);
_jtag->toggleClk(6);
_jtag->flush(); _jtag->flush();
/* send bit/bit full tx content (or set di to 0 when NULL) */ /* send bit/bit full tx content (or set di to 0 when NULL) */
@ -798,9 +657,11 @@ int Gowin::spi_put(const uint8_t *tx, uint8_t *rx, uint32_t len)
t = _spi_msk | _spi_do; t = _spi_msk | _spi_do;
if (tx != NULL && tx[i>>3] & (1 << (7-(i&0x07)))) if (tx != NULL && tx[i>>3] & (1 << (7-(i&0x07))))
t |= _spi_di; t |= _spi_di;
spi_gowin_write(&t, NULL, 8); _jtag->shiftDR(&t, NULL, 8);
_jtag->toggleClk(6);
t |= _spi_sck; t |= _spi_sck;
spi_gowin_write(&t, (rx) ? &r : NULL, 8); _jtag->shiftDR(&t, (rx) ? &r : NULL, 8);
_jtag->toggleClk(6);
_jtag->flush(); _jtag->flush();
/* if read reconstruct bytes */ /* if read reconstruct bytes */
if (rx) { if (rx) {
@ -813,7 +674,8 @@ int Gowin::spi_put(const uint8_t *tx, uint8_t *rx, uint32_t len)
/* set CS and unset SCK (next xfer) */ /* set CS and unset SCK (next xfer) */
t &= ~_spi_sck; t &= ~_spi_sck;
t |= _spi_cs; t |= _spi_cs;
spi_gowin_write(&t, NULL, 8); _jtag->shiftDR(&t, NULL, 8);
_jtag->toggleClk(6);
_jtag->flush(); _jtag->flush();
} }
return 0; return 0;
@ -831,11 +693,11 @@ int Gowin::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
tx[0] = FsParser::reverseByte(cmd); tx[0] = FsParser::reverseByte(cmd);
do { do {
bool ret = wr_rd(0x16, NULL, 0, NULL, 0, false); bool ret = send_command(0x16);
if (!ret) if (!ret)
return -1; return -1;
_jtag->set_state(Jtag::EXIT2_DR); _jtag->set_state(Jtag::EXIT2_DR);
ret = _jtag->shiftDR(tx, rx, 8 * 3); _jtag->shiftDR(tx, rx, 8 * 3);
tmp = (FsParser::reverseByte(rx[1]>>1)) | (0x01 & rx[2]); tmp = (FsParser::reverseByte(rx[1]>>1)) | (0x01 & rx[2]);
count ++; count ++;
@ -852,16 +714,19 @@ int Gowin::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
/* set CS/SCK/DI low */ /* set CS/SCK/DI low */
t = _spi_msk | _spi_do; t = _spi_msk | _spi_do;
spi_gowin_write(&t, NULL, 8); _jtag->shiftDR(&t, NULL, 8);
_jtag->toggleClk(6);
/* send command bit/bit */ /* send command bit/bit */
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
t = _spi_msk | _spi_do; t = _spi_msk | _spi_do;
if ((cmd & (1 << (7-i))) != 0) if ((cmd & (1 << (7-i))) != 0)
t |= _spi_di; t |= _spi_di;
spi_gowin_write(&t, NULL, 8); _jtag->shiftDR(&t, NULL, 8);
_jtag->toggleClk(6);
t |= _spi_sck; t |= _spi_sck;
spi_gowin_write(&t, NULL, 8); _jtag->shiftDR(&t, NULL, 8);
_jtag->toggleClk(6);
_jtag->flush(); _jtag->flush();
} }
@ -872,9 +737,11 @@ int Gowin::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
uint8_t r; uint8_t r;
t &= ~_spi_sck; t &= ~_spi_sck;
spi_gowin_write(&t, NULL, 8); _jtag->shiftDR(&t, NULL, 8);
_jtag->toggleClk(6);
t |= _spi_sck; t |= _spi_sck;
spi_gowin_write(&t, &r, 8); _jtag->shiftDR(&t, &r, 8);
_jtag->toggleClk(6);
_jtag->flush(); _jtag->flush();
if ((r & _spi_do) != 0) if ((r & _spi_do) != 0)
tmp |= 1 << (7-i); tmp |= 1 << (7-i);
@ -892,7 +759,8 @@ int Gowin::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
/* set CS & unset SCK (next xfer) */ /* set CS & unset SCK (next xfer) */
t &= ~_spi_sck; t &= ~_spi_sck;
t |= _spi_cs; t |= _spi_cs;
spi_gowin_write(&t, NULL, 8); _jtag->shiftDR(&t, NULL, 8);
_jtag->toggleClk(6);
_jtag->flush(); _jtag->flush();
} }

View File

@ -25,7 +25,6 @@ class Gowin: public Device, SPIInterface {
uint32_t idCode() override; uint32_t idCode() override;
void reset() override; void reset() override;
void program(unsigned int offset, bool unprotect_flash) override; void program(unsigned int offset, bool unprotect_flash) override;
void programFlash();
bool connectJtagToMCU() override; bool connectJtagToMCU() override;
/* spi interface */ /* spi interface */
@ -43,15 +42,19 @@ class Gowin: public Device, SPIInterface {
uint32_t timeout, bool verbose) override; uint32_t timeout, bool verbose) override;
private: private:
bool wr_rd(uint8_t cmd, uint8_t *tx, int tx_len, bool send_command(uint8_t cmd);
uint8_t *rx, int rx_len, bool verbose = false); uint32_t readReg32(uint8_t cmd);
bool EnableCfg(); void sendClkUs(unsigned us);
bool DisableCfg(); bool enableCfg();
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 eraseFLASH();
bool flashSRAM(const uint8_t *data, int length); void programFlash();
bool flashFLASH(uint32_t page, const uint8_t *data, int length); 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);
void displayReadReg(uint32_t dev); void displayReadReg(uint32_t dev);
uint32_t readStatusReg(); uint32_t readStatusReg();
uint32_t readUserCode(); uint32_t readUserCode();