lattice,device: introduce method to dump flash content

This commit is contained in:
Gwenhael Goavec-Merou 2021-06-24 18:19:09 +02:00
parent c471d25bb5
commit fe0a315456
5 changed files with 107 additions and 6 deletions

View File

@ -191,6 +191,9 @@ openFPGALoader -- a program to flash FPGA
-d, --device arg device to use (/dev/ttyUSBx) -d, --device arg device to use (/dev/ttyUSBx)
--detect detect FPGA --detect detect FPGA
--dfu DFU mode --dfu DFU mode
--dump-flash Dump flash mode
--file-size arg provides size in Byte to dump, must be used with
dump-flash
--file-type arg provides file type instead of let's deduced by --file-type arg provides file type instead of let's deduced by
using extension using extension
--fpga-part arg fpga model flavor + package --fpga-part arg fpga model flavor + package

View File

@ -17,18 +17,23 @@ class Device {
NONE_MODE = 0, NONE_MODE = 0,
SPI_MODE = 1, SPI_MODE = 1,
FLASH_MODE = 1, FLASH_MODE = 1,
MEM_MODE = 2 MEM_MODE = 2,
READ_MODE = 3,
}; };
typedef enum { typedef enum {
WR_SRAM = 0, WR_SRAM = 0,
WR_FLASH = 1 WR_FLASH = 1,
RD_FLASH = 2
} prog_type_t; } prog_type_t;
Device(Jtag *jtag, std::string filename, const std::string &file_type, Device(Jtag *jtag, std::string filename, const std::string &file_type,
bool verify, int8_t verbose = false); bool verify, int8_t verbose = false);
virtual ~Device(); virtual ~Device();
virtual void program(unsigned int offset = 0) = 0; virtual void program(unsigned int offset = 0) = 0;
virtual bool dumpFlash(const std::string &filename,
uint32_t base_addr, uint32_t len) {
(void)filename; (void) base_addr; (void) len; return false;}
virtual int idCode() = 0; virtual int idCode() = 0;
virtual void reset(); virtual void reset();

View File

@ -73,7 +73,9 @@ Lattice::Lattice(Jtag *jtag, const string filename, const string &file_type,
Device(jtag, filename, file_type, verify, verbose), Device(jtag, filename, file_type, verify, verbose),
_fpga_family(UNKNOWN_FAMILY) _fpga_family(UNKNOWN_FAMILY)
{ {
if (!_file_extension.empty()) { if (prg_type == Device::RD_FLASH) {
_mode = READ_MODE;
} else if (!_file_extension.empty()) {
if (_file_extension == "jed" || _file_extension == "mcs") { if (_file_extension == "jed" || _file_extension == "mcs") {
_mode = Device::FLASH_MODE; _mode = Device::FLASH_MODE;
} else if (_file_extension == "bit" || _file_extension == "bin") { } else if (_file_extension == "bit" || _file_extension == "bin") {
@ -556,6 +558,79 @@ void Lattice::program(unsigned int offset)
program_mem(); program_mem();
} }
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();
string data;
data.resize(len);
/* 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.read_id();
flash.read_status_reg();
flash.read(base_addr, (uint8_t*)&data[0], len);
FILE *fd = fopen(filename.c_str(), "wb");
if (!fd) {
return false;
}
fwrite(data.c_str(), sizeof(uint8_t), len, fd);
fclose(fd);
/* 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 : /* flash mode :
*/ */
bool Lattice::EnableISC(uint8_t flash_mode) bool Lattice::EnableISC(uint8_t flash_mode)

View File

@ -41,6 +41,8 @@ class Lattice: public Device, SPIInterface {
bool program_mem(); bool program_mem();
bool program_flash(unsigned int offset); bool program_flash(unsigned int offset);
bool Verify(std::vector<std::string> data, bool unlock = false); bool Verify(std::vector<std::string> data, bool unlock = false);
bool dumpFlash(const std::string &filename,
uint32_t base_addr, uint32_t len) override;
/* spi interface */ /* spi interface */
int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx,

View File

@ -67,6 +67,7 @@ struct arguments {
string fpga_part; string fpga_part;
string probe_firmware; string probe_firmware;
int index_chain; int index_chain;
unsigned int file_size;
}; };
int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *pins_config); int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *pins_config);
@ -82,7 +83,7 @@ int main(int argc, char **argv)
/* command line args. */ /* command line args. */
struct arguments args = {0, false, false, false, 0, "", "", "-", "", -1, struct arguments args = {0, false, false, false, 0, "", "", "-", "", -1,
6000000, "-", false, false, false, false, Device::WR_SRAM, false, 6000000, "-", false, false, false, false, Device::WR_SRAM, false,
false, false, "", "", "", -1}; false, false, "", "", "", -1, 0};
/* parse arguments */ /* parse arguments */
try { try {
if (parse_opt(argc, argv, &args, &pins_config)) if (parse_opt(argc, argv, &args, &pins_config))
@ -379,7 +380,8 @@ int main(int argc, char **argv)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (!args.bit_file.empty() || !args.file_type.empty()) { if ((!args.bit_file.empty() || !args.file_type.empty())
&& args.prg_type != Device::RD_FLASH) {
try { try {
fpga->program(args.offset); fpga->program(args.offset);
} catch (std::exception &e) { } catch (std::exception &e) {
@ -389,6 +391,14 @@ int main(int argc, char **argv)
} }
} }
if (args.prg_type == Device::RD_FLASH) {
if (args.file_size == 0) {
printError("Error: 0 size for dump");
} else {
fpga->dumpFlash(args.bit_file, args.offset, args.file_size);
}
}
if (args.reset) if (args.reset)
fpga->reset(); fpga->reset();
@ -455,6 +465,9 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p
("detect", "detect FPGA", ("detect", "detect FPGA",
cxxopts::value<bool>(args->detect)) cxxopts::value<bool>(args->detect))
("dfu", "DFU mode", cxxopts::value<bool>(args->dfu)) ("dfu", "DFU mode", cxxopts::value<bool>(args->dfu))
("dump-flash", "Dump flash mode")
("file-size", "provides size in Byte to dump, must be used with dump-flash",
cxxopts::value<unsigned int>(args->file_size))
("file-type", "provides file type instead of let's deduced by using extension", ("file-type", "provides file type instead of let's deduced by using extension",
cxxopts::value<string>(args->file_type)) cxxopts::value<string>(args->file_type))
("fpga-part", "fpga model flavor + package", cxxopts::value<string>(args->fpga_part)) ("fpga-part", "fpga model flavor + package", cxxopts::value<string>(args->fpga_part))
@ -511,7 +524,8 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p
return 1; return 1;
} }
if (result.count("write-flash") && result.count("write-sram")) { if (result.count("write-flash") && result.count("write-sram") &&
result.count("dump-flash")) {
printError("Error: both write to flash and write to ram enabled"); printError("Error: both write to flash and write to ram enabled");
throw std::exception(); throw std::exception();
} }
@ -520,6 +534,8 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p
args->prg_type = Device::WR_FLASH; args->prg_type = Device::WR_FLASH;
else if (result.count("write-sram")) else if (result.count("write-sram"))
args->prg_type = Device::WR_SRAM; args->prg_type = Device::WR_SRAM;
else if (result.count("dump-flash"))
args->prg_type = Device::RD_FLASH;
if (result.count("freq")) { if (result.count("freq")) {
double freq; double freq;