Generate device tree for target machine
authorAndrew Waterman <waterman@cs.berkeley.edu>
Fri, 13 Nov 2015 01:51:46 +0000 (17:51 -0800)
committerAndrew Waterman <waterman@cs.berkeley.edu>
Fri, 13 Nov 2015 01:52:56 +0000 (17:52 -0800)
riscv/decode.h
riscv/devices.cc [new file with mode: 0644]
riscv/devices.h [new file with mode: 0644]
riscv/devicetree.h [new file with mode: 0644]
riscv/encoding.h
riscv/mmu.cc
riscv/processor.cc
riscv/processor.h
riscv/riscv.mk.in
riscv/sim.cc
riscv/sim.h

index a9713f45f2b65e34b867cf6216ce8de22f4611eb..5be639853f39ddc681dbef6ad42ffe0f174a3b78 100644 (file)
@@ -21,6 +21,7 @@ typedef uint64_t freg_t;
 
 const int NXPR = 32;
 const int NFPR = 32;
+const int NCSR = 4096;
 
 #define X_RA 1
 #define X_SP 2
diff --git a/riscv/devices.cc b/riscv/devices.cc
new file mode 100644 (file)
index 0000000..25e39e0
--- /dev/null
@@ -0,0 +1,40 @@
+#include "devices.h"
+
+void bus_t::add_device(reg_t addr, abstract_device_t* dev)
+{
+  devices[-addr] = dev;
+}
+
+bool bus_t::load(reg_t addr, size_t len, uint8_t* bytes)
+{
+  auto it = devices.lower_bound(-addr);
+  if (it == devices.end())
+    return false;
+  return it->second->load(addr - -it->first, len, bytes);
+}
+
+bool bus_t::store(reg_t addr, size_t len, const uint8_t* bytes)
+{
+  auto it = devices.lower_bound(-addr);
+  if (it == devices.end())
+    return false;
+  return it->second->store(addr - -it->first, len, bytes);
+}
+
+rom_device_t::rom_device_t(std::vector<char> data)
+  : data(data)
+{
+}
+
+bool rom_device_t::load(reg_t addr, size_t len, uint8_t* bytes)
+{
+  if (addr + len > data.size())
+    return false;
+  memcpy(bytes, &data[addr], len);
+  return true;
+}
+
+bool rom_device_t::store(reg_t addr, size_t len, const uint8_t* bytes)
+{
+  return false;
+}
diff --git a/riscv/devices.h b/riscv/devices.h
new file mode 100644 (file)
index 0000000..558ecc7
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _RISCV_DEVICES_H
+#define _RISCV_DEVICES_H
+
+#include "decode.h"
+#include <map>
+#include <vector>
+
+class abstract_device_t {
+ public:
+  virtual bool load(reg_t addr, size_t len, uint8_t* bytes) = 0;
+  virtual bool store(reg_t addr, size_t len, const uint8_t* bytes) = 0;
+  virtual ~abstract_device_t() {}
+};
+
+class bus_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 add_device(reg_t addr, abstract_device_t* dev);
+
+ private:
+  std::map<reg_t, abstract_device_t*> devices;
+};
+
+class rom_device_t : public abstract_device_t {
+ public:
+  rom_device_t(std::vector<char> data);
+  bool load(reg_t addr, size_t len, uint8_t* bytes);
+  bool store(reg_t addr, size_t len, const uint8_t* bytes);
+ private:
+  std::vector<char> data;
+};
+
+#endif
diff --git a/riscv/devicetree.h b/riscv/devicetree.h
new file mode 100644 (file)
index 0000000..5d4a871
--- /dev/null
@@ -0,0 +1,142 @@
+// See LICENSE for license details.
+
+#ifndef _RISCV_DEVICETREE_H
+#define _RISCV_DEVICETREE_H
+
+#include <stdint.h>
+#include <string.h>
+#include <string>
+#include <map>
+#include <vector>
+#include <arpa/inet.h>
+
+#define FDT_MAGIC 0xd00dfeedU
+#define FDT_VERSION 17
+#define FDT_COMP_VERSION 16
+#define FDT_BEGIN_NODE 1
+#define FDT_END_NODE 2
+#define FDT_PROP 3
+#define FDT_END 9
+
+struct fdt_header {
+  uint32_t magic;
+  uint32_t totalsize;
+  uint32_t off_dt_struct;
+  uint32_t off_dt_strings;
+  uint32_t off_rsvmap;
+  uint32_t version;
+  uint32_t last_comp_version;
+  uint32_t boot_cpuid_phys;
+  uint32_t size_dt_strings;
+  uint32_t size_dt_struct;
+};
+
+struct fdt_reserve_entry {
+  uint64_t address;
+  uint64_t size;
+};
+
+struct string_table {
+  std::map<std::string, size_t> strings;
+  std::vector<char> data;
+
+  size_t add(std::string s) {
+    if (!strings.count(s)) {
+      strings[s] = data.size();
+      data.insert(data.end(), s.begin(), s.end());
+      data.push_back(0);
+    }
+    return strings[s];
+  }
+};
+
+struct device_tree {
+  device_tree() {
+    memset(rsvmap, 0, sizeof(rsvmap));
+  }
+
+  void begin_node(std::string s) {
+    std::vector<uint32_t> name = s2v(s);
+    sblock.push_back(FDT_BEGIN_NODE);
+    sblock.insert(sblock.end(), name.begin(), name.end());
+  }
+
+  void end_node() {
+    sblock.push_back(FDT_END_NODE);
+  }
+
+  std::vector<char> finalize() {
+    sblock.push_back(FDT_END);
+
+    struct fdt_header h;
+    h.size_dt_struct = sblock.size() * sizeof(sblock[0]);
+    h.size_dt_strings = strings.data.size();
+    h.magic = FDT_MAGIC;
+    h.off_rsvmap = sizeof(h);
+    h.off_dt_struct = h.off_rsvmap + sizeof(rsvmap);
+    h.off_dt_strings = h.off_dt_struct + h.size_dt_struct;
+    h.totalsize = h.off_dt_strings + h.size_dt_strings;
+    h.version = FDT_VERSION;
+    h.last_comp_version = FDT_COMP_VERSION;
+    h.boot_cpuid_phys = 0;
+
+    for (uint32_t* p = &h.magic; p < &h.magic + sizeof(h)/sizeof(uint32_t); p++)
+      *p = htonl(*p);
+    for (uint32_t& p : sblock)
+      p = htonl(p);
+
+    std::vector<char> res;
+    res.insert(res.end(), (char*)&h, (char*)&h + sizeof(h));
+    res.insert(res.end(), (char*)&rsvmap, (char*)&rsvmap + sizeof(rsvmap));
+    res.insert(res.end(), (char*)&sblock[0],
+               (char*)&sblock[0] + sblock.size() * sizeof(sblock[0]));
+    res.insert(res.end(), strings.data.begin(), strings.data.end());
+    return res;
+  }
+  
+  void add_prop(std::string name, uint32_t data)
+  {
+    add_prop(name, std::vector<uint32_t>(1, data), sizeof(data));
+  }
+  
+  void add_reg(std::vector<uint64_t> values)
+  {
+    std::vector<uint32_t> v;
+    for (auto x : values) {
+      v.push_back(x >> 32);
+      v.push_back(x);
+    }
+    add_prop("reg", v, v.size() * sizeof(v[0]));
+  }
+  
+  void add_prop(std::string name, std::string data)
+  {
+    add_prop(name, s2v(data), data.size()+1);
+  }
+
+ private:
+  struct string_table strings;
+  std::vector<uint32_t> sblock;
+  struct fdt_reserve_entry rsvmap[1];
+
+  std::vector<uint32_t> s2v(std::string data) {
+    std::vector<char> v(data.begin(), data.end());
+    do {
+      v.push_back(0);
+    } while (v.size() % 4);
+  
+    std::vector<uint32_t> words;
+    for (size_t i = 0; i < v.size(); i += 4)
+      words.push_back((v[i] << 24) | (v[i+1] << 16) | (v[i+2] << 8) | v[i+3]);
+    return words;
+  }
+  
+  void add_prop(std::string name, std::vector<uint32_t> data, size_t len) {
+    sblock.push_back(FDT_PROP);
+    sblock.push_back(len);
+    sblock.push_back(strings.add(name));
+    sblock.insert(sblock.end(), data.begin(), data.end());
+  }
+};
+
+#endif
index 7303a2b19d46084445611875630b0c2819b3148b..e9a495fa9a6504c76c042d0d3a21f84c9be2ca6f 100644 (file)
 #define MASK_C_SWSP  0xe003
 #define MATCH_C_FSWSP 0xe002
 #define MASK_C_FSWSP  0xe003
+#define MATCH_CUSTOM0 0xb
+#define MASK_CUSTOM0  0x707f
+#define MATCH_CUSTOM0_RS1 0x200b
+#define MASK_CUSTOM0_RS1  0x707f
+#define MATCH_CUSTOM0_RS1_RS2 0x300b
+#define MASK_CUSTOM0_RS1_RS2  0x707f
+#define MATCH_CUSTOM0_RD 0x400b
+#define MASK_CUSTOM0_RD  0x707f
+#define MATCH_CUSTOM0_RD_RS1 0x600b
+#define MASK_CUSTOM0_RD_RS1  0x707f
+#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b
+#define MASK_CUSTOM0_RD_RS1_RS2  0x707f
+#define MATCH_CUSTOM1 0x2b
+#define MASK_CUSTOM1  0x707f
+#define MATCH_CUSTOM1_RS1 0x202b
+#define MASK_CUSTOM1_RS1  0x707f
+#define MATCH_CUSTOM1_RS1_RS2 0x302b
+#define MASK_CUSTOM1_RS1_RS2  0x707f
+#define MATCH_CUSTOM1_RD 0x402b
+#define MASK_CUSTOM1_RD  0x707f
+#define MATCH_CUSTOM1_RD_RS1 0x602b
+#define MASK_CUSTOM1_RD_RS1  0x707f
+#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b
+#define MASK_CUSTOM1_RD_RS1_RS2  0x707f
+#define MATCH_CUSTOM2 0x5b
+#define MASK_CUSTOM2  0x707f
+#define MATCH_CUSTOM2_RS1 0x205b
+#define MASK_CUSTOM2_RS1  0x707f
+#define MATCH_CUSTOM2_RS1_RS2 0x305b
+#define MASK_CUSTOM2_RS1_RS2  0x707f
+#define MATCH_CUSTOM2_RD 0x405b
+#define MASK_CUSTOM2_RD  0x707f
+#define MATCH_CUSTOM2_RD_RS1 0x605b
+#define MASK_CUSTOM2_RD_RS1  0x707f
+#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b
+#define MASK_CUSTOM2_RD_RS1_RS2  0x707f
+#define MATCH_CUSTOM3 0x7b
+#define MASK_CUSTOM3  0x707f
+#define MATCH_CUSTOM3_RS1 0x207b
+#define MASK_CUSTOM3_RS1  0x707f
+#define MATCH_CUSTOM3_RS1_RS2 0x307b
+#define MASK_CUSTOM3_RS1_RS2  0x707f
+#define MATCH_CUSTOM3_RD 0x407b
+#define MASK_CUSTOM3_RD  0x707f
+#define MATCH_CUSTOM3_RD_RS1 0x607b
+#define MASK_CUSTOM3_RD_RS1  0x707f
+#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b
+#define MASK_CUSTOM3_RD_RS1_RS2  0x707f
 #define CSR_FFLAGS 0x1
 #define CSR_FRM 0x2
 #define CSR_FCSR 0x3
 #define CSR_MTOHOST 0x780
 #define CSR_MFROMHOST 0x781
 #define CSR_MRESET 0x782
-#define CSR_SEND_IPI 0x783
+#define CSR_MIPI 0x783
+#define CSR_MIOBASE 0x784
 #define CSR_CYCLEH 0xc80
 #define CSR_TIMEH 0xc81
 #define CSR_INSTRETH 0xc82
@@ -851,6 +900,30 @@ DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD)
 DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP)
 DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP)
 DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP)
+DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0)
+DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1)
+DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2)
+DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD)
+DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1)
+DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2)
+DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1)
+DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1)
+DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2)
+DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD)
+DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1)
+DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2)
+DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2)
+DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1)
+DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2)
+DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD)
+DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1)
+DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2)
+DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3)
+DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1)
+DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2)
+DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD)
+DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1)
+DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2)
 #endif
 #ifdef DECLARE_CSR
 DECLARE_CSR(fflags, CSR_FFLAGS)
@@ -908,7 +981,8 @@ DECLARE_CSR(mhartid, CSR_MHARTID)
 DECLARE_CSR(mtohost, CSR_MTOHOST)
 DECLARE_CSR(mfromhost, CSR_MFROMHOST)
 DECLARE_CSR(mreset, CSR_MRESET)
-DECLARE_CSR(send_ipi, CSR_SEND_IPI)
+DECLARE_CSR(mipi, CSR_MIPI)
+DECLARE_CSR(miobase, CSR_MIOBASE)
 DECLARE_CSR(cycleh, CSR_CYCLEH)
 DECLARE_CSR(timeh, CSR_TIMEH)
 DECLARE_CSR(instreth, CSR_INSTRETH)
index a8b167544cb64c9847c85f272b083ffa34b2daf7..4558b1e7bf0481d50a8f9e102ac86e6e78f8d308 100644 (file)
@@ -64,7 +64,7 @@ void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes)
       tracer.trace(paddr, len, LOAD);
     else
       refill_tlb(addr, paddr, LOAD);
-  } else if (!proc || !proc->sim->mmio_load(addr, len, bytes)) {
+  } else if (!proc || !proc->sim->mmio_load(paddr, len, bytes)) {
     throw trap_load_access_fault(addr);
   }
 }
@@ -78,7 +78,7 @@ void mmu_t::store_slow_path(reg_t addr, reg_t len, const uint8_t* bytes)
       tracer.trace(paddr, len, STORE);
     else
       refill_tlb(addr, paddr, STORE);
-  } else if (!proc || !proc->sim->mmio_store(addr, len, bytes)) {
+  } else if (!proc || !proc->sim->mmio_store(paddr, len, bytes)) {
     throw trap_store_access_fault(addr);
   }
 }
index 37b77c538f03fb905a0a06c18edb7b679002d6df..3206ed0a91676912c529a2240445d3442c98110b 100644 (file)
@@ -54,52 +54,56 @@ static void bad_isa_string(const char* isa)
   abort();
 }
 
-void processor_t::parse_isa_string(const char* isa)
+void processor_t::parse_isa_string(const char* str)
 {
-  const char* p = isa;
-  const char* all_subsets = "IMAFDC";
-  std::string tmp;
+  std::string lowercase, tmp;
+  for (const char *r = str; *r; r++)
+    lowercase += std::tolower(*r);
+
+  const char* p = lowercase.c_str();
+  const char* all_subsets = "imafdc";
 
   max_xlen = 64;
   cpuid = reg_t(2) << 62;
 
-  if (strncmp(p, "RV32", 4) == 0)
+  if (strncmp(p, "rv32", 4) == 0)
     max_xlen = 32, cpuid = 0, p += 4;
-  else if (strncmp(p, "RV64", 4) == 0)
+  else if (strncmp(p, "rv64", 4) == 0)
     p += 4;
-  else if (strncmp(p, "RV", 2) == 0)
+  else if (strncmp(p, "rv", 2) == 0)
     p += 2;
 
   if (!*p) {
     p = all_subsets;
-  } else if (*p == 'G') { // treat "G" as "IMAFD"
-    tmp = std::string("IMAFD") + (p+1);
+  } else if (*p == 'g') { // treat "G" as "IMAFD"
+    tmp = std::string("imafd") + (p+1);
     p = &tmp[0];
-  } else if (*p != 'I') {
-    bad_isa_string(isa);
+  } else if (*p != 'i') {
+    bad_isa_string(str);
   }
 
-  cpuid |= 1L << ('S' - 'A'); // advertise support for supervisor mode
+  isa = "rv" + std::to_string(max_xlen) + p;
+  cpuid |= 1L << ('s' - 'a'); // advertise support for supervisor mode
 
   while (*p) {
-    cpuid |= 1L << (*p - 'A');
+    cpuid |= 1L << (*p - 'a');
 
     if (auto next = strchr(all_subsets, *p)) {
       all_subsets = next + 1;
       p++;
-    } else if (*p == 'X') {
+    } else if (*p == 'x') {
       const char* ext = p+1, *end = ext;
       while (islower(*end))
         end++;
       register_extension(find_extension(std::string(ext, end - ext).c_str())());
       p = end;
     } else {
-      bad_isa_string(isa);
+      bad_isa_string(str);
     }
   }
 
   if (supports_extension('D') && !supports_extension('F'))
-    bad_isa_string(isa);
+    bad_isa_string(str);
 }
 
 void state_t::reset()
@@ -219,11 +223,6 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
   t.side_effects(&state); // might set badvaddr etc.
 }
 
-void processor_t::deliver_ipi()
-{
-  state.mip |= MIP_MSIP;
-}
-
 void processor_t::disasm(insn_t insn)
 {
   uint64_t bits = insn.bits() & ((1ULL << (8 * insn_length(insn.bits()))) - 1);
@@ -329,6 +328,10 @@ void processor_t::set_csr(int which, reg_t val)
       state.mip = (state.mip & ~mask) | (val & mask);
       break;
     }
+    case CSR_MIPI: {
+      state.mip |= MIP_MSIP;
+      break;
+    }
     case CSR_MIE: {
       reg_t mask = MIP_SSIP | MIP_MSIP | MIP_STIP | MIP_MTIP;
       state.mie = (state.mie & ~mask) | (val & mask);
@@ -366,7 +369,6 @@ void processor_t::set_csr(int which, reg_t val)
       state.mip &= ~MIP_MTIP;
       state.mtimecmp = val;
       break;
-    case CSR_SEND_IPI: sim->send_ipi(val); break;
     case CSR_MTOHOST:
       if (state.tohost == 0)
         state.tohost = val;
@@ -448,6 +450,7 @@ reg_t processor_t::get_csr(int which)
     case CSR_SSCRATCH: return state.sscratch;
     case CSR_MSTATUS: return state.mstatus;
     case CSR_MIP: return state.mip;
+    case CSR_MIPI: return 0;
     case CSR_MIE: return state.mie;
     case CSR_MEPC: return state.mepc;
     case CSR_MSCRATCH: return state.mscratch;
@@ -465,7 +468,7 @@ reg_t processor_t::get_csr(int which)
     case CSR_MFROMHOST:
       sim->get_htif()->tick(); // not necessary, but faster
       return state.fromhost;
-    case CSR_SEND_IPI: return 0;
+    case CSR_MIOBASE: return sim->memsz;
     case CSR_UARCH0:
     case CSR_UARCH1:
     case CSR_UARCH2:
@@ -569,3 +572,26 @@ void processor_t::register_base_instructions()
   register_insn({0, 0, &illegal_instruction, &illegal_instruction});
   build_opcode_map();
 }
+
+bool processor_t::load(reg_t addr, size_t len, uint8_t* bytes)
+{
+  try {
+    auto res = get_csr(addr / (max_xlen / 8));
+    memcpy(bytes, &res, len);
+    return true;
+  } catch (trap_illegal_instruction& t) {
+    return false;
+  }
+}
+
+bool processor_t::store(reg_t addr, size_t len, const uint8_t* bytes)
+{
+  try {
+    reg_t value = 0;
+    memcpy(&value, bytes, len);
+    set_csr(addr / (max_xlen / 8), value);
+    return true;
+  } catch (trap_illegal_instruction& t) {
+    return false;
+  }
+}
index fe0a1214673aedd13400a9a61cb4e3c19009ea16..b9564d6a7f947675c819cb88148fe9bd269f64ac 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "decode.h"
 #include "config.h"
+#include "devices.h"
 #include <cstring>
 #include <vector>
 #include <map>
@@ -72,7 +73,7 @@ struct state_t
 };
 
 // this class represents one processor in a RISC-V machine.
-class processor_t
+class processor_t : public abstract_device_t
 {
 public:
   processor_t(const char* isa, sim_t* sim, uint32_t id);
@@ -82,7 +83,6 @@ public:
   void set_histogram(bool value);
   void reset(bool value);
   void step(size_t n); // run for n cycles
-  void deliver_ipi(); // register an interprocessor interrupt
   bool running() { return run; }
   void set_csr(int which, reg_t val);
   void raise_interrupt(reg_t which);
@@ -91,6 +91,7 @@ public:
   state_t* get_state() { return &state; }
   extension_t* get_extension() { return ext; }
   bool supports_extension(unsigned char ext) {
+    if (ext >= 'a' && ext <= 'z') ext += 'A' - 'a';
     return ext >= 'A' && ext <= 'Z' && ((cpuid >> (ext - 'A')) & 1);
   }
   void push_privilege_stack();
@@ -101,6 +102,10 @@ public:
   void register_insn(insn_desc_t);
   void register_extension(extension_t*);
 
+  // MMIO slave interface
+  bool load(reg_t addr, size_t len, uint8_t* bytes);
+  bool store(reg_t addr, size_t len, const uint8_t* bytes);
+
 private:
   sim_t* sim;
   mmu_t* mmu; // main memory is always accessed via the mmu
@@ -111,6 +116,7 @@ private:
   uint32_t id;
   int max_xlen;
   int xlen;
+  std::string isa;
   bool run; // !reset
   bool debug;
   bool histogram_enabled;
index af4f04753547588fa823ae293f42fdb6ec9f0cbf..7d71fb51f3faf0fd81ae70ce3e70d981128fadf4 100644 (file)
@@ -40,6 +40,7 @@ riscv_srcs = \
        extensions.cc \
        rocc.cc \
        regnames.cc \
+       devices.cc \
        $(riscv_gen_srcs) \
 
 riscv_test_srcs =
index f7ff11dda7bc182da6b82ac770bf642cebafe40c..67b655e6634d79cc7ea033d691ab89dd95f867c2 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "sim.h"
 #include "htif.h"
+#include "devicetree.h"
 #include <map>
 #include <iostream>
 #include <climits>
@@ -43,6 +44,8 @@ sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb,
 
   for (size_t i = 0; i < procs.size(); i++)
     procs[i] = new processor_t(isa, this, i);
+
+  make_device_tree();
 }
 
 sim_t::~sim_t()
@@ -53,12 +56,6 @@ sim_t::~sim_t()
   free(mem);
 }
 
-void sim_t::send_ipi(reg_t who)
-{
-  if (who < procs.size())
-    procs[who]->deliver_ipi();
-}
-
 reg_t sim_t::get_scr(int which)
 {
   switch (which)
@@ -146,10 +143,52 @@ void sim_t::set_procs_debug(bool value)
 
 bool sim_t::mmio_load(reg_t addr, size_t len, uint8_t* bytes)
 {
-  return false;
+  if (addr + len < addr)
+    return false;
+  return bus.load(addr, len, bytes);
 }
 
 bool sim_t::mmio_store(reg_t addr, size_t len, const uint8_t* bytes)
 {
-  return false;
+  if (addr + len < addr)
+    return false;
+  return bus.store(addr, len, bytes);
+}
+
+void sim_t::make_device_tree()
+{
+  char buf[32];
+  size_t max_devtree_size = procs.size() * 4096; // sloppy upper bound
+  size_t cpu_size = NCSR * procs[0]->max_xlen / 8;
+  reg_t cpu_addr = memsz + max_devtree_size;
+
+  device_tree dt;
+  dt.begin_node("");
+  dt.add_prop("#address-cells", 2);
+  dt.add_prop("#size-cells", 2);
+  dt.add_prop("model", "Spike");
+    dt.begin_node("memory@0");
+      dt.add_prop("device_type", "memory");
+      dt.add_reg({0, memsz});
+    dt.end_node();
+    dt.begin_node("cpus");
+      dt.add_prop("#address-cells", 2);
+      dt.add_prop("#size-cells", 2);
+      for (size_t i = 0; i < procs.size(); i++) {
+        sprintf(buf, "cpu@%" PRIx64, cpu_addr);
+        dt.begin_node(buf);
+          dt.add_prop("device_type", "cpu");
+          dt.add_prop("compatible", "riscv");
+          dt.add_prop("isa", procs[i]->isa);
+          dt.add_reg({cpu_addr});
+        dt.end_node();
+
+        bus.add_device(cpu_addr, procs[i]);
+        cpu_addr += cpu_size;
+      }
+    dt.end_node();
+  dt.end_node();
+
+  devicetree.reset(new rom_device_t(dt.finalize()));
+  bus.add_device(memsz, devicetree.get());
 }
index 636190e1107326485cdf6f0e1428bb8a740537fa..6ef2c824c5f9d171dc1241e55a80ff1a0a8368a0 100644 (file)
@@ -8,6 +8,7 @@
 #include <memory>
 #include "processor.h"
 #include "mmu.h"
+#include "devices.h"
 
 class htif_isasim_t;
 
@@ -29,9 +30,6 @@ public:
   void set_procs_debug(bool value);
   htif_isasim_t* get_htif() { return htif.get(); }
 
-  // deliver an IPI to a specific processor
-  void send_ipi(reg_t who);
-
   // returns the number of processors in this simulator
   size_t num_cores() { return procs.size(); }
   processor_t* get_core(size_t i) { return procs.at(i); }
@@ -45,6 +43,8 @@ private:
   size_t memsz; // memory size in bytes
   mmu_t* debug_mmu;  // debug port into main memory
   std::vector<processor_t*> procs;
+  std::unique_ptr<rom_device_t> devicetree;
+  bus_t bus;
 
   processor_t* get_core(const std::string& i);
   void step(size_t n); // step through simulation
@@ -60,6 +60,7 @@ private:
   // memory-mapped I/O routines
   bool mmio_load(reg_t addr, size_t len, uint8_t* bytes);
   bool mmio_store(reg_t addr, size_t len, const uint8_t* bytes);
+  void make_device_tree();
 
   // presents a prompt for introspection into the simulation
   void interactive();