From b593e6df7afc0d356fa0ca0a8c2c8d05f1b87bd8 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Fri, 29 Apr 2016 13:48:56 -0700 Subject: [PATCH 1/1] Move much closer to new platform-M memory map Reset vector is at 0x1000; below that is reserved for debug Memory is at 0x80000000 --- riscv/encoding.h | 9 ++++++--- riscv/htif.cc | 24 +++++++++++++++++++----- riscv/interactive.cc | 1 + riscv/mmu.cc | 33 ++++++++++++++++++--------------- riscv/mmu.h | 16 ++++++---------- riscv/processor.cc | 9 +++++---- riscv/processor.h | 1 + riscv/sim.cc | 40 ++++++++++++++++++++++------------------ riscv/sim.h | 12 +++++++++--- spike_main/spike.cc | 1 + 10 files changed, 88 insertions(+), 58 deletions(-) diff --git a/riscv/encoding.h b/riscv/encoding.h index b219309..56a13c3 100644 --- a/riscv/encoding.h +++ b/riscv/encoding.h @@ -67,9 +67,12 @@ #define IRQ_COP 12 #define IRQ_HOST 13 -#define DEFAULT_RSTVEC 0x0 -#define DEFAULT_NMIVEC 0x4 -#define DEFAULT_MTVEC 0x8 +#define DEFAULT_RSTVEC 0x1000 +#define DEFAULT_NMIVEC 0x1004 +#define CFGSTRING_ADDR 0x100C +#define DEFAULT_MTVEC 0x1010 +#define IO_BASE 0x40000000 +#define MEM_BASE 0x80000000 // page table entry (PTE) fields #define PTE_V 0x001 // Valid diff --git a/riscv/htif.cc b/riscv/htif.cc index 14f6381..4a462ec 100644 --- a/riscv/htif.cc +++ b/riscv/htif.cc @@ -2,6 +2,7 @@ #include "htif.h" #include "sim.h" +#include "mmu.h" #include "encoding.h" #include #include @@ -46,17 +47,30 @@ void htif_isasim_t::tick_once() send(&ack, sizeof(ack)); uint64_t buf[hdr.data_size]; - for (size_t i = 0; i < hdr.data_size; i++) - buf[i] = sim->debug_mmu->load_uint64((hdr.addr+i)*HTIF_DATA_ALIGN); + for (size_t i = 0; i < hdr.data_size; i++) { + reg_t addr = (hdr.addr + i) * HTIF_DATA_ALIGN; + try { + buf[i] = sim->debug_mmu->load_uint64(addr); + } catch (trap_load_access_fault& e) { + fprintf(stderr, "HTIF: attempt to read from illegal address 0x%" PRIx64 "\n", addr); + exit(-1); + } + } send(buf, hdr.data_size * sizeof(buf[0])); break; } case HTIF_CMD_WRITE_MEM: { const uint64_t* buf = (const uint64_t*)p.get_payload(); - for (size_t i = 0; i < hdr.data_size; i++) - sim->debug_mmu->store_uint64((hdr.addr+i)*HTIF_DATA_ALIGN, buf[i]); - + for (size_t i = 0; i < hdr.data_size; i++) { + reg_t addr = (hdr.addr + i) * HTIF_DATA_ALIGN; + try { + sim->debug_mmu->store_uint64(addr, buf[i]); + } catch (trap_load_access_fault& e) { + fprintf(stderr, "HTIF: attempt to write to illegal address 0x%" PRIx64 "\n", addr); + exit(-1); + } + } packet_header_t ack(HTIF_CMD_ACK, seqno, 0, 0); send(&ack, sizeof(ack)); break; diff --git a/riscv/interactive.cc b/riscv/interactive.cc index 8e22c02..69f2461 100644 --- a/riscv/interactive.cc +++ b/riscv/interactive.cc @@ -3,6 +3,7 @@ #include "decode.h" #include "disasm.h" #include "sim.h" +#include "mmu.h" #include "htif.h" #include #include diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 45457d9..0113443 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -4,8 +4,8 @@ #include "sim.h" #include "processor.h" -mmu_t::mmu_t(char* _mem, size_t _memsz) - : mem(_mem), memsz(_memsz), proc(NULL) +mmu_t::mmu_t(sim_t* sim, processor_t* proc) + : sim(sim), proc(proc) { flush_tlb(); } @@ -54,23 +54,26 @@ reg_t mmu_t::translate(reg_t addr, access_type type) const uint16_t* mmu_t::fetch_slow_path(reg_t addr) { reg_t paddr = translate(addr, FETCH); - if (paddr < memsz) + if (sim->addr_is_mem(paddr)) { refill_tlb(addr, paddr, FETCH); - else - throw trap_instruction_access_fault(addr); - return (const uint16_t*)(mem + paddr); + return (const uint16_t*)sim->addr_to_mem(paddr); + } else { + if (!sim->mmio_load(paddr, sizeof fetch_temp, (uint8_t*)&fetch_temp)) + throw trap_instruction_access_fault(addr); + return &fetch_temp; + } } void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes) { reg_t paddr = translate(addr, LOAD); - if (paddr < memsz) { - memcpy(bytes, mem + paddr, len); + if (sim->addr_is_mem(paddr)) { + memcpy(bytes, sim->addr_to_mem(paddr), len); if (tracer.interested_in_range(paddr, paddr + PGSIZE, LOAD)) tracer.trace(paddr, len, LOAD); else refill_tlb(addr, paddr, LOAD); - } else if (!proc || !proc->sim->mmio_load(paddr, len, bytes)) { + } else if (!sim->mmio_load(paddr, len, bytes)) { throw trap_load_access_fault(addr); } } @@ -78,13 +81,13 @@ void mmu_t::load_slow_path(reg_t addr, reg_t len, uint8_t* bytes) void mmu_t::store_slow_path(reg_t addr, reg_t len, const uint8_t* bytes) { reg_t paddr = translate(addr, STORE); - if (paddr < memsz) { - memcpy(mem + paddr, bytes, len); + if (sim->addr_is_mem(paddr)) { + memcpy(sim->addr_to_mem(paddr), bytes, len); if (tracer.interested_in_range(paddr, paddr + PGSIZE, STORE)) tracer.trace(paddr, len, STORE); else refill_tlb(addr, paddr, STORE); - } else if (!proc || !proc->sim->mmio_store(paddr, len, bytes)) { + } else if (!sim->mmio_store(paddr, len, bytes)) { throw trap_store_access_fault(addr); } } @@ -102,7 +105,7 @@ 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] = mem + paddr - vaddr; + tlb_data[idx] = sim->addr_to_mem(paddr) - vaddr; } reg_t mmu_t::walk(reg_t addr, access_type type, bool supervisor, bool pum) @@ -130,10 +133,10 @@ reg_t mmu_t::walk(reg_t addr, access_type type, bool supervisor, bool pum) // check that physical address of PTE is legal reg_t pte_addr = base + idx * ptesize; - if (pte_addr >= memsz) + if (!sim->addr_is_mem(pte_addr)) break; - void* ppte = mem + pte_addr; + void* ppte = sim->addr_to_mem(pte_addr); reg_t pte = ptesize == 4 ? *(uint32_t*)ppte : *(uint64_t*)ppte; reg_t ppn = pte >> PTE_PPN_SHIFT; diff --git a/riscv/mmu.h b/riscv/mmu.h index b9948c5..b6aa2ca 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -7,6 +7,7 @@ #include "trap.h" #include "common.h" #include "config.h" +#include "sim.h" #include "processor.h" #include "memtracer.h" #include @@ -33,7 +34,7 @@ struct icache_entry_t { class mmu_t { public: - mmu_t(char* _mem, size_t _memsz); + mmu_t(sim_t* sim, processor_t* proc); ~mmu_t(); // template for functions that load an aligned value from memory @@ -93,10 +94,7 @@ public: int length = insn_length(insn); if (likely(length == 4)) { - if (likely(addr % PGSIZE < PGSIZE-2)) - insn |= (insn_bits_t)*(const int16_t*)(iaddr + 1) << 16; - else - insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr(addr + 2) << 16; + insn |= (insn_bits_t)*(const int16_t*)translate_insn_addr(addr + 2) << 16; } else if (length == 2) { insn = (int16_t)insn; } else if (length == 6) { @@ -113,7 +111,7 @@ public: entry->tag = addr; entry->data = fetch; - reg_t paddr = (const char*)iaddr - mem; + reg_t paddr = sim->mem_to_addr((char*)iaddr); if (tracer.interested_in_range(paddr, paddr + 1, FETCH)) { entry->tag = -1; tracer.trace(paddr, length, FETCH); @@ -134,18 +132,16 @@ public: return access_icache(addr)->data; } - void set_processor(processor_t* p) { proc = p; flush_tlb(); } - void flush_tlb(); void flush_icache(); void register_memtracer(memtracer_t*); private: - char* mem; - size_t memsz; + sim_t* sim; processor_t* proc; memtracer_list_t tracer; + uint16_t fetch_temp; // implement an instruction cache for simulator performance icache_entry_t icache[ICACHE_ENTRIES]; diff --git a/riscv/processor.cc b/riscv/processor.cc index b932034..d5825af 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -5,6 +5,7 @@ #include "common.h" #include "config.h" #include "sim.h" +#include "mmu.h" #include "htif.h" #include "disasm.h" #include @@ -25,8 +26,7 @@ processor_t::processor_t(const char* isa, sim_t* sim, uint32_t id) { parse_isa_string(isa); - mmu = new mmu_t(sim->mem, sim->memsz); - mmu->set_processor(this); + mmu = new mmu_t(sim, this); reset(true); @@ -217,7 +217,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc) set_csr(CSR_MSTATUS, s); set_privilege(PRV_S); } else { - state.pc = DEFAULT_MTVEC; + state.pc = state.mtvec; state.mcause = t.cause(); state.mepc = epc; if (t.has_badaddr()) @@ -344,6 +344,7 @@ void processor_t::set_csr(int which, reg_t val) case CSR_SCAUSE: state.scause = val; break; case CSR_SBADADDR: state.sbadaddr = val; break; case CSR_MEPC: state.mepc = val; break; + case CSR_MTVEC: state.mtvec = val >> 2 << 2; break; case CSR_MSCRATCH: state.mscratch = val; break; case CSR_MCAUSE: state.mcause = val; break; case CSR_MBADADDR: state.mbadaddr = val; break; @@ -441,7 +442,7 @@ reg_t processor_t::get_csr(int which) case CSR_MIMPID: return 0; case CSR_MVENDORID: return 0; case CSR_MHARTID: return id; - case CSR_MTVEC: return DEFAULT_MTVEC; + case CSR_MTVEC: return state.mtvec; case CSR_MEDELEG: return state.medeleg; case CSR_MIDELEG: return state.mideleg; case CSR_MTOHOST: diff --git a/riscv/processor.h b/riscv/processor.h index 5557e5a..9b48cc2 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -46,6 +46,7 @@ struct state_t reg_t mepc; reg_t mbadaddr; reg_t mscratch; + reg_t mtvec; reg_t mcause; reg_t minstret; reg_t mie; diff --git a/riscv/sim.cc b/riscv/sim.cc index b45c51e..7f80e6f 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -1,6 +1,7 @@ // See LICENSE for license details. #include "sim.h" +#include "mmu.h" #include "htif.h" #include #include @@ -40,7 +41,7 @@ sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, fprintf(stderr, "warning: only got %lu bytes of target mem (wanted %lu)\n", (unsigned long)memsz, (unsigned long)memsz0); - debug_mmu = new mmu_t(mem, memsz); + debug_mmu = new mmu_t(this, NULL); for (size_t i = 0; i < procs.size(); i++) procs[i] = new processor_t(isa, this, i); @@ -158,13 +159,20 @@ bool sim_t::mmio_store(reg_t addr, size_t len, const uint8_t* bytes) void sim_t::make_config_string() { - size_t csr_size = NCSR * 16 /* RV128 */; - size_t device_tree_addr = memsz; - size_t cpu_addr = memsz + csr_size; - - reg_t rtc_addr = memsz; + reg_t rtc_addr = IO_BASE; bus.add_device(rtc_addr, rtc.get()); - config_string_addr = rtc_addr + rtc->size(); + + uint32_t reset_vec[8] = { + 0x297 + MEM_BASE - DEFAULT_RSTVEC, // reset vector + 0x00028067, // jump straight to MEM_BASE + 0x00000000, // reserved + 0, // pointer to configuration string + 0, 0, 0, 0 // trap vector + }; + config_string_addr = DEFAULT_RSTVEC + sizeof(reset_vec); + reset_vec[3] = config_string_addr; + + std::vector rom((char*)reset_vec, (char*)reset_vec + sizeof(reset_vec)); std::stringstream s; s << std::hex << @@ -177,8 +185,8 @@ void sim_t::make_config_string() "};\n" "ram {\n" " 0 {\n" - " addr 0;\n" - " size 0x" << memsz << ";\n" + " addr 0x" << MEM_BASE << ";\n" + " size 0x" << (MEM_BASE + memsz) << ";\n" " };\n" "};\n" "core {\n"; @@ -187,19 +195,15 @@ void sim_t::make_config_string() " " << i << " {\n" " " << "0 {\n" << // hart 0 on core i " isa " << procs[i]->isa_string << ";\n" - " addr 0x" << cpu_addr << ";\n" " timecmp 0x" << (rtc_addr + 8*(1+i)) << ";\n" " };\n" " };\n"; - bus.add_device(cpu_addr, procs[i]); - cpu_addr += csr_size; } s << "};\n"; - std::string str = s.str(); - std::vector vec(str.begin(), str.end()); - vec.push_back(0); - assert(vec.size() <= csr_size); - config_string.reset(new rom_device_t(vec)); - bus.add_device(config_string_addr, config_string.get()); + config_string = s.str(); + rom.insert(rom.end(), config_string.begin(), config_string.end()); + rom.push_back(0); + boot_rom.reset(new rom_device_t(rom)); + bus.add_device(DEFAULT_RSTVEC, boot_rom.get()); } diff --git a/riscv/sim.h b/riscv/sim.h index d8f39e2..01025ed 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -7,10 +7,10 @@ #include #include #include "processor.h" -#include "mmu.h" #include "devices.h" class htif_isasim_t; +class mmu_t; // this class encapsulates the processors and memory in a RISC-V machine. class sim_t @@ -29,7 +29,7 @@ public: void set_histogram(bool value); void set_procs_debug(bool value); htif_isasim_t* get_htif() { return htif.get(); } - const char* get_config_string() { return &config_string->contents()[0]; } + const char* get_config_string() { return config_string.c_str(); } // returns the number of processors in this simulator size_t num_cores() { return procs.size(); } @@ -44,7 +44,8 @@ private: size_t memsz; // memory size in bytes mmu_t* debug_mmu; // debug port into main memory std::vector procs; - std::unique_ptr config_string; + std::string config_string; + std::unique_ptr boot_rom; std::unique_ptr rtc; reg_t config_string_addr; bus_t bus; @@ -60,6 +61,11 @@ private: bool histogram_enabled; // provide a histogram of PCs // memory-mapped I/O routines + bool addr_is_mem(reg_t addr) { + return addr >= MEM_BASE && addr < MEM_BASE + memsz; + } + char* addr_to_mem(reg_t addr) { return mem + addr - MEM_BASE; } + reg_t mem_to_addr(char* x) { return x - mem + MEM_BASE; } 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_config_string(); diff --git a/spike_main/spike.cc b/spike_main/spike.cc index 6ca7beb..2f88518 100644 --- a/spike_main/spike.cc +++ b/spike_main/spike.cc @@ -1,6 +1,7 @@ // See LICENSE for license details. #include "sim.h" +#include "mmu.h" #include "htif.h" #include "cachesim.h" #include "extension.h" -- 2.30.2