summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2022-12-11 23:00:37 -0600
committerAlejandro Soto <alejandro@34project.org>2022-12-16 16:29:10 -0600
commit0284628a47d5b4797c89f6846b9efee3f1243b94 (patch)
treef287cb931e7bba24a7953eacaf2769d0a80cf789
parentd006be2e89aa493237f212811ee880ed8b54241b (diff)
Implement register writes from gdb
-rw-r--r--rtl/core/fetch/fetch.sv4
-rw-r--r--sim/gdbstub.py23
-rwxr-xr-xsim/sim.py9
-rw-r--r--tb/avalon.hpp2
-rw-r--r--tb/avalon.impl.hpp9
-rw-r--r--tb/top/conspiracion.cpp49
6 files changed, 82 insertions, 14 deletions
diff --git a/rtl/core/fetch/fetch.sv b/rtl/core/fetch/fetch.sv
index c024e7d..ba9d677 100644
--- a/rtl/core/fetch/fetch.sv
+++ b/rtl/core/fetch/fetch.sv
@@ -7,7 +7,7 @@ module core_fetch
rst_n,
stall,
fetched,
- explicit_branch,
+ explicit_branch /*verilator public*/ /*verilator forceable*/,
wr_pc,
prefetch_flush,
input ptr branch_target,
@@ -24,7 +24,7 @@ module core_fetch
fetch_head
);
- ptr hold_addr, target;
+ ptr target /*verilator public*/ /*verilator forceable*/, hold_addr;
logic branch, prefetch_ready, fetched_valid, discard, pending, next_pending;
assign fetch = prefetch_ready && !discard;
diff --git a/sim/gdbstub.py b/sim/gdbstub.py
index 74d046c..3833da7 100644
--- a/sim/gdbstub.py
+++ b/sim/gdbstub.py
@@ -84,6 +84,9 @@ def yield_to_gdb():
out = b'OK'
elif data == b'g':
out = hexout(read_reg(gdb_reg(r)) for r in range(16))
+ elif data[0] == b'G':
+ for reg, value in enumerate(hexin(data[1:])):
+ write_reg(reg, value)
elif data[0] == b'm'[0]:
addr, length = (int(x, 16) for x in data[1:].split(b','))
out = hexout(read_mem(addr, length, may_fail = True))
@@ -99,6 +102,9 @@ def yield_to_gdb():
elif data[0] == b'p'[0]:
reg = gdb_reg(int(data[1:], 16))
out = hexout(read_reg(reg) if reg is not None else None)
+ elif data[0] == b'P'[0]:
+ reg, value = data[1:].split(b'=')
+ write_reg(gdb_reg(int(reg, 16)), hexin(value, single=True))
elif data == b's' and not dead:
return 'step'
else:
@@ -107,7 +113,7 @@ def yield_to_gdb():
reply(out)
def reply(out):
- client.send(b'$' + out + b'#' + hexout(sum(out) & 0xff, 1))
+ client.send(b'$' + out + b'#' + hexout(sum(out) & 0xff, size=1))
def gdb_reg(n):
if 0 <= n < 8:
@@ -147,7 +153,20 @@ def gdb_reg(n):
print('bad gdb regnum:', n, file=sys.stderr)
return None
-def hexout(data, size=4):
+def hexin(data, *, single=False):
+ if type(data) is bytes:
+ data = str(data, 'ascii')
+
+ output = []
+ for i in range(len(data) >> 3):
+ output.append(int.from_bytes(bytes.fromhex(data[i << 3:(i + 1) << 3]), 'little'))
+
+ if single:
+ output, = output
+
+ return output
+
+def hexout(data, *, size=4):
if data is None:
return b''
elif type(data) is bytes:
diff --git a/sim/sim.py b/sim/sim.py
index b4e0882..448c39f 100755
--- a/sim/sim.py
+++ b/sim/sim.py
@@ -73,6 +73,14 @@ all_regs = [
regs = {}
read_reg = lambda r: regs.setdefault(r, 0)
+def write_reg(reg, value):
+ assert halted
+
+ value = unsigned(value)
+ regs[reg] = value
+
+ print('patch-reg', value, reg, file=sim_end, flush=True)
+
dumped = []
halted = False
@@ -278,6 +286,7 @@ module = importlib.util.module_from_spec(spec)
prelude = {
'read_reg': read_reg,
+ 'write_reg': write_reg,
'read_mem': read_mem,
'write_mem': write_mem,
'assert_reg': assert_reg,
diff --git a/tb/avalon.hpp b/tb/avalon.hpp
index 763065c..347c8bd 100644
--- a/tb/avalon.hpp
+++ b/tb/avalon.hpp
@@ -81,7 +81,7 @@ namespace taller::avalon
void bail() noexcept;
bool dump(std::uint32_t addr, std::uint32_t &word);
- void patch(std::uint32_t addr, std::uint32_t readdata);
+ bool patch(std::uint32_t addr, std::uint32_t readdata);
private:
struct binding
diff --git a/tb/avalon.impl.hpp b/tb/avalon.impl.hpp
index 4dee4f2..6f4bfb9 100644
--- a/tb/avalon.impl.hpp
+++ b/tb/avalon.impl.hpp
@@ -146,12 +146,15 @@ namespace taller::avalon
}
template<class Platform>
- void interconnect<Platform>::patch(std::uint32_t addr, std::uint32_t writedata)
+ bool interconnect<Platform>::patch(std::uint32_t addr, std::uint32_t writedata)
{
std::uint32_t avl_address = addr << 2;
auto *dev = resolve_external(avl_address);
- assert(dev);
+ if(!dev)
+ {
+ return false;
+ }
auto pos = (avl_address & ~dev->address_mask()) >> dev->word_bits();
@@ -159,6 +162,8 @@ namespace taller::avalon
{
continue;
}
+
+ return true;
}
template<class Platform>
diff --git a/tb/top/conspiracion.cpp b/tb/top/conspiracion.cpp
index b7ec3eb..55798cc 100644
--- a/tb/top/conspiracion.cpp
+++ b/tb/top/conspiracion.cpp
@@ -17,6 +17,7 @@
#include "Vconspiracion_platform.h"
#include "Vconspiracion_vga_domain.h"
#include "Vconspiracion_core_control.h"
+#include "Vconspiracion_core_fetch.h"
#include "Vconspiracion_core_mmu.h"
#include "Vconspiracion_core_psr.h"
#include "Vconspiracion_core_regs.h"
@@ -347,11 +348,11 @@ int main(int argc, char **argv)
std::fclose(img_file);
}
+ auto &core = *top.conspiracion->core;
for(const auto &init : init_regs)
{
- auto &regs = *top.conspiracion->core->regs;
- regs.a->file[init.index] = init.value;
- regs.b->file[init.index] = init.value;
+ core.regs->a->file[init.index] = init.value;
+ core.regs->b->file[init.index] = init.value;
}
int time = 0;
@@ -411,7 +412,6 @@ int main(int argc, char **argv)
{
std::fputs("=== dump-regs ===\n", ctrl);
- const auto &core = *top.conspiracion->core;
const auto &regfile = core.regs->a->file;
int i = 0;
@@ -432,8 +432,8 @@ int main(int argc, char **argv)
auto do_mem_dump = [&](const mem_region *dumps, std::size_t count)
{
- bool mmu_enabled = top.conspiracion->core->mmu->mmu_enable;
- std::uint32_t ttbr = top.conspiracion->core->mmu->mmu_ttbr;
+ bool mmu_enabled = core.mmu->mmu_enable;
+ std::uint32_t ttbr = core.mmu->mmu_ttbr;
auto pagewalk = [&](std::uint32_t &addr)
{
@@ -519,6 +519,8 @@ int main(int argc, char **argv)
std::signal(SIGUSR1, async_halt_handler);
+ core.fetch->explicit_branch__VforceVal = 1;
+
unsigned i = 0;
// Abuse unsigned overflow (cycles is UINT_MAX by default)
while(!failed && i + 1 <= *cycles)
@@ -536,7 +538,7 @@ int main(int argc, char **argv)
halt_or_fail:
top.step = 0;
- top.halt = 0;
+ core.fetch->target__VforceVal = core.control->pc;
do_reg_dump();
std::fprintf(ctrl, "=== %s ===\n", failed ? "fault" : "halted");
@@ -600,11 +602,44 @@ halt_or_fail:
avl.patch(addr++, word);
}
+ } else if(!std::strcmp(cmd, "patch-reg"))
+ {
+ std::uint32_t value;
+ std::sscanf(std::strtok(nullptr, " "), "%u", &value);
+
+ const char *name = std::strtok(nullptr, " ");
+ if(!std::strcmp(name, "pc"))
+ {
+ core.fetch->target__VforceVal = value >> 2;
+ } else
+ {
+ std::size_t index = 0;
+ for(const char *reg : gp_regs)
+ {
+ if(!strcmp(name, reg))
+ {
+ core.regs->a->file[index] = value;
+ core.regs->b->file[index] = value;
+ break;
+ }
+
+ ++index;
+ }
+ }
}
}
std::free(line);
async_halt = 0;
+
+ core.fetch->target__VforceEn = 0xffff'ffff;
+ core.fetch->explicit_branch__VforceEn = 1;
+
+ cycle();
+ top.halt = 0;
+
+ core.fetch->target__VforceEn = 0;
+ core.fetch->explicit_branch__VforceEn = 0;
}
if(!no_tty)