Rewrite GOWIN algorithms
This commit is contained in:
parent
0f3afbcaea
commit
ff755f9811
632
src/gowin.cpp
632
src/gowin.cpp
|
|
@ -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 *)®, 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue