Merge remote-tracking branch 'origin/debug-0.13' into priv-1.10
authorPalmer Dabbelt <palmer@dabbelt.com>
Tue, 16 May 2017 16:33:40 +0000 (09:33 -0700)
committerPalmer Dabbelt <palmer@dabbelt.com>
Tue, 16 May 2017 19:35:49 +0000 (12:35 -0700)
17 files changed:
riscv/devices.cc
riscv/devices.h
riscv/encoding.h
riscv/insns/c_li.h
riscv/insns/c_lui.h
riscv/insns/fmv_s_x.h [deleted file]
riscv/insns/fmv_w_x.h [new file with mode: 0644]
riscv/insns/fmv_x_s.h [deleted file]
riscv/insns/fmv_x_w.h [new file with mode: 0644]
riscv/mmu.cc
riscv/mmu.h
riscv/processor.cc
riscv/riscv.mk.in
riscv/sim.cc
riscv/sim.h
spike_main/disasm.cc
spike_main/spike.cc

index c7a63b0044b87e5a9a5dbd3df2958abd95699cd5..15115c8a6ccd5ec13ece8c125c8625fad7cd55be 100644 (file)
@@ -20,3 +20,11 @@ bool bus_t::store(reg_t addr, size_t len, const uint8_t* bytes)
     return false;
   return it->second->store(addr - -it->first, len, bytes);
 }
+
+std::pair<reg_t, abstract_device_t*> bus_t::find_device(reg_t addr)
+{
+  auto it = devices.lower_bound(-addr);
+  if (it == devices.end() || addr < -it->first)
+    return std::make_pair((reg_t)0, (abstract_device_t*)NULL);
+  return std::make_pair(-it->first, it->second);
+}
index f3ecb67a3c7f3ac46c5385aee18bb175ea93395c..0f0c9166b7c7cb510a98d2b817ec25233e5d1da8 100644 (file)
@@ -20,6 +20,8 @@ class bus_t : public abstract_device_t {
   bool store(reg_t addr, size_t len, const uint8_t* bytes);
   void add_device(reg_t addr, abstract_device_t* dev);
 
+  std::pair<reg_t, abstract_device_t*> find_device(reg_t addr);
+
  private:
   std::map<reg_t, abstract_device_t*> devices;
 };
@@ -34,6 +36,26 @@ class rom_device_t : public abstract_device_t {
   std::vector<char> data;
 };
 
+class mem_t : public abstract_device_t {
+ public:
+  mem_t(size_t size) : len(size) {
+    data = (char*)calloc(1, size);
+    if (!data)
+      throw std::runtime_error("couldn't allocate " + std::to_string(size) + " bytes of target memory");
+  }
+  mem_t(const mem_t& that) = delete;
+  ~mem_t() { free(data); }
+
+  bool load(reg_t addr, size_t len, uint8_t* bytes) { return false; }
+  bool store(reg_t addr, size_t len, const uint8_t* bytes) { return false; }
+  char* contents() { return data; }
+  size_t size() { return len; }
+
+ private:
+  char* data;
+  size_t len;
+};
+
 class clint_t : public abstract_device_t {
  public:
   clint_t(std::vector<processor_t*>&);
index 55f8461026fa9e122cf076adade3675bdbe25b6a..8ec134596e9497d739897772eba81bd9e9566d31 100644 (file)
@@ -23,6 +23,8 @@
 #define MSTATUS_TW          0x00200000
 #define MSTATUS_TSR         0x00400000
 #define MSTATUS32_SD        0x80000000
+#define MSTATUS_UXL         0x0000000300000000
+#define MSTATUS_SXL         0x0000000C00000000
 #define MSTATUS64_SD        0x8000000000000000
 
 #define SSTATUS_UIE         0x00000001
@@ -35,6 +37,7 @@
 #define SSTATUS_SUM         0x00040000
 #define SSTATUS_MXR         0x00080000
 #define SSTATUS32_SD        0x80000000
+#define SSTATUS_UXL         0x0000000300000000
 #define SSTATUS64_SD        0x8000000000000000
 
 #define DCSR_XDEBUGVER      (3U<<30)
 #define MASK_URET  0xffffffff
 #define MATCH_SRET 0x10200073
 #define MASK_SRET  0xffffffff
-#define MATCH_HRET 0x20200073
-#define MASK_HRET  0xffffffff
 #define MATCH_MRET 0x30200073
 #define MASK_MRET  0xffffffff
 #define MATCH_DRET 0x7b200073
 #define MASK_FCVT_L_S  0xfff0007f
 #define MATCH_FCVT_LU_S 0xc0300053
 #define MASK_FCVT_LU_S  0xfff0007f
-#define MATCH_FMV_X_S 0xe0000053
-#define MASK_FMV_X_S  0xfff0707f
+#define MATCH_FMV_X_W 0xe0000053
+#define MASK_FMV_X_W  0xfff0707f
 #define MATCH_FCLASS_S 0xe0001053
 #define MASK_FCLASS_S  0xfff0707f
 #define MATCH_FCVT_W_D 0xc2000053
 #define MASK_FCVT_S_L  0xfff0007f
 #define MATCH_FCVT_S_LU 0xd0300053
 #define MASK_FCVT_S_LU  0xfff0007f
-#define MATCH_FMV_S_X 0xf0000053
-#define MASK_FMV_S_X  0xfff0707f
+#define MATCH_FMV_W_X 0xf0000053
+#define MASK_FMV_W_X  0xfff0707f
 #define MATCH_FCVT_D_W 0xd2000053
 #define MASK_FCVT_D_W  0xfff0007f
 #define MATCH_FCVT_D_WU 0xd2100053
@@ -1065,7 +1066,6 @@ DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL)
 DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK)
 DECLARE_INSN(uret, MATCH_URET, MASK_URET)
 DECLARE_INSN(sret, MATCH_SRET, MASK_SRET)
-DECLARE_INSN(hret, MATCH_HRET, MASK_HRET)
 DECLARE_INSN(mret, MATCH_MRET, MASK_MRET)
 DECLARE_INSN(dret, MATCH_DRET, MASK_DRET)
 DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA)
@@ -1125,7 +1125,7 @@ DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S)
 DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S)
 DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S)
 DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S)
-DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S)
+DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W)
 DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S)
 DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D)
 DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D)
@@ -1143,7 +1143,7 @@ DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W)
 DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU)
 DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L)
 DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU)
-DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X)
+DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X)
 DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W)
 DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU)
 DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L)
index 844686dd21d9a595a8c095463eb98fdc6b778a53..f9fd66b2f32ee651f97a76c89ba68da0bce1cc56 100644 (file)
@@ -1,3 +1,2 @@
 require_extension('C');
-require(insn.rvc_rd() != 0);
 WRITE_RD(insn.rvc_imm());
index 130aaed8f4c93bc9cc23b12909bb1a7db5e31d60..75d8eb892fa966dccc966690f3640e124d68ceda 100644 (file)
@@ -3,6 +3,6 @@ if (insn.rvc_rd() == 2) { // c.addi16sp
   require(insn.rvc_addi16sp_imm() != 0);
   WRITE_REG(X_SP, sext_xlen(RVC_SP + insn.rvc_addi16sp_imm()));
 } else {
-  require(insn.rvc_rd() != 0);
+  require(insn.rvc_imm() != 0);
   WRITE_RD(insn.rvc_imm() << 12);
 }
diff --git a/riscv/insns/fmv_s_x.h b/riscv/insns/fmv_s_x.h
deleted file mode 100644 (file)
index 5f71323..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-require_extension('F');
-require_fp;
-WRITE_FRD(f32(RS1));
diff --git a/riscv/insns/fmv_w_x.h b/riscv/insns/fmv_w_x.h
new file mode 100644 (file)
index 0000000..5f71323
--- /dev/null
@@ -0,0 +1,3 @@
+require_extension('F');
+require_fp;
+WRITE_FRD(f32(RS1));
diff --git a/riscv/insns/fmv_x_s.h b/riscv/insns/fmv_x_s.h
deleted file mode 100644 (file)
index b722479..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-require_extension('F');
-require_fp;
-WRITE_RD(sext32(FRS1.v));
diff --git a/riscv/insns/fmv_x_w.h b/riscv/insns/fmv_x_w.h
new file mode 100644 (file)
index 0000000..b722479
--- /dev/null
@@ -0,0 +1,3 @@
+require_extension('F');
+require_fp;
+WRITE_RD(sext32(FRS1.v));
index 8df38e5e9d2ebf1a1ce352bf193441f1dab64fac..76a6ab1d4f685cf142a83d03a87f68847529e266 100644 (file)
@@ -47,17 +47,17 @@ reg_t mmu_t::translate(reg_t addr, access_type type)
   return walk(addr, type, mode) | (addr & (PGSIZE-1));
 }
 
-const uint16_t* mmu_t::fetch_slow_path(reg_t vaddr)
+tlb_entry_t mmu_t::fetch_slow_path(reg_t vaddr)
 {
   reg_t paddr = translate(vaddr, FETCH);
 
-  if (sim->addr_is_mem(paddr)) {
-    refill_tlb(vaddr, paddr, FETCH);
-    return (const uint16_t*)sim->addr_to_mem(paddr);
+  if (auto host_addr = sim->addr_to_mem(paddr)) {
+    return refill_tlb(vaddr, paddr, host_addr, FETCH);
   } else {
     if (!sim->mmio_load(paddr, sizeof fetch_temp, (uint8_t*)&fetch_temp))
       throw trap_instruction_access_fault(vaddr);
-    return &fetch_temp;
+    tlb_entry_t entry = {(char*)&fetch_temp - vaddr, paddr - vaddr};
+    return entry;
   }
 }
 
@@ -91,12 +91,12 @@ void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes)
 {
   reg_t paddr = translate(addr, LOAD);
 
-  if (sim->addr_is_mem(paddr)) {
-    memcpy(bytes, sim->addr_to_mem(paddr), len);
+  if (auto host_addr = sim->addr_to_mem(paddr)) {
+    memcpy(bytes, host_addr, len);
     if (tracer.interested_in_range(paddr, paddr + PGSIZE, LOAD))
       tracer.trace(paddr, len, LOAD);
     else
-      refill_tlb(addr, paddr, LOAD);
+      refill_tlb(addr, paddr, host_addr, LOAD);
   } else if (!sim->mmio_load(paddr, len, bytes)) {
     throw trap_load_access_fault(addr);
   }
@@ -120,18 +120,18 @@ void mmu_t::store_slow_path(reg_t addr, reg_t len, const uint8_t* bytes)
       throw *matched_trigger;
   }
 
-  if (sim->addr_is_mem(paddr)) {
-    memcpy(sim->addr_to_mem(paddr), bytes, len);
+  if (auto host_addr = sim->addr_to_mem(paddr)) {
+    memcpy(host_addr, bytes, len);
     if (tracer.interested_in_range(paddr, paddr + PGSIZE, STORE))
       tracer.trace(paddr, len, STORE);
     else
-      refill_tlb(addr, paddr, STORE);
+      refill_tlb(addr, paddr, host_addr, STORE);
   } else if (!sim->mmio_store(paddr, len, bytes)) {
     throw trap_store_access_fault(addr);
   }
 }
 
-void mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, access_type type)
+tlb_entry_t mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, char* host_addr, access_type type)
 {
   reg_t idx = (vaddr >> PGSHIFT) % TLB_ENTRIES;
   reg_t expected_tag = vaddr >> PGSHIFT;
@@ -152,7 +152,9 @@ void mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, access_type type)
   else if (type == STORE) tlb_store_tag[idx] = expected_tag;
   else tlb_load_tag[idx] = expected_tag;
 
-  tlb_data[idx] = sim->addr_to_mem(paddr) - vaddr;
+  tlb_entry_t entry = {host_addr - vaddr, paddr - vaddr};
+  tlb_data[idx] = entry;
+  return entry;
 }
 
 reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode)
@@ -178,11 +180,10 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode)
     reg_t idx = (addr >> (PGSHIFT + ptshift)) & ((1 << vm.idxbits) - 1);
 
     // check that physical address of PTE is legal
-    reg_t pte_addr = base + idx * vm.ptesize;
-    if (!sim->addr_is_mem(pte_addr))
+    auto ppte = sim->addr_to_mem(base + idx * vm.ptesize);
+    if (!ppte)
       throw trap_load_access_fault(addr);
 
-    void* ppte = sim->addr_to_mem(pte_addr);
     reg_t pte = vm.ptesize == 4 ? *(uint32_t*)ppte : *(uint64_t*)ppte;
     reg_t ppn = pte >> PTE_PPN_SHIFT;
 
@@ -196,6 +197,8 @@ reg_t mmu_t::walk(reg_t addr, access_type type, reg_t mode)
                type == LOAD ?  !(pte & PTE_R) && !(mxr && (pte & PTE_X)) :
                                !((pte & PTE_R) && (pte & PTE_W))) {
       break;
+    } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) {
+      break;
     } else {
       reg_t ad = PTE_A | ((type == STORE) * PTE_D);
 #ifdef RISCV_ENABLE_DIRTY
index a8d9675b402ad421eb8b7ab70528062e66250f4f..f70a969be48eba4a148d25c8b9684d789bbb2cb3 100644 (file)
@@ -30,6 +30,11 @@ struct icache_entry_t {
   insn_fetch_t data;
 };
 
+struct tlb_entry_t {
+  char* host_offset;
+  reg_t target_offset;
+};
+
 class trigger_matched_t
 {
   public:
@@ -80,9 +85,9 @@ public:
         return misaligned_load(addr, sizeof(type##_t)); \
       reg_t vpn = addr >> PGSHIFT; \
       if (likely(tlb_load_tag[vpn % TLB_ENTRIES] == vpn)) \
-        return *(type##_t*)(tlb_data[vpn % TLB_ENTRIES] + addr); \
+        return *(type##_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr); \
       if (unlikely(tlb_load_tag[vpn % TLB_ENTRIES] == (vpn | TLB_CHECK_TRIGGERS))) { \
-        type##_t data = *(type##_t*)(tlb_data[vpn % TLB_ENTRIES] + addr); \
+        type##_t data = *(type##_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr); \
         if (!matched_trigger) { \
           matched_trigger = trigger_exception(OPERATION_LOAD, addr, data); \
           if (matched_trigger) \
@@ -114,14 +119,14 @@ public:
         return misaligned_store(addr, val, sizeof(type##_t)); \
       reg_t vpn = addr >> PGSHIFT; \
       if (likely(tlb_store_tag[vpn % TLB_ENTRIES] == vpn)) \
-        *(type##_t*)(tlb_data[vpn % TLB_ENTRIES] + addr) = val; \
+        *(type##_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr) = val; \
       else if (unlikely(tlb_store_tag[vpn % TLB_ENTRIES] == (vpn | TLB_CHECK_TRIGGERS))) { \
         if (!matched_trigger) { \
           matched_trigger = trigger_exception(OPERATION_STORE, addr, val); \
           if (matched_trigger) \
             throw *matched_trigger; \
         } \
-        *(type##_t*)(tlb_data[vpn % TLB_ENTRIES] + addr) = val; \
+        *(type##_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr) = val; \
       } \
       else \
         store_slow_path(addr, sizeof(type##_t), (const uint8_t*)&val); \
@@ -165,29 +170,29 @@ public:
 
   inline icache_entry_t* refill_icache(reg_t addr, icache_entry_t* entry)
   {
-    const uint16_t* iaddr = translate_insn_addr(addr);
-    insn_bits_t insn = *iaddr;
+    auto tlb_entry = translate_insn_addr(addr);
+    insn_bits_t insn = *(uint16_t*)(tlb_entry.host_offset + addr);
     int length = insn_length(insn);
 
     if (likely(length == 4)) {
-      insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr(addr + 2) << 16;
+      insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr_to_host(addr + 2) << 16;
     } else if (length == 2) {
       insn = (int16_t)insn;
     } else if (length == 6) {
-      insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr(addr + 4) << 32;
-      insn |= (insn_bits_t)*(const uint16_t*)translate_insn_addr(addr + 2) << 16;
+      insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr_to_host(addr + 4) << 32;
+      insn |= (insn_bits_t)*(const uint16_t*)translate_insn_addr_to_host(addr + 2) << 16;
     } else {
       static_assert(sizeof(insn_bits_t) == 8, "insn_bits_t must be uint64_t");
-      insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr(addr + 6) << 48;
-      insn |= (insn_bits_t)*(const uint16_t*)translate_insn_addr(addr + 4) << 32;
-      insn |= (insn_bits_t)*(const uint16_t*)translate_insn_addr(addr + 2) << 16;
+      insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr_to_host(addr + 6) << 48;
+      insn |= (insn_bits_t)*(const uint16_t*)translate_insn_addr_to_host(addr + 4) << 32;
+      insn |= (insn_bits_t)*(const uint16_t*)translate_insn_addr_to_host(addr + 2) << 16;
     }
 
     insn_fetch_t fetch = {proc->decode_insn(insn), insn};
     entry->tag = addr;
     entry->data = fetch;
 
-    reg_t paddr = sim->mem_to_addr((char*)iaddr);
+    reg_t paddr = tlb_entry.target_offset + addr;;
     if (tracer.interested_in_range(paddr, paddr + 1, FETCH)) {
       entry->tag = -1;
       tracer.trace(paddr, length, FETCH);
@@ -228,39 +233,43 @@ private:
   // If a TLB tag has TLB_CHECK_TRIGGERS set, then the MMU must check for a
   // trigger match before completing an access.
   static const reg_t TLB_CHECK_TRIGGERS = reg_t(1) << 63;
-  char* tlb_data[TLB_ENTRIES];
+  tlb_entry_t tlb_data[TLB_ENTRIES];
   reg_t tlb_insn_tag[TLB_ENTRIES];
   reg_t tlb_load_tag[TLB_ENTRIES];
   reg_t tlb_store_tag[TLB_ENTRIES];
 
   // finish translation on a TLB miss and update the TLB
-  void refill_tlb(reg_t vaddr, reg_t paddr, access_type type);
+  tlb_entry_t refill_tlb(reg_t vaddr, reg_t paddr, char* host_addr, access_type type);
   const char* fill_from_mmio(reg_t vaddr, reg_t paddr);
 
   // perform a page table walk for a given VA; set referenced/dirty bits
   reg_t walk(reg_t addr, access_type type, reg_t prv);
 
   // handle uncommon cases: TLB misses, page faults, MMIO
-  const uint16_t* fetch_slow_path(reg_t addr);
+  tlb_entry_t fetch_slow_path(reg_t addr);
   void load_slow_path(reg_t addr, reg_t len, uint8_t* bytes);
   void store_slow_path(reg_t addr, reg_t len, const uint8_t* bytes);
   reg_t translate(reg_t addr, access_type type);
 
   // ITLB lookup
-  inline const uint16_t* translate_insn_addr(reg_t addr) {
+  inline tlb_entry_t translate_insn_addr(reg_t addr) {
     reg_t vpn = addr >> PGSHIFT;
     if (likely(tlb_insn_tag[vpn % TLB_ENTRIES] == vpn))
-      return (uint16_t*)(tlb_data[vpn % TLB_ENTRIES] + addr);
+      return tlb_data[vpn % TLB_ENTRIES];
     if (unlikely(tlb_insn_tag[vpn % TLB_ENTRIES] == (vpn | TLB_CHECK_TRIGGERS))) {
-      uint16_t* ptr = (uint16_t*)(tlb_data[vpn % TLB_ENTRIES] + addr);
+      uint16_t* ptr = (uint16_t*)(tlb_data[vpn % TLB_ENTRIES].host_offset + addr);
       int match = proc->trigger_match(OPERATION_EXECUTE, addr, *ptr);
       if (match >= 0)
         throw trigger_matched_t(match, OPERATION_EXECUTE, addr, *ptr);
-      return ptr;
+      return tlb_data[vpn % TLB_ENTRIES];
     }
     return fetch_slow_path(addr);
   }
 
+  inline const uint16_t* translate_insn_addr_to_host(reg_t addr) {
+    return (uint16_t*)(translate_insn_addr(addr).host_offset + addr);
+  }
+
   inline trigger_matched_t *trigger_exception(trigger_operation_t operation,
       reg_t address, reg_t data)
   {
index 6f0d3a7b9008bef422a8769ec4b881e2edc81fb7..1e3573df903e56fc9982bc729baba3a9640f6df1 100644 (file)
@@ -178,6 +178,15 @@ void processor_t::take_interrupt(reg_t pending_interrupts)
     throw trap_t(((reg_t)1 << (max_xlen-1)) | ctz(enabled_interrupts));
 }
 
+static int xlen_to_uxl(int xlen)
+{
+  if (xlen == 32)
+    return 1;
+  if (xlen == 64)
+    return 2;
+  abort();
+}
+
 void processor_t::set_privilege(reg_t prv)
 {
   assert(prv <= PRV_M);
@@ -318,7 +327,8 @@ void processor_t::set_csr(int which, reg_t val)
       reg_t mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE
                  | MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM
                  | MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TW | MSTATUS_TVM
-                 | MSTATUS_TSR | (ext ? MSTATUS_XS : 0);
+                 | MSTATUS_TSR | MSTATUS_UXL | MSTATUS_SXL |
+                 (ext ? MSTATUS_XS : 0);
 
       state.mstatus = (state.mstatus & ~mask) | (val & mask);
 
@@ -329,8 +339,9 @@ void processor_t::set_csr(int which, reg_t val)
       else
         state.mstatus = set_field(state.mstatus, MSTATUS64_SD, dirty);
 
-      // spike supports the notion of xlen < max_xlen, but current priv spec
-      // doesn't provide a mechanism to run RV32 software on an RV64 machine
+      state.mstatus = set_field(state.mstatus, MSTATUS_UXL, xlen_to_uxl(max_xlen));
+      state.mstatus = set_field(state.mstatus, MSTATUS_SXL, xlen_to_uxl(max_xlen));
+      // U-XLEN == S-XLEN == M-XLEN
       xlen = max_xlen;
       break;
     }
@@ -531,7 +542,7 @@ reg_t processor_t::get_csr(int which)
     case CSR_MCOUNTEREN: return state.mcounteren;
     case CSR_SSTATUS: {
       reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS
-                 | SSTATUS_XS | SSTATUS_SUM;
+                 | SSTATUS_XS | SSTATUS_SUM | SSTATUS_UXL;
       reg_t sstatus = state.mstatus & mask;
       if ((sstatus & SSTATUS_FS) == SSTATUS_FS ||
           (sstatus & SSTATUS_XS) == SSTATUS_XS)
index 40054cfbaa289793f4ca8051dc1edf0157be20e4..05e316a438ad4dd68e1e9f2646328afc1d5c1758 100644 (file)
@@ -182,9 +182,9 @@ riscv_insn_list = \
        fmul_d \
        fmul_s \
        fmv_d_x \
-       fmv_s_x \
+       fmv_w_x \
        fmv_x_d \
-       fmv_x_s \
+       fmv_x_w \
        fnmadd_d \
        fnmadd_s \
        fnmsub_d \
index a44ced6a832a67950bd4d620b1b66cccde310c15..42d60a13266d6fcafa1503e952e54b4a1e641ecf 100644 (file)
@@ -23,26 +23,17 @@ static void handle_signal(int sig)
   signal(sig, &handle_signal);
 }
 
-sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, bool halted,
+sim_t::sim_t(const char* isa, size_t nprocs, bool halted, reg_t start_pc,
+             std::vector<std::pair<reg_t, mem_t*>> mems,
              const std::vector<std::string>& args)
-  : htif_t(args), debug_module(this), procs(std::max(nprocs, size_t(1))),
+  : htif_t(args), debug_module(this), mems(mems), procs(std::max(nprocs, size_t(1))),
+    start_pc(start_pc),
     current_step(0), current_proc(0), debug(false), remote_bitbang(NULL)
 {
   signal(SIGINT, &handle_signal);
-  // allocate target machine's memory, shrinking it as necessary
-  // until the allocation succeeds
-  size_t memsz0 = (size_t)mem_mb << 20;
-  size_t quantum = 1L << 20;
-  if (memsz0 == 0)
-    memsz0 = (size_t)2048 << 20;
 
-  memsz = memsz0;
-  while ((mem = (char*)calloc(1, memsz)) == NULL)
-    memsz = (size_t)(memsz*0.9)/quantum*quantum;
-
-  if (memsz != memsz0)
-    fprintf(stderr, "warning: only got %zu bytes of target mem (wanted %zu)\n",
-            memsz, memsz0);
+  for (auto& x : mems)
+    bus.add_device(x.first, x.second);
 
   debug_module.add_device(&bus);
 
@@ -54,8 +45,6 @@ sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, bool halted,
 
   clint.reset(new clint_t(procs));
   bus.add_device(CLINT_BASE, clint.get());
-
-  make_dtb();
 }
 
 sim_t::~sim_t()
@@ -63,7 +52,6 @@ sim_t::~sim_t()
   for (size_t i = 0; i < procs.size(); i++)
     delete procs[i];
   delete debug_mmu;
-  free(mem);
 }
 
 void sim_thread_main(void* arg)
@@ -238,14 +226,24 @@ static std::string dts_compile(const std::string& dts)
 
 void sim_t::make_dtb()
 {
-  uint32_t reset_vec[] = {
-    0x297 + DRAM_BASE - DEFAULT_RSTVEC, // auipc t0, DRAM_BASE
-    0x597,                              // auipc a1, 0
-    0x58593,                            // addi a1, a1, 0
-    0xf1402573,                                // csrr a0,mhartid
-    0x00028067                          // jalr zero, t0, 0 (jump straight to DRAM_BASE)
+  const int reset_vec_size = 8;
+
+  start_pc = start_pc == reg_t(-1) ? get_entry_point() : start_pc;
+  reg_t pc_delta = start_pc - DEFAULT_RSTVEC;
+  reg_t pc_delta_hi = (pc_delta + 0x800U) & ~reg_t(0xfffU);
+  reg_t pc_delta_lo = pc_delta - pc_delta_hi;
+  if ((pc_delta_hi >> 31) != 0 && (pc_delta_hi >> 31) != reg_t(-1) >> 31) {
+    fprintf(stderr, "initial pc %" PRIx64 " out of range\n", pc_delta);
+    abort();
+  }
+
+  uint32_t reset_vec[reset_vec_size] = {
+    0x297 + uint32_t(pc_delta_hi),              // auipc t0, &pc
+    0x597,                                      // auipc a1, &dtb
+    0x58593 + ((reset_vec_size - 1) * 4 << 20), // addi a1, a1, &dtb
+    0xf1402573,                                 // csrr a0, mhartid
+    0x28067 + uint32_t(pc_delta_lo << 20)       // jalr zero, t0, &pc
   };
-  reset_vec[2] += (sizeof(reset_vec) - 4) << 20; // addi a1, a1, sizeof(reset_vec) - 4 = DTB start
 
   std::vector<char> rom((char*)reset_vec, (char*)reset_vec + sizeof(reset_vec));
 
@@ -278,15 +276,16 @@ void sim_t::make_dtb()
          "      };\n"
          "    };\n";
   }
-  reg_t membs = DRAM_BASE;
-  s << std::hex <<
-         "  };\n"
-         "  memory@" << DRAM_BASE << " {\n"
+  s <<   "  };\n";
+  for (auto& m : mems) {
+    s << std::hex <<
+         "  memory@" << m.first << " {\n"
          "    device_type = \"memory\";\n"
-         "    reg = <0x" << (membs >> 32) << " 0x" << (membs & (uint32_t)-1) <<
-                   " 0x" << (memsz >> 32) << " 0x" << (memsz & (uint32_t)-1) << ">;\n"
-         "  };\n"
-         "  soc {\n"
+         "    reg = <0x" << (m.first >> 32) << " 0x" << (m.first & (uint32_t)-1) <<
+                   " 0x" << (m.second->size() >> 32) << " 0x" << (m.second->size() & (uint32_t)-1) << ">;\n"
+         "  };\n";
+  }
+  s <<   "  soc {\n"
          "    #address-cells = <2>;\n"
          "    #size-cells = <2>;\n"
          "    compatible = \"ucbbar,spike-bare-soc\", \"simple-bus\";\n"
@@ -316,8 +315,21 @@ void sim_t::make_dtb()
   bus.add_device(DEFAULT_RSTVEC, boot_rom.get());
 }
 
+char* sim_t::addr_to_mem(reg_t addr) {
+  auto desc = bus.find_device(addr);
+  if (auto mem = dynamic_cast<mem_t*>(desc.second))
+    if (addr - desc.first < mem->size())
+      return mem->contents() + (addr - desc.first);
+  return NULL;
+}
+
 // htif
 
+void sim_t::reset()
+{
+  make_dtb();
+}
+
 void sim_t::idle()
 {
   target.switch_to();
index d3353a1bbcfd4cebb79abcfddadd11c552b14ea1..9372cc1e2d3207d3015e3c43059e8054a9f13acf 100644 (file)
@@ -19,7 +19,8 @@ class remote_bitbang_t;
 class sim_t : public htif_t
 {
 public:
-  sim_t(const char* isa, size_t _nprocs, size_t mem_mb, bool halted,
+  sim_t(const char* isa, size_t _nprocs,  bool halted, reg_t start_pc,
+        std::vector<std::pair<reg_t, mem_t*>> mems,
         const std::vector<std::string>& args);
   ~sim_t();
 
@@ -32,17 +33,17 @@ public:
   void set_remote_bitbang(remote_bitbang_t* remote_bitbang) {
     this->remote_bitbang = remote_bitbang;
   }
-  const char* get_dts() { return dts.c_str(); }
+  const char* get_dts() { if (dts.empty()) reset(); return dts.c_str(); }
   processor_t* get_core(size_t i) { return procs.at(i); }
   unsigned nprocs() const { return procs.size(); }
 
   debug_module_t debug_module;
 
 private:
-  char* mem; // main memory
-  size_t memsz; // memory size in bytes
+  std::vector<std::pair<reg_t, mem_t*>> mems;
   mmu_t* debug_mmu;  // debug port into main memory
   std::vector<processor_t*> procs;
+  reg_t start_pc;
   std::string dts;
   std::unique_ptr<rom_device_t> boot_rom;
   std::unique_ptr<clint_t> clint;
@@ -61,11 +62,7 @@ private:
   remote_bitbang_t* remote_bitbang;
 
   // memory-mapped I/O routines
-  bool addr_is_mem(reg_t addr) {
-    return addr >= DRAM_BASE && addr < DRAM_BASE + memsz;
-  }
-  char* addr_to_mem(reg_t addr) { return mem + addr - DRAM_BASE; }
-  reg_t mem_to_addr(char* x) { return x - mem + DRAM_BASE; }
+  char* addr_to_mem(reg_t addr);
   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_dtb();
@@ -101,7 +98,7 @@ private:
 
   context_t* host;
   context_t target;
-  void reset() { }
+  void reset();
   void idle();
   void read_chunk(addr_t taddr, size_t len, void* dst);
   void write_chunk(addr_t taddr, size_t len, const void* src);
index bdbef9cef869759a563c7e72b1d41fcbb31d6977..56c6fe62d5d1fbeec86523f4d0123ad7f5784eb1 100644 (file)
@@ -418,7 +418,6 @@ disassembler_t::disassembler_t(int xlen)
   DEFINE_NOARG(ebreak);
   DEFINE_NOARG(uret);
   DEFINE_NOARG(sret);
-  DEFINE_NOARG(hret);
   DEFINE_NOARG(mret);
   DEFINE_NOARG(fence);
   DEFINE_NOARG(fence_i);
@@ -457,13 +456,13 @@ disassembler_t::disassembler_t(int xlen)
   DEFINE_XFTYPE(fcvt_s_w);
   DEFINE_XFTYPE(fcvt_s_wu);
   DEFINE_XFTYPE(fcvt_s_wu);
-  DEFINE_XFTYPE(fmv_s_x);
+  DEFINE_XFTYPE(fmv_w_x);
   DEFINE_FXTYPE(fcvt_l_s);
   DEFINE_FXTYPE(fcvt_lu_s);
   DEFINE_FXTYPE(fcvt_w_s);
   DEFINE_FXTYPE(fcvt_wu_s);
   DEFINE_FXTYPE(fclass_s);
-  DEFINE_FXTYPE(fmv_x_s);
+  DEFINE_FXTYPE(fmv_x_w);
   DEFINE_FXTYPE(feq_s);
   DEFINE_FXTYPE(flt_s);
   DEFINE_FXTYPE(fle_s);
index 38529b2504e3297e2101e7594cd63ec9c6db305a..23f8e49c0deeca8bffe414cc341353912f244fd4 100644 (file)
@@ -18,13 +18,16 @@ static void help()
   fprintf(stderr, "usage: spike [host options] <target program> [target options]\n");
   fprintf(stderr, "Host Options:\n");
   fprintf(stderr, "  -p<n>                 Simulate <n> processors [default 1]\n");
-  fprintf(stderr, "  -m<n>                 Provide <n> MiB of target memory [default 4096]\n");
+  fprintf(stderr, "  -m<n>                 Provide <n> MiB of target memory [default 2048]\n");
+  fprintf(stderr, "  -m<a:m,b:n,...>       Provide memory regions of size m and n bytes\n");
+  fprintf(stderr, "                          at base addresses a and b (with 4 KiB alignment)\n");
   fprintf(stderr, "  -d                    Interactive debug mode\n");
   fprintf(stderr, "  -g                    Track histogram of PCs\n");
   fprintf(stderr, "  -l                    Generate a log of execution\n");
   fprintf(stderr, "  -h                    Print this help message\n");
   fprintf(stderr, "  -H                 Start halted, allowing a debugger to connect\n");
   fprintf(stderr, "  --isa=<name>          RISC-V ISA string [default %s]\n", DEFAULT_ISA);
+  fprintf(stderr, "  --pc=<address>        Override ELF entry point\n");
   fprintf(stderr, "  --ic=<S>:<W>:<B>      Instantiate a cache model with S sets,\n");
   fprintf(stderr, "  --dc=<S>:<W>:<B>        W ways, and B-byte blocks (with S and\n");
   fprintf(stderr, "  --l2=<S>:<W>:<B>        B both powers of 2).\n");
@@ -35,6 +38,35 @@ static void help()
   exit(1);
 }
 
+static std::vector<std::pair<reg_t, mem_t*>> make_mems(const char* arg)
+{
+  // handle legacy mem argument
+  char* p;
+  auto mb = strtoull(arg, &p, 0);
+  if (*p == 0) {
+    reg_t size = reg_t(mb) << 20;
+    return std::vector<std::pair<reg_t, mem_t*>>(1, std::make_pair(reg_t(DRAM_BASE), new mem_t(size)));
+  }
+
+  // handle base/size tuples
+  std::vector<std::pair<reg_t, mem_t*>> res;
+  while (true) {
+    auto base = strtoull(arg, &p, 0);
+    if (!*p || *p != ':')
+      help();
+    auto size = strtoull(p + 1, &p, 0);
+    if ((size | base) % PGSIZE != 0)
+      help();
+    res.push_back(std::make_pair(reg_t(base), new mem_t(size)));
+    if (!*p)
+      break;
+    if (*p != ',')
+      help();
+    arg = p + 1;
+  }
+  return res;
+}
+
 int main(int argc, char** argv)
 {
   bool debug = false;
@@ -43,7 +75,8 @@ int main(int argc, char** argv)
   bool log = false;
   bool dump_dts = false;
   size_t nprocs = 1;
-  size_t mem_mb = 0;
+  reg_t start_pc = reg_t(-1);
+  std::vector<std::pair<reg_t, mem_t*>> mems;
   std::unique_ptr<icache_sim_t> ic;
   std::unique_ptr<dcache_sim_t> dc;
   std::unique_ptr<cache_sim_t> l2;
@@ -59,10 +92,11 @@ int main(int argc, char** argv)
   parser.option('g', 0, 0, [&](const char* s){histogram = true;});
   parser.option('l', 0, 0, [&](const char* s){log = true;});
   parser.option('p', 0, 1, [&](const char* s){nprocs = atoi(s);});
-  parser.option('m', 0, 1, [&](const char* s){mem_mb = atoi(s);});
+  parser.option('m', 0, 1, [&](const char* s){mems = make_mems(s);});
   // I wanted to use --halted, but for some reason that doesn't work.
   parser.option('H', 0, 0, [&](const char* s){halted = true;});
   parser.option(0, "rbb-port", 1, [&](const char* s){use_rbb = true; rbb_port = atoi(s);});
+  parser.option(0, "pc", 1, [&](const char* s){start_pc = strtoull(s, 0, 0);});
   parser.option(0, "ic", 1, [&](const char* s){ic.reset(new icache_sim_t(s));});
   parser.option(0, "dc", 1, [&](const char* s){dc.reset(new dcache_sim_t(s));});
   parser.option(0, "l2", 1, [&](const char* s){l2.reset(cache_sim_t::construct(s, "L2$"));});
@@ -79,9 +113,12 @@ int main(int argc, char** argv)
 
   auto argv1 = parser.parse(argv);
   std::vector<std::string> htif_args(argv1, (const char*const*)argv + argc);
-  sim_t s(isa, nprocs, mem_mb, halted, htif_args);
-  std::unique_ptr<jtag_dtm_t> jtag_dtm(new jtag_dtm_t(&s.debug_module));
+  if (mems.empty())
+    mems = make_mems("2048");
+
+  sim_t s(isa, nprocs, halted, start_pc, mems, htif_args);
   std::unique_ptr<remote_bitbang_t> remote_bitbang((remote_bitbang_t *) NULL);
+  std::unique_ptr<jtag_dtm_t> jtag_dtm(new jtag_dtm_t(&s.debug_module));
   if (use_rbb) {
     remote_bitbang.reset(new remote_bitbang_t(rbb_port, &(*jtag_dtm)));
     s.set_remote_bitbang(&(*remote_bitbang));