diff --git a/src/anlogic.cpp b/src/anlogic.cpp index aa94e30..4b481a8 100644 --- a/src/anlogic.cpp +++ b/src/anlogic.cpp @@ -21,6 +21,7 @@ #include "jtag.hpp" #include "device.hpp" #include "progressBar.hpp" +#include "spiFlash.hpp" #define REFRESH 0x01 #define IDCODE 0x06 @@ -32,13 +33,19 @@ #define IRLENGTH 8 -Anlogic::Anlogic(Jtag *jtag, const std::string &filename, bool verbose): +Anlogic::Anlogic(Jtag *jtag, const std::string &filename, + bool flash_wr, bool sram_wr, bool verbose): Device(jtag, filename, verbose), _svf(_jtag, _verbose) { if (_filename != "") { - if (_file_extension == "svf" || _file_extension == "bit") + if (_file_extension == "svf") _mode = Device::MEM_MODE; - else + else if (_file_extension == "bit") { + if (sram_wr) + _mode = Device::MEM_MODE; + else + _mode = Device::SPI_MODE; + } else throw std::exception(); } } @@ -58,13 +65,57 @@ void Anlogic::program(unsigned int offset) { if (_mode == Device::NONE_MODE) return; - if (_mode == Device::MEM_MODE) { - if (_file_extension == "svf") { - _svf.parse(_filename); - return; + + if (_file_extension == "svf") { + _svf.parse(_filename); + return; + } + + AnlogicBitParser bit(_filename, (_mode == Device::MEM_MODE), _verbose); + bit.parse(); + uint8_t *data = bit.getData(); + int len = bit.getLength() / 8; + + if (_mode == Device::SPI_MODE) { + SPIFlash flash(this, _verbose); + + for (int i = 0; i < 5; i++) + _jtag->shiftIR(BYPASS, IRLENGTH); + //Verify Device id. + //SIR 8 TDI (06) ; + //SDR 32 TDI (00000000) TDO (0a014c35) MASK (ffffffff) ; + //Boundary Scan Chain Contents + //Position 1: BG256 + //Loading device with 'refresh' instruction. + _jtag->shiftIR(REFRESH, IRLENGTH); + //Loading device with 'bypass' & 'spi_program' instruction. + _jtag->shiftIR(BYPASS, IRLENGTH); + _jtag->shiftIR(SPI_PROGRAM, IRLENGTH); + for (int i = 0; i < 4; i++) + _jtag->toggleClk(50000); + + flash.reset(); + flash.read_id(); + flash.read_status_reg(); + + flash.erase_and_prog(offset, data, len); + + //Loading device with 'bypass' instruction. + _jtag->shiftIR(BYPASS, IRLENGTH); + ////Loading device with 'refresh' instruction. + _jtag->shiftIR(REFRESH, IRLENGTH); + _jtag->toggleClk(20); + ////Loading device with 'bypass' instruction. + for (int i = 0; i < 4; i++) { + _jtag->shiftIR(BYPASS, IRLENGTH); + _jtag->toggleClk(20); } - AnlogicBitParser bit(_filename, _verbose); - bit.parse(); + _jtag->shiftIR(BYPASS, IRLENGTH); + _jtag->toggleClk(10000); + + return; + } + if (_mode == Device::MEM_MODE) { // Loading device with 'bypass' instruction. _jtag->shiftIR(BYPASS, IRLENGTH); @@ -87,8 +138,6 @@ void Anlogic::program(unsigned int offset) _jtag->shiftIR(CFG_IN, IRLENGTH); _jtag->toggleClk(15); - uint8_t *data = bit.getData(); - int len = bit.getLength() / 8; _jtag->set_state(Jtag::SHIFT_DR); ProgressBar progress("Loading", len, 50); int pos = 0; @@ -136,3 +185,93 @@ int Anlogic::idCode() ((rx_data[2] << 16) & 0x00ff0000) | ((rx_data[3] << 24) & 0xff000000)); } + +/* SPI wrapper + * For read operation a delay of one bit is added + * So add one bit more and move everything by one + * In write only operations to care about this delay + */ + +int Anlogic::spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, uint32_t len) +{ + int xfer_len = len + 1; + if (rx) + xfer_len++; + uint8_t jtx[xfer_len]; + uint8_t jrx[xfer_len]; + + jtx[0] = AnlogicBitParser::reverseByte(cmd); + if (tx != NULL) { + for (int i = 0; i < len; i++) + jtx[i+1] = AnlogicBitParser::reverseByte(tx[i]); + } + + /* write anlogic command before sending packet */ + uint8_t op = 0x60; + _jtag->shiftDR(&op, NULL, 8); + + _jtag->shiftDR(jtx, (rx == NULL)? NULL: jrx, 8*xfer_len); + if (rx != NULL) { + for (int i=0; i < len; i++) + rx[i] = AnlogicBitParser::reverseByte(jrx[i+1]>>1) + | (jrx[i+2]&0x01); + } + return 0; +} +int Anlogic::spi_put(uint8_t *tx, uint8_t *rx, uint32_t len) +{ + int xfer_len = len; + if (rx) + xfer_len++; + uint8_t jtx[xfer_len]; + uint8_t jrx[xfer_len]; + + if (tx != NULL) { + for (int i = 0; i < len; i++) + jtx[i] = AnlogicBitParser::reverseByte(tx[i]); + } + + /* write anlogic command before sending packet */ + uint8_t op = 0x60; + _jtag->shiftDR(&op, NULL, 8); + + _jtag->shiftDR(jtx, (rx == NULL)? NULL: jrx, 8*xfer_len); + if (rx != NULL) { + for (int i=0; i < len; i++) + rx[i] = AnlogicBitParser::reverseByte(jrx[i]>>1) | + (jrx[i+1]&0x01); + } + return 0; +} +int Anlogic::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond, + uint32_t timeout, bool verbose) +{ + uint8_t rx[3]; + uint8_t tx[3]; + tx[0] = AnlogicBitParser::reverseByte(cmd); + uint8_t op = 0x60; + uint8_t tmp; + uint32_t count = 0; + + do { + _jtag->shiftDR(&op, NULL, 8); + _jtag->shiftDR(tx, rx, 8 * 3); + tmp = (AnlogicBitParser::reverseByte(rx[1]>>1)) | (0x01 & rx[2]); + 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); + + if (count == timeout) { + printf("%02x\n", tmp); + std::cout << "wait: Error" << std::endl; + return -ETIME; + } + + return 0; +} diff --git a/src/anlogic.hpp b/src/anlogic.hpp index 753e8e4..25924ff 100644 --- a/src/anlogic.hpp +++ b/src/anlogic.hpp @@ -23,16 +23,25 @@ #include "bitparser.hpp" #include "device.hpp" #include "jtag.hpp" +#include "spiInterface.hpp" #include "svf_jtag.hpp" -class Anlogic: public Device { +class Anlogic: public Device, SPIInterface { public: - Anlogic(Jtag *jtag, const std::string &filename, bool verbose); + Anlogic(Jtag *jtag, const std::string &filename, + bool flash_wr, bool sram_wr, bool verbose); ~Anlogic(); 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: SVF_jtag _svf; };