jtag memory interface working
This commit is contained in:
@@ -4,7 +4,7 @@ CC := $(TOOLCHAIN_PREFIX)g++
|
||||
|
||||
TARGET := test
|
||||
SRCS_C :=
|
||||
SRCS_CPP:= test.cpp digilent_jtag.cpp
|
||||
SRCS_CPP:= test.cpp digilent_jtag.cpp argparse.cpp
|
||||
OBJS := $(SRCS_C:.c=.o) $(SRCS_CPP:.cpp=.o)
|
||||
|
||||
ADEPT_LIBDIR := /opt/packages/digilent.adept.runtime_2.27.9-x86_64/lib64
|
||||
@@ -29,4 +29,4 @@ $(TARGET): $(OBJS)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET) $(OBJS)
|
||||
rm -f $(TARGET) $(OBJS)
|
||||
|
||||
158
tools/argparse.cpp
Normal file
158
tools/argparse.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
#include "argparse.hpp"
|
||||
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
|
||||
ArgParser::ArgParser(std::string program_name)
|
||||
: program_name_(std::move(program_name)) {}
|
||||
|
||||
void ArgParser::addString(const std::string &name,
|
||||
const std::string &default_value,
|
||||
const std::string &help,
|
||||
bool required) {
|
||||
order_.push_back(name);
|
||||
meta_[name] = {OptionType::kString, help, required};
|
||||
string_values_[name] = default_value;
|
||||
provided_[name] = false;
|
||||
}
|
||||
|
||||
void ArgParser::addInt(const std::string &name,
|
||||
int default_value,
|
||||
const std::string &help,
|
||||
bool required) {
|
||||
order_.push_back(name);
|
||||
meta_[name] = {OptionType::kInt, help, required};
|
||||
int_values_[name] = default_value;
|
||||
provided_[name] = false;
|
||||
}
|
||||
|
||||
bool ArgParser::parse(int argc, char **argv, std::string *error) {
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string token(argv[i]);
|
||||
if (token == "--help" || token == "-h") {
|
||||
if (error) {
|
||||
*error = "help";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (token.rfind("--", 0) != 0) {
|
||||
if (error) {
|
||||
*error = "Unexpected positional argument: " + token;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string key;
|
||||
std::string value;
|
||||
size_t eq = token.find('=');
|
||||
if (eq == std::string::npos) {
|
||||
key = token.substr(2);
|
||||
if (i + 1 >= argc) {
|
||||
if (error) {
|
||||
*error = "Missing value for --" + key;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
value = argv[++i];
|
||||
} else {
|
||||
key = token.substr(2, eq - 2);
|
||||
value = token.substr(eq + 1);
|
||||
}
|
||||
|
||||
auto m = meta_.find(key);
|
||||
if (m == meta_.end()) {
|
||||
if (error) {
|
||||
*error = "Unknown option: --" + key;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m->second.type == OptionType::kString) {
|
||||
string_values_[key] = value;
|
||||
provided_[key] = true;
|
||||
} else {
|
||||
errno = 0;
|
||||
char *endp = nullptr;
|
||||
long parsed = std::strtol(value.c_str(), &endp, 0);
|
||||
if (errno != 0 || endp == value.c_str() || *endp != '\0' ||
|
||||
parsed < INT_MIN || parsed > INT_MAX) {
|
||||
if (error) {
|
||||
*error = "Invalid integer for --" + key + ": " + value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
int_values_[key] = static_cast<int>(parsed);
|
||||
provided_[key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &key : order_) {
|
||||
auto m = meta_.find(key);
|
||||
if (m != meta_.end() && m->second.required && !has(key)) {
|
||||
if (error) {
|
||||
*error = "Missing required option: --" + key;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArgParser::has(const std::string &name) const {
|
||||
auto p = provided_.find(name);
|
||||
return p != provided_.end() && p->second;
|
||||
}
|
||||
|
||||
std::string ArgParser::getString(const std::string &name) const {
|
||||
auto it = string_values_.find(name);
|
||||
if (it == string_values_.end()) {
|
||||
return std::string();
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
int ArgParser::getInt(const std::string &name) const {
|
||||
auto it = int_values_.find(name);
|
||||
if (it == int_values_.end()) {
|
||||
return 0;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::string ArgParser::helpText() const {
|
||||
std::ostringstream oss;
|
||||
oss << "Usage: " << program_name_ << " [options]\n\n";
|
||||
oss << "Options:\n";
|
||||
oss << " -h, --help Show this help\n";
|
||||
for (const auto &key : order_) {
|
||||
auto m = meta_.find(key);
|
||||
if (m == meta_.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
oss << " --" << key << " <value>";
|
||||
if (m->second.required) {
|
||||
oss << " (required)";
|
||||
}
|
||||
oss << "\n";
|
||||
oss << " " << m->second.help;
|
||||
if (m->second.type == OptionType::kString) {
|
||||
auto s = string_values_.find(key);
|
||||
if (s != string_values_.end()) {
|
||||
oss << " [default: '" << s->second << "']";
|
||||
}
|
||||
} else {
|
||||
auto iv = int_values_.find(key);
|
||||
if (iv != int_values_.end()) {
|
||||
oss << " [default: " << iv->second << "]";
|
||||
}
|
||||
}
|
||||
oss << "\n";
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
63
tools/argparse.hpp
Normal file
63
tools/argparse.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class ArgParser {
|
||||
public:
|
||||
struct StringOption {
|
||||
std::string name;
|
||||
std::string default_value;
|
||||
std::string help;
|
||||
bool required;
|
||||
};
|
||||
|
||||
struct IntOption {
|
||||
std::string name;
|
||||
int default_value;
|
||||
std::string help;
|
||||
bool required;
|
||||
};
|
||||
|
||||
explicit ArgParser(std::string program_name);
|
||||
|
||||
void addString(const std::string &name,
|
||||
const std::string &default_value,
|
||||
const std::string &help,
|
||||
bool required = false);
|
||||
|
||||
void addInt(const std::string &name,
|
||||
int default_value,
|
||||
const std::string &help,
|
||||
bool required = false);
|
||||
|
||||
bool parse(int argc, char **argv, std::string *error);
|
||||
|
||||
bool has(const std::string &name) const;
|
||||
std::string getString(const std::string &name) const;
|
||||
int getInt(const std::string &name) const;
|
||||
|
||||
std::string helpText() const;
|
||||
|
||||
private:
|
||||
enum class OptionType {
|
||||
kString,
|
||||
kInt
|
||||
};
|
||||
|
||||
struct OptionMeta {
|
||||
OptionType type;
|
||||
std::string help;
|
||||
bool required;
|
||||
};
|
||||
|
||||
std::string program_name_;
|
||||
std::vector<std::string> order_;
|
||||
std::unordered_map<std::string, OptionMeta> meta_;
|
||||
|
||||
std::unordered_map<std::string, std::string> string_values_;
|
||||
std::unordered_map<std::string, int> int_values_;
|
||||
std::unordered_map<std::string, bool> provided_;
|
||||
};
|
||||
@@ -1,19 +1,90 @@
|
||||
#include "digilent_jtag.hpp"
|
||||
#include "argparse.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
void write(DigilentJtag &jtag, uint32_t addr, uint8_t data, bool reset){
|
||||
uint8_t d[6], din[6];
|
||||
d[0] = data;
|
||||
d[1] = (uint8_t)addr;
|
||||
d[2] = (uint8_t)(addr>>8);
|
||||
d[3] = (uint8_t)(addr>>16);
|
||||
d[4] = (uint8_t)(addr>>24);
|
||||
d[5] = ((reset) ? 1 : 0) | 0x2; // <we><rst>
|
||||
|
||||
jtag.shiftData(d, din, 42);
|
||||
}
|
||||
|
||||
uint8_t read(DigilentJtag &jtag, uint32_t addr, bool reset){
|
||||
uint8_t d[6], din[6];
|
||||
d[0] = 0xff;
|
||||
d[1] = (uint8_t)addr;
|
||||
d[2] = (uint8_t)(addr>>8);
|
||||
d[3] = (uint8_t)(addr>>16);
|
||||
d[4] = (uint8_t)(addr>>24);
|
||||
d[5] = ((reset) ? 1 : 0); // <we><rst>
|
||||
|
||||
jtag.shiftData(d, din, 42);
|
||||
// Read back
|
||||
jtag.shiftData(d, din, 42);
|
||||
|
||||
return din[0];
|
||||
}
|
||||
|
||||
int main(int argc, char** argv){
|
||||
ArgParser parser(argc > 0 ? argv[0] : "test");
|
||||
parser.addString("write", "", "file to write");
|
||||
|
||||
std::string parse_error;
|
||||
if (!parser.parse(argc, argv, &parse_error)) {
|
||||
if (parse_error == "help") {
|
||||
std::printf("%s", parser.helpText().c_str());
|
||||
return 0;
|
||||
}
|
||||
std::printf("Argument error: %s\n\n", parse_error.c_str());
|
||||
std::printf("%s", parser.helpText().c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
const std::string arg_write = parser.getString("write");
|
||||
|
||||
DigilentJtag jtag;
|
||||
if(!jtag.open()){
|
||||
printf("Could not open programmer\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
jtag.setChain(1);
|
||||
|
||||
uint8_t data_out = 0xAB;
|
||||
uint8_t data_in;
|
||||
jtag.shiftData(&data_out, &data_in, 8);
|
||||
|
||||
// Start reset
|
||||
read(jtag, 0, true);
|
||||
|
||||
if(arg_write!=""){
|
||||
uint32_t addr = 0;
|
||||
uint8_t buf[32];
|
||||
int nr;
|
||||
FILE* f = fopen(arg_write.c_str(), "rb");
|
||||
if(!f){
|
||||
goto end;
|
||||
}
|
||||
|
||||
do{
|
||||
nr = fread(buf, 1, 32, f);
|
||||
for(int i=0; i<32; i++){
|
||||
write(jtag, addr, buf[i], true);
|
||||
addr++;
|
||||
}
|
||||
}while(nr>0);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
end:
|
||||
// End reset
|
||||
read(jtag, 0, false);
|
||||
|
||||
jtag.close();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user