openFPGALoader/src/lattice.cpp

822 lines
18 KiB
C++
Raw Normal View History

/*
* Copyright (C) 2019 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include "jtag.hpp"
#include "lattice.hpp"
#include "progressBar.hpp"
2019-11-20 07:51:48 +01:00
#include "display.hpp"
using namespace std;
#define ISC_ENABLE 0xc6
# define ISC_ENABLE_FLASH_MODE (1 << 3)
# define ISC_ENABLE_SRAM_MODE (0 << 3)
#define ISC_DISABLE 0x26
#define READ_DEVICE_ID_CODE 0xE0
#define FLASH_ERASE 0x0E
# define FLASH_ERASE_UFM (1<<3)
# define FLASH_ERASE_CFG (1<<2)
# define FLASH_ERASE_FEATURE (1<<1)
# define FLASH_ERASE_SRAM (1<<0)
# define FLASH_ERASE_ALL 0x0F
#define CHECK_BUSY_FLAG 0xF0
# define CHECK_BUSY_FLAG_BUSY (1 << 7)
#define RESET_CFG_ADDR 0x46
#define PROG_CFG_FLASH 0x70
#define PROG_FEATURE_ROW 0xE4
#define PROG_FEABITS 0xF8
#define PROG_DONE 0x5E
#define REFRESH 0x79
#define READ_FEATURE_ROW 0xE7
#define READ_FEABITS 0xFB
#define READ_STATUS_REGISTER 0x3C
# define REG_STATUS_DONE (1 << 8)
# define REG_STATUS_ISC_EN (1 << 9)
# define REG_STATUS_BUSY (1 << 12)
# define REG_STATUS_FAIL (1 << 13)
# define REG_STATUS_CNF_CHK_MASK (0x7 << 23)
# define REG_STATUS_EXEC_ERR (1 << 26)
Lattice::Lattice(Jtag *jtag, const string filename, bool verbose):
2019-11-21 08:38:45 +01:00
Device(jtag, filename, verbose)
{
if (_filename != "") {
if (_file_extension == "jed") {
_mode = Device::FLASH_MODE;
} else if (_file_extension == "bit") {
_mode = Device::MEM_MODE;
} else {
throw std::exception();
}
}
}
void displayFeabits(uint16_t _featbits)
{
uint8_t boot_sequence = (_featbits >> 12) & 0x03;
uint8_t m = (_featbits >> 11) & 0x01;
printf("\tboot mode :");
switch (boot_sequence) {
case 0:
if (m != 0x01)
printf(" Single Boot from NVCM/Flash\n");
else
printf(" Dual Boot from NVCM/Flash then External if there is a failure\n");
break;
case 1:
if (m == 0x01)
printf(" Single Boot from External Flash\n");
else
printf(" Error!\n");
break;
default:
printf(" Error!\n");
}
printf("\tMaster Mode SPI : %s\n",
(((_featbits>>11)&0x01)?"enable":"disable"));
printf("\tI2c port : %s\n",
(((_featbits>>10)&0x01)?"disable":"enable"));
printf("\tSlave SPI port : %s\n",
(((_featbits>>9)&0x01)?"disable":"enable"));
printf("\tJTAG port : %s\n",
(((_featbits>>8)&0x01)?"disable":"enable"));
printf("\tDONE : %s\n",
(((_featbits>>7)&0x01)?"enable":"disable"));
printf("\tINITN : %s\n",
(((_featbits>>6)&0x01)?"enable":"disable"));
printf("\tPROGRAMN : %s\n",
(((_featbits>>5)&0x01)?"disable":"enable"));
printf("\tMy_ASSP : %s\n",
(((_featbits>>4)&0x01)?"enable":"disable"));
printf("\tPassword (Flash Protect Key) Protect All : %s\n",
(((_featbits>>3)&0x01)?"Enaabled" : "Disabled"));
printf("\tPassword (Flash Protect Key) Protect : %s\n",
(((_featbits>>2)&0x01)?"Enabled" : "Disabled"));
}
bool Lattice::checkStatus(uint32_t val, uint32_t mask)
{
uint32_t reg = readStatusReg();
return ((reg & mask) == val) ? true : false;
}
bool Lattice::program_mem()
{
bool err;
LatticeBitParser _bit(_filename, _verbose);
printInfo("Open file " + _filename + " ", false);
printSuccess("DONE");
err = _bit.parse();
printInfo("Parse file ", false);
if (err == EXIT_FAILURE) {
printError("FAIL");
return false;
} else {
printSuccess("DONE");
}
if (_verbose)
_bit.displayHeader();
/* read ID Code 0xE0 */
if (_verbose) {
printf("IDCode : %x\n", idCode());
displayReadReg(readStatusReg());
}
/* preload 0x1C */
uint8_t tx_buf[26];
memset(tx_buf, 0xff, 26);
wr_rd(0x1C, tx_buf, 26, NULL, 0);
wr_rd(0xFf, NULL, 0, NULL, 0);
/* ISC Enable 0xC6 */
printInfo("Enable configuration: ", false);
if (!EnableISC(0x00)) {
printError("FAIL");
displayReadReg(readStatusReg());
return false;
} else {
printSuccess("DONE");
}
/* ISC ERASE */
printInfo("SRAM erase: ", false);
if (flashErase(FLASH_ERASE_SRAM) == false) {
printError("FAIL");
displayReadReg(readStatusReg());
return false;
} else {
printSuccess("DONE");
}
/* LSC_INIT_ADDRESS */
wr_rd(0x46, NULL, 0, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
uint8_t *data = _bit.getData();
int length = _bit.getLength()/8;
wr_rd(0x7A, NULL, 0, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(2);
uint8_t tmp[1024];
int size = 1024;
ProgressBar progress("Loading", length, 50);
for (int i = 0; i < length; i += size) {
progress.display(i);
if (length < i + size)
size = length-i;
for (int ii = 0; ii < size; ii++)
tmp[ii] = ConfigBitstreamParser::reverseByte(data[i+ii]);
_jtag->shiftDR(tmp, NULL, size*8, Jtag::SHIFT_DR);
}
_jtag->set_state(Jtag::RUN_TEST_IDLE);
if (checkStatus(0, REG_STATUS_CNF_CHK_MASK))
progress.done();
else {
progress.fail();
displayReadReg(readStatusReg());
return false;
}
wr_rd(0xff, NULL, 0, NULL, 0);
if (_verbose)
printf("userCode: %08x\n", userCode());
/* bypass */
wr_rd(0xff, NULL, 0, NULL, 0);
/* disable configuration mode */
printInfo("Disable configuration: ", false);
if (!DisableISC()) {
printError("FAIL");
displayReadReg(readStatusReg());
return false;
} else {
printSuccess("DONE");
}
if (_verbose)
displayReadReg(readStatusReg());
/* bypass */
wr_rd(0xff, NULL, 0, NULL, 0);
_jtag->go_test_logic_reset();
return true;
}
bool Lattice::program_flash()
{
bool err;
uint64_t featuresRow;
uint16_t feabits;
uint8_t eraseMode;
vector<string> ufm_data, cfg_data;
2019-11-21 08:38:45 +01:00
JedParser _jed(_filename, _verbose);
printInfo("Open file " + _filename + " ", false);
printSuccess("DONE");
err = _jed.parse();
printInfo("Parse file ", false);
if (err == EXIT_FAILURE) {
2019-11-21 08:38:45 +01:00
printError("FAIL");
return false;
2019-11-21 08:38:45 +01:00
} else {
printSuccess("DONE");
}
/* read ID Code 0xE0 */
if (_verbose) {
2019-11-21 08:38:45 +01:00
printf("IDCode : %x\n", idCode());
displayReadReg(readStatusReg());
}
/* preload 0x1C */
uint8_t tx_buf[26];
memset(tx_buf, 0xff, 26);
wr_rd(0x1C, tx_buf, 26, NULL, 0);
wr_rd(0xFf, NULL, 0, NULL, 0);
/* ISC Enable 0xC6 */
2019-11-20 07:51:48 +01:00
printInfo("Enable configuration: ", false);
if (!EnableISC(0x00)) {
printError("FAIL");
displayReadReg(readStatusReg());
return false;
} else {
2019-11-20 07:51:48 +01:00
printSuccess("DONE");
}
/* ISC ERASE */
2019-11-20 07:51:48 +01:00
printInfo("SRAM erase: ", false);
if (flashErase(FLASH_ERASE_SRAM) == false) {
2019-11-20 07:51:48 +01:00
printError("FAIL");
displayReadReg(readStatusReg());
return false;
} else {
2019-11-20 07:51:48 +01:00
printSuccess("DONE");
}
/* bypass */
wr_rd(0xff, NULL, 0, NULL, 0);
/* ISC Enable 0xC6 followed by 0x08 */
2019-11-20 07:51:48 +01:00
printInfo("Enable configuration: ", false);
if (!EnableISC(0x08)) {
2019-11-20 07:51:48 +01:00
printError("FAIL");
displayReadReg(readStatusReg());
return false;
} else {
2019-11-20 07:51:48 +01:00
printSuccess("DONE");
}
for (size_t i = 0; i < _jed.nb_section(); i++) {
string note = _jed.noteForSection(i);
if (note == "TAG DATA") {
eraseMode |= FLASH_ERASE_UFM;
ufm_data = _jed.data_for_section(i);
} else if (note == "END CONFIG DATA") {
continue;
} else {
cfg_data = _jed.data_for_section(i);
}
}
/* check if feature area must be updated */
featuresRow = _jed.featuresRow();
feabits = _jed.feabits();
eraseMode = FLASH_ERASE_CFG;
if (featuresRow != readFeaturesRow() || feabits != readFeabits())
eraseMode |= FLASH_ERASE_FEATURE;
/* ISC ERASE */
2019-11-20 07:51:48 +01:00
printInfo("Flash erase: ", false);
if (flashErase(eraseMode) == false) {
2019-11-20 07:51:48 +01:00
printError("FAIL");
return false;
} else {
2019-11-20 07:51:48 +01:00
printSuccess("DONE");
}
/* LSC_INIT_ADDRESS */
wr_rd(0x46, NULL, 0, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
/* flash UFM */
if (false == flashProg(0, cfg_data))
return false;
if (Verify(_jed) == false)
return false;
/* missing usercode update */
/* LSC_INIT_ADDRESS */
wr_rd(0x46, NULL, 0, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
if ((eraseMode & FLASH_ERASE_FEATURE) != 0) {
/* write feature row */
printInfo("Program features Row: ", false);
if (writeFeaturesRow(_jed.featuresRow(), true) == false) {
printError("FAIL");
return false;
} else {
printSuccess("DONE");
}
/* write feabits */
printInfo("Program feabits: ", false);
if (writeFeabits(_jed.feabits(), true) == false) {
printError("FAIL");
return false;
} else {
printSuccess("DONE");
}
}
/* ISC program done 0x5E */
2019-11-20 07:51:48 +01:00
printInfo("Write program Done: ", false);
if (writeProgramDone() == false) {
2019-11-20 07:51:48 +01:00
printError("FAIL");
return false;
} else {
2019-11-20 07:51:48 +01:00
printSuccess("DONE");
}
/* bypass */
wr_rd(0xff, NULL, 0, NULL, 0);
/* disable configuration mode */
2019-11-20 07:51:48 +01:00
printInfo("Disable configuration: ", false);
if (!DisableISC()) {
2019-11-20 07:51:48 +01:00
printError("FAIL");
return false;
} else {
2019-11-20 07:51:48 +01:00
printSuccess("DONE");
}
/* ISC REFRESH 0x79 */
2019-11-20 07:51:48 +01:00
printInfo("Refresh: ", false);
if (loadConfiguration() == false) {
2019-11-20 07:51:48 +01:00
printError("FAIL");
return false;
} else {
2019-11-20 07:51:48 +01:00
printSuccess("DONE");
}
/* bypass */
wr_rd(0xff, NULL, 0, NULL, 0);
_jtag->go_test_logic_reset();
return true;
}
void Lattice::program(unsigned int offset)
{
(void) offset;
if (_mode == FLASH_MODE)
program_flash();
else if (_mode == MEM_MODE)
program_mem();
}
bool Lattice::EnableISC(uint8_t flash_mode)
{
wr_rd(ISC_ENABLE, &flash_mode, 1, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
if (!pollBusyFlag())
return false;
if (!checkStatus(REG_STATUS_ISC_EN, REG_STATUS_ISC_EN))
return false;
return true;
}
bool Lattice::DisableISC()
{
wr_rd(ISC_DISABLE, NULL, 0, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
if (!pollBusyFlag())
return false;
if (!checkStatus(0, REG_STATUS_ISC_EN))
return false;
return true;
}
bool Lattice::EnableCfgIf()
{
uint8_t tx_buf = 0x08;
wr_rd(0x74, &tx_buf, 1, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
return pollBusyFlag();
}
bool Lattice::DisableCfg()
{
uint8_t tx_buf, rx_buf;
wr_rd(0x26, &tx_buf, 1, &rx_buf, 1);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
return true;
}
int Lattice::idCode()
{
uint8_t device_id[4];
wr_rd(READ_DEVICE_ID_CODE, NULL, 0, device_id, 4);
return device_id[3] << 24 |
device_id[2] << 16 |
device_id[1] << 8 |
device_id[0];
}
int Lattice::userCode()
{
uint8_t usercode[4];
wr_rd(0xC0, NULL, 0, usercode, 4);
return usercode[3] << 24 |
usercode[2] << 16 |
usercode[1] << 8 |
usercode[0];
}
bool Lattice::checkID()
{
printf("\n");
printf("check ID\n");
uint8_t tx[4];
wr_rd(0xE2, tx, 4, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
uint32_t reg = readStatusReg();
displayReadReg(reg);
tx[3] = 0x61;
tx[2] = 0x2b;
tx[1] = 0xd0;
tx[0] = 0x43;
wr_rd(0xE2, tx, 4, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
reg = readStatusReg();
displayReadReg(reg);
printf("%08x\n", reg);
printf("\n");
return true;
}
/* feabits is MSB first
* maybe this register too
* or not
*/
uint32_t Lattice::readStatusReg()
{
uint32_t reg;
uint8_t rx[4], tx[4];
wr_rd(0x3C, tx, 4, rx, 4);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
reg = rx[3] << 24 | rx[2] << 16 | rx[1] << 8 | rx[0];
return reg;
}
bool Lattice::wr_rd(uint8_t cmd,
uint8_t *tx, int tx_len,
uint8_t *rx, int rx_len,
bool verbose)
{
int xfer_len = rx_len;
if (tx_len > rx_len)
xfer_len = tx_len;
uint8_t xfer_tx[xfer_len];
uint8_t xfer_rx[xfer_len];
bzero(xfer_tx, xfer_len);
int i;
if (tx != NULL) {
for (i = 0; i < tx_len; i++)
xfer_tx[i] = tx[i];
}
_jtag->shiftIR(&cmd, NULL, 8, Jtag::PAUSE_IR);
if (rx || tx) {
_jtag->shiftDR(xfer_tx, (rx) ? xfer_rx : NULL, 8 * xfer_len,
Jtag::PAUSE_DR);
}
if (rx) {
if (verbose) {
for (i=xfer_len-1; i >= 0; i--)
printf("%02x ", xfer_rx[i]);
printf("\n");
}
for (i = 0; i < rx_len; i++)
rx[i] = (xfer_rx[i]);
}
return true;
}
void Lattice::displayReadReg(uint32_t dev)
{
printf("displayReadReg\n");
if (dev & 1<<0)
printf("\tTRAN Mode\n");
printf("\tConfig Target Selection : %x\n", (dev >> 1) & 0x07);
if (dev & 1<<4)
printf("\tJTAG Active\n");
if (dev & 1<<5)
printf("\tPWD Protect\n");
if (dev & 1<<6)
printf("\tOTP\n");
if (dev & 1<<7)
printf("\tDecrypt Enable\n");
if (dev & REG_STATUS_DONE)
printf("\tDone Flag\n");
if (dev & REG_STATUS_ISC_EN)
printf("\tISC Enable\n");
if (dev & 1 << 10)
printf("\tWrite Enable\n");
if (dev & 1 << 11)
printf("\tRead Enable\n");
if (dev & REG_STATUS_BUSY)
printf("\tBusy Flag\n");
if (dev & REG_STATUS_FAIL)
printf("\tFail Flag\n");
if (dev & 1 << 14)
printf("\tFFEA OTP\n");
if (dev & 1 << 15)
printf("\tDecrypt Only\n");
if (dev & 1 << 16)
printf("\tPWD Enable\n");
if (dev & 1 << 17)
printf("\tUFM OTP\n");
if (dev & 1 << 18)
printf("\tASSP\n");
if (dev & 1 << 19)
printf("\tSDM Enable\n");
if (dev & 1 << 20)
printf("\tEncryption PreAmble\n");
if (dev & 1 << 21)
printf("\tStd PreAmble\n");
if (dev & 1 << 22)
printf("\tSPIm Fail1\n");
uint8_t err = (dev >> 23)&0x07;
printf("\t");
switch (err) {
case 0:
printf("No err\n");
break;
case 1:
printf("ID ERR\n");
break;
case 2:
printf("CMD ERR\n");
break;
case 3:
printf("CRC ERR\n");
break;
case 4:
printf("Preamble ERR\n");
break;
case 5:
printf("Abort ERR\n");
break;
case 6:
printf("Overflow ERR\n");
break;
case 7:
printf("SDM EOF\n");
break;
default:
printf("unknown %x\n", err);
}
if (dev & REG_STATUS_EXEC_ERR)
printf("\tEXEC Error\n");
if (dev & 1 << 27)
printf("\tDevice failed to verify\n");
if (dev & 1 << 28)
printf("\tInvalid Command\n");
if (dev & 1 << 29) printf("\tSED Error\n");
if (dev & 1 << 30) printf("\tBypass Mode\n");
if (dev & ((uint32_t)1 << 31)) printf("\tFT Mode\n");
}
bool Lattice::pollBusyFlag(bool verbose)
{
uint8_t rx;
int timeout = 0;
do {
wr_rd(CHECK_BUSY_FLAG, NULL, 0, &rx, 1);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
if (verbose)
printf("pollBusyFlag :%02x\n", rx);
if (timeout == 100000000){
cerr << "timeout" << endl;
return false;
} else {
timeout++;
}
} while (rx != 0);
return true;
}
bool Lattice::flashEraseAll()
{
return flashErase(0xf);
}
bool Lattice::flashErase(uint8_t mask)
{
uint8_t tx[1] = {mask};
wr_rd(FLASH_ERASE, tx, 1, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
if (!pollBusyFlag())
return false;
if (!checkStatus(0, REG_STATUS_FAIL))
return false;
return true;
}
bool Lattice::flashProg(uint32_t start_addr, std::vector<std::string> data)
{
(void)start_addr;
ProgressBar progress("Writing", data.size(), 50);
for (uint32_t line = 0; line < data.size(); line++) {
wr_rd(PROG_CFG_FLASH, (uint8_t *)data[line].c_str(),
16, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
progress.display(line);
if (pollBusyFlag() == false)
return false;
}
progress.done();
return true;
}
bool Lattice::Verify(JedParser &_jed, bool unlock)
{
uint8_t tx_buf[16], rx_buf[16];
if (unlock)
EnableISC(0x08);
wr_rd(0x46, NULL, 0, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
tx_buf[0] = 0x73;
_jtag->shiftIR(tx_buf, NULL, 8, Jtag::PAUSE_IR);
bzero(tx_buf, 16);
bool failure = false;
vector<string> data = _jed.data_for_section(0);
ProgressBar progress("Verifying", data.size(), 50);
for (size_t line = 0; line< data.size(); line++) {
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(2);
_jtag->shiftDR(tx_buf, rx_buf, 16*8, Jtag::PAUSE_DR);
for (size_t i = 0; i < data[i].size(); i++) {
if (rx_buf[i] != (unsigned char)data[line][i]) {
printf("%3ld %3ld %02x -> %02x\n", line, i,
rx_buf[i], (unsigned char)data[line][i]);
failure = true;
}
}
if (failure) {
printf("Verify Failure\n");
break;
}
progress.display(line);
}
if (unlock)
DisableISC();
progress.done();
return true;
}
uint64_t Lattice::readFeaturesRow()
{
uint8_t tx_buf[8];
uint8_t rx_buf[8];
uint64_t reg = 0;
bzero(tx_buf, 8);
wr_rd(READ_FEATURE_ROW, tx_buf, 8, rx_buf, 8);
for (int i = 0; i < 8; i++)
reg |= ((uint64_t)rx_buf[i] << (i*8));
return reg;
}
uint16_t Lattice::readFeabits()
{
uint8_t rx_buf[2];
wr_rd(READ_FEABITS, NULL, 0, rx_buf, 2);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
return rx_buf[0] | (((uint16_t)rx_buf[1]) << 8);
}
bool Lattice::writeFeaturesRow(uint64_t features, bool verify)
{
uint8_t tx_buf[8];
for (int i=0; i < 8; i++)
tx_buf[i] = ((features >> (i*8)) & 0x00ff);
wr_rd(PROG_FEATURE_ROW, tx_buf, 8, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
if (!pollBusyFlag())
return false;
if (verify)
return (features == readFeaturesRow()) ? true : false;
return true;
}
bool Lattice::writeFeabits(uint16_t feabits, bool verify)
{
uint8_t tx_buf[2] = {(uint8_t)(feabits&0x00ff),
(uint8_t)(0x00ff & (feabits>>8))};
wr_rd(PROG_FEABITS, tx_buf, 2, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
if (!pollBusyFlag())
return false;
if (verify)
return (feabits == readFeabits()) ? true : false;
return true;
}
bool Lattice::writeProgramDone()
{
wr_rd(PROG_DONE, NULL, 0, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
if (!pollBusyFlag())
return false;
if (!checkStatus(REG_STATUS_DONE, REG_STATUS_DONE))
return false;
return true;
}
bool Lattice::loadConfiguration()
{
wr_rd(REFRESH, NULL, 0, NULL, 0);
_jtag->set_state(Jtag::RUN_TEST_IDLE);
_jtag->toggleClk(1000);
if (!pollBusyFlag())
return false;
if (!checkStatus(REG_STATUS_DONE, REG_STATUS_DONE))
return false;
return true;
}