all devices: add support to (un)protect flash, implement pre/post flash access. Use new spiInterface methods

This commit is contained in:
Gwenhael Goavec-Merou 2021-12-22 19:11:35 +01:00
parent af14e9b518
commit 45f7f72030
18 changed files with 431 additions and 347 deletions

View File

@ -26,8 +26,9 @@
Altera::Altera(Jtag *jtag, const std::string &filename,
const std::string &file_type, Device::prog_type_t prg_type,
const std::string &device_package, bool verify, int8_t verbose):
Device(jtag, filename, file_type, verify, verbose), _svf(_jtag, _verbose),
_device_package(device_package),
Device(jtag, filename, file_type, verify, verbose),
SPIInterface(filename, verbose, 256, verify),
_svf(_jtag, _verbose), _device_package(device_package),
_vir_addr(0x1000), _vir_length(14)
{
if (prg_type == Device::RD_FLASH) {
@ -177,7 +178,7 @@ bool Altera::load_bridge()
return true;
}
void Altera::program(unsigned int offset)
void Altera::program(unsigned int offset, bool unprotect_flash)
{
if (_mode == Device::NONE_MODE)
return;
@ -197,14 +198,6 @@ void Altera::program(unsigned int offset)
programMem(_bit);
}
} else if (_mode == Device::SPI_MODE) {
/* try to load spiOverJtag bridge
* to have an access to SPI flash
*/
if (!load_bridge()) {
printError("Fail to load bridge");
return;
}
// reverse only bitstream raw binaries data no
bool reverseOrder = false;
if (_file_extension == "rbf" || _file_extension == "rpd")
@ -224,51 +217,11 @@ void Altera::program(unsigned int offset)
throw std::runtime_error(e.what());
}
/* GGM: TODO: fix this issue */
EPCQ epcq(this, 0);
try {
epcq.reset();
epcq.read_id();
epcq.display_status_reg(epcq.read_status_reg());
epcq.erase_and_prog(offset, data, length);
} catch (std::exception &e) {
printError(e.what());
throw std::runtime_error(e.what());
}
if (_verify)
epcq.verify(offset, data, length, 256);
reset();
if (!SPIInterface::write(offset, data, length, unprotect_flash))
throw std::runtime_error("Fail to write data");
}
}
bool Altera::dumpFlash(const std::string filename, uint32_t base_addr,
uint32_t len)
{
int ret = true;
/* try to load spiOverJtag bridge
* to have an access to SPI flash
*/
if (!load_bridge()) {
printError("Fail to load bridge");
return false;
}
EPCQ epcq(this, 0);
try {
epcq.reset();
ret = epcq.dump(filename, base_addr, len, 256);
} catch (std::exception &e) {
printError(e.what());
ret = false;
}
reset();
return ret;
}
int Altera::idCode()
{
unsigned char tx_data[4] = {IDCODE};
@ -308,7 +261,7 @@ int Altera::spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, uint32_t len)
}
}
return len;
return 0;
}
int Altera::spi_put(uint8_t *tx, uint8_t *rx, uint32_t len)
{

View File

@ -24,7 +24,7 @@ class Altera: public Device, SPIInterface {
~Altera();
void programMem(RawParser &_bit);
void program(unsigned int offset = 0) override;
void program(unsigned int offset, bool unprotect_flash) override;
/*!
* \brief read len Byte starting at base_addr and store
* into filename
@ -33,18 +33,40 @@ class Altera: public Device, SPIInterface {
* \param[in] len: length (in Byte)
* \return false if read fails or filename can't be open, true otherwise
*/
bool dumpFlash(const std::string filename, uint32_t base_addr,
uint32_t len);
bool dumpFlash(uint32_t base_addr, uint32_t len) override {
return SPIInterface::dump(base_addr, len);
}
int idCode() override;
void reset() override;
/* spi interface */
/*************************/
/* spi interface */
/*************************/
/*!
* \brief protect SPI flash blocks
*/
bool protect_flash(uint32_t len) override {
return SPIInterface::protect_flash(len);
}
/*!
* \brief unprotect SPI flash blocks
*/
bool unprotect_flash() override {
return SPIInterface::unprotect_flash();
}
int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx,
uint32_t len) override;
int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) override;
int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
uint32_t timeout, bool verbose = false) override;
protected:
bool prepare_flash_access() override {return load_bridge();}
bool post_flash_access() override {reset(); return true;}
private:
/*!
* \brief with intel devices SPI flash direct access is not possible

View File

@ -28,18 +28,23 @@
Anlogic::Anlogic(Jtag *jtag, const std::string &filename,
const std::string &file_type,
Device::prog_type_t prg_type, bool verify, int8_t verbose):
Device(jtag, filename, file_type, verify, verbose), _svf(_jtag, _verbose)
Device(jtag, filename, file_type, verify, verbose),
SPIInterface(filename, verbose, 0, verify), _svf(_jtag, _verbose)
{
if (!_file_extension.empty()) {
if (_file_extension == "svf")
if (prg_type == Device::RD_FLASH) {
_mode = Device::READ_MODE;
} else if (!_file_extension.empty()) {
if (_file_extension == "svf") {
_mode = Device::MEM_MODE;
else if (_file_extension == "bit") {
if (prg_type == Device::WR_SRAM)
_mode = Device::MEM_MODE;
else
} else if (_file_extension == "bit") {
_mode = (prg_type == Device::WR_SRAM)? Device::MEM_MODE:
Device::SPI_MODE;
} else {
if (prg_type == Device::WR_FLASH)
_mode = Device::SPI_MODE;
} else
throw std::runtime_error("incompatible file format");
else
throw std::runtime_error("incompatible file format");
}
}
}
Anlogic::~Anlogic()
@ -54,7 +59,7 @@ void Anlogic::reset()
_jtag->toggleClk(200000);
}
void Anlogic::program(unsigned int offset)
void Anlogic::program(unsigned int offset, bool unprotect_flash)
{
if (_mode == Device::NONE_MODE)
return;
@ -70,10 +75,10 @@ void Anlogic::program(unsigned int offset)
if (bit.parse() == EXIT_FAILURE) {
printError("FAIL");
return;
} else {
printSuccess("DONE");
}
printSuccess("DONE");
if (_verbose)
bit.displayHeader();
@ -81,47 +86,10 @@ void Anlogic::program(unsigned int offset)
int len = bit.getLength() / 8;
if (_mode == Device::SPI_MODE) {
SPIFlash flash(this, _verbose);
for (int i = 0; i < 5; i++)
_jtag->shiftIR(BYPASS, IRLENGTH);
//Verify Device id.
//SIR 8 TDI (06) ;
//SDR 32 TDI (00000000) TDO (0a014c35) MASK (ffffffff) ;
//Boundary Scan Chain Contents
//Position 1: BG256
//Loading device with 'refresh' instruction.
_jtag->shiftIR(REFRESH, IRLENGTH);
//Loading device with 'bypass' & 'spi_program' instruction.
_jtag->shiftIR(BYPASS, IRLENGTH);
_jtag->shiftIR(SPI_PROGRAM, IRLENGTH);
for (int i = 0; i < 4; i++)
_jtag->toggleClk(50000);
flash.reset();
flash.read_id();
flash.display_status_reg(flash.read_status_reg());
flash.erase_and_prog(offset, data, len);
if (_verify)
printWarn("writing verification not supported");
//Loading device with 'bypass' instruction.
_jtag->shiftIR(BYPASS, IRLENGTH);
////Loading device with 'refresh' instruction.
_jtag->shiftIR(REFRESH, IRLENGTH);
_jtag->toggleClk(20);
////Loading device with 'bypass' instruction.
for (int i = 0; i < 4; i++) {
_jtag->shiftIR(BYPASS, IRLENGTH);
_jtag->toggleClk(20);
}
_jtag->shiftIR(BYPASS, IRLENGTH);
_jtag->toggleClk(10000);
SPIInterface::write(offset, data, len, unprotect_flash);
return;
}
if (_mode == Device::MEM_MODE) {
// Loading device with 'bypass' instruction.
@ -196,6 +164,25 @@ int Anlogic::idCode()
((rx_data[3] << 24) & 0xff000000));
}
bool Anlogic::prepare_flash_access()
{
for (int i = 0; i < 5; i++)
_jtag->shiftIR(BYPASS, IRLENGTH);
//Verify Device id.
//SIR 8 TDI (06) ;
//SDR 32 TDI (00000000) TDO (0a014c35) MASK (ffffffff) ;
//Boundary Scan Chain Contents
//Position 1: BG256
//Loading device with 'refresh' instruction.
_jtag->shiftIR(REFRESH, IRLENGTH);
//Loading device with 'bypass' & 'spi_program' instruction.
_jtag->shiftIR(BYPASS, IRLENGTH);
_jtag->shiftIR(SPI_PROGRAM, IRLENGTH);
for (int i = 0; i < 4; i++)
_jtag->toggleClk(50000);
return true;
}
/* SPI wrapper
* For read operation a delay of one bit is added
* So add one bit more and move everything by one

View File

@ -21,16 +21,51 @@ class Anlogic: public Device, SPIInterface {
Device::prog_type_t prg_type, bool verify, int8_t verbose);
~Anlogic();
void program(unsigned int offset = 0) override;
void program(unsigned int offset, bool unprotect_flash) override;
int idCode() override;
void reset() override;
/* spi interface */
/*!
* \brief protect SPI flash blocks
*/
bool protect_flash(uint32_t len) override {
return SPIInterface::protect_flash(len);
}
/*!
* \brief protect SPI flash blocks
*/
bool unprotect_flash() override {
return SPIInterface::unprotect_flash();
}
/*!
* \brief dump len byte from base_addr from SPI flash
* \param[in] base_addr: start offset
* \param[in] len: dump len
* \return false if something wrong
*/
virtual bool dumpFlash(uint32_t base_addr, uint32_t len) override {
return SPIInterface::dump(base_addr, len);
}
int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx,
uint32_t len) override;
int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) override;
int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
uint32_t timeout, bool verbose=false) override;
protected:
/*!
* \brief move device to SPI access
*/
virtual bool prepare_flash_access() override;
/*!
* \brief end of device to SPI access
*/
virtual bool post_flash_access() override {reset(); return true;}
private:
SVF_jtag _svf;
};

View File

@ -136,9 +136,10 @@ bool CologneChip::dumpFlash(const std::string &filename, uint32_t base_addr,
try {
SPIFlash *flash;
if (_spi) {
flash = new SPIFlash(reinterpret_cast<SPIInterface *>(_spi), _verbose);
flash = new SPIFlash(reinterpret_cast<SPIInterface *>(_spi), false,
_verbose);
} else if (_ftdi_jtag) {
flash = new SPIFlash(this, _verbose);
flash = new SPIFlash(this, false, _verbose);
}
flash->reset();
flash->power_up();
@ -165,7 +166,7 @@ bool CologneChip::dumpFlash(const std::string &filename, uint32_t base_addr,
* Parse bitstream from *.bit or *.cfg and program FPGA in SPI or JTAG mode
* or write configuration to external flash via SPI or JTAG-SPI-bypass.
*/
void CologneChip::program(unsigned int offset)
void CologneChip::program(unsigned int offset, bool unprotect_flash)
{
ConfigBitstreamParser *cfg;
if (_file_extension == "cfg") {
@ -188,9 +189,9 @@ void CologneChip::program(unsigned int offset)
switch (_mode) {
case Device::FLASH_MODE:
if (_jtag != NULL) {
programJTAG_flash(offset, data, length);
programJTAG_flash(offset, data, length, unprotect_flash);
} else if (_jtag == NULL) {
programSPI_flash(offset, data, length);
programSPI_flash(offset, data, length, unprotect_flash);
}
break;
case Device::MEM_MODE:
@ -227,13 +228,15 @@ void CologneChip::programSPI_sram(uint8_t *data, int length)
* done, release reset to start FPGA in active SPI mode (load from flash).
* CFG_MD[3:0] must be set to 0x00 (SPI active).
*/
void CologneChip::programSPI_flash(unsigned int offset, uint8_t *data, int length)
void CologneChip::programSPI_flash(unsigned int offset, uint8_t *data,
int length, bool unprotect_flash)
{
/* hold device in reset during flash write access */
_spi->gpio_clear(_rstn_pin | _oen_pin);
usleep(SLEEP_US);
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), _verbose);
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), unprotect_flash,
_verbose);
flash.reset();
flash.power_up();
@ -294,12 +297,13 @@ void CologneChip::programJTAG_sram(uint8_t *data, int length)
* Write configuration to flash via JTAG-SPI-bypass. The FPGA will not start
* as it is in JTAG mode with CFG_MD[3:0] set to 0xF0 (JTAG).
*/
void CologneChip::programJTAG_flash(unsigned int offset, uint8_t *data, int length)
void CologneChip::programJTAG_flash(unsigned int offset, uint8_t *data,
int length, bool unprotect_flash)
{
/* hold device in reset for a moment */
reset();
SPIFlash flash(this, _verbose);
SPIFlash flash(this, unprotect_flash, _verbose);
flash.reset();
flash.power_up();

View File

@ -35,16 +35,23 @@ class CologneChip: public Device, SPIInterface {
bool cfgDone();
void waitCfgDone();
bool dumpFlash(const std::string &filename, uint32_t base_addr, uint32_t len);
void program(unsigned int offset = 0) override;
virtual bool protect_flash(uint32_t len) override {
(void) len;
printError("protect flash not supported"); return false;}
virtual bool unprotect_flash() override {
printError("unprotect flash not supported"); return false;}
void program(unsigned int offset, bool unprotect_flash) override;
int idCode() override {return 0;}
void reset() override;
private:
void programSPI_sram(uint8_t *data, int length);
void programSPI_flash(unsigned int offset, uint8_t *data, int length);
void programSPI_flash(unsigned int offset, uint8_t *data, int length,
bool unprotect_flash);
void programJTAG_sram(uint8_t *data, int length);
void programJTAG_flash(unsigned int offset, uint8_t *data, int length);
void programJTAG_flash(unsigned int offset, uint8_t *data, int length,
bool unprotect_flash);
/* spi interface via jtag */
int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx,

View File

@ -101,7 +101,7 @@ void Efinix::reset()
printSuccess("DONE");
}
void Efinix::program(unsigned int offset)
void Efinix::program(unsigned int offset, bool unprotect_flash)
{
if (_file_extension.empty())
return;
@ -140,7 +140,7 @@ void Efinix::program(unsigned int offset)
if (_ftdi_jtag)
programJTAG(data, length);
else
programSPI(offset, data, length);
programSPI(offset, data, length, unprotect_flash);
}
bool Efinix::dumpFlash(const std::string &filename,
@ -152,7 +152,7 @@ bool Efinix::dumpFlash(const std::string &filename,
/* prepare SPI access */
printInfo("Read Flash ", false);
try {
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), _verbose);
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), false, _verbose);
flash.reset();
flash.power_up();
flash.dump(filename, base_addr, len);
@ -179,13 +179,15 @@ bool Efinix::dumpFlash(const std::string &filename,
return false;
}
void Efinix::programSPI(unsigned int offset, uint8_t *data, int length)
void Efinix::programSPI(unsigned int offset, uint8_t *data, int length,
bool unprotect_flash)
{
uint32_t timeout = 1000;
_spi->gpio_clear(_rst_pin | _oe_pin);
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), _verbose);
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), unprotect_flash,
_verbose);
flash.reset();
flash.power_up();

View File

@ -25,15 +25,21 @@ class Efinix: public Device {
bool verify, int8_t verbose);
~Efinix();
void program(unsigned int offset = 0) override;
void program(unsigned int offset, bool unprotect_flash) override;
bool dumpFlash(const std::string &filename,
uint32_t base_addr, uint32_t len);
virtual bool protect_flash(uint32_t len) override {
(void) len;
printError("protect flash not supported"); return false;}
virtual bool unprotect_flash() override {
printError("unprotect flash not supported"); return false;}
/* not supported in SPI Active mode */
int idCode() override {return 0;}
void reset() override;
private:
void programSPI(unsigned int offset, uint8_t *data, int length);
void programSPI(unsigned int offset, uint8_t *data, int length,
bool unprotect_flash);
void programJTAG(uint8_t *data, int length);
FtdiSpi *_spi;
FtdiJtagMPSSE *_ftdi_jtag;

View File

@ -62,8 +62,15 @@ void EPCQ::read_id()
printf("silicon id 0x%x attendu 0x14\n", _silicon_id);
}
EPCQ::EPCQ(SPIInterface *spi, int8_t verbose):SPIFlash(spi, verbose),
_device_id(0), _silicon_id(0)
void EPCQ::reset()
{
printf("reset\n");
_spi->spi_put(0x66, NULL, NULL, 0);
_spi->spi_put(0x99, NULL, NULL, 0);
}
EPCQ::EPCQ(SPIInterface *spi, bool unprotect_flash, int8_t verbose):
SPIFlash(spi, unprotect_flash, verbose), _device_id(0), _silicon_id(0)
{}
EPCQ::~EPCQ()

View File

@ -15,11 +15,13 @@ using namespace std;
class EPCQ: public SPIFlash {
public:
EPCQ(SPIInterface *spi, int8_t verbose);
EPCQ(SPIInterface *spi, bool unprotect_flash, int8_t verbose);
~EPCQ();
void read_id() override;
void reset() override;
/* not supported */
void power_up() override {}
void power_down() override {}

View File

@ -206,7 +206,7 @@ void Gowin::programFlash()
displayReadReg(readStatusReg());
}
void Gowin::program(unsigned int offset)
void Gowin::program(unsigned int offset, bool unprotect_flash)
{
(void) offset;
@ -235,7 +235,8 @@ void Gowin::program(unsigned int offset)
wr_rd(0x3D, NULL, 0, NULL, 0);
SPIFlash spiFlash(this, (_verbose ? 1 : (_quiet ? -1 : 0)));
SPIFlash spiFlash(this, unprotect_flash,
(_verbose ? 1 : (_quiet ? -1 : 0)));
spiFlash.reset();
spiFlash.read_id();
spiFlash.display_status_reg(spiFlash.read_status_reg());

View File

@ -24,10 +24,15 @@ class Gowin: public Device, SPIInterface {
~Gowin();
int idCode() override;
void reset() override;
void program(unsigned int offset) override;
void program(unsigned int offset, bool unprotect_flash) override;
void programFlash();
/* spi interface */
virtual bool protect_flash(uint32_t len) override {
(void) len;
printError("protect flash not supported"); return false;}
virtual bool unprotect_flash() override {
printError("unprotect flash not supported"); return false;}
int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx,
uint32_t len) override;
int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) override;

View File

@ -40,17 +40,18 @@ void Ice40::reset()
usleep(1000);
_spi->gpio_set(_rst_pin);
printInfo("Reset ", false);
usleep(12000);
do {
timeout--;
usleep(12000);
} while (((_spi->gpio_get(true) & _done_pin) == 0) || timeout > 0);
} while (((_spi->gpio_get(true) & _done_pin) == 0) && timeout > 0);
if (timeout == 0)
printError("FAIL");
else
printSuccess("DONE");
}
void Ice40::program(unsigned int offset)
void Ice40::program(unsigned int offset, bool unprotect_flash)
{
uint32_t timeout = 1000;
@ -72,7 +73,8 @@ void Ice40::program(unsigned int offset)
_spi->gpio_clear(_rst_pin);
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), _quiet);
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), unprotect_flash,
_quiet);
flash.reset();
flash.power_up();
@ -97,8 +99,7 @@ void Ice40::program(unsigned int offset)
printSuccess("DONE");
}
bool Ice40::dumpFlash(const std::string &filename,
uint32_t base_addr, uint32_t len)
bool Ice40::dumpFlash(uint32_t base_addr, uint32_t len)
{
uint32_t timeout = 1000;
_spi->gpio_clear(_rst_pin);
@ -106,10 +107,10 @@ bool Ice40::dumpFlash(const std::string &filename,
/* prepare SPI access */
printInfo("Read Flash ", false);
try {
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), _verbose);
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), false, _verbose);
flash.reset();
flash.power_up();
flash.dump(filename, base_addr, len);
flash.dump(_filename, base_addr, len);
} catch (std::exception &e) {
printError("Fail");
printError(std::string(e.what()));
@ -133,3 +134,57 @@ bool Ice40::dumpFlash(const std::string &filename,
return false;
}
bool Ice40::protect_flash(uint32_t len)
{
/* SPI access */
prepare_flash_access();
/* acess */
try {
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), false, _verbose);
/* configure flash protection */
if (flash.enable_protection(len) == -1)
return false;
} catch (std::exception &e) {
printError("Fail");
printError(std::string(e.what()));
return false;
}
/* reload */
return post_flash_access();
}
bool Ice40::unprotect_flash()
{
/* SPI access */
prepare_flash_access();
/* acess */
try {
SPIFlash flash(reinterpret_cast<SPIInterface *>(_spi), false, _verbose);
/* configure flash protection */
if (flash.disable_protection() == -1)
return false;
} catch (std::exception &e) {
printError("Fail");
printError(std::string(e.what()));
return false;
}
/* reload */
return post_flash_access();
}
bool Ice40::prepare_flash_access()
{
/* SPI access: shutdown ICE40 */
_spi->gpio_clear(_rst_pin);
usleep(1000);
return true;
}
bool Ice40::post_flash_access()
{
reset();
return ((_spi->gpio_get(true) & _done_pin) == 0) ? false : true;
}

View File

@ -10,8 +10,9 @@
#include "device.hpp"
#include "ftdispi.hpp"
#include "spiInterface.hpp"
class Ice40: public Device {
class Ice40: public Device, SPIInterface {
public:
Ice40(FtdiSpi *spi, const std::string &filename,
const std::string &file_type,
@ -19,13 +20,39 @@ class Ice40: public Device {
bool verify, int8_t verbose);
~Ice40();
void program(unsigned int offset = 0) override;
bool dumpFlash(const std::string &filename,
uint32_t base_addr, uint32_t len);
void program(unsigned int offset, bool unprotect_flash) override;
bool dumpFlash(uint32_t base_addr, uint32_t len);
bool protect_flash(uint32_t len) override;
bool unprotect_flash() override;
/* not supported in SPI Active mode */
int idCode() override {return 0;}
void reset() override;
int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx,
uint32_t len) {
(void)cmd; (void)tx; (void)rx; (void)len;
return 0;
}
int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) {
(void)tx; (void)rx; (void)len;
return 0;
}
int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
uint32_t timeout, bool verbose = false) {
(void)cmd; (void)mask; (void)cond; (void)timeout; (void) verbose;
return 0;
}
protected:
/*!
* \brief prepare SPI flash access
*/
bool prepare_flash_access() override;
/*!
* \brief end of SPI flash access
*/
bool post_flash_access() override;
private:
FtdiSpi *_spi;
uint16_t _rst_pin;

View File

@ -139,6 +139,7 @@ using namespace std;
Lattice::Lattice(Jtag *jtag, const string filename, const string &file_type,
Device::prog_type_t prg_type, std::string flash_sector, bool verify, int8_t verbose):
Device(jtag, filename, file_type, verify, verbose),
SPIInterface(filename, verbose, 0, verify),
_fpga_family(UNKNOWN_FAMILY), _flash_sector(LATTICE_FLASH_UNDEFINED)
{
if (prg_type == Device::RD_FLASH) {
@ -512,46 +513,11 @@ bool Lattice::program_intFlash(JedParser& _jed)
return true;
}
bool Lattice::program_extFlash(unsigned int offset)
bool Lattice::prepare_flash_access()
{
ConfigBitstreamParser *_bit;
if (_file_extension == "mcs")
_bit = new McsParser(_filename, true, _verbose);
else if (_file_extension == "bit")
_bit = new LatticeBitParser(_filename, _verbose);
else
_bit = new RawParser(_filename, false);
printInfo("Open file ", false);
printSuccess("DONE");
int err = _bit->parse();
printInfo("Parse file ", false);
if (err == EXIT_FAILURE) {
printError("FAIL");
delete _bit;
/* clear SRAM before SPI access */
if (!clearSRAM())
return false;
} else {
printSuccess("DONE");
}
if (_verbose)
_bit->displayHeader();
if (_file_extension == "bit") {
uint32_t bit_idcode = std::stoul(_bit->getHeaderVal("idcode").c_str(), NULL, 16);
uint32_t idcode = idCode();
if (idcode != bit_idcode) {
char mess[256];
sprintf(mess, "mismatch between target's idcode and bitstream idcode\n"
"\tbitstream has 0x%08X hardware requires 0x%08x", bit_idcode, idcode);
printError(mess);
delete _bit;
return false;
}
}
/*IR = 0h3A, DR=0hFE,0h68. Enter RUNTESTIDLE.
* thank @GregDavill
* https://twitter.com/GregDavill/status/1251786406441086977
@ -559,35 +525,31 @@ bool Lattice::program_extFlash(unsigned int offset)
_jtag->shiftIR(0x3A, 8, Jtag::EXIT1_IR);
uint8_t tmp[2] = {0xFE, 0x68};
_jtag->shiftDR(tmp, NULL, 16);
uint8_t *data = _bit->getData();
int length = _bit->getLength()/8;
/* test SPI */
SPIFlash flash(this, _verbose);
flash.reset();
flash.read_id();
flash.read_status_reg();
flash.erase_and_prog(offset, data, length);
int ret = true;
if (_verify)
ret = flash.verify(offset, data, length);
delete _bit;
return ret;
return true;
}
bool Lattice::program_flash(unsigned int offset)
bool Lattice::post_flash_access()
{
/* ISC REFRESH 0x79 */
printInfo("Refresh: ", false);
if (loadConfiguration() == false) {
printError("FAIL");
displayReadReg(readStatusReg());
return false;
} else {
printSuccess("DONE");
}
/* bypass */
wr_rd(0xff, NULL, 0, NULL, 0);
_jtag->go_test_logic_reset();
return true;
}
bool Lattice::clearSRAM()
{
uint32_t erase_op;
/* read ID Code 0xE0 */
if (_verbose) {
printf("IDCode : %x\n", idCode());
displayReadReg(readStatusReg());
}
/* preload 0x1C */
uint8_t tx_buf[26];
memset(tx_buf, 0xff, 26);
@ -620,7 +582,69 @@ bool Lattice::program_flash(unsigned int offset)
printSuccess("DONE");
}
DisableISC();
return DisableISC();
}
bool Lattice::program_extFlash(unsigned int offset, bool unprotect_flash)
{
int ret;
ConfigBitstreamParser *_bit;
printInfo("Open file ", false);
try {
if (_file_extension == "mcs")
_bit = new McsParser(_filename, true, _verbose);
else if (_file_extension == "bit")
_bit = new LatticeBitParser(_filename, _verbose);
else
_bit = new RawParser(_filename, false);
printSuccess("DONE");
} catch (std::exception &e) {
printError("FAIL");
printError(e.what());
return false;
}
printInfo("Parse file ", false);
if (_bit->parse() == EXIT_FAILURE) {
printError("FAIL");
delete _bit;
return false;
} else {
printSuccess("DONE");
}
if (_verbose)
_bit->displayHeader();
if (_file_extension == "bit") {
uint32_t bit_idcode = std::stoul(_bit->getHeaderVal("idcode").c_str(), NULL, 16);
uint32_t idcode = idCode();
if (idcode != bit_idcode) {
char mess[256];
sprintf(mess, "mismatch between target's idcode and bitstream idcode\n"
"\tbitstream has 0x%08X hardware requires 0x%08x", bit_idcode, idcode);
printError(mess);
delete _bit;
return false;
}
}
ret = SPIInterface::write(offset, _bit->getData(), _bit->getLength() / 8,
unprotect_flash);
delete _bit;
return ret;
}
bool Lattice::program_flash(unsigned int offset, bool unprotect_flash)
{
/* read ID Code 0xE0 */
if (_verbose) {
printf("IDCode : %x\n", idCode());
displayReadReg(readStatusReg());
}
bool retval;
if (_file_extension == "jed") {
@ -641,113 +665,41 @@ bool Lattice::program_flash(unsigned int offset)
if (_verbose)
_jed.displayHeader();
/* clear current SRAM content */
clearSRAM();
if (_fpga_family == MACHXO3D_FAMILY)
retval = program_intFlash_MachXO3D(_jed);
else
retval = program_intFlash(_jed);
return post_flash_access() && retval;
} else if (_file_extension == "fea") {
/* clear current SRAM content */
clearSRAM();
retval = program_fea_MachXO3D();
return post_flash_access() && retval;
} else if (_file_extension == "pub") {
/* clear current SRAM content */
clearSRAM();
retval = program_pubkey_MachXO3D();
} else {
retval = program_extFlash(offset);
return program_extFlash(offset, unprotect_flash);
}
if (!retval)
return false;
/* *************************** */
/* reload bitstream from flash */
/* *************************** */
/* ISC REFRESH 0x79 */
printInfo("Refresh: ", false);
if (loadConfiguration() == false) {
printError("FAIL");
displayReadReg(readStatusReg());
return false;
} else {
printSuccess("DONE");
}
/* bypass */
wr_rd(0xff, NULL, 0, NULL, 0);
_jtag->go_test_logic_reset();
return true;
}
void Lattice::program(unsigned int offset)
void Lattice::program(unsigned int offset, bool unprotect_flash)
{
bool retval = true;
if (_mode == FLASH_MODE)
retval = program_flash(offset);
retval = program_flash(offset, unprotect_flash);
else if (_mode == MEM_MODE)
retval = program_mem();
if (!retval)
throw std::exception();
}
bool Lattice::dumpFlash(const string &filename,
uint32_t base_addr, uint32_t len)
{
/* idem program */
/* preload 0x1C */
uint8_t tx_buf[26];
memset(tx_buf, 0xff, 26);
wr_rd(0x1C, tx_buf, 26, NULL, 0);
wr_rd(0xFf, NULL, 0, NULL, 0);
/* ISC Enable 0xC6 */
printInfo("Enable configuration: ", false);
if (!EnableISC(0x00)) {
printError("FAIL");
displayReadReg(readStatusReg());
return false;
} else {
printSuccess("DONE");
}
/* ISC ERASE */
printInfo("SRAM erase: ", false);
if (flashErase(FLASH_ERASE_SRAM) == false) {
printError("FAIL");
displayReadReg(readStatusReg());
return false;
} else {
printSuccess("DONE");
}
DisableISC();
/* switch to SPI mode */
_jtag->shiftIR(0x3A, 8, Jtag::EXIT1_IR);
uint8_t tmp[2] = {0xFE, 0x68};
_jtag->shiftDR(tmp, NULL, 16);
/* prepare SPI access */
SPIFlash flash(this, _verbose);
flash.reset();
flash.dump(filename, base_addr, len);
/* ISC REFRESH 0x79 */
printInfo("Refresh: ", false);
if (loadConfiguration() == false) {
printError("FAIL");
displayReadReg(readStatusReg());
return false;
} else {
printSuccess("DONE");
}
/* bypass */
wr_rd(0xff, NULL, 0, NULL, 0);
_jtag->go_test_logic_reset();
return true;
}
/* flash mode :
*/
bool Lattice::EnableISC(uint8_t flash_mode)

View File

@ -26,13 +26,27 @@ class Lattice: public Device, SPIInterface {
int idCode() override;
int userCode();
void reset() override {}
void program(unsigned int offset) override;
void program(unsigned int offset, bool unprotect_flash) override;
bool program_mem();
bool program_flash(unsigned int offset);
bool program_flash(unsigned int offset, bool unprotect_flash);
bool Verify(std::vector<std::string> data, bool unlock = false,
uint32_t flash_area = 0);
bool dumpFlash(const std::string &filename,
uint32_t base_addr, uint32_t len) override;
bool dumpFlash(uint32_t base_addr, uint32_t len) override {
return SPIInterface::dump(base_addr, len);
}
/*!
* \brief protect SPI flash blocks
*/
bool protect_flash(uint32_t len) override {
return SPIInterface::protect_flash(len);
}
/*!
* \brief protect SPI flash blocks
*/
bool unprotect_flash() override {
return SPIInterface::unprotect_flash();
}
/* spi interface */
int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx,
@ -54,9 +68,22 @@ class Lattice: public Device, SPIInterface {
lattice_family_t _fpga_family;
bool program_intFlash(JedParser& _jed);
bool program_extFlash(unsigned int offset);
bool program_extFlash(unsigned int offset, bool unprotect_flash);
bool wr_rd(uint8_t cmd, uint8_t *tx, int tx_len,
uint8_t *rx, int rx_len, bool verbose = false);
/*!
* \brief move device to SPI access
*/
bool prepare_flash_access() override;
/*!
* \brief end of device to SPI access
* reload btistream from flash
*/
bool post_flash_access() override;
/*!
* \brief erase SRAM
*/
bool clearSRAM();
void unlock();
bool EnableISC(uint8_t flash_mode);
bool DisableISC();

View File

@ -30,6 +30,7 @@ Xilinx::Xilinx(Jtag *jtag, const std::string &filename,
Device::prog_type_t prg_type,
const std::string &device_package, bool verify, int8_t verbose):
Device(jtag, filename, file_type, verify, verbose),
SPIInterface(filename, verbose, 256, verify),
_device_package(device_package)
{
if (prg_type == Device::RD_FLASH) {
@ -160,7 +161,7 @@ int Xilinx::idCode()
return id;
}
void Xilinx::program(unsigned int offset)
void Xilinx::program(unsigned int offset, bool unprotect_flash)
{
ConfigBitstreamParser *bit;
bool reverse = false;
@ -226,15 +227,14 @@ void Xilinx::program(unsigned int offset)
if (_fpga_family == XCF_FAMILY) {
xcf_program(bit);
delete bit;
return;
}
if (_mode == Device::SPI_MODE) {
program_spi(bit, offset);
reset();
} else {
if (_mode == Device::SPI_MODE)
program_spi(bit, offset, unprotect_flash);
else
program_mem(bit);
}
delete bit;
}
@ -264,29 +264,16 @@ bool Xilinx::load_bridge()
return true;
}
void Xilinx::program_spi(ConfigBitstreamParser * bit, unsigned int offset)
void Xilinx::program_spi(ConfigBitstreamParser * bit, unsigned int offset,
bool unprotect_flash)
{
/* first need to have bridge in RAM */
if (load_bridge() == false)
return;
uint8_t *data = bit->getData();
int length = bit->getLength() / 8;
SPIFlash spiFlash(this, (_verbose ? 1 : (_quiet ? -1 : 0)));
spiFlash.reset();
spiFlash.read_id();
spiFlash.display_status_reg(spiFlash.read_status_reg());
spiFlash.erase_and_prog(offset, data, length);
/* verify write if required */
if (_verify)
spiFlash.verify(offset, data, length, 256);
SPIInterface::write(offset, data, length, unprotect_flash);
}
void Xilinx::program_mem(ConfigBitstreamParser *bitfile)
{
if (_file_extension.empty()) return;
std::cout << "load program" << std::endl;
unsigned char tx_buf, rx_buf;
/* comment TDI TMS TCK
@ -393,8 +380,7 @@ void Xilinx::program_mem(ConfigBitstreamParser *bitfile)
_jtag->go_test_logic_reset();
}
bool Xilinx::dumpFlash(const std::string &filename,
uint32_t base_addr, uint32_t len)
bool Xilinx::dumpFlash(uint32_t base_addr, uint32_t len)
{
if (_fpga_family == XC95_FAMILY || _fpga_family == XCF_FAMILY) {
std::string buffer;
@ -412,7 +398,7 @@ bool Xilinx::dumpFlash(const std::string &filename,
xcf_flow_disable();
}
printInfo("Open dump file ", false);
FILE *fd = fopen(filename.c_str(), "wb");
FILE *fd = fopen(_filename.c_str(), "wb");
if (!fd) {
printError("FAIL");
return false;
@ -429,26 +415,8 @@ bool Xilinx::dumpFlash(const std::string &filename,
return true;
}
int ret = true;
/* first need to have bridge in RAM */
if (load_bridge() == false)
return false;
/* prepare SPI access */
SPIFlash flash(this, _verbose);
try {
flash.reset();
ret = flash.dump(filename, base_addr, len, 256);
} catch (std::exception &e) {
printError(e.what());
ret = false;
}
/* reset device */
reset();
return ret;
/* dump SPI Flash */
return SPIInterface::dump(base_addr, len);
}
/* */

View File

@ -22,11 +22,25 @@ class Xilinx: public Device, SPIInterface {
bool verify, int8_t verbose);
~Xilinx();
void program(unsigned int offset = 0) override;
void program_spi(ConfigBitstreamParser * bit, unsigned int offset = 0);
void program(unsigned int offset, bool unprotect_flash) override;
void program_spi(ConfigBitstreamParser * bit, unsigned int offset,
bool unprotect_flash);
void program_mem(ConfigBitstreamParser *bitfile);
bool dumpFlash(const std::string &filename,
uint32_t base_addr, uint32_t len) override;
bool dumpFlash(uint32_t base_addr, uint32_t len) override;
/*!
* \brief protect SPI flash blocks
*/
bool protect_flash(uint32_t len) override {
return SPIInterface::protect_flash(len);
}
/*!
* \brief unprotect SPI flash blocks
*/
bool unprotect_flash() override {
return SPIInterface::unprotect_flash();
}
int idCode() override;
void reset() override;
@ -105,6 +119,16 @@ class Xilinx: public Device, SPIInterface {
int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
uint32_t timeout, bool verbose = false) override;
protected:
/*!
* \brief prepare SPI flash access (need to have bridge in RAM)
*/
virtual bool prepare_flash_access() override {return load_bridge();}
/*!
* \brief end of SPI flash access
*/
virtual bool post_flash_access() override {reset(); return true;}
private:
/* list of xilinx family devices */
enum xilinx_family_t {