From c29fbb15f928500ed80fee6ac54297ccac340bea Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Thu, 8 Jul 2021 20:52:46 +0200 Subject: [PATCH] altera: use new epcq interface, add device type and prog type. Now more generic and not specific to cyc1000 --- src/altera.cpp | 209 +++++++++++++++++++++++++++++++++++++++++++++---- src/altera.hpp | 52 ++++++++++-- 2 files changed, 238 insertions(+), 23 deletions(-) diff --git a/src/altera.cpp b/src/altera.cpp index b39ea0c..585ed50 100644 --- a/src/altera.cpp +++ b/src/altera.cpp @@ -16,22 +16,39 @@ #include "rawParser.hpp" #define IDCODE 6 +#define USER0 0x0C +#define USER1 0x0E #define BYPASS 0x3FF #define IRLENGTH 10 // DATA_DIR is defined at compile time. #define BIT_FOR_FLASH (DATA_DIR "/openFPGALoader/test_sfl.svf") Altera::Altera(Jtag *jtag, const std::string &filename, - const std::string &file_type, bool verify, int8_t verbose): - Device(jtag, filename, file_type, verify, verbose), _svf(_jtag, _verbose) + const std::string &file_type, Device::prog_type_t prg_type, + const std::string &device_package, bool verify, int8_t verbose): + Device(jtag, filename, file_type, verify, verbose), _svf(_jtag, _verbose), + _device_package(device_package), + _vir_addr(0x1000), _vir_length(14) { - if (!_file_extension.empty()) { - if (_file_extension == "svf" || _file_extension == "rbf") - _mode = Device::MEM_MODE; - else - _mode = Device::SPI_MODE; + if (prg_type == Device::RD_FLASH) { + _mode = Device::READ_MODE; + } else { + if (!_file_extension.empty()) { + if (_file_extension == "svf") { + _mode = Device::MEM_MODE; + } else if (_file_extension == "rpd" || + _file_extension == "rbf") { + if (prg_type == Device::WR_SRAM) + _mode = Device::MEM_MODE; + else + _mode = Device::SPI_MODE; + } else { + _mode = Device::SPI_MODE; + } + } } } + Altera::~Altera() {} void Altera::reset() @@ -44,14 +61,12 @@ void Altera::reset() _jtag->set_state(Jtag::TEST_LOGIC_RESET); } -void Altera::programMem() +void Altera::programMem(RawParser &_bit) { - RawParser _bit(_filename, false); - _bit.parse(); int byte_length = _bit.getLength()/8; uint8_t *data = _bit.getData(); - uint32_t clk_period = 1e9/(float)_jtag->getClkFreq(); + uint32_t clk_period = 1e9/static_cast(_jtag->getClkFreq()); unsigned char cmd[2]; unsigned char tx[864/8], rx[864/8]; @@ -124,6 +139,32 @@ void Altera::programMem() _jtag->set_state(Jtag::RUN_TEST_IDLE); } +bool Altera::load_bridge() +{ + if (_device_package.empty()) { + printError("Can't program SPI flash: missing device-package information"); + return false; + } + + // DATA_DIR is defined at compile time. + std::string bitname = DATA_DIR "/openFPGALoader/spiOverJtag_"; + bitname += _device_package + ".rbf"; + + std::cout << "use: " << bitname << std::endl; + + /* first: load spi over jtag */ + try { + RawParser bridge(bitname, false); + bridge.parse(); + programMem(bridge); + } catch (std::exception &e) { + printError(e.what()); + throw std::runtime_error(e.what()); + } + + return true; +} + void Altera::program(unsigned int offset) { if (_mode == Device::NONE_MODE) @@ -136,15 +177,53 @@ void Altera::program(unsigned int offset) */ /* mem mode -> svf */ if (_mode == Device::MEM_MODE) { - if (_file_extension == "svf") + if (_file_extension == "svf") { _svf.parse(_filename); - else - programMem(); + } else { + RawParser _bit(_filename, false); + _bit.parse(); + programMem(_bit); + } } else if (_mode == Device::SPI_MODE) { + /* try to load spiOverJtag bridge + * to have an access to SPI flash + */ + if (!load_bridge()) { + printError("Fail to load bridge"); + return; + } + + // reverse only bitstream raw binaries data no + bool reverseOrder = false; + if (_file_extension == "rbf" || _file_extension == "rpd") + reverseOrder = true; + + /* prepare data to write */ + uint8_t *data = NULL; + int length = 0; + + RawParser bit(_filename, reverseOrder); + try { + bit.parse(); + data = bit.getData(); + length = bit.getLength() / 8; + } catch (std::exception &e) { + printError(e.what()); + throw std::runtime_error(e.what()); + } + /* GGM: TODO: fix this issue */ - EPCQ epcq(0x403, 0x6010/*_jtag->vid(), _jtag->pid()*/, 2, 6000000); - _svf.parse(BIT_FOR_FLASH); - epcq.program(offset, _filename, (_file_extension == "rpd")? true:false); + EPCQ epcq(this, 0); + + try { + epcq.reset(); + epcq.read_id(); + epcq.read_status_reg(); + epcq.erase_and_prog(offset, data, length); + } catch (std::exception &e) { + printError(e.what()); + throw std::runtime_error(e.what()); + } if (_verify) printWarn("writing verification not supported"); @@ -164,3 +243,99 @@ int Altera::idCode() ((rx_data[2] << 16) & 0x00ff0000) | ((rx_data[3] << 24) & 0xff000000)); } + +/* SPI interface */ + +int Altera::spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, uint32_t len) +{ + /* +1 because send first cmd + len byte + 1 for rx due to a delay of + * one bit + */ + int xfer_len = len + 1 + ((rx == NULL) ? 0 : 1); + uint8_t jtx[xfer_len]; + uint8_t jrx[xfer_len]; + + if (tx != NULL) { + for (uint32_t i = 0; i < len; i++) + jtx[i] = RawParser::reverseByte(tx[i]); + } + + shiftVIR(RawParser::reverseByte(cmd)); + shiftVDR(jtx, (rx) ? jrx : NULL, 8 * xfer_len); + + if (rx) { + for (uint32_t i = 0; i < len; i++) { + rx[i] = RawParser::reverseByte(jrx[i+1] >> 1) | (jrx[i+2] & 0x01); + } + } + + return len; +} +int Altera::spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) +{ + return spi_put(tx[0], &tx[1], rx, len-1); +} + +int Altera::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, + uint32_t timeout, bool verbose) +{ + uint8_t rx[3]; + uint8_t tmp; + uint32_t count = 0; + bool first = true; + + shiftVIR(RawParser::reverseByte(cmd)); + do { + if (first) { + first = false; + shiftVDR(NULL, rx, 24, Jtag::SHIFT_DR); + tmp = RawParser::reverseByte(rx[1] >> 1) | (rx[2] & 0x01); + } else { + _jtag->shiftDR(NULL, rx, 16, Jtag::SHIFT_DR); + tmp = RawParser::reverseByte(rx[0] >> 1) | (rx[1] & 0x01); + } + + 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); + } + } while ((tmp & mask) != cond); + _jtag->set_state(Jtag::UPDATE_DR); + + if (count == timeout) { + printf("%x\n", tmp); + std::cout << "wait: Error" << std::endl; + return -1; + } + return 0; +} + +/* VIrtual Jtag Access */ +void Altera::shiftVIR(uint32_t reg) +{ + uint32_t len = _vir_length; + uint32_t mask = (1 << len) - 1; + uint32_t tmp = (reg & mask) | _vir_addr; + uint8_t *tx = (uint8_t *) & tmp; + uint8_t tx_ir[2] = {USER1, 0}; + + _jtag->set_state(Jtag::RUN_TEST_IDLE); + + _jtag->shiftIR(tx_ir, NULL, IRLENGTH, Jtag::UPDATE_IR); + /* len + 1 + 1 => IRLENGTH + Slave ID + 1 (ASMI/SFL) */ + _jtag->shiftDR(tx, NULL, len/* + 2*/, Jtag::UPDATE_DR); +} + +void Altera::shiftVDR(uint8_t * tx, uint8_t * rx, uint32_t len, + int end_state, bool debug) +{ + (void) debug; + uint8_t tx_ir[2] = {USER0, 0}; + _jtag->shiftIR(tx_ir, NULL, IRLENGTH, Jtag::UPDATE_IR); + _jtag->shiftDR(tx, rx, len, end_state); +} diff --git a/src/altera.hpp b/src/altera.hpp index 0250aaf..fa24b74 100644 --- a/src/altera.hpp +++ b/src/altera.hpp @@ -3,27 +3,67 @@ * Copyright (C) 2019 Gwenhael Goavec-Merou */ -#ifndef ALTERA_HPP -#define ALTERA_HPP +#ifndef SRC_ALTERA_HPP_ +#define SRC_ALTERA_HPP_ #include #include "device.hpp" #include "jtag.hpp" +#include "rawParser.hpp" +#include "spiInterface.hpp" #include "svf_jtag.hpp" -class Altera: public Device { +class Altera: public Device, SPIInterface { public: Altera(Jtag *jtag, const std::string &filename, - const std::string &file_type, bool verify, int8_t verbose); + const std::string &file_type, + Device::prog_type_t prg_type, + const std::string &device_package, + bool verify, int8_t verbose); ~Altera(); - void programMem(); + void programMem(RawParser &_bit); void program(unsigned int offset = 0) override; int idCode() override; void reset() override; + + /* spi interface */ + int spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, + uint32_t len) override; + int spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) override; + int spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, + uint32_t timeout, bool verbose = false) override; + private: + /*! + * \brief with intel devices SPI flash direct access is not possible + * so a bridge must be loaded in RAM to access flash + * \return false if missing device mode, true otherwise + */ + bool load_bridge(); + /* virtual JTAG access */ + /*! + * \brief virtual IR: send USER0 IR followed, in DR, by + * address (_vir_addr) in a burst of _vir_length + * \param[in] reg: data to send in shiftDR mode with addr + */ + void shiftVIR(uint32_t reg); + /*! + * \brief virtual IR: send USER1 IR followed by + * data in DR with an optional read + * \param[in] tx: data to send in shiftDR mode + * \param[in] rx: data to read in shiftDR mode + * \param[in] len: len of tx & rx + * \param[in] end_state: next state at the end of xfer + */ + void shiftVDR(uint8_t * tx, uint8_t * rx, uint32_t len, + int end_state = Jtag::UPDATE_DR, bool debug = false); + SVF_jtag _svf; + std::string _device_package; + uint32_t _vir_addr; /**< addr affected to virtual jtag */ + uint32_t _vir_length; /**< length of virtual jtag IR */ }; -#endif +#endif // SRC_ALTERA_HPP_