Entering debug mode now jumps to "dynamic rom"
authorTim Newsome <tim@sifive.com>
Sat, 11 Feb 2017 03:08:16 +0000 (19:08 -0800)
committerTim Newsome <tim@sifive.com>
Sat, 11 Feb 2017 03:08:16 +0000 (19:08 -0800)
riscv/debug_module.cc
riscv/debug_module.h
riscv/decode.h
riscv/opcodes.h [new file with mode: 0644]
riscv/processor.cc
riscv/processor.h
riscv/sim.h

index ba30603b5c2fc69df99e33863e5471dfb343e187..b8954e98cb55f9b933eca0690151ac67adb747f7 100644 (file)
@@ -2,6 +2,7 @@
 
 #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;
 }
 
@@ -49,38 +64,25 @@ bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes)
     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) |
@@ -88,47 +90,71 @@ uint32_t debug_module_t::ram_read32(unsigned int index)
   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));
@@ -138,6 +164,28 @@ bool debug_module_t::dmi_write(unsigned address, uint32_t 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;
 }
index b64a454b0ecfb5a9345aaec6da23e846b6e55a84..934463f9795cfec2487fedc08fe9176ca65715df 100644 (file)
@@ -8,6 +8,27 @@
 
 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:
@@ -16,9 +37,6 @@ class debug_module_t : public abstract_device_t
     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);
     }
@@ -51,15 +69,22 @@ class debug_module_t : public abstract_device_t
     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
index b607bf38a02daccce1b90daafa71b89eb38a8c4c..c34b07eddbbae6fbf9de925517f4427d919e0388 100644 (file)
@@ -225,17 +225,13 @@ private:
     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
diff --git a/riscv/opcodes.h b/riscv/opcodes.h
new file mode 100644 (file)
index 0000000..eb76455
--- /dev/null
@@ -0,0 +1,241 @@
+#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;
+}
index 17d4069f2fc34fa66d707f4dc7a1fde1c8d8503a..82f74448b93e07ffbeae097e3417aba8c67d4c61 100644 (file)
@@ -21,7 +21,8 @@
 
 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();
@@ -199,7 +200,7 @@ void processor_t::enter_debug_mode(uint8_t cause)
   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)
index 32dc9cd2443a709ba0bb3e60db3afaa07d2d5456..3268029e458d5832bd09b274bace4a88ca05a249 100644 (file)
@@ -193,6 +193,12 @@ public:
   // 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)
index 99b6809d7deb9b26239e926377a9867a86ccde13..4cb70b4d47deee29839968be430810be2e75e4d2 100644 (file)
@@ -34,6 +34,7 @@ public:
   }
   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;