New wishbone-jtag bridge

This commit is contained in:
2026-02-27 15:56:56 +01:00
parent 838204653a
commit 3a9b2acf9e
13 changed files with 1495 additions and 457 deletions

View File

@@ -12,21 +12,41 @@ ArgParser::ArgParser(std::string program_name)
void ArgParser::addString(const std::string &name,
const std::string &default_value,
const std::string &help,
bool required) {
bool required,
const std::string &short_name) {
order_.push_back(name);
meta_[name] = {OptionType::kString, help, required};
meta_[name] = {OptionType::kString, help, required, short_name};
string_values_[name] = default_value;
provided_[name] = false;
if (!short_name.empty()) {
short_to_long_[short_name] = name;
}
}
void ArgParser::addInt(const std::string &name,
int default_value,
const std::string &help,
bool required) {
bool required,
const std::string &short_name) {
order_.push_back(name);
meta_[name] = {OptionType::kInt, help, required};
meta_[name] = {OptionType::kInt, help, required, short_name};
int_values_[name] = default_value;
provided_[name] = false;
if (!short_name.empty()) {
short_to_long_[short_name] = name;
}
}
void ArgParser::addFlag(const std::string &name,
const std::string &help,
const std::string &short_name) {
order_.push_back(name);
meta_[name] = {OptionType::kFlag, help, false, short_name};
flag_values_[name] = false;
provided_[name] = false;
if (!short_name.empty()) {
short_to_long_[short_name] = name;
}
}
bool ArgParser::parse(int argc, char **argv, std::string *error) {
@@ -39,6 +59,79 @@ bool ArgParser::parse(int argc, char **argv, std::string *error) {
return false;
}
if (token.rfind("--", 0) != 0 && token.rfind("-", 0) == 0) {
std::string short_key = token.substr(1);
std::string short_value;
size_t short_eq = short_key.find('=');
if (short_eq != std::string::npos) {
short_value = short_key.substr(short_eq + 1);
short_key = short_key.substr(0, short_eq);
}
auto sk = short_to_long_.find(short_key);
if (sk == short_to_long_.end()) {
if (error) {
*error = "Unknown option: -" + short_key;
}
return false;
}
auto m = meta_.find(sk->second);
if (m == meta_.end()) {
if (error) {
*error = "Unknown option: -" + short_key;
}
return false;
}
if (m->second.type == OptionType::kFlag) {
if (short_eq != std::string::npos) {
if (error) {
*error = "Flag does not take a value: -" + short_key;
}
return false;
}
flag_values_[sk->second] = true;
provided_[sk->second] = true;
} else if (m->second.type == OptionType::kString) {
if (short_eq == std::string::npos) {
if (i + 1 >= argc) {
if (error) {
*error = "Missing value for -" + short_key;
}
return false;
}
short_value = argv[++i];
}
string_values_[sk->second] = short_value;
provided_[sk->second] = true;
} else if (m->second.type == OptionType::kInt) {
long parsed;
if (short_eq == std::string::npos) {
if (i + 1 >= argc) {
if (error) {
*error = "Missing value for -" + short_key;
}
return false;
}
short_value = argv[++i];
}
errno = 0;
char *endp = nullptr;
parsed = std::strtol(short_value.c_str(), &endp, 0);
if (errno != 0 || endp == short_value.c_str() || *endp != '\0' ||
parsed < INT_MIN || parsed > INT_MAX) {
if (error) {
*error = "Invalid integer for -" + short_key + ": " + short_value;
}
return false;
}
int_values_[sk->second] = static_cast<int>(parsed);
provided_[sk->second] = true;
}
continue;
}
if (token.rfind("--", 0) != 0) {
if (error) {
*error = "Unexpected positional argument: " + token;
@@ -51,13 +144,6 @@ bool ArgParser::parse(int argc, char **argv, std::string *error) {
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);
@@ -71,10 +157,32 @@ bool ArgParser::parse(int argc, char **argv, std::string *error) {
return false;
}
if (m->second.type == OptionType::kFlag) {
if (eq != std::string::npos) {
if (error) {
*error = "Flag does not take a value: --" + key;
}
return false;
}
flag_values_[key] = true;
provided_[key] = true;
continue;
}
if (eq == std::string::npos) {
if (i + 1 >= argc) {
if (error) {
*error = "Missing value for --" + key;
}
return false;
}
value = argv[++i];
}
if (m->second.type == OptionType::kString) {
string_values_[key] = value;
provided_[key] = true;
} else {
} else if (m->second.type == OptionType::kInt) {
errno = 0;
char *endp = nullptr;
long parsed = std::strtol(value.c_str(), &endp, 0);
@@ -124,6 +232,14 @@ int ArgParser::getInt(const std::string &name) const {
return it->second;
}
bool ArgParser::getFlag(const std::string &name) const {
auto it = flag_values_.find(name);
if (it == flag_values_.end()) {
return false;
}
return it->second;
}
std::string ArgParser::helpText() const {
std::ostringstream oss;
oss << "Usage: " << program_name_ << " [options]\n\n";
@@ -135,7 +251,16 @@ std::string ArgParser::helpText() const {
continue;
}
oss << " --" << key << " <value>";
oss << " ";
if (!m->second.short_name.empty()) {
oss << "-" << m->second.short_name << ", ";
} else {
oss << " ";
}
oss << "--" << key;
if (m->second.type != OptionType::kFlag) {
oss << " <value>";
}
if (m->second.required) {
oss << " (required)";
}
@@ -147,9 +272,11 @@ std::string ArgParser::helpText() const {
oss << " [default: '" << s->second << "']";
}
} else {
auto iv = int_values_.find(key);
if (iv != int_values_.end()) {
oss << " [default: " << iv->second << "]";
if (m->second.type == OptionType::kInt) {
auto iv = int_values_.find(key);
if (iv != int_values_.end()) {
oss << " [default: " << iv->second << "]";
}
}
}
oss << "\n";

View File

@@ -26,31 +26,40 @@ public:
void addString(const std::string &name,
const std::string &default_value,
const std::string &help,
bool required = false);
bool required = false,
const std::string &short_name = "");
void addInt(const std::string &name,
int default_value,
const std::string &help,
bool required = false);
bool required = false,
const std::string &short_name = "");
void addFlag(const std::string &name,
const std::string &help,
const std::string &short_name = "");
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;
bool getFlag(const std::string &name) const;
std::string helpText() const;
private:
enum class OptionType {
kString,
kInt
kInt,
kFlag
};
struct OptionMeta {
OptionType type;
std::string help;
bool required;
std::string short_name;
};
std::string program_name_;
@@ -59,5 +68,7 @@ private:
std::unordered_map<std::string, std::string> string_values_;
std::unordered_map<std::string, int> int_values_;
std::unordered_map<std::string, bool> flag_values_;
std::unordered_map<std::string, bool> provided_;
std::unordered_map<std::string, std::string> short_to_long_;
};

View File

@@ -5,37 +5,55 @@
#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>
static constexpr uint8_t OP_NOP = 0x00;
static constexpr uint8_t OP_RESET_ON = 0x10;
static constexpr uint8_t OP_RESET_OFF = 0x11;
static constexpr uint8_t OP_WRITE8 = 0x20;
static constexpr uint8_t OP_READ8 = 0x21;
static constexpr uint8_t OP_PING = 0x30;
static constexpr uint8_t OP_CLEAR_FLAGS = 0x40;
jtag.shiftData(d, din, 42);
static void shift48(DigilentJtag &jtag, const uint8_t tx[6], uint8_t rx[6]) {
jtag.shiftData(tx, rx, 48);
}
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];
static void make_cmd(uint8_t out[6], uint8_t opcode, uint32_t addr, uint8_t data) {
out[0] = data;
out[1] = (uint8_t)addr;
out[2] = (uint8_t)(addr >> 8);
out[3] = (uint8_t)(addr >> 16);
out[4] = (uint8_t)(addr >> 24);
out[5] = opcode;
}
static uint8_t do_cmd(DigilentJtag& jtag, uint8_t opcode, uint32_t addr, uint8_t data){
uint8_t tx[6], rx[6];
make_cmd(tx, opcode, addr, data);
shift48(jtag, tx, rx);
for(int i=0; i<32; i++){
make_cmd(tx, OP_NOP, 0, 0);
shift48(jtag, tx, rx);
if(rx[0] == opcode){
return rx[2];
}
}
printf("Could not do command\r\n");
return 0;
}
struct Resp48 {
uint8_t last_op;
uint8_t flags;
uint8_t data;
uint8_t cmd_seq;
uint8_t status;
uint8_t resp_seq;
};
int main(int argc, char** argv){
ArgParser parser(argc > 0 ? argv[0] : "test");
parser.addString("write", "", "file to write");
parser.addString("file", "", "File to write", true, "f");
parser.addFlag("verify", "Verify", "v");
std::string parse_error;
if (!parser.parse(argc, argv, &parse_error)) {
@@ -48,8 +66,6 @@ int main(int argc, char** argv){
return -1;
}
const std::string arg_write = parser.getString("write");
DigilentJtag jtag;
if(!jtag.open()){
printf("Could not open programmer\r\n");
@@ -57,34 +73,51 @@ int main(int argc, char** argv){
}
jtag.setChain(1);
// 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);
do_cmd(jtag, OP_CLEAR_FLAGS, 0, 0);
// Check for ping
if(do_cmd(jtag, OP_PING, 0, 0) != 0xa5){
printf("PING response was not right\r\n");
jtag.close();
return -1;
}
const std::string file = parser.getString("file");
FILE* f = fopen(file.c_str(), "rb");
if(!f){
printf("Could not open file\r\n");
jtag.close();
return -1;
}
end:
// End reset
read(jtag, 0, false);
do_cmd(jtag, OP_RESET_ON, 0, 0);
int nr = 0;
int addr = 0;
do{
uint8_t buf[64];
nr = fread(buf, 1, 64, f);
for(int i=0; i<nr; i++){
do_cmd(jtag, OP_WRITE8, addr+i, buf[i]);
printf(".");
}
printf("\r\n");
if(parser.getFlag("verify")){
for(int i=0; i<nr; i++){
uint8_t r = do_cmd(jtag, OP_READ8, addr+i, 0);
if(r!=buf[i]){
printf(" -- Verify failed at %04x : %02x != %02x\r\n", addr+i, r, buf[i]);
}
}
}
addr += nr;
}while(nr > 0);
do_cmd(jtag, OP_RESET_OFF, 0, 0);
fclose(f);
jtag.close();
return 0;
}