synth/alchitry-loader/src/loader.cpp

389 lines
8.8 KiB
C++
Raw Normal View History

2022-05-17 03:36:27 +00:00
/*
* Loader.cpp
*
* Created on: Nov 6, 2017
* Author: justin
*/
#include "loader.h"
#include "jtag.h"
#include <iomanip>
#include <sstream>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <chrono>
#include "config_type.h"
#ifdef _WIN32
#include "mingw.thread.h"
#else
#include <thread>
#endif
using namespace std;
Loader::Loader(Jtag *dev) {
device = dev;
currentState = Jtag_fsm::TEST_LOGIC_RESET;
}
bool Loader::setState(Jtag_fsm::State state) {
if (!device->navigateToState(currentState, state))
return false;
currentState = state;
return true;
}
bool Loader::resetState() {
currentState = Jtag_fsm::TEST_LOGIC_RESET;
return device->navigateToState(Jtag_fsm::CAPTURE_DR,
Jtag_fsm::TEST_LOGIC_RESET);
}
bool Loader::setIR(Instruction inst) {
stringstream inst_str;
inst_str << std::setfill('0') << std::setw(2) << hex
<< static_cast<int>(inst);
if (!device->navigateToState(currentState, Jtag_fsm::SHIFT_IR)) {
cerr << "Failed to change to SHIFT_IR state!" << endl;
return false;
}
if (!device->shiftData(6, inst_str.str(), "", "")) {
cerr << "Failed to shift instruction data!" << endl;
return false;
}
if (!device->navigateToState(Jtag_fsm::EXIT1_IR, Jtag_fsm::RUN_TEST_IDLE)) {
cerr << "Failed to change to RUN_TEST_IDLE state!" << endl;
return false;
}
currentState = Jtag_fsm::RUN_TEST_IDLE;
return true;
}
// basically the same as shiftDR but ignores the first four bits
bool Loader::shiftUDR(int bits, string write, string read, string mask) {
string uread = read;
string umask = mask;
string uwrite = write;
if (!read.empty()) {
uread = read + "0";
umask = mask + "0";
uwrite = "0" + write;
bits += 4;
}
return shiftDR(bits, uwrite, uread, umask);
}
bool Loader::shiftDR(int bits, string write, string read, string mask) {
if (!device->navigateToState(currentState, Jtag_fsm::SHIFT_DR)) {
cerr << "Failed to change to SHIFT_DR state!" << endl;
return false;
}
if (!device->shiftData(bits, write, read, mask)) {
cerr << "Failed to shift data!" << endl;
return false;
}
if (!device->navigateToState(Jtag_fsm::EXIT1_DR, Jtag_fsm::RUN_TEST_IDLE)) {
cerr << "Failed to change to RUN_TEST_IDLE state!" << endl;
return false;
}
currentState = Jtag_fsm::RUN_TEST_IDLE;
return true;
}
bool Loader::shiftIR(int bits, string write, string read, string mask) {
if (!device->navigateToState(currentState, Jtag_fsm::SHIFT_IR)) {
cerr << "Failed to change to SHIFT_IR state!" << endl;
return false;
}
if (!device->shiftData(bits, write, read, mask)) {
cerr << "Failed to shift data!" << endl;
return false;
}
if (!device->navigateToState(Jtag_fsm::EXIT1_IR, Jtag_fsm::RUN_TEST_IDLE)) {
cerr << "Failed to change to RUN_TEST_IDLE state!" << endl;
return false;
}
currentState = Jtag_fsm::RUN_TEST_IDLE;
return true;
}
string Loader::shiftDR(int bits, string write) {
if (!device->navigateToState(currentState, Jtag_fsm::SHIFT_DR)) {
cerr << "Failed to change to SHIFT_DR state!" << endl;
return NULL;
}
string data = device->shiftData(bits, write);
if (data.empty()) {
cerr << "Failed to shift data!" << endl;
return NULL;
}
if (!device->navigateToState(Jtag_fsm::EXIT1_DR, Jtag_fsm::RUN_TEST_IDLE)) {
cerr << "Failed to change to RUN_TEST_IDLE state!" << endl;
return NULL;
}
currentState = Jtag_fsm::RUN_TEST_IDLE;
return data;
}
bool Loader::loadBin(string file) {
string binStr = fileToBinStr(file);
string reversedBinStr = reverseBytes(binStr);
if (!device->setFreq(10000000)) {
cerr << "Failed to set JTAG frequency!" << endl;
return false;
}
if (!resetState())
return false;
if (!setState(Jtag_fsm::RUN_TEST_IDLE))
return false;
if (!setIR(JPROGRAM))
return false;
if (!setIR(ISC_NOOP))
return false;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// config/jprog/poll
if (!device->sendClocks(10000))
return false;
if (!shiftIR(6, "14", "11", "31"))
return false;
// config/slr
if (!setIR(CFG_IN))
return false;
if (!shiftDR(binStr.length() * 4, reversedBinStr, "", ""))
return false;
// config/start
if (!setState(Jtag_fsm::RUN_TEST_IDLE))
return false;
if (!device->sendClocks(100000))
return false;
if (!setIR(JSTART))
return false;
if (!setState(Jtag_fsm::RUN_TEST_IDLE))
return false;
if (!device->sendClocks(100))
return false;
if (!shiftIR(6, "09", "31", "11"))
return false;
// config/status
if (!setState(Jtag_fsm::TEST_LOGIC_RESET))
return false;
if (!device->sendClocks(5))
return false;
if (!setIR(CFG_IN))
return false;
if (!shiftDR(160, "0000000400000004800700140000000466aa9955", "", ""))
return false;
if (!setIR(CFG_OUT))
return false;
if (!shiftDR(32, "00000000", "3f5e0d40", "08000000"))
return false;
if (!setState(Jtag_fsm::TEST_LOGIC_RESET))
return false;
if (!device->sendClocks(5))
return false;
return true;
}
string Loader::fileToBinStr(string file) {
ifstream binFile(file);
stringstream hexString;
char *buffer;
binFile.seekg(0, ios::end);
unsigned int byteCount = binFile.tellg();
binFile.seekg(0, ios::beg);
buffer = new char[byteCount];
binFile.read(buffer, byteCount);
binFile.close();
for (int i = byteCount - 1; i >= 0; i--) {
hexString << setfill('0') << setw(2) << std::hex
<< (int) ((unsigned char) buffer[i]);
}
delete buffer;
return hexString.str();
}
bool Loader::eraseFlash(string loaderFile) {
cout << "Initializing FPGA..." << endl;
if (!loadBin(loaderFile)) {
cerr << "Failed to initialize FPGA!" << endl;
return false;
}
if (!device->setFreq(1500000)) {
cerr << "Failed to set JTAG frequency!" << endl;
return false;
}
cout << "Erasing..." << endl;
// Erase the flash
if (!setIR(USER1))
return false;
if (!shiftDR(1, "0", "", ""))
return false;
std::this_thread::sleep_for(std::chrono::seconds(1)); // wait for erase
if (!setIR(JPROGRAM))
return false;
// reset just for good measure
if (!resetState())
return false;
return true;
}
bool Loader::writeBin(string binFile, bool flash, string loaderFile) {
if (flash) {
string binStr = fileToBinStr(binFile);
cout << "Initializing FPGA..." << endl;
if (!loadBin(loaderFile)) {
cerr << "Failed to initialize FPGA!" << endl;
return false;
}
if (!device->setFreq(1500000)) {
cerr << "Failed to set JTAG frequency!" << endl;
return false;
}
cout << "Erasing..." << endl;
// Erase the flash
if (!setIR(USER1))
return false;
if (!shiftDR(1, "0", "", ""))
return false;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
cout << "Writing..." << endl;
// Write the flash
if (!setIR(USER2))
return false;
if (!shiftDR(binStr.length() * 4, binStr, "", ""))
return false;
// If you enter the reset state after a write
// the loader firmware resets the flash into
// regular SPI mode and gets stuck in a dead FSM
// state. You need to do this before issuing a
// JPROGRAM command or the FPGA can't read the
// flash.
if (!resetState())
return false;
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 100ms delay is required before issuing JPROGRAM
cout << "Resetting FPGA..." << endl;
// JPROGRAM resets the FPGA configuration and will
// cause it to read the flash memory
if (!setIR(JPROGRAM))
return false;
} else {
cout << "Programming FPGA..." << endl;
if (!loadBin(binFile)) {
cerr << "Failed to initialize FPGA!" << endl;
return false;
}
}
// reset just for good measure
if (!resetState())
return false;
cout << "Done." << endl;
return true;
}
bool Loader::checkIDCODE() {
if (!setIR(IDCODE))
return false;
if (!shiftDR(32, "00000000", "0362D093", "0FFFFFFF")) // FPGA IDCODE
return false;
return true;
}
BYTE reverse(BYTE b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
bool Loader::setWREN() {
if (!setIR(USER1))
return false;
if (!shiftDR(8, reverseBytes("06"), "", ""))
return false;
return true;
}
int Loader::getStatus() {
if (!setIR(USER1))
return -1;
string data = shiftDR(17, reverseBytes("00005"));
cout << data << endl;
if (data.empty())
return -1;
int status = stoi(data, 0, 16);
status >>= 9;
return reverse(status);
}
void hexToByte(string hex, BYTE* out) {
int length = hex.length();
for (int i = 0; i < length / 2; i++) {
out[i] = stoi(hex.substr(length - 2 - i * 2, 2), 0, 16);
}
if ((length & 1) != 0)
out[length / 2] = stoi(hex.substr(0, 1), 0, 16);
}
string Loader::reverseBytes(string start) {
unsigned long l = start.length();
if (l & 1)
l++;
l /= 2;
BYTE* bytes = new BYTE[l];
hexToByte(start, bytes);
for (unsigned long i = 0; i < l; i++) {
bytes[i] = reverse(bytes[i]);
}
std::stringstream ss;
for (long i = l - 1; i >= 0; i--)
ss << setfill('0') << setw(2) << hex << (unsigned int) bytes[i];
string out = ss.str();
if (out.length() - 1 == start.length())
out = out.substr(1, out.length() - 1);
delete bytes;
return out;
}