Skip to content

Commit

Permalink
Add gdb vector support
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonWin committed Jun 23, 2023
1 parent 81c4d70 commit ffeb06a
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 84 deletions.
6 changes: 6 additions & 0 deletions include/vcml/core/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ class processor : public component, protected debugging::target

using cpureg = debugging::cpureg;
virtual bool read_cpureg_dbg(const cpureg& r, vcml::u64& val) override;
virtual bool read_cpureg_dbg(const cpureg& r,
vector<vcml::u64>& val) override;
virtual bool write_cpureg_dbg(const cpureg& r, vcml::u64 val) override;
virtual bool write_cpureg_dbg(const cpureg& r,
vector<vcml::u64>& val) override;

u64 simulate_cycles(unsigned int cycles);
void processor_thread();
Expand Down Expand Up @@ -129,6 +133,8 @@ class processor : public component, protected debugging::target
virtual void define_cpuregs(const vector<cpureg>& regs) override;

virtual bool read_reg_dbg(vcml::u64 idx, vcml::u64& val);
virtual bool read_reg_dbg(vcml::u64 idx, vector<vcml::u64>& val);
virtual bool write_reg_dbg(vcml::u64 idx, vector<vcml::u64>& val);
virtual bool write_reg_dbg(vcml::u64 idx, vcml::u64 val);

virtual u64 read_pmem_dbg(u64 addr, void* ptr, u64 sz) override;
Expand Down
1 change: 1 addition & 0 deletions include/vcml/debugging/gdbarch.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct gdbfeature {
bool supported(const target& t) const;
bool supported(const target& t, vector<string>& missing) const;

void write_vec_init(const cpureg* reg, ostream& os) const;
void write_xml(const target& t, ostream& os) const;
};

Expand Down
22 changes: 18 additions & 4 deletions include/vcml/debugging/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,27 @@ struct cpureg {
u64 regno;
string name;
u64 size;
u64 count;
bool isvector;
int prot;
target* host;

cpureg(const cpureg&) = default;

cpureg(): regno(~0ul), name(), size(), prot(), host() {}
cpureg():
regno(~0ul), name(), size(), count(), isvector(), prot(), host() {}

cpureg(u64 no, const string& nm, u64 sz, int p):
regno(no), name(nm), size(sz), prot(p), host() {}
regno(no),
name(nm),
size(sz),
count(1),
isvector(false),
prot(p),
host() {}

cpureg(u64 no, const string& nm, u64 sz, u64 cnt, bool vec, int p):
regno(no), name(nm), size(sz), count(cnt), isvector(vec), host() {}

u64 width() const { return size * 8; }

Expand All @@ -48,8 +60,8 @@ struct cpureg {
bool is_write_only() const { return prot == VCML_ACCESS_WRITE; }
bool is_read_write() const { return prot == VCML_ACCESS_READ_WRITE; }

u64 read() const;
void write(u64 val) const;
vector<u64> read() const;
void write(vector<u64>& val) const;
};

struct disassembly {
Expand Down Expand Up @@ -124,7 +136,9 @@ class target
const cpureg* find_cpureg(const string& name) const;

virtual bool read_cpureg_dbg(const cpureg& reg, u64& val);
virtual bool read_cpureg_dbg(const cpureg& reg, vector<u64>& val);
virtual bool write_cpureg_dbg(const cpureg& reg, u64 val);
virtual bool write_cpureg_dbg(const cpureg& reg, vector<u64>& val);

virtual u64 read_pmem_dbg(u64 addr, void* buffer, u64 size);
virtual u64 write_pmem_dbg(u64 addr, const void* buffer, u64 size);
Expand Down
142 changes: 102 additions & 40 deletions src/vcml/core/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -545,26 +545,30 @@ void processor::fetch_cpuregs() {
property_base* prop = it.second;
VCML_ERROR_ON(!prop, "no propery for cpureg %llu", it.first);

u64 val = 0;
vector<u64> val;
val.push_back(0);
if (reg->is_readable())
val = reg->read();

switch (reg->size) {
case 1:
dynamic_cast<property<u8>*>(prop)->set((u8)val);
break;
case 2:
dynamic_cast<property<u16>*>(prop)->set((u16)val);
break;
case 4:
dynamic_cast<property<u32>*>(prop)->set((u32)val);
break;
case 8:
dynamic_cast<property<u64>*>(prop)->set((u64)val);
break;
default:
VCML_ERROR("register %s has illegal size: %llu bytes",
reg->name.c_str(), reg->size);
if (!reg->isvector) {
switch (reg->size) {
case 1:
dynamic_cast<property<u8>*>(prop)->set((u8)val[0]);
break;
case 2:
dynamic_cast<property<u16>*>(prop)->set((u16)val[0]);
break;
case 4:
dynamic_cast<property<u32>*>(prop)->set((u32)val[0]);
break;
case 8:
dynamic_cast<property<u64>*>(prop)->set((u64)val[0]);
break;
default:
VCML_ERROR("register %s has illegal size: %llu bytes",
reg->name.c_str(), reg->size);
}
} else {
return; // Todo: implement vector property
}
}
}
Expand All @@ -580,30 +584,34 @@ void processor::flush_cpuregs() {
if (!reg->is_writeable())
continue;

u64 val = 0;
switch (reg->size) {
case 1:
val = dynamic_cast<property<u8>*>(prop)->get();
break;
case 2:
val = dynamic_cast<property<u16>*>(prop)->get();
break;
case 4:
val = dynamic_cast<property<u32>*>(prop)->get();
break;
case 8:
val = dynamic_cast<property<u64>*>(prop)->get();
break;
default:
VCML_ERROR("register %s has illegal size: %llu bytes",
reg->name.c_str(), reg->size);
}
vector<u64> val;
if (!reg->isvector) {
switch (reg->size) {
case 1:
val.push_back(dynamic_cast<property<u8>*>(prop)->get());
break;
case 2:
val.push_back(
val[0] = dynamic_cast<property<u16>*>(prop)->get());
break;
case 4:
val.push_back(dynamic_cast<property<u32>*>(prop)->get());
break;
case 8:
val.push_back(dynamic_cast<property<u64>*>(prop)->get());
break;
default:
VCML_ERROR("register %s has illegal size: %llu bytes",
reg->name.c_str(), reg->size);
}
} else
return; // Todo: implement vector property

const u64 mask = bitmask(reg->width());
if (reg->size < 8 && val > mask) {
if (reg->size < 8 && val[0] > mask) {
log_warn("truncating value 0x%llx for %llu bit cpu register %s",
val, reg->width(), reg->name.c_str());
val &= mask;
val[0], reg->width(), reg->name.c_str());
val[0] &= mask;
}

reg->write(val);
Expand All @@ -614,6 +622,9 @@ void processor::define_cpuregs(const vector<debugging::cpureg>& regs) {
target::define_cpuregs(regs);

for (const auto& reg : regs) {
if (reg.isvector)
continue; // Todo: implement vector property

u64 defval = 0;

const char* regnm = reg.name.c_str();
Expand All @@ -624,7 +635,6 @@ void processor::define_cpuregs(const vector<debugging::cpureg>& regs) {

property_base*& prop = m_regprops[reg.regno];
VCML_ERROR_ON(prop, "property %s already exists", regnm);

switch (reg.size) {
case 1:
prop = new property<u8>(regnm, defval);
Expand All @@ -651,17 +661,32 @@ bool processor::read_reg_dbg(vcml::u64 idx, vcml::u64& val) {
return false; // to be overloaded
}

bool processor::read_reg_dbg(vcml::u64 idx, vector<vcml::u64>& val) {
return false; // to be overloaded
}

bool processor::write_reg_dbg(vcml::u64 idx, vcml::u64 val) {
return false; // to be overloaded
}

bool processor::write_reg_dbg(vcml::u64 idx, vector<vcml::u64>& val) {
return false; // to be overloaded
}

bool processor::read_cpureg_dbg(const cpureg& reg, vcml::u64& val) {
if (!reg.is_readable())
return false;

return read_reg_dbg(reg.regno, val);
}

bool processor::read_cpureg_dbg(const cpureg& reg, vector<vcml::u64>& val) {
if (!reg.is_readable())
return false;

return read_reg_dbg(reg.regno, val);
}

bool processor::write_cpureg_dbg(const cpureg& reg, vcml::u64 val) {
if (!reg.is_writeable())
return false;
Expand Down Expand Up @@ -696,6 +721,43 @@ bool processor::write_cpureg_dbg(const cpureg& reg, vcml::u64 val) {
return true;
}

bool processor::write_cpureg_dbg(const cpureg& reg, vector<vcml::u64>& val) {
if (!reg.is_writeable())
return false;

if (!write_reg_dbg(reg.regno, val))
return false;

if (reg.isvector)
return true; // Todo: implement vector property

auto it = m_regprops.find(reg.regno);
if (it == m_regprops.end())
VCML_ERROR("no propery for cpureg %s", reg.name.c_str());

property_base* prop = it->second;

switch (reg.size) {
case 1:
dynamic_cast<property<u8>*>(prop)->set((u8)val[0]);
break;
case 2:
dynamic_cast<property<u16>*>(prop)->set((u16)val[0]);
break;
case 4:
dynamic_cast<property<u32>*>(prop)->set((u32)val[0]);
break;
case 8:
dynamic_cast<property<u64>*>(prop)->set((u64)val[0]);
break;
default:
VCML_ERROR("register %s has illegal size: %llu bytes",
reg.name.c_str(), reg.size);
}

return true;
}

u64 processor::read_pmem_dbg(u64 addr, void* buffer, u64 size) {
try {
if (success(data.read(addr, buffer, size, SBI_DEBUG)))
Expand Down
65 changes: 62 additions & 3 deletions src/vcml/debugging/gdbarch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,71 @@ bool gdbfeature::collect_regs(const target& t, vector<const cpureg*>& regs,
return missing.empty();
}

struct VEC_TYPE_SIZE {
const char* gdb_type;
const char* id;
size_t size;
const char suffix;
};

static constexpr VEC_TYPE_SIZE vec_lanes[]{
{ "uint128", "quads", 128, 'q' }, { "uint64", "longs", 64, 'l' },
{ "uint32", "words", 32, 'w' }, { "uint16", "shorts", 16, 's' },
{ "uint8", "bytes", 8, 'b' },
};

void gdbfeature::write_vec_init(const cpureg* reg, ostream& os) const {
for (auto& vec : vec_lanes) {
if (vec.size <= reg->count * reg->size * 8) {
os << "<vector id=\"" << vec.id << "\""
<< " type=\"" << vec.gdb_type << "\""
<< " count=\"" << (reg->count * reg->size * 8) / vec.size
<< "\" />" << std::endl;
}
}
os << "<union id=\"vector_union\">" << std::endl;
for (auto& vec : vec_lanes) {
if (vec.size <= reg->count * reg->size * 8) {
os << "<field name=\"" << vec.suffix << "\""
<< " type=\"" << vec.id << "\"/>" << std::endl;
}
}
os << "</union>";
}

void gdbfeature::write_xml(const target& t, ostream& os) const {
vector<const cpureg*> cpuregs;
if (!collect_regs(t, cpuregs) || cpuregs.empty())
return;

os << "<feature name=\"" << name << "\">" << std::endl;

u64 vec_count = 0;
for (size_t i = 0; i < cpuregs.size(); i++) {
os << "<reg name=\"" << registers[i] << "\""
<< " regnum=\"" << cpuregs[i]->regno << "\""
<< " bitsize=\"" << cpuregs[i]->size * 8 << "\" />" << std::endl;
if (!cpuregs[i]->isvector) {
os << "<reg name=\"" << registers[i] << "\""
<< " regnum=\"" << cpuregs[i]->regno << "\""
<< " bitsize=\"" << cpuregs[i]->size * 8 << "\" />"
<< std::endl;
} else {
if (vec_count == 0) {
write_vec_init(cpuregs[i], os);
vec_count = cpuregs[i]->count;
} else if (vec_count != cpuregs[i]->count)
VCML_ERROR(
"all vector registers must have the same number of "
"elements");

if (cpuregs[i]->size != 8)
VCML_ERROR("vector register must have a size of 64 bits");

os << "<reg name=\"" << registers[i] << "\""
<< " regnum=\"" << cpuregs[i]->regno << "\""
<< " bitsize=\"" << cpuregs[i]->size * cpuregs[i]->count * 8
<< "\""
<< " group=\"vector\""
<< " type=\"vector_union\" />" << std::endl;
}
}

os << "</feature>" << std::endl;
Expand Down Expand Up @@ -163,6 +217,11 @@ const gdbarch gdbarch::RISCV = gdbarch(
"fa4", "fa5", "fa6", "fa7", "fs2", "fs3", "fs4",
"fs5", "fs6", "fs7", "fs8", "fs9", "fs10", "fs11",
"ft8", "ft9", "ft10", "ft11", "fflags", "frm", "fcsr" } },
{ "org.gnu.gdb.riscv.vector",
{ "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" } },
{ "org.gnu.gdb.riscv.virtual", { "priv" } },
});

Expand Down
Loading

0 comments on commit ffeb06a

Please sign in to comment.