From fe0a3154560f750c409c3ebca4d6eae8cab9843b Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 24 Jun 2021 18:19:09 +0200 Subject: [PATCH] lattice,device: introduce method to dump flash content --- README.md | 3 ++ src/device.hpp | 9 ++++-- src/lattice.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++++++++- src/lattice.hpp | 2 ++ src/main.cpp | 22 ++++++++++++-- 5 files changed, 107 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2c6c854..8193d0b 100644 --- a/README.md +++ b/README.md @@ -191,6 +191,9 @@ openFPGALoader -- a program to flash FPGA -d, --device arg device to use (/dev/ttyUSBx) --detect detect FPGA --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 using extension --fpga-part arg fpga model flavor + package diff --git a/src/device.hpp b/src/device.hpp index bc2ba88..e03bfa9 100644 --- a/src/device.hpp +++ b/src/device.hpp @@ -17,18 +17,23 @@ class Device { NONE_MODE = 0, SPI_MODE = 1, FLASH_MODE = 1, - MEM_MODE = 2 + MEM_MODE = 2, + READ_MODE = 3, }; typedef enum { WR_SRAM = 0, - WR_FLASH = 1 + WR_FLASH = 1, + RD_FLASH = 2 } prog_type_t; Device(Jtag *jtag, std::string filename, const std::string &file_type, bool verify, int8_t verbose = false); virtual ~Device(); 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 void reset(); diff --git a/src/lattice.cpp b/src/lattice.cpp index ff3918c..6234e1d 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -73,7 +73,9 @@ Lattice::Lattice(Jtag *jtag, const string filename, const string &file_type, Device(jtag, filename, file_type, verify, verbose), _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") { _mode = Device::FLASH_MODE; } else if (_file_extension == "bit" || _file_extension == "bin") { @@ -556,6 +558,79 @@ void Lattice::program(unsigned int offset) 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 : */ bool Lattice::EnableISC(uint8_t flash_mode) diff --git a/src/lattice.hpp b/src/lattice.hpp index 8dfcdb2..edcc782 100644 --- a/src/lattice.hpp +++ b/src/lattice.hpp @@ -41,6 +41,8 @@ class Lattice: public Device, SPIInterface { bool program_mem(); bool program_flash(unsigned int offset); bool Verify(std::vector data, bool unlock = false); + bool dumpFlash(const std::string &filename, + uint32_t base_addr, uint32_t len) override; /* spi interface */ int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, diff --git a/src/main.cpp b/src/main.cpp index 5d055b1..f71ea9b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -67,6 +67,7 @@ struct arguments { string fpga_part; string probe_firmware; int index_chain; + unsigned int file_size; }; 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. */ struct arguments args = {0, false, false, false, 0, "", "", "-", "", -1, 6000000, "-", false, false, false, false, Device::WR_SRAM, false, - false, false, "", "", "", -1}; + false, false, "", "", "", -1, 0}; /* parse arguments */ try { if (parse_opt(argc, argv, &args, &pins_config)) @@ -379,7 +380,8 @@ int main(int argc, char **argv) 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 { fpga->program(args.offset); } 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) fpga->reset(); @@ -455,6 +465,9 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p ("detect", "detect FPGA", cxxopts::value(args->detect)) ("dfu", "DFU mode", cxxopts::value(args->dfu)) + ("dump-flash", "Dump flash mode") + ("file-size", "provides size in Byte to dump, must be used with dump-flash", + cxxopts::value(args->file_size)) ("file-type", "provides file type instead of let's deduced by using extension", cxxopts::value(args->file_type)) ("fpga-part", "fpga model flavor + package", cxxopts::value(args->fpga_part)) @@ -511,7 +524,8 @@ int parse_opt(int argc, char **argv, struct arguments *args, jtag_pins_conf_t *p 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"); 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; else if (result.count("write-sram")) args->prg_type = Device::WR_SRAM; + else if (result.count("dump-flash")) + args->prg_type = Device::RD_FLASH; if (result.count("freq")) { double freq;