xilinx: adapted code to support existing spiOverJtag bitstreams (v1) and new bitstreams (v2)
This commit is contained in:
parent
971a8db4e9
commit
03045dc407
142
src/xilinx.cpp
142
src/xilinx.cpp
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
/* Used for xc3s */
|
||||
#define USER1 0x02
|
||||
#define USER4 0x23
|
||||
#define CFG_IN 0x05
|
||||
#define USERCODE 0x08
|
||||
#define IDCODE 0x09
|
||||
|
|
@ -278,7 +279,8 @@ Xilinx::Xilinx(Jtag *jtag, const std::string &filename,
|
|||
SPIInterface(filename, verbose, 256, verify, skip_load_bridge,
|
||||
skip_reset),
|
||||
_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) {
|
||||
_mode = Device::READ_MODE;
|
||||
|
|
@ -673,11 +675,24 @@ bool Xilinx::post_flash_access()
|
|||
|
||||
bool Xilinx::prepare_flash_access()
|
||||
{
|
||||
bool ret = false;
|
||||
if (_skip_load_bridge) {
|
||||
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()
|
||||
|
|
@ -714,9 +729,32 @@ bool Xilinx::load_bridge()
|
|||
printError(e.what());
|
||||
throw std::runtime_error(e.what());
|
||||
}
|
||||
|
||||
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,
|
||||
bool unprotect_flash)
|
||||
{
|
||||
|
|
@ -2023,6 +2061,10 @@ bool Xilinx::xc2c_flow_program(JedParser *jed)
|
|||
int Xilinx::spi_put(uint8_t cmd,
|
||||
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);
|
||||
uint8_t jtx[xfer_len];
|
||||
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)
|
||||
{
|
||||
uint8_t rx[2];
|
||||
uint8_t dummy[2];
|
||||
memset(dummy, 0xff, sizeof(dummy));
|
||||
uint8_t tx[2];
|
||||
uint8_t tmp;
|
||||
uint8_t tx = McsParser::reverseByte(cmd);
|
||||
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->shiftDR(&tx, NULL, 8, Jtag::SHIFT_DR);
|
||||
_jtag->shiftDR(tx, NULL, 8 * idx, Jtag::SHIFT_DR);
|
||||
|
||||
do {
|
||||
_jtag->shiftDR(dummy, rx, 8*2, Jtag::SHIFT_DR);
|
||||
tmp = (McsParser::reverseByte(rx[0]>>1)) | (0x01 & rx[1]);
|
||||
_jtag->shiftDR(tx, rx, 8*2, Jtag::SHIFT_DR);
|
||||
tmp = McsParser::reverseByte(rx[0 ]>> shift);
|
||||
if (shift == 1)
|
||||
tmp |= (0x01 & rx[1]);
|
||||
else
|
||||
tmp |= McsParser::reverseByte(rx[1]) >> (8 - shift);
|
||||
|
||||
count++;
|
||||
if (count == timeout){
|
||||
printf("timeout: %x %x %x\n", tmp, rx[0], rx[1]);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
_jtag->shiftDR(dummy, rx, 8*2, Jtag::EXIT1_DR);
|
||||
_jtag->shiftDR(tx, rx, 8 * 2, Jtag::EXIT1_DR);
|
||||
_jtag->go_test_logic_reset();
|
||||
|
||||
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) {
|
||||
switch (flash_chip) {
|
||||
case SECONDARY_FLASH:
|
||||
|
|
|
|||
|
|
@ -168,6 +168,10 @@ class Xilinx: public Device, SPIInterface {
|
|||
int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
|
||||
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:
|
||||
/*!
|
||||
* \brief prepare SPI flash access (need to have bridge in RAM)
|
||||
|
|
@ -215,6 +219,12 @@ class Xilinx: public Device, SPIInterface {
|
|||
*/
|
||||
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 {
|
||||
PRIMARY_FLASH = 0x1,
|
||||
SECONDARY_FLASH = 0x2
|
||||
|
|
@ -249,6 +259,8 @@ class Xilinx: public Device, SPIInterface {
|
|||
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 */
|
||||
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_
|
||||
|
|
|
|||
Loading…
Reference in New Issue