2021-06-26 15:24:07 +02:00
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
2019-11-18 16:03:59 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2019 Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <strings.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
2021-02-21 18:30:13 +01:00
|
|
|
#include <stdexcept>
|
2019-11-18 16:03:59 +01:00
|
|
|
|
2020-03-06 09:05:57 +01:00
|
|
|
#include "jtag.hpp"
|
2019-11-18 16:03:59 +01:00
|
|
|
#include "lattice.hpp"
|
2020-05-19 07:59:19 +02:00
|
|
|
#include "latticeBitParser.hpp"
|
|
|
|
|
#include "mcsParser.hpp"
|
2019-11-18 16:03:59 +01:00
|
|
|
#include "progressBar.hpp"
|
2020-09-05 07:55:20 +02:00
|
|
|
#include "rawParser.hpp"
|
2019-11-20 07:51:48 +01:00
|
|
|
#include "display.hpp"
|
2020-09-26 08:40:43 +02:00
|
|
|
#include "part.hpp"
|
2020-04-22 15:21:01 +02:00
|
|
|
#include "spiFlash.hpp"
|
2019-11-18 16:03:59 +01:00
|
|
|
|
|
|
|
|
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
|
2020-04-27 16:37:05 +02:00
|
|
|
#define REG_CFG_FLASH 0x73
|
2019-11-18 16:03:59 +01:00
|
|
|
#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
|
2019-11-20 07:30:54 +01:00
|
|
|
# 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)
|
2019-12-20 09:09:38 +01:00
|
|
|
# define REG_STATUS_CNF_CHK_MASK (0x7 << 23)
|
2019-11-20 07:30:54 +01:00
|
|
|
# define REG_STATUS_EXEC_ERR (1 << 26)
|
2019-11-18 16:03:59 +01:00
|
|
|
|
2021-02-21 18:30:13 +01:00
|
|
|
Lattice::Lattice(Jtag *jtag, const string filename, const string &file_type,
|
2021-06-24 18:06:48 +02:00
|
|
|
Device::prog_type_t prg_type, bool verify, int8_t verbose):
|
|
|
|
|
Device(jtag, filename, file_type, verify, verbose),
|
|
|
|
|
_fpga_family(UNKNOWN_FAMILY)
|
2019-11-18 16:03:59 +01:00
|
|
|
{
|
2021-06-24 18:19:09 +02:00
|
|
|
if (prg_type == Device::RD_FLASH) {
|
|
|
|
|
_mode = READ_MODE;
|
|
|
|
|
} else if (!_file_extension.empty()) {
|
2020-05-19 07:59:19 +02:00
|
|
|
if (_file_extension == "jed" || _file_extension == "mcs") {
|
2019-11-18 16:03:59 +01:00
|
|
|
_mode = Device::FLASH_MODE;
|
2021-02-27 06:49:42 +01:00
|
|
|
} else if (_file_extension == "bit" || _file_extension == "bin") {
|
2021-02-18 21:09:34 +01:00
|
|
|
if (prg_type == Device::WR_FLASH)
|
2020-04-22 15:21:01 +02:00
|
|
|
_mode = Device::FLASH_MODE;
|
|
|
|
|
else
|
|
|
|
|
_mode = Device::MEM_MODE;
|
2019-12-20 09:09:38 +01:00
|
|
|
} else {
|
2021-02-21 18:30:13 +01:00
|
|
|
throw std::runtime_error("incompatible file format");
|
2019-12-20 09:09:38 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-26 08:40:43 +02:00
|
|
|
/* check device family */
|
|
|
|
|
uint32_t idcode = idCode();
|
|
|
|
|
string family = fpga_list[idcode].family;
|
|
|
|
|
if (family == "MachXO2")
|
|
|
|
|
_fpga_family = MACHXO2_FAMILY;
|
2020-09-29 16:13:54 +02:00
|
|
|
else if (family == "MachXO3LF")
|
2020-09-26 08:40:43 +02:00
|
|
|
_fpga_family = MACHXO3_FAMILY;
|
2020-10-16 08:03:45 +02:00
|
|
|
else if (family == "MachXO3D")
|
|
|
|
|
_fpga_family = MACHXO3D_FAMILY;
|
2020-09-26 08:40:43 +02:00
|
|
|
else if (family == "ECP5")
|
|
|
|
|
_fpga_family = ECP5_FAMILY;
|
|
|
|
|
else if (family == "CrosslinkNX")
|
|
|
|
|
_fpga_family = NEXUS_FAMILY;
|
|
|
|
|
else if (family == "CertusNX")
|
|
|
|
|
_fpga_family = NEXUS_FAMILY;
|
|
|
|
|
else {
|
|
|
|
|
printError("Unknown device family");
|
|
|
|
|
throw std::exception();
|
|
|
|
|
}
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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"));
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 07:30:54 +01:00
|
|
|
bool Lattice::checkStatus(uint32_t val, uint32_t mask)
|
|
|
|
|
{
|
|
|
|
|
uint32_t reg = readStatusReg();
|
|
|
|
|
|
|
|
|
|
return ((reg & mask) == val) ? true : false;
|
|
|
|
|
}
|
2019-11-18 16:03:59 +01:00
|
|
|
|
2019-12-20 09:09:38 +01:00
|
|
|
bool Lattice::program_mem()
|
|
|
|
|
{
|
|
|
|
|
bool err;
|
|
|
|
|
LatticeBitParser _bit(_filename, _verbose);
|
|
|
|
|
|
2021-02-21 18:30:13 +01:00
|
|
|
printInfo("Open file ", false);
|
2019-12-20 09:09:38 +01:00
|
|
|
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);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-12-20 09:09:38 +01:00
|
|
|
_jtag->toggleClk(1000);
|
|
|
|
|
|
|
|
|
|
uint8_t *data = _bit.getData();
|
|
|
|
|
int length = _bit.getLength()/8;
|
|
|
|
|
wr_rd(0x7A, NULL, 0, NULL, 0);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-12-20 09:09:38 +01:00
|
|
|
_jtag->toggleClk(2);
|
|
|
|
|
|
|
|
|
|
uint8_t tmp[1024];
|
|
|
|
|
int size = 1024;
|
2021-06-12 09:27:16 +02:00
|
|
|
int next_state = Jtag::SHIFT_DR;
|
2019-12-20 09:09:38 +01:00
|
|
|
|
2021-01-30 07:57:49 +01:00
|
|
|
ProgressBar progress("Loading", length, 50, _quiet);
|
2019-12-20 09:09:38 +01:00
|
|
|
|
|
|
|
|
for (int i = 0; i < length; i += size) {
|
|
|
|
|
progress.display(i);
|
|
|
|
|
|
2021-06-12 09:27:16 +02:00
|
|
|
if (length < i + size) {
|
2019-12-20 09:09:38 +01:00
|
|
|
size = length-i;
|
2021-06-12 09:27:16 +02:00
|
|
|
next_state = Jtag::RUN_TEST_IDLE;
|
|
|
|
|
}
|
2019-12-20 09:09:38 +01:00
|
|
|
|
|
|
|
|
for (int ii = 0; ii < size; ii++)
|
|
|
|
|
tmp[ii] = ConfigBitstreamParser::reverseByte(data[i+ii]);
|
|
|
|
|
|
2021-06-12 09:27:16 +02:00
|
|
|
_jtag->shiftDR(tmp, NULL, size*8, next_state);
|
2019-12-20 09:09:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (checkStatus(0, REG_STATUS_CNF_CHK_MASK))
|
|
|
|
|
progress.done();
|
|
|
|
|
else {
|
|
|
|
|
progress.fail();
|
2019-12-22 08:17:01 +01:00
|
|
|
displayReadReg(readStatusReg());
|
2019-12-20 09:09:38 +01:00
|
|
|
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");
|
2019-12-22 08:17:01 +01:00
|
|
|
displayReadReg(readStatusReg());
|
2019-12-20 09:09:38 +01:00
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
printSuccess("DONE");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_verbose)
|
|
|
|
|
displayReadReg(readStatusReg());
|
|
|
|
|
|
|
|
|
|
/* bypass */
|
|
|
|
|
wr_rd(0xff, NULL, 0, NULL, 0);
|
|
|
|
|
_jtag->go_test_logic_reset();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-22 15:21:01 +02:00
|
|
|
bool Lattice::program_intFlash()
|
2019-11-18 16:03:59 +01:00
|
|
|
{
|
2019-12-20 09:09:38 +01:00
|
|
|
bool err;
|
2019-11-20 20:42:52 +01:00
|
|
|
uint64_t featuresRow;
|
|
|
|
|
uint16_t feabits;
|
2021-02-21 18:30:13 +01:00
|
|
|
uint8_t eraseMode = 0;
|
2020-05-02 09:47:41 +02:00
|
|
|
vector<string> ufm_data, cfg_data, ebr_data;
|
2019-11-18 16:03:59 +01:00
|
|
|
|
2019-11-21 08:38:45 +01:00
|
|
|
JedParser _jed(_filename, _verbose);
|
|
|
|
|
|
2021-02-21 18:30:13 +01:00
|
|
|
printInfo("Open file ", false);
|
2019-11-21 08:38:45 +01:00
|
|
|
printSuccess("DONE");
|
|
|
|
|
|
2019-12-20 09:09:38 +01:00
|
|
|
err = _jed.parse();
|
|
|
|
|
|
|
|
|
|
printInfo("Parse file ", false);
|
|
|
|
|
if (err == EXIT_FAILURE) {
|
2019-11-21 08:38:45 +01:00
|
|
|
printError("FAIL");
|
2019-12-20 09:09:38 +01:00
|
|
|
return false;
|
2019-11-21 08:38:45 +01:00
|
|
|
} else {
|
|
|
|
|
printSuccess("DONE");
|
|
|
|
|
}
|
2019-11-18 16:03:59 +01:00
|
|
|
|
2021-02-24 06:36:48 +01:00
|
|
|
if (_verbose)
|
|
|
|
|
_jed.displayHeader();
|
|
|
|
|
|
2019-11-18 16:03:59 +01:00
|
|
|
/* bypass */
|
|
|
|
|
wr_rd(0xff, NULL, 0, NULL, 0);
|
2020-04-27 16:37:05 +02:00
|
|
|
/* ISC Enable 0xC6 followed by
|
|
|
|
|
* 0x08 (Enable nVCM/Flash Normal mode */
|
2019-11-20 07:51:48 +01:00
|
|
|
printInfo("Enable configuration: ", false);
|
2019-11-20 07:30:54 +01:00
|
|
|
if (!EnableISC(0x08)) {
|
2019-11-20 07:51:48 +01:00
|
|
|
printError("FAIL");
|
2019-11-20 07:30:54 +01:00
|
|
|
displayReadReg(readStatusReg());
|
2019-12-20 09:09:38 +01:00
|
|
|
return false;
|
2019-11-20 07:30:54 +01:00
|
|
|
} else {
|
2019-11-20 07:51:48 +01:00
|
|
|
printSuccess("DONE");
|
2019-11-20 07:30:54 +01:00
|
|
|
}
|
2019-11-20 20:42:52 +01:00
|
|
|
|
|
|
|
|
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;
|
2020-05-02 09:47:41 +02:00
|
|
|
} else if (note == "EBR_INIT DATA") {
|
|
|
|
|
ebr_data = _jed.data_for_section(i);
|
2019-11-20 20:42:52 +01:00
|
|
|
} 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;
|
|
|
|
|
|
2019-11-18 16:03:59 +01:00
|
|
|
/* ISC ERASE */
|
2019-11-20 07:51:48 +01:00
|
|
|
printInfo("Flash erase: ", false);
|
2019-11-20 20:42:52 +01:00
|
|
|
if (flashErase(eraseMode) == false) {
|
2019-11-20 07:51:48 +01:00
|
|
|
printError("FAIL");
|
2019-12-20 09:09:38 +01:00
|
|
|
return false;
|
2019-11-20 07:30:54 +01:00
|
|
|
} else {
|
2019-11-20 07:51:48 +01:00
|
|
|
printSuccess("DONE");
|
2019-11-20 07:30:54 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-18 16:03:59 +01:00
|
|
|
/* LSC_INIT_ADDRESS */
|
|
|
|
|
wr_rd(0x46, NULL, 0, NULL, 0);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
|
|
|
|
|
2020-04-27 16:37:05 +02:00
|
|
|
/* flash CfgFlash */
|
2020-05-02 09:47:41 +02:00
|
|
|
if (false == flashProg(0, "data", cfg_data))
|
2019-12-20 09:09:38 +01:00
|
|
|
return false;
|
2020-05-02 09:47:41 +02:00
|
|
|
|
|
|
|
|
/* flash EBR Init */
|
|
|
|
|
if (ebr_data.size()) {
|
|
|
|
|
if (false == flashProg(0, "EBR", ebr_data))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-04-27 16:37:05 +02:00
|
|
|
/* verify write */
|
2021-06-24 18:06:48 +02:00
|
|
|
if (_verify) {
|
|
|
|
|
if (Verify(cfg_data) == false)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-11-18 16:03:59 +01:00
|
|
|
|
2019-11-20 07:30:54 +01:00
|
|
|
/* missing usercode update */
|
|
|
|
|
|
2019-11-18 16:03:59 +01:00
|
|
|
/* LSC_INIT_ADDRESS */
|
|
|
|
|
wr_rd(0x46, NULL, 0, NULL, 0);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
2019-11-20 20:42:52 +01:00
|
|
|
|
|
|
|
|
if ((eraseMode & FLASH_ERASE_FEATURE) != 0) {
|
|
|
|
|
/* write feature row */
|
|
|
|
|
printInfo("Program features Row: ", false);
|
|
|
|
|
if (writeFeaturesRow(_jed.featuresRow(), true) == false) {
|
|
|
|
|
printError("FAIL");
|
2019-12-20 09:09:38 +01:00
|
|
|
return false;
|
2019-11-20 20:42:52 +01:00
|
|
|
} else {
|
|
|
|
|
printSuccess("DONE");
|
|
|
|
|
}
|
|
|
|
|
/* write feabits */
|
|
|
|
|
printInfo("Program feabits: ", false);
|
|
|
|
|
if (writeFeabits(_jed.feabits(), true) == false) {
|
|
|
|
|
printError("FAIL");
|
2019-12-20 09:09:38 +01:00
|
|
|
return false;
|
2019-11-20 20:42:52 +01:00
|
|
|
} else {
|
|
|
|
|
printSuccess("DONE");
|
|
|
|
|
}
|
2019-11-20 07:30:54 +01:00
|
|
|
}
|
2019-11-20 20:42:52 +01:00
|
|
|
|
2019-11-18 16:03:59 +01:00
|
|
|
/* ISC program done 0x5E */
|
2019-11-20 07:51:48 +01:00
|
|
|
printInfo("Write program Done: ", false);
|
2019-11-18 16:03:59 +01:00
|
|
|
if (writeProgramDone() == false) {
|
2019-11-20 07:51:48 +01:00
|
|
|
printError("FAIL");
|
2019-12-20 09:09:38 +01:00
|
|
|
return false;
|
2019-11-20 07:30:54 +01:00
|
|
|
} else {
|
2019-11-20 07:51:48 +01:00
|
|
|
printSuccess("DONE");
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
2019-12-20 09:09:38 +01:00
|
|
|
|
2019-11-18 16:03:59 +01:00
|
|
|
/* bypass */
|
|
|
|
|
wr_rd(0xff, NULL, 0, NULL, 0);
|
2019-11-20 07:30:54 +01:00
|
|
|
/* disable configuration mode */
|
2019-11-20 07:51:48 +01:00
|
|
|
printInfo("Disable configuration: ", false);
|
2019-11-20 07:30:54 +01:00
|
|
|
if (!DisableISC()) {
|
2019-11-20 07:51:48 +01:00
|
|
|
printError("FAIL");
|
2019-12-20 09:09:38 +01:00
|
|
|
return false;
|
2019-11-20 07:30:54 +01:00
|
|
|
} else {
|
2019-11-20 07:51:48 +01:00
|
|
|
printSuccess("DONE");
|
2019-11-20 07:30:54 +01:00
|
|
|
}
|
2020-04-22 15:21:01 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Lattice::program_extFlash(unsigned int offset)
|
|
|
|
|
{
|
2020-05-19 07:59:19 +02:00
|
|
|
ConfigBitstreamParser *_bit;
|
|
|
|
|
if (_file_extension == "mcs")
|
|
|
|
|
_bit = new McsParser(_filename, true, _verbose);
|
2020-09-05 07:55:20 +02:00
|
|
|
else if (_file_extension == "bit")
|
2020-05-19 07:59:19 +02:00
|
|
|
_bit = new LatticeBitParser(_filename, _verbose);
|
2021-02-27 06:49:42 +01:00
|
|
|
else
|
2020-09-05 07:55:20 +02:00
|
|
|
_bit = new RawParser(_filename, false);
|
2020-04-22 15:21:01 +02:00
|
|
|
|
2021-02-21 18:30:13 +01:00
|
|
|
printInfo("Open file ", false);
|
2020-04-22 15:21:01 +02:00
|
|
|
printSuccess("DONE");
|
|
|
|
|
|
2020-05-19 07:59:19 +02:00
|
|
|
int err = _bit->parse();
|
2020-04-22 15:21:01 +02:00
|
|
|
|
|
|
|
|
printInfo("Parse file ", false);
|
|
|
|
|
if (err == EXIT_FAILURE) {
|
|
|
|
|
printError("FAIL");
|
2021-02-21 18:30:13 +01:00
|
|
|
delete _bit;
|
2020-04-22 15:21:01 +02:00
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
printSuccess("DONE");
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-24 06:36:48 +01:00
|
|
|
if (_verbose)
|
|
|
|
|
_bit->displayHeader();
|
|
|
|
|
|
2020-04-22 15:21:01 +02:00
|
|
|
/*IR = 0h3A, DR=0hFE,0h68. Enter RUNTESTIDLE.
|
|
|
|
|
* thank @GregDavill
|
|
|
|
|
* https://twitter.com/GregDavill/status/1251786406441086977
|
|
|
|
|
*/
|
|
|
|
|
_jtag->shiftIR(0x3A, 8, Jtag::EXIT1_IR);
|
|
|
|
|
uint8_t tmp[2] = {0xFE, 0x68};
|
|
|
|
|
_jtag->shiftDR(tmp, NULL, 16);
|
|
|
|
|
|
2020-05-19 07:59:19 +02:00
|
|
|
uint8_t *data = _bit->getData();
|
|
|
|
|
int length = _bit->getLength()/8;
|
2020-04-22 15:21:01 +02:00
|
|
|
|
|
|
|
|
/* test SPI */
|
|
|
|
|
SPIFlash flash(this, _verbose);
|
|
|
|
|
flash.reset();
|
|
|
|
|
flash.read_id();
|
|
|
|
|
flash.read_status_reg();
|
|
|
|
|
flash.erase_and_prog(offset, data, length);
|
2020-05-19 07:59:19 +02:00
|
|
|
|
2021-07-11 11:34:14 +02:00
|
|
|
int ret = true;
|
|
|
|
|
if (_verify)
|
|
|
|
|
ret = flash.verify(offset, data, length);
|
2021-06-24 18:06:48 +02:00
|
|
|
|
2020-05-19 07:59:19 +02:00
|
|
|
delete _bit;
|
2021-07-11 11:34:14 +02:00
|
|
|
return ret;
|
2020-04-22 15:21:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Lattice::program_flash(unsigned int offset)
|
|
|
|
|
{
|
|
|
|
|
/* 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");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DisableISC();
|
|
|
|
|
|
2021-08-23 16:27:28 +02:00
|
|
|
bool retval;
|
2020-04-22 15:21:01 +02:00
|
|
|
if (_file_extension == "jed")
|
2021-08-23 16:27:28 +02:00
|
|
|
retval = program_intFlash();
|
2020-04-22 15:21:01 +02:00
|
|
|
else
|
2021-08-23 16:27:28 +02:00
|
|
|
retval = program_extFlash(offset);
|
|
|
|
|
|
|
|
|
|
if (!retval)
|
|
|
|
|
return false;
|
2020-04-22 15:21:01 +02:00
|
|
|
|
|
|
|
|
/* *************************** */
|
|
|
|
|
/* reload bitstream from flash */
|
|
|
|
|
/* *************************** */
|
2019-12-20 09:09:38 +01:00
|
|
|
|
|
|
|
|
/* ISC REFRESH 0x79 */
|
2019-11-20 07:51:48 +01:00
|
|
|
printInfo("Refresh: ", false);
|
2019-11-18 16:03:59 +01:00
|
|
|
if (loadConfiguration() == false) {
|
2019-11-20 07:51:48 +01:00
|
|
|
printError("FAIL");
|
2020-04-28 10:00:55 +02:00
|
|
|
displayReadReg(readStatusReg());
|
2019-12-20 09:09:38 +01:00
|
|
|
return false;
|
2019-11-20 07:30:54 +01:00
|
|
|
} else {
|
2019-11-20 07:51:48 +01:00
|
|
|
printSuccess("DONE");
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
2019-12-20 09:09:38 +01:00
|
|
|
|
2019-11-18 16:03:59 +01:00
|
|
|
/* bypass */
|
|
|
|
|
wr_rd(0xff, NULL, 0, NULL, 0);
|
|
|
|
|
_jtag->go_test_logic_reset();
|
2019-12-20 09:09:38 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Lattice::program(unsigned int offset)
|
|
|
|
|
{
|
2021-08-23 16:27:28 +02:00
|
|
|
bool retval;
|
2019-12-20 09:09:38 +01:00
|
|
|
if (_mode == FLASH_MODE)
|
2021-08-23 16:27:28 +02:00
|
|
|
retval = program_flash(offset);
|
2019-12-20 09:09:38 +01:00
|
|
|
else if (_mode == MEM_MODE)
|
2021-08-23 16:27:28 +02:00
|
|
|
retval = program_mem();
|
|
|
|
|
if (!retval)
|
|
|
|
|
throw std::exception();
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
2021-06-24 18:19:09 +02:00
|
|
|
bool Lattice::dumpFlash(const string &filename,
|
|
|
|
|
uint32_t base_addr, uint32_t len)
|
|
|
|
|
{
|
|
|
|
|
/* idem program */
|
|
|
|
|
|
|
|
|
|
/* 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");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DisableISC();
|
|
|
|
|
|
|
|
|
|
/* switch to SPI mode */
|
|
|
|
|
_jtag->shiftIR(0x3A, 8, Jtag::EXIT1_IR);
|
|
|
|
|
uint8_t tmp[2] = {0xFE, 0x68};
|
|
|
|
|
_jtag->shiftDR(tmp, NULL, 16);
|
|
|
|
|
|
|
|
|
|
/* prepare SPI access */
|
|
|
|
|
SPIFlash flash(this, _verbose);
|
|
|
|
|
flash.reset();
|
2021-07-11 11:34:14 +02:00
|
|
|
flash.dump(filename, base_addr, len);
|
2021-06-24 18:19:09 +02:00
|
|
|
|
|
|
|
|
/* ISC REFRESH 0x79 */
|
|
|
|
|
printInfo("Refresh: ", false);
|
|
|
|
|
if (loadConfiguration() == false) {
|
|
|
|
|
printError("FAIL");
|
|
|
|
|
displayReadReg(readStatusReg());
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
printSuccess("DONE");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* bypass */
|
|
|
|
|
wr_rd(0xff, NULL, 0, NULL, 0);
|
|
|
|
|
_jtag->go_test_logic_reset();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-22 15:21:01 +02:00
|
|
|
/* flash mode :
|
|
|
|
|
*/
|
2019-11-18 16:03:59 +01:00
|
|
|
bool Lattice::EnableISC(uint8_t flash_mode)
|
|
|
|
|
{
|
|
|
|
|
wr_rd(ISC_ENABLE, &flash_mode, 1, NULL, 0);
|
|
|
|
|
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
2019-11-20 07:30:54 +01:00
|
|
|
if (!pollBusyFlag())
|
|
|
|
|
return false;
|
|
|
|
|
if (!checkStatus(REG_STATUS_ISC_EN, REG_STATUS_ISC_EN))
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Lattice::DisableISC()
|
|
|
|
|
{
|
|
|
|
|
wr_rd(ISC_DISABLE, NULL, 0, NULL, 0);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
2019-11-20 07:30:54 +01:00
|
|
|
if (!pollBusyFlag())
|
|
|
|
|
return false;
|
|
|
|
|
if (!checkStatus(0, REG_STATUS_ISC_EN))
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Lattice::EnableCfgIf()
|
|
|
|
|
{
|
|
|
|
|
uint8_t tx_buf = 0x08;
|
|
|
|
|
wr_rd(0x74, &tx_buf, 1, NULL, 0);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
|
|
|
|
return pollBusyFlag();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Lattice::DisableCfg()
|
|
|
|
|
{
|
|
|
|
|
uint8_t tx_buf, rx_buf;
|
|
|
|
|
wr_rd(0x26, &tx_buf, 1, &rx_buf, 1);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_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];
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-20 09:09:38 +01:00
|
|
|
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];
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-18 16:03:59 +01:00
|
|
|
bool Lattice::checkID()
|
|
|
|
|
{
|
|
|
|
|
printf("\n");
|
|
|
|
|
printf("check ID\n");
|
|
|
|
|
uint8_t tx[4];
|
|
|
|
|
wr_rd(0xE2, tx, 4, NULL, 0);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_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);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_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];
|
2020-11-27 08:29:09 +01:00
|
|
|
/* valgrind warn */
|
|
|
|
|
memset(tx, 0, 4);
|
2019-11-20 07:30:54 +01:00
|
|
|
wr_rd(0x3C, tx, 4, rx, 4);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_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];
|
2020-07-25 04:55:41 +02:00
|
|
|
memset(xfer_tx, 0, xfer_len);
|
2019-11-18 16:03:59 +01:00
|
|
|
int i;
|
|
|
|
|
if (tx != NULL) {
|
|
|
|
|
for (i = 0; i < tx_len; i++)
|
|
|
|
|
xfer_tx[i] = tx[i];
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->shiftIR(&cmd, NULL, 8, Jtag::PAUSE_IR);
|
2019-11-18 16:03:59 +01:00
|
|
|
if (rx || tx) {
|
|
|
|
|
_jtag->shiftDR(xfer_tx, (rx) ? xfer_rx : NULL, 8 * xfer_len,
|
2020-03-06 09:05:57 +01:00
|
|
|
Jtag::PAUSE_DR);
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2020-09-26 08:40:43 +02:00
|
|
|
uint8_t err;
|
2019-11-18 16:03:59 +01:00
|
|
|
printf("displayReadReg\n");
|
2020-09-26 08:40:43 +02:00
|
|
|
if (dev & 1<<0) printf("\tTRAN Mode\n");
|
2019-11-18 16:03:59 +01:00
|
|
|
printf("\tConfig Target Selection : %x\n", (dev >> 1) & 0x07);
|
2020-09-26 08:40:43 +02:00
|
|
|
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 (_fpga_family == NEXUS_FAMILY) {
|
|
|
|
|
if (dev & 1 << 17) printf("\tPWD All\n");
|
|
|
|
|
if (dev & 1 << 18) printf("\tCID En\n");
|
|
|
|
|
if (dev & 1 << 19) printf("\tinternal use\n");
|
|
|
|
|
if (dev & 1 << 21) printf("\tEncryption PreAmble\n");
|
|
|
|
|
if (dev & 1 << 22) printf("\tStd PreAmble\n");
|
|
|
|
|
if (dev & 1 << 23) printf("\tSPIm Fail1\n");
|
|
|
|
|
err = (dev >> 24)&0x0f;
|
|
|
|
|
} else {
|
|
|
|
|
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");
|
|
|
|
|
err = (dev >> 23)&0x07;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-18 16:03:59 +01:00
|
|
|
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);
|
|
|
|
|
}
|
2020-09-26 08:40:43 +02:00
|
|
|
|
|
|
|
|
if (_fpga_family == NEXUS_FAMILY) {
|
|
|
|
|
if ((dev >> 28) & 0x01) printf("\tEXEC Error\n");
|
|
|
|
|
if ((dev >> 29) & 0x01) printf("\tID Error\n");
|
|
|
|
|
if ((dev >> 30) & 0x01) printf("\tInvalid Command\n");
|
|
|
|
|
if ((dev >> 31) & 0x01) printf("\tWDT Busy\n");
|
|
|
|
|
} else {
|
|
|
|
|
if (dev & REG_STATUS_EXEC_ERR) printf("\tEXEC Error\n");
|
|
|
|
|
if ((dev >> 27) & 0x01) printf("\tDevice failed to verify\n");
|
|
|
|
|
if ((dev >> 28) & 0x01) printf("\tInvalid Command\n");
|
|
|
|
|
if ((dev >> 29) & 0x01) printf("\tSED Error\n");
|
|
|
|
|
if ((dev >> 30) & 0x01) printf("\tBypass Mode\n");
|
|
|
|
|
if ((dev >> 31) & 0x01) printf("\tFT Mode\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
if (_fpga_family == NEXUS_FAMILY) {
|
|
|
|
|
if ((dev >> 33) & 0x01) printf("\tDry Run Done\n");
|
|
|
|
|
err = (dev >> 34)&0x0f;
|
|
|
|
|
printf("\tBSE Error 1 Code for previous bitstream execution\n");
|
|
|
|
|
printf("\t\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;
|
|
|
|
|
case 8:
|
|
|
|
|
printf("Authentification ERR\n");
|
|
|
|
|
break;
|
|
|
|
|
case 9:
|
|
|
|
|
printf("Authentification Setup ERR\n");
|
|
|
|
|
break;
|
|
|
|
|
case 10:
|
|
|
|
|
printf("Bitstream Engine Timeout ERR\n");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
printf("unknown %x\n", err);
|
|
|
|
|
}
|
|
|
|
|
if ((dev >> 38) & 0x01) printf("\tBypass Mode\n");
|
|
|
|
|
if ((dev >> 39) & 0x01) printf("\tFlow Through Mode\n");
|
|
|
|
|
if ((dev >> 42) & 0x01) printf("\tSFDP Timeout\n");
|
|
|
|
|
if ((dev >> 43) & 0x01) printf("\tKey Destroy pass\n");
|
|
|
|
|
if ((dev >> 44) & 0x01) printf("\tINITN\n");
|
|
|
|
|
if ((dev >> 45) & 0x01) printf("\tI3C Parity Error2\n");
|
|
|
|
|
if ((dev >> 46) & 0x01) printf("\tINIT Bus ID Error\n");
|
|
|
|
|
if ((dev >> 47) & 0x01) printf("\tI3C Parity Error1\n");
|
|
|
|
|
err = (dev >> 48) & 0x03;
|
|
|
|
|
printf("\tAuthentification mode:\n");
|
|
|
|
|
printf("\t\t");
|
|
|
|
|
switch (err) {
|
|
|
|
|
case 3:
|
|
|
|
|
case 0:
|
|
|
|
|
printf("No Auth\n");
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
printf("ECDSA\n");
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
printf("HMAC\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if ((dev >> 50) & 0x01) printf("\tAuthentification Done\n");
|
|
|
|
|
if ((dev >> 51) & 0x01) printf("\tDry Run Authentification Done\n");
|
|
|
|
|
#endif
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Lattice::pollBusyFlag(bool verbose)
|
|
|
|
|
{
|
|
|
|
|
uint8_t rx;
|
|
|
|
|
int timeout = 0;
|
|
|
|
|
do {
|
|
|
|
|
wr_rd(CHECK_BUSY_FLAG, NULL, 0, &rx, 1);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_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);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
2019-11-20 07:30:54 +01:00
|
|
|
if (!pollBusyFlag())
|
|
|
|
|
return false;
|
|
|
|
|
if (!checkStatus(0, REG_STATUS_FAIL))
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
2020-08-19 17:00:44 +02:00
|
|
|
bool Lattice::flashProg(uint32_t start_addr, const string &name, vector<string> data)
|
2019-11-18 16:03:59 +01:00
|
|
|
{
|
|
|
|
|
(void)start_addr;
|
2021-01-30 07:57:49 +01:00
|
|
|
ProgressBar progress("Writing " + name, data.size(), 50, _quiet);
|
2019-11-18 16:03:59 +01:00
|
|
|
for (uint32_t line = 0; line < data.size(); line++) {
|
|
|
|
|
wr_rd(PROG_CFG_FLASH, (uint8_t *)data[line].c_str(),
|
|
|
|
|
16, NULL, 0);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
|
|
|
|
progress.display(line);
|
|
|
|
|
if (pollBusyFlag() == false)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
progress.done();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-27 16:37:05 +02:00
|
|
|
bool Lattice::Verify(std::vector<std::string> data, bool unlock)
|
2019-11-18 16:03:59 +01:00
|
|
|
{
|
|
|
|
|
uint8_t tx_buf[16], rx_buf[16];
|
|
|
|
|
if (unlock)
|
|
|
|
|
EnableISC(0x08);
|
|
|
|
|
|
|
|
|
|
wr_rd(0x46, NULL, 0, NULL, 0);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
|
|
|
|
|
2020-04-27 16:37:05 +02:00
|
|
|
tx_buf[0] = REG_CFG_FLASH;
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->shiftIR(tx_buf, NULL, 8, Jtag::PAUSE_IR);
|
2019-11-18 16:03:59 +01:00
|
|
|
|
2020-07-25 04:55:41 +02:00
|
|
|
memset(tx_buf, 0, 16);
|
2019-11-18 16:03:59 +01:00
|
|
|
bool failure = false;
|
2021-01-30 07:57:49 +01:00
|
|
|
ProgressBar progress("Verifying", data.size(), 50, _quiet);
|
2019-11-18 16:03:59 +01:00
|
|
|
for (size_t line = 0; line< data.size(); line++) {
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(2);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->shiftDR(tx_buf, rx_buf, 16*8, Jtag::PAUSE_DR);
|
2020-04-27 16:37:05 +02:00
|
|
|
for (size_t i = 0; i < data[line].size(); i++) {
|
2019-11-18 16:03:59 +01:00
|
|
|
if (rx_buf[i] != (unsigned char)data[line][i]) {
|
2020-12-13 00:48:45 +01:00
|
|
|
printf("%3zu %3zu %02x -> %02x\n", line, i,
|
2019-11-18 16:03:59 +01:00
|
|
|
rx_buf[i], (unsigned char)data[line][i]);
|
|
|
|
|
failure = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (failure) {
|
|
|
|
|
printf("Verify Failure\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
progress.display(line);
|
|
|
|
|
}
|
|
|
|
|
if (unlock)
|
|
|
|
|
DisableISC();
|
|
|
|
|
|
2021-01-30 07:57:49 +01:00
|
|
|
if (failure)
|
|
|
|
|
progress.fail();
|
|
|
|
|
else
|
|
|
|
|
progress.done();
|
2019-11-18 16:03:59 +01:00
|
|
|
|
2021-01-30 07:57:49 +01:00
|
|
|
return !failure;
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 07:30:54 +01:00
|
|
|
uint64_t Lattice::readFeaturesRow()
|
2019-11-18 16:03:59 +01:00
|
|
|
{
|
|
|
|
|
uint8_t tx_buf[8];
|
|
|
|
|
uint8_t rx_buf[8];
|
2019-11-20 07:30:54 +01:00
|
|
|
uint64_t reg = 0;
|
2020-07-25 04:55:41 +02:00
|
|
|
memset(tx_buf, 0, 8);
|
2019-11-18 16:03:59 +01:00
|
|
|
wr_rd(READ_FEATURE_ROW, tx_buf, 8, rx_buf, 8);
|
2019-11-20 07:30:54 +01:00
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
|
reg |= ((uint64_t)rx_buf[i] << (i*8));
|
|
|
|
|
return reg;
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 07:30:54 +01:00
|
|
|
uint16_t Lattice::readFeabits()
|
2019-11-18 16:03:59 +01:00
|
|
|
{
|
|
|
|
|
uint8_t rx_buf[2];
|
|
|
|
|
wr_rd(READ_FEABITS, NULL, 0, rx_buf, 2);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
|
|
|
|
|
2019-11-20 07:30:54 +01:00
|
|
|
return rx_buf[0] | (((uint16_t)rx_buf[1]) << 8);
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 07:30:54 +01:00
|
|
|
bool Lattice::writeFeaturesRow(uint64_t features, bool verify)
|
2019-11-18 16:03:59 +01:00
|
|
|
{
|
|
|
|
|
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);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
2019-11-20 07:30:54 +01:00
|
|
|
if (!pollBusyFlag())
|
|
|
|
|
return false;
|
|
|
|
|
if (verify)
|
|
|
|
|
return (features == readFeaturesRow()) ? true : false;
|
|
|
|
|
return true;
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 07:30:54 +01:00
|
|
|
bool Lattice::writeFeabits(uint16_t feabits, bool verify)
|
2019-11-18 16:03:59 +01:00
|
|
|
{
|
|
|
|
|
uint8_t tx_buf[2] = {(uint8_t)(feabits&0x00ff),
|
|
|
|
|
(uint8_t)(0x00ff & (feabits>>8))};
|
|
|
|
|
|
|
|
|
|
wr_rd(PROG_FEABITS, tx_buf, 2, NULL, 0);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
2019-11-20 07:30:54 +01:00
|
|
|
if (!pollBusyFlag())
|
|
|
|
|
return false;
|
|
|
|
|
if (verify)
|
|
|
|
|
return (feabits == readFeabits()) ? true : false;
|
|
|
|
|
return true;
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Lattice::writeProgramDone()
|
|
|
|
|
{
|
|
|
|
|
wr_rd(PROG_DONE, NULL, 0, NULL, 0);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
2019-11-20 07:30:54 +01:00
|
|
|
if (!pollBusyFlag())
|
|
|
|
|
return false;
|
|
|
|
|
if (!checkStatus(REG_STATUS_DONE, REG_STATUS_DONE))
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Lattice::loadConfiguration()
|
|
|
|
|
{
|
|
|
|
|
wr_rd(REFRESH, NULL, 0, NULL, 0);
|
2020-03-06 09:05:57 +01:00
|
|
|
_jtag->set_state(Jtag::RUN_TEST_IDLE);
|
2019-11-18 16:03:59 +01:00
|
|
|
_jtag->toggleClk(1000);
|
2019-11-20 07:30:54 +01:00
|
|
|
if (!pollBusyFlag())
|
|
|
|
|
return false;
|
|
|
|
|
if (!checkStatus(REG_STATUS_DONE, REG_STATUS_DONE))
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
2019-11-18 16:03:59 +01:00
|
|
|
}
|
2020-04-22 15:21:01 +02:00
|
|
|
|
|
|
|
|
/* ------------------ */
|
|
|
|
|
/* SPI implementation */
|
|
|
|
|
/* ------------------ */
|
|
|
|
|
|
2020-08-23 17:16:21 +02:00
|
|
|
int Lattice::spi_put(uint8_t cmd, uint8_t *tx, uint8_t *rx, uint32_t len)
|
2020-04-22 15:21:01 +02:00
|
|
|
{
|
|
|
|
|
int xfer_len = len + 1;
|
|
|
|
|
uint8_t jtx[xfer_len];
|
|
|
|
|
uint8_t jrx[xfer_len];
|
|
|
|
|
|
|
|
|
|
jtx[0] = LatticeBitParser::reverseByte(cmd);
|
|
|
|
|
|
|
|
|
|
if (tx != NULL) {
|
2020-09-05 08:00:58 +02:00
|
|
|
for (uint32_t i=0; i < len; i++)
|
2020-04-22 15:21:01 +02:00
|
|
|
jtx[i+1] = LatticeBitParser::reverseByte(tx[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* send first already stored cmd,
|
|
|
|
|
* in the same time store each byte
|
|
|
|
|
* to next
|
|
|
|
|
*/
|
|
|
|
|
_jtag->shiftDR(jtx, (rx == NULL)? NULL: jrx, 8*xfer_len);
|
|
|
|
|
|
|
|
|
|
if (rx != NULL) {
|
2020-09-05 08:00:58 +02:00
|
|
|
for (uint32_t i=0; i < len; i++)
|
2020-04-22 15:21:01 +02:00
|
|
|
rx[i] = LatticeBitParser::reverseByte(jrx[i+1]);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-23 17:16:21 +02:00
|
|
|
int Lattice::spi_put(uint8_t *tx, uint8_t *rx, uint32_t len)
|
2020-04-22 15:21:01 +02:00
|
|
|
{
|
|
|
|
|
int xfer_len = len;
|
|
|
|
|
uint8_t jtx[xfer_len];
|
|
|
|
|
uint8_t jrx[xfer_len];
|
|
|
|
|
|
|
|
|
|
if (tx != NULL) {
|
2020-09-05 08:00:58 +02:00
|
|
|
for (uint32_t i=0; i < len; i++)
|
2020-04-22 15:21:01 +02:00
|
|
|
jtx[i] = LatticeBitParser::reverseByte(tx[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* send first already stored cmd,
|
|
|
|
|
* in the same time store each byte
|
|
|
|
|
* to next
|
|
|
|
|
*/
|
|
|
|
|
_jtag->shiftDR(jtx, (rx == NULL)? NULL: jrx, 8*xfer_len);
|
|
|
|
|
|
|
|
|
|
if (rx != NULL) {
|
2020-09-05 08:00:58 +02:00
|
|
|
for (uint32_t i=0; i < len; i++)
|
2020-04-22 15:21:01 +02:00
|
|
|
rx[i] = LatticeBitParser::reverseByte(jrx[i]);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Lattice::spi_wait(uint8_t cmd, uint8_t mask, uint8_t cond,
|
|
|
|
|
uint32_t timeout, bool verbose)
|
|
|
|
|
{
|
|
|
|
|
uint8_t rx;
|
|
|
|
|
uint8_t dummy[2];
|
|
|
|
|
uint8_t tmp;
|
|
|
|
|
uint8_t tx = LatticeBitParser::reverseByte(cmd);
|
|
|
|
|
uint32_t count = 0;
|
|
|
|
|
|
|
|
|
|
/* CS is low until state goes to EXIT1_IR
|
|
|
|
|
* so manually move to state machine to stay is this
|
|
|
|
|
* state as long as needed
|
|
|
|
|
*/
|
2021-05-18 08:27:34 +02:00
|
|
|
_jtag->shiftDR(&tx, NULL, 8, Jtag::SHIFT_DR);
|
2020-04-22 15:21:01 +02:00
|
|
|
|
|
|
|
|
do {
|
2021-05-18 08:27:34 +02:00
|
|
|
_jtag->shiftDR(dummy, &rx, 8, Jtag::SHIFT_DR);
|
2020-04-22 15:21:01 +02:00
|
|
|
tmp = (LatticeBitParser::reverseByte(rx));
|
|
|
|
|
count ++;
|
|
|
|
|
if (count == timeout){
|
2020-08-19 17:00:44 +02:00
|
|
|
printf("timeout: %x %x %u\n", tmp, rx, count);
|
2020-04-22 15:21:01 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (verbose) {
|
2020-08-19 17:00:44 +02:00
|
|
|
printf("%x %x %x %u\n", tmp, mask, cond, count);
|
2020-04-22 15:21:01 +02:00
|
|
|
}
|
|
|
|
|
} while ((tmp & mask) != cond);
|
2021-05-18 08:27:34 +02:00
|
|
|
_jtag->shiftDR(dummy, &rx, 8, Jtag::RUN_TEST_IDLE);
|
2020-04-22 15:21:01 +02:00
|
|
|
if (count == timeout) {
|
|
|
|
|
printf("%x\n", tmp);
|
|
|
|
|
std::cout << "wait: Error" << std::endl;
|
|
|
|
|
return -ETIME;
|
|
|
|
|
} else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|