#include "debug_module.h"
#include "debug_defines.h"
+#include "opcodes.h"
#include "mmu.h"
#include "debug_rom/debug_rom.h"
# define D(x)
#endif
-debug_module_t::debug_module_t(sim_t *sim) :
- sim(sim),
- dmcontrol(1 << DMI_DMCONTROL_VERSION_OFFSET |
- 1 << DMI_DMCONTROL_AUTHENTICATED_OFFSET),
- abstractcs(datacount << DMI_ABSTRACTCS_DATACOUNT_OFFSET)
+debug_module_t::debug_module_t(sim_t *sim) : sim(sim)
{
+ dmcontrol.version = 1;
+
+ write32(debug_rom_entry, 0, jal(0, 0));
+}
+
+void debug_module_t::reset()
+{
+ for (unsigned i = 0; i < sim->nprocs(); i++) {
+ processor_t *proc = sim->get_core(i);
+ if (proc)
+ proc->halt_request = false;
+ }
+
+ dmcontrol.haltreq = 0;
+ dmcontrol.reset = 0;
+ dmcontrol.dmactive = 0;
+ dmcontrol.hartsel = 0;
+ dmcontrol.authenticated = 1;
+ dmcontrol.version = 1;
+ dmcontrol.authbusy = 0;
+ dmcontrol.authtype = dmcontrol.AUTHTYPE_NOAUTH;
+ abstractcs = datacount << DMI_ABSTRACTCS_DATACOUNT_OFFSET;
}
bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes)
{
addr = DEBUG_START + addr;
- if (addr >= DEBUG_RAM_START && addr + len <= DEBUG_RAM_END) {
- memcpy(bytes, debug_ram + addr - DEBUG_RAM_START, len);
- return true;
- }
-
- if (addr >= DEBUG_ROM_START && addr + len <= DEBUG_ROM_END) {
- memcpy(bytes, debug_rom_raw + addr - DEBUG_ROM_START, len);
+ if (addr >= DEBUG_ROM_ENTRY && addr <= DEBUG_ROM_CODE) {
+ memcpy(bytes, debug_rom_entry + addr - DEBUG_ROM_ENTRY, len);
return true;
}
fprintf(stderr, "ERROR: invalid load from debug module: %zd bytes at 0x%016"
PRIx64 "\n", len, addr);
+
return false;
}
return false;
}
- if (addr >= DEBUG_RAM_START && addr + len <= DEBUG_RAM_END) {
- memcpy(debug_ram + addr - DEBUG_RAM_START, bytes, len);
- return true;
- } else if (len == 4 && addr == DEBUG_CLEARDEBINT) {
- clear_interrupt(bytes[0] | (bytes[1] << 8) |
- (bytes[2] << 16) | (bytes[3] << 24));
- return true;
- } else if (len == 4 && addr == DEBUG_SETHALTNOT) {
- set_halt_notification(bytes[0] | (bytes[1] << 8) |
- (bytes[2] << 16) | (bytes[3] << 24));
- return true;
- }
+ // memcpy(debug_ram + addr - DEBUG_RAM_START, bytes, len);
fprintf(stderr, "ERROR: invalid store to debug module: %zd bytes at 0x%016"
PRIx64 "\n", len, addr);
return false;
}
-void debug_module_t::ram_write32(unsigned int index, uint32_t value)
+void debug_module_t::write32(uint8_t *memory, unsigned int index, uint32_t value)
{
- char* base = debug_ram + index * 4;
+ uint8_t* base = memory + index * 4;
base[0] = value & 0xff;
base[1] = (value >> 8) & 0xff;
base[2] = (value >> 16) & 0xff;
base[3] = (value >> 24) & 0xff;
}
-uint32_t debug_module_t::ram_read32(unsigned int index)
+uint32_t debug_module_t::read32(uint8_t *memory, unsigned int index)
{
- // It'd be better for raw_page (and all memory) to be unsigned chars, but mem
- // in sim_t is just chars, so I'm following that convention.
- unsigned char* base = (unsigned char*) (debug_ram + index * 4);
+ uint8_t* base = memory + index * 4;
uint32_t value = ((uint32_t) base[0]) |
(((uint32_t) base[1]) << 8) |
(((uint32_t) base[2]) << 16) |
return value;
}
+processor_t *debug_module_t::current_proc() const
+{
+ processor_t *proc = NULL;
+ try {
+ proc = sim->get_core(dmcontrol.hartsel);
+ } catch (const std::out_of_range&) {
+ }
+ return proc;
+}
+
bool debug_module_t::dmi_read(unsigned address, uint32_t *value)
{
+ uint32_t result = 0;
D(fprintf(stderr, "dmi_read(0x%x) -> ", address));
if (address >= DMI_DATA0 && address < DMI_DATA0 + datacount) {
- *value = data[address - DMI_DATA0];
+ result = data[address - DMI_DATA0];
} else if (address >= DMI_IBUF0 && address < DMI_IBUF0 + progsize) {
- *value = ibuf[address - DMI_IBUF0];
+ result = ibuf[address - DMI_IBUF0];
} else {
switch (address) {
case DMI_DMCONTROL:
{
- processor_t *proc = sim->get_core(get_field(dmcontrol,
- DMI_DMCONTROL_HARTSEL));
+ processor_t *proc = current_proc();
if (proc) {
- D(fprintf(stderr, "(halted=%d) ", proc->halted()));
if (proc->halted()) {
- dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSTATUS, 0);
+ dmcontrol.hartstatus = dmcontrol.HARTSTATUS_HALTED;
} else {
- dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSTATUS, 1);
+ dmcontrol.hartstatus = dmcontrol.HARTSTATUS_RUNNING;
}
+ dmcontrol.haltreq = proc->halt_request;
} else {
- dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSTATUS, 3);
+ dmcontrol.hartstatus = dmcontrol.HARTSTATUS_NOTEXIST;
}
- *value = dmcontrol;
+ result = set_field(result, DMI_DMCONTROL_HALTREQ, dmcontrol.haltreq);
+ result = set_field(result, DMI_DMCONTROL_RESET, dmcontrol.reset);
+ result = set_field(result, DMI_DMCONTROL_DMACTIVE, dmcontrol.dmactive);
+ result = set_field(result, DMI_DMCONTROL_HARTSTATUS, dmcontrol.hartstatus);
+ result = set_field(result, DMI_DMCONTROL_HARTSEL, dmcontrol.hartsel);
+ result = set_field(result, DMI_DMCONTROL_AUTHENTICATED, dmcontrol.authenticated);
+ result = set_field(result, DMI_DMCONTROL_AUTHBUSY, dmcontrol.authbusy);
+ result = set_field(result, DMI_DMCONTROL_AUTHTYPE, dmcontrol.authtype);
+ result = set_field(result, DMI_DMCONTROL_VERSION, dmcontrol.version);
}
break;
case DMI_ABSTRACTCS:
- *value = abstractcs;
+ result = abstractcs;
break;
case DMI_ACCESSCS:
- *value = progsize << DMI_ACCESSCS_PROGSIZE_OFFSET;
+ result = progsize << DMI_ACCESSCS_PROGSIZE_OFFSET;
break;
default:
D(fprintf(stderr, "error\n"));
return false;
}
}
- D(fprintf(stderr, "0x%x\n", *value));
+ D(fprintf(stderr, "0x%x\n", result));
+ *value = result;
return true;
}
+bool debug_module_t::perform_abstract_command(uint32_t command)
+{
+ return false;
+}
+
bool debug_module_t::dmi_write(unsigned address, uint32_t value)
{
D(fprintf(stderr, "dmi_write(0x%x, 0x%x)\n", address, value));
} else if (address >= DMI_IBUF0 && address < DMI_IBUF0 + progsize) {
ibuf[address - DMI_IBUF0] = value;
return true;
+ } else {
+ switch (address) {
+ case DMI_DMCONTROL:
+ {
+ dmcontrol.dmactive = get_field(value, DMI_DMCONTROL_DMACTIVE);
+ if (dmcontrol.dmactive) {
+ dmcontrol.haltreq = get_field(value, DMI_DMCONTROL_HALTREQ);
+ dmcontrol.reset = get_field(value, DMI_DMCONTROL_RESET);
+ dmcontrol.hartsel = get_field(value, DMI_DMCONTROL_HARTSEL);
+ } else {
+ reset();
+ }
+ processor_t *proc = current_proc();
+ if (proc) {
+ proc->halt_request = dmcontrol.haltreq;
+ }
+ }
+ return true;
+
+ case DMI_ABSTRACTCS:
+ return perform_abstract_command(value);
+ }
}
return false;
}
class sim_t;
+typedef struct {
+ bool haltreq;
+ bool reset;
+ bool dmactive;
+ enum {
+ HARTSTATUS_HALTED,
+ HARTSTATUS_RUNNING,
+ HARTSTATUS_UNAVAILABLE,
+ HARTSTATUS_NOTEXIST
+ } hartstatus;
+ unsigned hartsel;
+ bool authenticated;
+ bool authbusy;
+ enum {
+ AUTHTYPE_NOAUTH,
+ AUTHTYPE_PASSWORD,
+ AUTHTYPE_CHALLENGE
+ } authtype;
+ unsigned version;
+} dmcontrol_t;
+
class debug_module_t : public abstract_device_t
{
public:
bool load(reg_t addr, size_t len, uint8_t* bytes);
bool store(reg_t addr, size_t len, const uint8_t* bytes);
- void ram_write32(unsigned int index, uint32_t value);
- uint32_t ram_read32(unsigned int index);
-
void set_interrupt(uint32_t hartid) {
interrupt.insert(hartid);
}
std::set<uint32_t> interrupt;
// Track which halt notifications from debugger to module are set.
std::set<uint32_t> halt_notification;
- char debug_ram[DEBUG_RAM_SIZE];
+ uint8_t debug_rom_entry[1024 * 4];
+
+ void write32(uint8_t *rom, unsigned int index, uint32_t value);
+ uint32_t read32(uint8_t *rom, unsigned int index);
static const unsigned datacount = 8;
static const unsigned progsize = 8;
- uint32_t dmcontrol;
+ dmcontrol_t dmcontrol;
uint32_t abstractcs;
uint32_t data[datacount];
uint32_t ibuf[progsize];
+
+ processor_t *current_proc() const;
+ void reset();
+ bool perform_abstract_command(uint32_t command);
};
#endif
throw trap_illegal_instruction(); \
(which); })
-#define DEBUG_START 0x100
-#define DEBUG_ROM_START 0x800
-#define DEBUG_ROM_RESUME (DEBUG_ROM_START + 4)
-#define DEBUG_ROM_EXCEPTION (DEBUG_ROM_START + 8)
-#define DEBUG_ROM_END (DEBUG_ROM_START + debug_rom_raw_len)
-#define DEBUG_RAM_START 0x400
+#define DEBUG_START 0x20000
+#define DEBUG_ROM_ENTRY DEBUG_START
+#define DEBUG_ROM_CODE (DEBUG_ROM_ENTRY + 1024 * 4)
+#define DEBUG_ROM_EXCEPTION (DEBUG_ROM_CODE + 4)
+#define DEBUG_RAM_START (DEBUG_ROM_EXCEPTION + 256)
#define DEBUG_RAM_SIZE 64
#define DEBUG_RAM_END (DEBUG_RAM_START + DEBUG_RAM_SIZE)
-#define DEBUG_END 0xfff
-#define DEBUG_CLEARDEBINT 0x100
-#define DEBUG_SETHALTNOT 0x10c
-#define DEBUG_SIZE (DEBUG_END - DEBUG_START + 1)
+#define DEBUG_END DEBUG_RAM_END
#endif
--- /dev/null
+#include "encoding.h"
+
+#define ZERO 0
+#define T0 5
+#define S0 8
+#define S1 9
+
+static uint32_t bits(uint32_t value, unsigned int hi, unsigned int lo) {
+ return (value >> lo) & ((1 << (hi+1-lo)) - 1);
+}
+
+static uint32_t bit(uint32_t value, unsigned int b) {
+ return (value >> b) & 1;
+}
+
+static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused));
+static uint32_t jal(unsigned int rd, uint32_t imm) {
+ return (bit(imm, 20) << 31) |
+ (bits(imm, 10, 1) << 21) |
+ (bit(imm, 11) << 20) |
+ (bits(imm, 19, 12) << 12) |
+ (rd << 7) |
+ MATCH_JAL;
+}
+
+static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused));
+static uint32_t csrsi(unsigned int csr, uint16_t imm) {
+ return (csr << 20) |
+ (bits(imm, 4, 0) << 15) |
+ MATCH_CSRRSI;
+}
+
+static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t sw(unsigned int src, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 5) << 25) |
+ (src << 20) |
+ (base << 15) |
+ (bits(offset, 4, 0) << 7) |
+ MATCH_SW;
+}
+
+static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t sd(unsigned int src, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 5) << 25) |
+ (src << 20) |
+ (base << 15) |
+ (bits(offset, 4, 0) << 7) |
+ MATCH_SD;
+}
+
+static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t sh(unsigned int src, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 5) << 25) |
+ (src << 20) |
+ (base << 15) |
+ (bits(offset, 4, 0) << 7) |
+ MATCH_SH;
+}
+
+static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t sb(unsigned int src, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 5) << 25) |
+ (src << 20) |
+ (base << 15) |
+ (bits(offset, 4, 0) << 7) |
+ MATCH_SB;
+}
+
+static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t ld(unsigned int rd, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 0) << 20) |
+ (base << 15) |
+ (bits(rd, 4, 0) << 7) |
+ MATCH_LD;
+}
+
+static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t lw(unsigned int rd, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 0) << 20) |
+ (base << 15) |
+ (bits(rd, 4, 0) << 7) |
+ MATCH_LW;
+}
+
+static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 0) << 20) |
+ (base << 15) |
+ (bits(rd, 4, 0) << 7) |
+ MATCH_LH;
+}
+
+static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 0) << 20) |
+ (base << 15) |
+ (bits(rd, 4, 0) << 7) |
+ MATCH_LB;
+}
+
+static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused));
+static uint32_t csrw(unsigned int source, unsigned int csr) {
+ return (csr << 20) | (source << 15) | MATCH_CSRRW;
+}
+
+static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
+static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm)
+{
+ return (bits(imm, 11, 0) << 20) |
+ (src << 15) |
+ (dest << 7) |
+ MATCH_ADDI;
+}
+
+static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused));
+static uint32_t csrr(unsigned int rd, unsigned int csr) {
+ return (csr << 20) | (rd << 7) | MATCH_CSRRS;
+}
+
+static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t fsw(unsigned int src, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 5) << 25) |
+ (bits(src, 4, 0) << 20) |
+ (base << 15) |
+ (bits(offset, 4, 0) << 7) |
+ MATCH_FSW;
+}
+
+static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 5) << 25) |
+ (bits(src, 4, 0) << 20) |
+ (base << 15) |
+ (bits(offset, 4, 0) << 7) |
+ MATCH_FSD;
+}
+
+static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t flw(unsigned int dest, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 0) << 20) |
+ (base << 15) |
+ (bits(dest, 4, 0) << 7) |
+ MATCH_FLW;
+}
+
+static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 0) << 20) |
+ (base << 15) |
+ (bits(dest, 4, 0) << 7) |
+ MATCH_FLD;
+}
+
+static uint32_t ebreak(void) __attribute__ ((unused));
+static uint32_t ebreak(void) { return MATCH_EBREAK; }
+static uint32_t ebreak_c(void) __attribute__ ((unused));
+static uint32_t ebreak_c(void) { return MATCH_C_EBREAK; }
+
+static uint32_t fence_i(void) __attribute__ ((unused));
+static uint32_t fence_i(void)
+{
+ return MATCH_FENCE_I;
+}
+
+/*
+static uint32_t lui(unsigned int dest, uint32_t imm) __attribute__ ((unused));
+static uint32_t lui(unsigned int dest, uint32_t imm)
+{
+ return (bits(imm, 19, 0) << 12) |
+ (dest << 7) |
+ MATCH_LUI;
+}
+
+static uint32_t csrci(unsigned int csr, uint16_t imm) __attribute__ ((unused));
+static uint32_t csrci(unsigned int csr, uint16_t imm) {
+ return (csr << 20) |
+ (bits(imm, 4, 0) << 15) |
+ MATCH_CSRRCI;
+}
+
+static uint32_t li(unsigned int dest, uint16_t imm) __attribute__ ((unused));
+static uint32_t li(unsigned int dest, uint16_t imm)
+{
+ return addi(dest, 0, imm);
+}
+
+static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset) __attribute__ ((unused));
+static uint32_t fsd(unsigned int src, unsigned int base, uint16_t offset)
+{
+ return (bits(offset, 11, 5) << 25) |
+ (bits(src, 4, 0) << 20) |
+ (base << 15) |
+ (bits(offset, 4, 0) << 7) |
+ MATCH_FSD;
+}
+
+static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
+static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm)
+{
+ return (bits(imm, 11, 0) << 20) |
+ (src << 15) |
+ (dest << 7) |
+ MATCH_ORI;
+}
+
+static uint32_t nop(void) __attribute__ ((unused));
+static uint32_t nop(void)
+{
+ return addi(0, 0, 0);
+}
+*/
+
+static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused));
+static uint32_t xori(unsigned int dest, unsigned int src, uint16_t imm)
+{
+ return (bits(imm, 11, 0) << 20) |
+ (src << 15) |
+ (dest << 7) |
+ MATCH_XORI;
+}
+
+static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt) __attribute__ ((unused));
+static uint32_t srli(unsigned int dest, unsigned int src, uint8_t shamt)
+{
+ return (bits(shamt, 4, 0) << 20) |
+ (src << 15) |
+ (dest << 7) |
+ MATCH_SRLI;
+}
processor_t::processor_t(const char* isa, sim_t* sim, uint32_t id,
bool halt_on_reset)
- : debug(false), sim(sim), ext(NULL), id(id), halt_on_reset(halt_on_reset)
+ : debug(false), halt_request(false), sim(sim), ext(NULL), id(id),
+ halt_on_reset(halt_on_reset)
{
parse_isa_string(isa);
register_base_instructions();
state.dcsr.prv = state.prv;
set_privilege(PRV_M);
state.dpc = state.pc;
- state.pc = DEBUG_ROM_START;
+ state.pc = debug_rom_entry();
}
void processor_t::take_trap(trap_t& t, reg_t epc)
// When true, take the slow simulation path.
bool slow_path();
bool halted() { return state.dcsr.cause ? true : false; }
+ bool halt_request;
+ // The unique debug rom address that this hart jumps to when entering debug
+ // mode. Rely on the fact that spike hart IDs start at 0 and are consecutive.
+ uint32_t debug_rom_entry() {
+ return DEBUG_ROM_ENTRY + 4 * id;
+ }
// Return the index of a trigger that matched, or -1.
inline int trigger_match(trigger_operation_t operation, reg_t address, reg_t data)
}
const char* get_config_string() { return config_string.c_str(); }
processor_t* get_core(size_t i) { return procs.at(i); }
+ unsigned nprocs() const { return procs.size(); }
debug_module_t debug_module;