Add debug module authentication.
COMPILE = $(CC) -nostdlib -nostartfiles -I.. -Tlink.ld
ELFS = debug_rom
-DEPS = debug_rom.S link.ld debug_rom_defines.h
+DEPS = debug_rom.S link.ld ../riscv/debug_rom_defines.h ../riscv/encoding.h
all: $(patsubst %,%.h,$(ELFS))
// See LICENSE.SiFive for license details.
#include "riscv/encoding.h"
-#include "debug_rom_defines.h"
-
+#include "riscv/debug_rom_defines.h"
+
.option norvc
.global entry
.global exception
+++ /dev/null
-// See LICENSE file for license details.
-
-#ifndef DEBUG_ROM_DEFINES_H
-#define DEBUG_ROM_DEFINES_H
-
-// These are implementation-specific addresses in the Debug Module
-#define DEBUG_ROM_HALTED 0x100
-#define DEBUG_ROM_GOING 0x104
-#define DEBUG_ROM_RESUMING 0x108
-#define DEBUG_ROM_EXCEPTION 0x10C
-
-// Region of memory where each hart has 1
-// byte to read.
-#define DEBUG_ROM_FLAGS 0x400
-#define DEBUG_ROM_FLAG_GO 0
-#define DEBUG_ROM_FLAG_RESUME 1
-
-// These needs to match the link.ld
-#define DEBUG_ROM_WHERETO 0x300
-#define DEBUG_ROM_ENTRY 0x800
-#define DEBUG_ROM_TVEC 0x808
-
-#endif
#include "mmu.h"
#include "debug_rom/debug_rom.h"
-#include "debug_rom/debug_rom_defines.h"
+#include "debug_rom_defines.h"
#if 0
# define D(x) x
debug_abstract_start(debug_progbuf_start - debug_abstract_size*4),
sim(sim)
{
+ D(fprintf(stderr, "debug_data_start=0x%x\n", debug_data_start));
+ D(fprintf(stderr, "debug_progbuf_start=0x%x\n", debug_progbuf_start));
+ D(fprintf(stderr, "debug_abstract_start=0x%x\n", debug_abstract_start));
+
program_buffer = new uint8_t[program_buffer_bytes];
memset(halted, 0, sizeof(halted));
return true;
}
+ unsigned i = 0;
if (get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
- if (regno < 0x1000 || regno >= 0x1020) {
- abstractcs.cmderr = CMDERR_NOTSUP;
- return true;
- }
+ if (regno < 0x1000 && progbufsize < 2) {
+ // Make the debugger use the program buffer if it's available, so it
+ // can test both use cases.
+ write32(debug_abstract, i++, csrw(S0, CSR_DSCRATCH));
+
+ if (write) {
+ switch (size) {
+ case 2:
+ write32(debug_abstract, i++, lw(S0, ZERO, debug_data_start));
+ break;
+ case 3:
+ write32(debug_abstract, i++, ld(S0, ZERO, debug_data_start));
+ break;
+ default:
+ abstractcs.cmderr = CMDERR_NOTSUP;
+ return true;
+ }
+ write32(debug_abstract, i++, csrw(S0, regno));
+
+ } else {
+ write32(debug_abstract, i++, csrr(S0, regno));
+ switch (size) {
+ case 2:
+ write32(debug_abstract, i++, sw(S0, ZERO, debug_data_start));
+ break;
+ case 3:
+ write32(debug_abstract, i++, sd(S0, ZERO, debug_data_start));
+ break;
+ default:
+ abstractcs.cmderr = CMDERR_NOTSUP;
+ return true;
+ }
+ }
+ write32(debug_abstract, i++, csrr(S0, CSR_DSCRATCH));
+
+ } else if (regno >= 0x1000 && regno < 0x1020) {
+ unsigned regnum = regno - 0x1000;
+
+ switch (size) {
+ case 2:
+ if (write)
+ write32(debug_abstract, i++, lw(regnum, ZERO, debug_data_start));
+ else
+ write32(debug_abstract, i++, sw(regnum, ZERO, debug_data_start));
+ break;
+ case 3:
+ if (write)
+ write32(debug_abstract, i++, ld(regnum, ZERO, debug_data_start));
+ else
+ write32(debug_abstract, i++, sd(regnum, ZERO, debug_data_start));
+ break;
+ default:
+ abstractcs.cmderr = CMDERR_NOTSUP;
+ return true;
+ }
- unsigned regnum = regno - 0x1000;
+ } else if (regno >= 0x1020 && regno < 0x1040) {
+ // Don't force the debugger to use progbuf if it exists, so the
+ // debugger has to make the decision not to use abstract commands to
+ // access 64-bit FPRs on 32-bit targets.
+ unsigned fprnum = regno - 0x1020;
+
+ if (write) {
+ switch (size) {
+ case 2:
+ write32(debug_abstract, i++, flw(fprnum, ZERO, debug_data_start));
+ break;
+ case 3:
+ write32(debug_abstract, i++, fld(fprnum, ZERO, debug_data_start));
+ break;
+ default:
+ abstractcs.cmderr = CMDERR_NOTSUP;
+ return true;
+ }
- switch (size) {
- case 2:
- if (write)
- write32(debug_abstract, 0, lw(regnum, ZERO, debug_data_start));
- else
- write32(debug_abstract, 0, sw(regnum, ZERO, debug_data_start));
- break;
- case 3:
- if (write)
- write32(debug_abstract, 0, ld(regnum, ZERO, debug_data_start));
- else
- write32(debug_abstract, 0, sd(regnum, ZERO, debug_data_start));
- break;
- /*
- case 4:
- if (write)
- write32(debug_rom_code, 0, lq(regnum, ZERO, debug_data_start));
- else
- write32(debug_rom_code, 0, sq(regnum, ZERO, debug_data_start));
- break;
- */
- default:
+ } else {
+ switch (size) {
+ case 2:
+ write32(debug_abstract, i++, fsw(fprnum, ZERO, debug_data_start));
+ break;
+ case 3:
+ write32(debug_abstract, i++, fsd(fprnum, ZERO, debug_data_start));
+ break;
+ default:
+ abstractcs.cmderr = CMDERR_NOTSUP;
+ return true;
+ }
+ }
+
+ } else {
abstractcs.cmderr = CMDERR_NOTSUP;
return true;
}
- } else {
- //NOP
- write32(debug_abstract, 0, addi(ZERO, ZERO, 0));
}
if (get_field(command, AC_ACCESS_REGISTER_POSTEXEC)) {
- // Since the next instruction is what we will use, just use nother NOP
- // to get there.
- write32(debug_abstract, 1, addi(ZERO, ZERO, 0));
+ write32(debug_abstract, i,
+ jal(ZERO, debug_progbuf_start - debug_abstract_start - 4 * i));
+ i++;
} else {
- write32(debug_abstract, 1, ebreak());
+ write32(debug_abstract, i++, ebreak());
}
debug_rom_flags[dmcontrol.hartsel] |= 1 << DEBUG_ROM_FLAG_GO;
static const unsigned debug_data_start = 0x380;
unsigned debug_progbuf_start;
- static const unsigned debug_abstract_size = 2;
+ static const unsigned debug_abstract_size = 5;
unsigned debug_abstract_start;
static const unsigned hartsellen = 10;
--- /dev/null
+// See LICENSE file for license details.
+
+#ifndef DEBUG_ROM_DEFINES_H
+#define DEBUG_ROM_DEFINES_H
+
+// These are implementation-specific addresses in the Debug Module
+#define DEBUG_ROM_HALTED 0x100
+#define DEBUG_ROM_GOING 0x104
+#define DEBUG_ROM_RESUMING 0x108
+#define DEBUG_ROM_EXCEPTION 0x10C
+
+// Region of memory where each hart has 1
+// byte to read.
+#define DEBUG_ROM_FLAGS 0x400
+#define DEBUG_ROM_FLAG_GO 0
+#define DEBUG_ROM_FLAG_RESUME 1
+
+// These needs to match the link.ld
+#define DEBUG_ROM_WHERETO 0x300
+#define DEBUG_ROM_ENTRY 0x800
+#define DEBUG_ROM_TVEC 0x808
+
+#endif
#define zext_xlen(x) (((reg_t)(x) << (64-xlen)) >> (64-xlen))
#define set_pc(x) \
- do { if (unlikely(((x) & 2)) && !p->supports_extension('C')) \
- throw trap_instruction_address_misaligned(x); \
+ do { p->check_pc_alignment(x); \
npc = sext_xlen(x); \
} while(0)
#define set_pc_and_serialize(x) \
do { reg_t __npc = (x); \
- set_pc(__npc); /* check alignment */ \
npc = PC_SERIALIZE_AFTER; \
STATE.pc = __npc; \
} while(0)
+#define serialize() set_pc_and_serialize(npc)
+
/* Sentinel PC values to serialize simulator pipeline */
#define PC_SERIALIZE_BEFORE 3
#define PC_SERIALIZE_AFTER 5
#include "processor.h"
#include "mmu.h"
-#include "sim.h"
#include <cassert>
default: abort(); \
} \
pc = state.pc; \
+ check_pc_alignment(pc); \
break; \
} else { \
state.pc = pc; \
p->set_csr(csr, old & ~RS1);
}
WRITE_RD(sext_xlen(old));
+serialize();
p->set_csr(csr, old & ~(reg_t)insn.rs1());
}
WRITE_RD(sext_xlen(old));
+serialize();
p->set_csr(csr, old | RS1);
}
WRITE_RD(sext_xlen(old));
+serialize();
p->set_csr(csr, old | insn.rs1());
}
WRITE_RD(sext_xlen(old));
+serialize();
reg_t old = p->get_csr(csr);
p->set_csr(csr, RS1);
WRITE_RD(sext_xlen(old));
+serialize();
reg_t old = p->get_csr(csr);
p->set_csr(csr, insn.rs1());
WRITE_RD(sext_xlen(old));
+serialize();
throw trap_interactive();
processor_t *p = get_core(args[0]);
- return p->state.pc;
+ return p->get_state()->pc;
}
void sim_t::interactive_pc(const std::string& cmd, const std::vector<std::string>& args)
if (r >= NXPR)
throw trap_interactive();
- return p->state.XPR[r];
+ return p->get_state()->XPR[r];
}
freg_t sim_t::get_freg(const std::vector<std::string>& args)
if (r >= NFPR)
throw trap_interactive();
- return p->state.FPR[r];
+ return p->get_state()->FPR[r];
}
void sim_t::interactive_reg(const std::string& cmd, const std::vector<std::string>& args)
processor_t *p = get_core(args[0]);
for (int r = 0; r < NXPR; ++r) {
- fprintf(stderr, "%-4s: 0x%016" PRIx64 " ", xpr_name[r], p->state.XPR[r]);
+ fprintf(stderr, "%-4s: 0x%016" PRIx64 " ", xpr_name[r], p->get_state()->XPR[r]);
if ((r + 1) % 4 == 0)
fprintf(stderr, "\n");
}
#include "sim.h"
#include "processor.h"
-mmu_t::mmu_t(sim_t* sim, processor_t* proc)
+mmu_t::mmu_t(simif_t* sim, processor_t* proc)
: sim(sim), proc(proc),
check_triggers_fetch(false),
check_triggers_load(false),
class mmu_t
{
public:
- mmu_t(sim_t* sim, processor_t* proc);
+ mmu_t(simif_t* sim, processor_t* proc);
~mmu_t();
inline reg_t misaligned_load(reg_t addr, size_t size)
void register_memtracer(memtracer_t*);
private:
- sim_t* sim;
+ simif_t* sim;
processor_t* proc;
memtracer_list_t tracer;
uint16_t fetch_temp;
#undef STATE
#define STATE state
-processor_t::processor_t(const char* isa, sim_t* sim, uint32_t id,
+processor_t::processor_t(const char* isa, simif_t* sim, uint32_t id,
bool halt_on_reset)
: debug(false), halt_request(false), sim(sim), ext(NULL), id(id),
halt_on_reset(halt_on_reset), last_pc(1), executions(1)
state.satp = val & (SATP64_PPN | SATP64_MODE);
break;
}
- case CSR_SEPC: state.sepc = val; break;
+ case CSR_SEPC: state.sepc = val & ~(reg_t)1; break;
case CSR_STVEC: state.stvec = val >> 2 << 2; break;
case CSR_SSCRATCH: state.sscratch = val; break;
case CSR_SCAUSE: state.scause = val; break;
case CSR_STVAL: state.stval = val; break;
- case CSR_MEPC: state.mepc = val; break;
+ case CSR_MEPC: state.mepc = val & ~(reg_t)1; break;
case CSR_MTVEC: state.mtvec = val & ~(reg_t)2; break;
case CSR_MSCRATCH: state.mscratch = val; break;
case CSR_MCAUSE: state.mcause = val; break;
state.dcsr.halt = get_field(val, DCSR_HALT);
break;
case CSR_DPC:
- state.dpc = val;
+ state.dpc = val & ~(reg_t)1;
break;
case CSR_DSCRATCH:
state.dscratch = val;
#include "decode.h"
#include "config.h"
#include "devices.h"
+#include "trap.h"
#include <string>
#include <vector>
#include <map>
-#include "debug_rom/debug_rom_defines.h"
+#include "debug_rom_defines.h"
class processor_t;
class mmu_t;
typedef reg_t (*insn_func_t)(processor_t*, insn_t, reg_t);
-class sim_t;
+class simif_t;
class trap_t;
class extension_t;
class disassembler_t;
class processor_t : public abstract_device_t
{
public:
- processor_t(const char* isa, sim_t* sim, uint32_t id, bool halt_on_reset=false);
+ processor_t(const char* isa, simif_t* sim, uint32_t id, bool halt_on_reset=false);
~processor_t();
void set_debug(bool value);
mmu_t* get_mmu() { return mmu; }
state_t* get_state() { return &state; }
unsigned get_xlen() { return xlen; }
+ unsigned get_max_xlen() { return max_xlen; }
+ std::string get_isa_string() { return isa_string; }
unsigned get_flen() {
return supports_extension('Q') ? 128 :
supports_extension('D') ? 64 :
if (ext >= 'a' && ext <= 'z') ext += 'A' - 'a';
return ext >= 'A' && ext <= 'Z' && ((isa >> (ext - 'A')) & 1);
}
+ void check_pc_alignment(reg_t pc) {
+ if (unlikely(pc & 2) && !supports_extension('C'))
+ throw trap_instruction_address_misaligned(pc);
+ }
reg_t legalize_privilege(reg_t);
void set_privilege(reg_t);
void yield_load_reservation() { state.load_reservation = (reg_t)-1; }
void trigger_updated();
private:
- sim_t* sim;
+ simif_t* sim;
mmu_t* mmu; // main memory is always accessed via the mmu
extension_t* ext;
disassembler_t* disassembler;
void enter_debug_mode(uint8_t cause);
- friend class sim_t;
friend class mmu_t;
friend class clint_t;
friend class extension_t;
0x297, // auipc t0,0x0
0x28593 + (reset_vec_size * 4 << 20), // addi a1, t0, &dtb
0xf1402573, // csrr a0, mhartid
- get_core(0)->xlen == 32 ?
+ get_core(0)->get_xlen() == 32 ?
0x0182a283u : // lw t0,24(t0)
0x0182b283u, // ld t0,24(t0)
0x28067, // jr t0
" reg = <" << i << ">;\n"
" status = \"okay\";\n"
" compatible = \"riscv\";\n"
- " riscv,isa = \"" << procs[i]->isa_string << "\";\n"
- " mmu-type = \"riscv," << (procs[i]->max_xlen <= 32 ? "sv32" : "sv48") << "\";\n"
+ " riscv,isa = \"" << procs[i]->get_isa_string() << "\";\n"
+ " mmu-type = \"riscv," << (procs[i]->get_max_xlen() <= 32 ? "sv32" : "sv48") << "\";\n"
" clock-frequency = <" << CPU_HZ << ">;\n"
" CPU" << i << "_intc: interrupt-controller {\n"
" #interrupt-cells = <1>;\n"
class mmu_t;
class remote_bitbang_t;
+// this is the interface to the simulator used by the processors and memory
+class simif_t
+{
+public:
+ // should return NULL for MMIO addresses
+ virtual char* addr_to_mem(reg_t addr) = 0;
+ // used for MMIO addresses
+ virtual bool mmio_load(reg_t addr, size_t len, uint8_t* bytes) = 0;
+ virtual bool mmio_store(reg_t addr, size_t len, const uint8_t* bytes) = 0;
+};
+
// this class encapsulates the processors and memory in a RISC-V machine.
-class sim_t : public htif_t
+class sim_t : public htif_t, public simif_t
{
public:
sim_t(const char* isa, size_t _nprocs, bool halted, reg_t start_pc,
softfloat_hdrs = \
internals.h \
+ platform.h \
primitives.h \
primitiveTypes.h \
softfloat.h \