xilinx/doc: add spartan3 and XCF flash

This commit is contained in:
Gwenhael Goavec-Merou 2021-08-30 15:08:11 +02:00
parent 92a4b9bcd8
commit 2606bf7017
6 changed files with 279 additions and 12 deletions

View File

@ -50,6 +50,7 @@ openFPGALoader -b arty -f bitstream.bit # Writing in flash (non-volatile)
| **tec0117** | [Trenz Gowin LittleBee (TEC0117)](https://shop.trenz-electronic.de/en/TEC0117-01-FPGA-Module-with-GOWIN-LittleBee-and-8-MByte-internal-SDRAM) | littleBee</br>GW1NR-9 | OK | IF |
| **xtrx** | [FairWaves XTRXPro](https://www.crowdsupply.com/fairwaves/xtrx) | Artix</br>xc7a50tcpg236 | OK | OK |
| **xyloni_spi** | [Efinix Xyloni](https://www.efinixinc.com/products-devkits-xyloni.html) | Trion</br>T8F81 | NA | AS |
| **xmf3** | [PLDkit XMF3](https://pldkit.com/xilinx/xmf3) | Xilinx</br>xc3s200ft256, xcf01s | OK | OK |
| **zedboard** | [Avnet ZedBoard](https://www.avnet.com/wps/portal/us/products/avnet-boards/avnet-board-families/zedboard/) | zynq7000</br>xc7z020clg484 | OK | NA |
- *IF* Internal Flash

View File

@ -17,9 +17,11 @@
| | [MachXO3LF](http://www.latticesemi.com/en/Products/FPGAandCPLD/MachXO3.aspx) | OK | OK |
| Xilinx | Artix 7 [xc7a35ti, xc7a50t, xc7a75t, xc7a100t, xc7a200t](https://www.xilinx.com/products/silicon-devices/fpga/artix-7.html) | OK | OK |
| | Kintex 7 [xc7k325t](https://www.xilinx.com/products/silicon-devices/fpga/kintex-7.html#productTable) | OK | NT |
| | Spartan 3 [xc3s200](https://www.xilinx.com/products/silicon-devices/fpga/spartan-3.html) | OK | NA |
| | Spartan 6 [xc6slx9, xc6slx16, xc6slx25, xc6slx45](https://www.xilinx.com/products/silicon-devices/fpga/spartan-6.html) | OK | OK |
| | Spartan 7 [xc7s15, xc7s25, xc7s50](https://www.xilinx.com/products/silicon-devices/fpga/spartan-7.html) | OK | OK |
| | XC9500XL [xc9536xl, xc9572xl, xc95144xl, xc95188xl](https://www.xilinx.com/support/documentation/data_sheets/ds054.pdf) | NA | OK |
| | XCF [xcf01s, xcf02s, xcf04s](https://www.xilinx.com/products/silicon-devices/configuration-memory/platform-flash.html) | NA | OK |
- *IF* Internal Flash
- *AS* Active Serial flash mode

View File

@ -10,6 +10,8 @@ current directory.
3. board provides the device/package model, but if the targeted board is not
officially supported but the FPGA yes, you can use --fpga-part to provides
model
4. with spartan3 the flash is an independent JTAG device. User has to use
`--index-chain` to access FPGA (RAM only) or flash (write/read only)
<span style="color:red">**Warning** *.bin* may be loaded in memory or in flash, but this extension is a classic extension
for CPU firmware and, by default, *openFPGALoader* load file in memory, double check

View File

@ -28,6 +28,8 @@ static std::map <int, fpga_model> fpga_list = {
{0x03651093, {"xilinx", "kintex7", "xc7k325t", 6}},
{0x01414093, {"xilinx", "spartan3", "xc3s200", 6}},
{0x04001093, {"xilinx", "spartan6", "xc6slx9", 6}},
{0x04002093, {"xilinx", "spartan6", "xc6slx16", 6}},
{0x04004093, {"xilinx", "spartan6", "xc6slx25", 6}},
@ -42,6 +44,10 @@ static std::map <int, fpga_model> fpga_list = {
{0x09608093, {"xilinx", "xc9500xl", "xc95144xl", 8}},
{0x09616093, {"xilinx", "xc9500xl", "xc95188xl", 8}},
{0x05044093, {"xilinx", "xcf", "xcf01s", 8}},
{0x05045093, {"xilinx", "xcf", "xcf02s", 8}},
{0x05046093, {"xilinx", "xcf", "xcf04s", 8}},
{0x03727093, {"xilinx", "zynq", "xc7z020", 6}},
{0x020f20dd, {"altera", "cyclone III", "EP3C16", 10}},

View File

@ -57,6 +57,16 @@ Xilinx::Xilinx(Jtag *jtag, const std::string &filename,
_fpga_family = ZYNQ_FAMILY;
} else if (family == "kintex7") {
_fpga_family = KINTEX_FAMILY;
} else if (family == "spartan3") {
_fpga_family = SPARTAN3_FAMILY;
if (_mode != Device::MEM_MODE) {
throw std::runtime_error("Error: Only load to mem is supported");
}
} else if (family == "xcf") {
_fpga_family = XCF_FAMILY;
if (_mode == Device::MEM_MODE) {
throw std::runtime_error("Error: Only write or read is supported");
}
} else if (family == "spartan6") {
_fpga_family = SPARTAN6_FAMILY;
} else if (family == "xc9500xl") {
@ -89,6 +99,7 @@ Xilinx::~Xilinx() {}
#define JPROGRAM 0x0B
#define JSTART 0x0C
#define JSHUTDOWN 0x0D
#define ISC_PROGRAM 0x11
#define ISC_DISABLE 0x16
#define BYPASS 0xff
@ -164,7 +175,7 @@ void Xilinx::program(unsigned int offset)
return;
}
if (_mode == Device::MEM_MODE)
if (_mode == Device::MEM_MODE || _fpga_family == XCF_FAMILY)
reverse = true;
printInfo("Open file ", false);
@ -194,6 +205,11 @@ void Xilinx::program(unsigned int offset)
if (_verbose)
bit->displayHeader();
if (_fpga_family == XCF_FAMILY) {
xcf_program(bit);
return;
}
if (_mode == Device::SPI_MODE) {
program_spi(bit, offset);
reset();
@ -361,10 +377,21 @@ void Xilinx::program_mem(ConfigBitstreamParser *bitfile)
bool Xilinx::dumpFlash(const std::string &filename,
uint32_t base_addr, uint32_t len)
{
if (_fpga_family == XC95_FAMILY) {
/* enable ISC */
flow_enable();
std::string buffer = flow_read();
if (_fpga_family == XC95_FAMILY || _fpga_family == XCF_FAMILY) {
std::string buffer;
if (_fpga_family == XC95_FAMILY) {
/* enable ISC */
flow_enable();
buffer = flow_read();
/* disable ISC */
flow_disable();
} else {
/* enable ISC */
xcf_flow_enable(0x34);
buffer = xcf_read();
/* disable ISC */
xcf_flow_disable();
}
printInfo("Open dump file ", false);
FILE *fd = fopen(filename.c_str(), "wb");
if (!fd) {
@ -379,8 +406,6 @@ bool Xilinx::dumpFlash(const std::string &filename,
printSuccess("DONE");
fclose(fd);
/* disable ISC */
flow_disable();
return true;
}
@ -610,6 +635,226 @@ std::string Xilinx::flow_read()
return buffer;
}
/* */
/* XCF Prom */
/* */
#define XCF_FVFY3 0xE2
#define XCF_ISCTESTSTATUS 0xE3
#define XCF_ISC_ENABLE 0xE8
#define XCF_ISC_PROGRAM 0xEA
#define XCF_ISC_ADDR_SHIFT 0xEB
#define XCF_ISC_ERASE 0xEC
#define XCF_ISC_DATA_SHIFT 0xED
#define XCF_ISC_READ 0xeF
#define XCF_ISC_DISABLE 0xF0
void Xilinx::xcf_flow_enable(uint8_t mode)
{
_jtag->shiftIR(XCF_ISC_ENABLE, 8);
_jtag->shiftDR(&mode, NULL, 6);
_jtag->toggleClk(1);
}
void Xilinx::xcf_flow_disable()
{
_jtag->shiftIR(XCF_ISC_DISABLE, 8);
usleep(110000);
_jtag->shiftIR(BYPASS, 8);
_jtag->toggleClk(1);
}
bool Xilinx::xcf_flow_erase()
{
uint8_t xfer_buf[2] = {0x01, 0x00};
printInfo("Erase flash ", false);
xcf_flow_enable();
_jtag->shiftIR(XCF_ISC_ADDR_SHIFT, 8);
_jtag->shiftDR(xfer_buf, NULL, 16);
_jtag->toggleClk(1);
_jtag->shiftIR(XCF_ISC_ERASE, 8);
usleep(500000);
int i;
for (i = 0; i < 32; i++) {
_jtag->shiftIR(XCF_ISCTESTSTATUS, 8);
usleep(500000);
_jtag->shiftDR(NULL, xfer_buf, 8);
if ((xfer_buf[0] & 0x04))
break;
}
if (i == 32) {
printError("FAIL");
return false;
}
printSuccess("DONE");
xcf_flow_disable();
return true;
}
bool Xilinx::xcf_program(ConfigBitstreamParser *bitfile)
{
uint8_t tx_buf[4096 / 8];
uint16_t pkt_len =
((_jtag->get_target_device_id() == 0x05044093) ? 2048 : 4096) / 8;
uint8_t *data = bitfile->getData();
uint32_t data_len = bitfile->getLength() / 8;
uint32_t xfer_len, offset = 0;
uint32_t addr = 0;
int xfer_end;
/* limit JTAG clock frequency to 15MHz */
if (_jtag->getClkFreq() > 15e6)
_jtag->setClkFreq(15e6);
if (!xcf_flow_erase()) {
printError("flow erase failed");
return false;
}
xcf_flow_enable();
int blk_id = 0;
ProgressBar progress("Write PROM", (data_len / pkt_len), 50, _quiet);
while (data_len > 0) {
if (data_len < pkt_len) {
xfer_len = data_len;
xfer_end = Jtag::SHIFT_DR;
} else {
xfer_len = pkt_len;
xfer_end = Jtag::RUN_TEST_IDLE;
}
/* send data to PROM */
_jtag->shiftIR(XCF_ISC_DATA_SHIFT, 8);
_jtag->shiftDR(data+offset, NULL, xfer_len * 8, xfer_end);
if (xfer_len != pkt_len) {
uint32_t res = pkt_len - xfer_len;
memset(tx_buf, 0xff, res);
_jtag->shiftDR(tx_buf, NULL, res * 8);
}
_jtag->toggleClk(1);
/* send address */
tx_buf[0] = (addr >> 0) & 0x00ff;
tx_buf[1] = (addr >> 8) & 0x00ff;
_jtag->shiftIR(XCF_ISC_ADDR_SHIFT, 8);
_jtag->shiftDR(tx_buf, NULL, 16);
_jtag->toggleClk(1);
/* send program instruction */
_jtag->shiftIR(XCF_ISC_PROGRAM, 8);
usleep((addr == 0) ? 14000: 500);
/* wait until bit 3 != 1 */
int i;
for (i = 0; i < 29; i++) {
_jtag->shiftIR(XCF_ISCTESTSTATUS, 8);
usleep(500);
_jtag->shiftDR(NULL, tx_buf, 8);
if ((tx_buf[0] & 0x04))
break;
}
if (i == 29) {
progress.fail();
return false;
}
blk_id++;
offset += xfer_len;
addr += 32;
data_len -= xfer_len;
progress.display(blk_id);
}
progress.done();
/* program done */
_jtag->shiftIR(BYPASS, 8);
_jtag->toggleClk(1);
if (_verify) {
std::string flash = xcf_read();
uint32_t file_size = bitfile->getLength() / 8;
uint32_t prom_size = (uint32_t)flash.size();
uint32_t nb_bytes = (file_size > prom_size) ? prom_size : file_size;
ProgressBar progress2("Verify Flash", nb_bytes, 50, _quiet);
for (uint32_t pos = 0; pos < nb_bytes; pos++) {
if (data[pos] != (uint8_t)flash[pos]) {
progress2.fail();
char error[64];
snprintf(error, sizeof(error),
"Error: wrong value: read %02x instead of %02x",
(uint8_t)flash[pos], (uint8_t)data[pos]);
printError(error);
xcf_flow_disable();
return false;
}
progress.display(pos);
}
progress2.done();
}
_jtag->go_test_logic_reset();
xcf_flow_disable();
return true;
}
std::string Xilinx::xcf_read()
{
uint32_t addr = 0;
uint8_t rx_buf[4096 / 8];
uint16_t pkt_len =
((_jtag->get_target_device_id() == 0x05044093) ? 2048 : 4096) / 8;
uint16_t nb_section =
((_jtag->get_target_device_id() == 0x05046093) ? 1024 : 512);
std::string buffer;
/* limit JTAG clock frequency to 15MHz */
if (_jtag->getClkFreq() > 15e6)
_jtag->setClkFreq(15e6);
ProgressBar progress("Read PROM", nb_section, 50, _quiet);
for (size_t section = 0; section < nb_section; section++) {
/* send address */
rx_buf[0] = (addr >> 0) & 0x00ff;
rx_buf[1] = (addr >> 8) & 0x00ff;
_jtag->shiftIR(XCF_ISC_ADDR_SHIFT, 8);
_jtag->shiftDR(rx_buf, NULL, 16);
_jtag->toggleClk(1);
/* send data to PROM */
_jtag->shiftIR(XCF_ISC_READ, 8);
usleep(50);
_jtag->shiftDR(NULL, rx_buf, pkt_len * 8);
for (int i = 0; i < pkt_len; i++)
buffer += rx_buf[i];
progress.display(section);
addr += 32;
}
progress.done();
return buffer;
}
/* */
/* SPI interface */
/* */

View File

@ -60,6 +60,15 @@ class Xilinx: public Device, SPIInterface {
*/
std::string flow_read();
/* ------------------- */
/* XCF JTAG Flash PROM */
/* ------------------- */
void xcf_flow_enable(uint8_t mode = 0x37);
void xcf_flow_disable();
bool xcf_flow_erase();
bool xcf_program(ConfigBitstreamParser *bitfile);
std::string xcf_read();
/* spi interface */
int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx,
uint32_t len) override;
@ -71,11 +80,13 @@ class Xilinx: public Device, SPIInterface {
/* list of xilinx family devices */
enum xilinx_family_t {
XC95_FAMILY = 0,
SPARTAN6_FAMILY = 1,
SPARTAN7_FAMILY = 2,
ARTIX_FAMILY = 3,
KINTEX_FAMILY = 4,
ZYNQ_FAMILY = 5,
SPARTAN3_FAMILY,
SPARTAN6_FAMILY,
SPARTAN7_FAMILY,
ARTIX_FAMILY,
KINTEX_FAMILY,
ZYNQ_FAMILY,
XCF_FAMILY,
UNKNOWN_FAMILY = 999
};