xilinx: adapted code to support existing spiOverJtag bitstreams (v1) and new bitstreams (v2)
This commit is contained in:
parent
971a8db4e9
commit
03045dc407
146
src/xilinx.cpp
146
src/xilinx.cpp
|
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
/* Used for xc3s */
|
/* Used for xc3s */
|
||||||
#define USER1 0x02
|
#define USER1 0x02
|
||||||
|
#define USER4 0x23
|
||||||
#define CFG_IN 0x05
|
#define CFG_IN 0x05
|
||||||
#define USERCODE 0x08
|
#define USERCODE 0x08
|
||||||
#define IDCODE 0x09
|
#define IDCODE 0x09
|
||||||
|
|
@ -278,7 +279,8 @@ Xilinx::Xilinx(Jtag *jtag, const std::string &filename,
|
||||||
SPIInterface(filename, verbose, 256, verify, skip_load_bridge,
|
SPIInterface(filename, verbose, 256, verify, skip_load_bridge,
|
||||||
skip_reset),
|
skip_reset),
|
||||||
_device_package(device_package), _spiOverJtagPath(spiOverJtagPath),
|
_device_package(device_package), _spiOverJtagPath(spiOverJtagPath),
|
||||||
_irlen(6), _secondary_filename(secondary_filename)
|
_irlen(6), _secondary_filename(secondary_filename), _soj_is_v2(false),
|
||||||
|
_jtag_chain_len(1)
|
||||||
{
|
{
|
||||||
if (prg_type == Device::RD_FLASH) {
|
if (prg_type == Device::RD_FLASH) {
|
||||||
_mode = Device::READ_MODE;
|
_mode = Device::READ_MODE;
|
||||||
|
|
@ -673,11 +675,24 @@ bool Xilinx::post_flash_access()
|
||||||
|
|
||||||
bool Xilinx::prepare_flash_access()
|
bool Xilinx::prepare_flash_access()
|
||||||
{
|
{
|
||||||
|
bool ret = false;
|
||||||
if (_skip_load_bridge) {
|
if (_skip_load_bridge) {
|
||||||
printInfo("Skip loading bridge for spiOverjtag");
|
printInfo("Skip loading bridge for spiOverjtag");
|
||||||
return true;
|
ret = true;
|
||||||
|
} else {
|
||||||
|
ret = load_bridge();
|
||||||
}
|
}
|
||||||
return load_bridge();
|
|
||||||
|
/* Get number of FPGAs in the Jtag Chain */
|
||||||
|
_jtag_chain_len = _jtag->get_chain_len();
|
||||||
|
|
||||||
|
/* check SpiOverJtag version */
|
||||||
|
if (ret) {
|
||||||
|
if (get_spiOverJtag_version() == 2.0f)
|
||||||
|
_soj_is_v2 = true;
|
||||||
|
printf("SOJ version: %f\n", _soj_is_v2 ? 2.0f : 1.0f);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Xilinx::load_bridge()
|
bool Xilinx::load_bridge()
|
||||||
|
|
@ -714,9 +729,32 @@ bool Xilinx::load_bridge()
|
||||||
printError(e.what());
|
printError(e.what());
|
||||||
throw std::runtime_error(e.what());
|
throw std::runtime_error(e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Xilinx::get_spiOverJtag_version()
|
||||||
|
{
|
||||||
|
uint8_t jtx[6] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
uint8_t jrx[7];
|
||||||
|
uint8_t rx[6];
|
||||||
|
|
||||||
|
_jtag->shiftIR(USER4, _irlen, Jtag::UPDATE_IR);
|
||||||
|
printf("jtag_chain_len: %d\n", _jtag_chain_len);
|
||||||
|
if (_jtag_chain_len > 1)
|
||||||
|
_jtag->shiftDR(jtx, NULL, _jtag_chain_len - 1, Jtag::SHIFT_DR);
|
||||||
|
_jtag->shiftDR(jtx, jrx, 6 * 8);
|
||||||
|
_jtag->flush();
|
||||||
|
|
||||||
|
memcpy(rx, &jrx[1], 5);
|
||||||
|
rx[5] = '\0';
|
||||||
|
|
||||||
|
float version = atof((const char *)rx);
|
||||||
|
if (version == 0.0f) // not supported => 1.0
|
||||||
|
return 1.0f;
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
void Xilinx::program_spi(ConfigBitstreamParser * bit, unsigned int offset,
|
void Xilinx::program_spi(ConfigBitstreamParser * bit, unsigned int offset,
|
||||||
bool unprotect_flash)
|
bool unprotect_flash)
|
||||||
{
|
{
|
||||||
|
|
@ -889,7 +927,7 @@ static const std::map<std::string, std::list<reg_struct_t>> reg_content = {
|
||||||
REG_ENTRY("ConfigFallback", 10, 1,
|
REG_ENTRY("ConfigFallback", 10, 1,
|
||||||
{0, "Disable"}, {1, "Enable"}),
|
{0, "Disable"}, {1, "Enable"}),
|
||||||
REG_ENTRY("Reserved", 11, 1),
|
REG_ENTRY("Reserved", 11, 1),
|
||||||
REG_ENTRY("OverTempPwrDown",12, 1,
|
REG_ENTRY("OverTempPwrDown", 12, 1,
|
||||||
{0, "Disable"}, {1, "Enable"}),
|
{0, "Disable"}, {1, "Enable"}),
|
||||||
REG_ENTRY("Reserved", 13, 17),
|
REG_ENTRY("Reserved", 13, 17),
|
||||||
REG_ENTRY("ICAP Select", 30, 1,
|
REG_ENTRY("ICAP Select", 30, 1,
|
||||||
|
|
@ -1003,7 +1041,7 @@ uint32_t Xilinx::dumpRegister(std::string reg_name)
|
||||||
if (code == reg_code.end()) {
|
if (code == reg_code.end()) {
|
||||||
printError("Unknown register " + reg_name);
|
printError("Unknown register " + reg_name);
|
||||||
printError("Known Register are:");
|
printError("Known Register are:");
|
||||||
for (auto reg :reg_code)
|
for (auto reg : reg_code)
|
||||||
printError("\t" + reg.first);
|
printError("\t" + reg.first);
|
||||||
return 0xdeadbeef;
|
return 0xdeadbeef;
|
||||||
}
|
}
|
||||||
|
|
@ -2023,6 +2061,10 @@ bool Xilinx::xc2c_flow_program(JedParser *jed)
|
||||||
int Xilinx::spi_put(uint8_t cmd,
|
int Xilinx::spi_put(uint8_t cmd,
|
||||||
const uint8_t *tx, uint8_t *rx, uint32_t len)
|
const uint8_t *tx, uint8_t *rx, uint32_t len)
|
||||||
{
|
{
|
||||||
|
/* SpiOverJtag v2 */
|
||||||
|
if (_soj_is_v2)
|
||||||
|
return spi_put_v2(cmd, tx, rx, len);
|
||||||
|
|
||||||
int xfer_len = len + 1 + ((rx == NULL) ? 0 : 1);
|
int xfer_len = len + 1 + ((rx == NULL) ? 0 : 1);
|
||||||
uint8_t jtx[xfer_len];
|
uint8_t jtx[xfer_len];
|
||||||
jtx[0] = McsParser::reverseByte(cmd);
|
jtx[0] = McsParser::reverseByte(cmd);
|
||||||
|
|
@ -2075,28 +2117,37 @@ int Xilinx::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
|
||||||
uint32_t timeout, bool verbose)
|
uint32_t timeout, bool verbose)
|
||||||
{
|
{
|
||||||
uint8_t rx[2];
|
uint8_t rx[2];
|
||||||
uint8_t dummy[2];
|
uint8_t tx[2];
|
||||||
memset(dummy, 0xff, sizeof(dummy));
|
|
||||||
uint8_t tmp;
|
uint8_t tmp;
|
||||||
uint8_t tx = McsParser::reverseByte(cmd);
|
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
|
const uint8_t shift = _jtag_chain_len;
|
||||||
|
uint8_t idx = 0;
|
||||||
|
|
||||||
|
if (_soj_is_v2)
|
||||||
|
tx[idx++] = (0x2 << 1) | 1;
|
||||||
|
tx[idx++] = McsParser::reverseByte(cmd);
|
||||||
|
|
||||||
_jtag->shiftIR(get_ircode(_ircode_map, _user_instruction), NULL, _irlen, Jtag::UPDATE_IR);
|
_jtag->shiftIR(get_ircode(_ircode_map, _user_instruction), NULL, _irlen, Jtag::UPDATE_IR);
|
||||||
_jtag->shiftDR(&tx, NULL, 8, Jtag::SHIFT_DR);
|
_jtag->shiftDR(tx, NULL, 8 * idx, Jtag::SHIFT_DR);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
_jtag->shiftDR(dummy, rx, 8*2, Jtag::SHIFT_DR);
|
_jtag->shiftDR(tx, rx, 8*2, Jtag::SHIFT_DR);
|
||||||
tmp = (McsParser::reverseByte(rx[0]>>1)) | (0x01 & rx[1]);
|
tmp = McsParser::reverseByte(rx[0 ]>> shift);
|
||||||
|
if (shift == 1)
|
||||||
|
tmp |= (0x01 & rx[1]);
|
||||||
|
else
|
||||||
|
tmp |= McsParser::reverseByte(rx[1]) >> (8 - shift);
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
if (count == timeout){
|
if (count == timeout){
|
||||||
printf("timeout: %x %x %x\n", tmp, rx[0], rx[1]);
|
printf("timeout: %x %x %x\n", tmp, rx[0], rx[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("%x %x %x %u\n", tmp, mask, cond, count);
|
printf("%x %x %x %u %02x %02x\n", tmp, mask, cond, count, rx[0], rx[1]);
|
||||||
}
|
}
|
||||||
} while ((tmp & mask) != cond);
|
} while ((tmp & mask) != cond);
|
||||||
_jtag->shiftDR(dummy, rx, 8*2, Jtag::EXIT1_DR);
|
_jtag->shiftDR(tx, rx, 8 * 2, Jtag::EXIT1_DR);
|
||||||
_jtag->go_test_logic_reset();
|
_jtag->go_test_logic_reset();
|
||||||
|
|
||||||
if (count == timeout) {
|
if (count == timeout) {
|
||||||
|
|
@ -2108,6 +2159,75 @@ int Xilinx::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Xilinx::spi_put_v2(uint8_t cmd, const uint8_t *tx, uint8_t *rx,
|
||||||
|
uint32_t len)
|
||||||
|
{
|
||||||
|
const uint32_t real_len = len + 1; // rx/tx length + cmd
|
||||||
|
uint32_t kPktLen = real_len + 2; // One header and +1 due to the needs of an additional bit/byte
|
||||||
|
uint8_t mode = 0x01;
|
||||||
|
if (real_len > 32) {
|
||||||
|
kPktLen++; // Additional header
|
||||||
|
mode = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t xfer_bit_len = (kPktLen - 1) * 8 + (rx ? 8 : 1);
|
||||||
|
|
||||||
|
uint8_t jrx[kPktLen];
|
||||||
|
uint8_t pkt[kPktLen];
|
||||||
|
uint32_t idx = 0;
|
||||||
|
|
||||||
|
pkt[idx++] = ((0x1f & real_len) << 3) | ((0x03 & mode) << 1) | 1;
|
||||||
|
if (mode == 0x00)
|
||||||
|
pkt[idx++] = 0xff & (real_len >> 5);
|
||||||
|
|
||||||
|
pkt[idx++] = McsParser::reverseByte(cmd);
|
||||||
|
if (tx) {
|
||||||
|
for (uint32_t i=0; i < len; i++)
|
||||||
|
pkt[idx++] = McsParser::reverseByte(tx[i]);
|
||||||
|
} else {
|
||||||
|
memset(&pkt[idx], 0, len);
|
||||||
|
idx += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* addr BSCAN user1 */
|
||||||
|
_jtag->shiftIR(get_ircode(_ircode_map, _user_instruction), NULL, _irlen);
|
||||||
|
_jtag->shiftDR(pkt, (rx == NULL) ? NULL : jrx, xfer_bit_len);
|
||||||
|
_jtag->go_test_logic_reset();
|
||||||
|
_jtag->flush();
|
||||||
|
|
||||||
|
if (_verbose) {
|
||||||
|
for (uint32_t i = 0; i < kPktLen; i++)
|
||||||
|
printf("%02x ", pkt[i]);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rx != NULL) {
|
||||||
|
if (_verbose) {
|
||||||
|
for (uint32_t i = 0; i < kPktLen; i++)
|
||||||
|
printf("%02x ", jrx[i]);
|
||||||
|
printf("\n");
|
||||||
|
for (uint32_t i = 0; i < kPktLen; i++)
|
||||||
|
printf("%02x ", McsParser::reverseByte(jrx[i]));
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
idx = (mode == 0 ? 3 : 2);
|
||||||
|
const uint8_t shift = _jtag_chain_len;
|
||||||
|
for (uint32_t i = 0; i < len; i++) {
|
||||||
|
rx[i] = McsParser::reverseByte(jrx[i + idx] >> shift);
|
||||||
|
if (shift == 1)
|
||||||
|
rx[i] |= (jrx[i + idx + 1] & 0x01);
|
||||||
|
else
|
||||||
|
rx[i] |= McsParser::reverseByte(jrx[i + idx + 1]) >> (8 - shift);
|
||||||
|
if (_verbose)
|
||||||
|
printf("%02x ", rx[i]);
|
||||||
|
}
|
||||||
|
if (_verbose)
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Xilinx::select_flash_chip(xilinx_flash_chip_t flash_chip) {
|
void Xilinx::select_flash_chip(xilinx_flash_chip_t flash_chip) {
|
||||||
switch (flash_chip) {
|
switch (flash_chip) {
|
||||||
case SECONDARY_FLASH:
|
case SECONDARY_FLASH:
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,10 @@ class Xilinx: public Device, SPIInterface {
|
||||||
int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
|
int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
|
||||||
uint32_t timeout, bool verbose = false) override;
|
uint32_t timeout, bool verbose = false) override;
|
||||||
|
|
||||||
|
/* SpiOverJtag v2 specifics methods */
|
||||||
|
int spi_put_v2(uint8_t cmd, const uint8_t *tx, uint8_t *rx,
|
||||||
|
uint32_t len);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/*!
|
/*!
|
||||||
* \brief prepare SPI flash access (need to have bridge in RAM)
|
* \brief prepare SPI flash access (need to have bridge in RAM)
|
||||||
|
|
@ -215,6 +219,12 @@ class Xilinx: public Device, SPIInterface {
|
||||||
*/
|
*/
|
||||||
bool load_bridge();
|
bool load_bridge();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief read SpiOverJtag version to select between v1 and v2
|
||||||
|
* \return 2.0 for v2 or 1.0 for v1
|
||||||
|
*/
|
||||||
|
float get_spiOverJtag_version();
|
||||||
|
|
||||||
enum xilinx_flash_chip_t {
|
enum xilinx_flash_chip_t {
|
||||||
PRIMARY_FLASH = 0x1,
|
PRIMARY_FLASH = 0x1,
|
||||||
SECONDARY_FLASH = 0x2
|
SECONDARY_FLASH = 0x2
|
||||||
|
|
@ -249,6 +259,8 @@ class Xilinx: public Device, SPIInterface {
|
||||||
std::string _secondary_file_extension; /* file type for the secondary flash file */
|
std::string _secondary_file_extension; /* file type for the secondary flash file */
|
||||||
int _flash_chips; /* bitfield to select the target in boards with two flash chips */
|
int _flash_chips; /* bitfield to select the target in boards with two flash chips */
|
||||||
std::string _user_instruction; /* which USER bscan instruction to interface with SPI */
|
std::string _user_instruction; /* which USER bscan instruction to interface with SPI */
|
||||||
|
bool _soj_is_v2; /* SpiOverJtag version (1.0 or 2.0) */
|
||||||
|
uint32_t _jtag_chain_len; /* Jtag Chain Length */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SRC_XILINX_HPP_
|
#endif // SRC_XILINX_HPP_
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue