From d999dfc0d41a119730ff8944d37dbee88bf99723 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Sun, 24 Apr 2016 08:54:19 -0700 Subject: [PATCH] Add debug_module bus device. This should replace the ROM hack I implemented earlier, but for now both exist together. Back to the point where gdb connects, core jumps to ROM->RAM->ROM. --- debug_rom/Makefile | 2 +- debug_rom/debug_rom.S | 19 ++++++------ debug_rom/debug_rom.h | 8 ++--- riscv/debug_module.cc | 69 +++++++++++++++++++++++++++++++++++++++++++ riscv/debug_module.h | 37 +++++++++++++++++++++++ riscv/decode.h | 9 ++++-- riscv/devices.cc | 8 +++++ riscv/devices.h | 6 ++++ riscv/execute.cc | 11 ++++++- riscv/gdbserver.cc | 59 ++++++++++++++++++++++++++++-------- riscv/gdbserver.h | 8 +++++ riscv/mmu.cc | 36 +++++++++++++++++++--- riscv/mmu.h | 6 ++-- riscv/processor.cc | 8 ++--- riscv/processor.h | 2 -- riscv/riscv.mk.in | 2 ++ riscv/sim.cc | 15 +++++----- riscv/sim.h | 12 ++++---- 18 files changed, 259 insertions(+), 58 deletions(-) create mode 100644 riscv/debug_module.cc create mode 100644 riscv/debug_module.h diff --git a/debug_rom/Makefile b/debug_rom/Makefile index d66b84f..9d286c9 100644 --- a/debug_rom/Makefile +++ b/debug_rom/Makefile @@ -5,7 +5,7 @@ CC = $(RISCV)/bin/riscv64-unknown-elf-gcc OBJCOPY = $(RISCV)/bin/riscv64-unknown-elf-objcopy %.o: %.S - $(CC) -c $< + $(CC) -I.. -c $< debug_rom.h: debug_rom.raw xxd -i $^ | sed "s/^unsigned/static const unsigned/" > $@ diff --git a/debug_rom/debug_rom.S b/debug_rom/debug_rom.S index 577edbb..7130364 100755 --- a/debug_rom/debug_rom.S +++ b/debug_rom/debug_rom.S @@ -1,6 +1,8 @@ # This code should be functional. Doesn't have to be optimal. # I'm writing it to prove that it can be done. +#include "riscv/encoding.h" + # TODO: Update these constants once they're finalized in the doc. #define DCSR 0x790 @@ -10,16 +12,13 @@ #define DSCRATCH 0x792 -#define MCPUID 0xf00 -#define MHARTID 0xf10 - # TODO: Should be 0x400 #define DEBUG_RAM (-0x400) #define DEBUG_RAM_SIZE 64 -#define SETHALTNOT 0x100 -#define CLEARHALTNOT 0x104 -#define CLEARDEBINT 0x108 +# TODO: Should be 0x100, 0x108 +#define SETHALTNOT (-0x100) +#define CLEARDEBINT (-0x108) .global entry .global resume @@ -31,7 +30,7 @@ entry: j _entry resume: # Clear debug interrupt. clear_debint: - csrr s1, MHARTID + csrr s1, CSR_MHARTID sw s1, CLEARDEBINT(zero) clear_debint_loop: csrr s1, DCSR @@ -39,7 +38,7 @@ clear_debint_loop: bnez s1, clear_debint_loop # Restore s1. - csrr s1, MCPUID + csrr s1, CSR_MISA bltz s1, restore_not_32 restore_32: lw s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 4)(zero) @@ -78,7 +77,7 @@ _entry: jdebugram: # Save s1 so that the debug program can use two registers. - csrr s0, MCPUID + csrr s0, CSR_MISA bltz s0, save_not_32 save_32: sw s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 4)(zero) @@ -94,7 +93,7 @@ save_128: jr zero, DEBUG_RAM spontaneous_halt: - csrr s0, MHARTID + csrr s0, CSR_MHARTID sw s0, SETHALTNOT(zero) csrsi DCSR, DCSR_HALT_OFFSET diff --git a/debug_rom/debug_rom.h b/debug_rom/debug_rom.h index 10c4fef..79162c2 100644 --- a/debug_rom/debug_rom.h +++ b/debug_rom/debug_rom.h @@ -1,17 +1,17 @@ static const unsigned char debug_rom_raw[] = { - 0x6f, 0x00, 0x40, 0x05, 0xf3, 0x24, 0x00, 0xf1, 0x23, 0x24, 0x90, 0x10, + 0x6f, 0x00, 0x40, 0x05, 0xf3, 0x24, 0x50, 0xf1, 0x23, 0x2c, 0x90, 0xee, 0xf3, 0x24, 0x00, 0x79, 0x93, 0xf4, 0x04, 0x40, 0xe3, 0x9c, 0x04, 0xfe, - 0xf3, 0x24, 0x00, 0xf0, 0x63, 0xc6, 0x04, 0x00, 0x83, 0x24, 0xc0, 0xc3, + 0xf3, 0x24, 0x00, 0xf1, 0x63, 0xc6, 0x04, 0x00, 0x83, 0x24, 0xc0, 0xc3, 0x6f, 0x00, 0x80, 0x01, 0x93, 0x94, 0x14, 0x00, 0x63, 0xc6, 0x04, 0x00, 0x83, 0x34, 0x80, 0xc3, 0x6f, 0x00, 0x80, 0x00, 0x13, 0x00, 0x00, 0x00, 0x73, 0x24, 0x00, 0x79, 0x13, 0x74, 0x84, 0x00, 0x63, 0x04, 0x04, 0x00, 0x6f, 0x00, 0x40, 0x05, 0x73, 0x24, 0x20, 0x79, 0x73, 0x00, 0x00, 0x10, 0x73, 0x10, 0x24, 0x79, 0x73, 0x24, 0x00, 0x79, 0x13, 0x74, 0x74, 0x00, - 0x13, 0x04, 0xd4, 0xff, 0x63, 0x16, 0x04, 0x02, 0x73, 0x24, 0x00, 0xf0, + 0x13, 0x04, 0xd4, 0xff, 0x63, 0x16, 0x04, 0x02, 0x73, 0x24, 0x00, 0xf1, 0x63, 0x46, 0x04, 0x00, 0x23, 0x2e, 0x90, 0xc2, 0x67, 0x00, 0x00, 0xc0, 0x13, 0x14, 0x14, 0x00, 0x63, 0x46, 0x04, 0x00, 0x23, 0x3c, 0x90, 0xc2, 0x67, 0x00, 0x00, 0xc0, 0x13, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0xc0, - 0x73, 0x24, 0x00, 0xf1, 0x23, 0x20, 0x80, 0x10, 0x73, 0xe0, 0x01, 0x79, + 0x73, 0x24, 0x50, 0xf1, 0x23, 0x20, 0x80, 0xf0, 0x73, 0xe0, 0x01, 0x79, 0x73, 0x24, 0x00, 0x79, 0x13, 0x74, 0x04, 0x40, 0xe3, 0x0c, 0x04, 0xfe, 0x6f, 0xf0, 0x1f, 0xfc }; diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc new file mode 100644 index 0000000..b31c4a6 --- /dev/null +++ b/riscv/debug_module.cc @@ -0,0 +1,69 @@ +#include + +#include "debug_module.h" +#include "mmu.h" + +#include "debug_rom/debug_rom.h" + +debug_module_t::debug_module_t() +{ + /* Copy Debug ROM into the page. */ + memcpy(raw_page + DEBUG_ROM_START - DEBUG_START, + debug_rom_raw, debug_rom_raw_len); +} + +bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes) +{ + addr = DEBUG_START + addr; + + fprintf(stderr, "ERROR: invalid load from debug module: %ld bytes at 0x%lx\n", + len, addr); + return false; +} + +bool debug_module_t::store(reg_t addr, size_t len, const uint8_t* bytes) +{ + addr = DEBUG_START + addr; + + if (addr & (len-1)) { + fprintf(stderr, "ERROR: unaligned store to debug module: %ld bytes at 0x%lx\n", + len, addr); + return false; + } + + if (addr >= DEBUG_RAM_START && addr + len <= DEBUG_RAM_END) { + memcpy(raw_page + addr - DEBUG_START, bytes, len); + return true; + } else if (len == 4 && addr == DEBUG_CLEARDEBINT) { + clear_interrupt(bytes[4] | (bytes[5] << 8) | + (bytes[6] << 16) | (bytes[7] << 24)); + return true; + } + + fprintf(stderr, "ERROR: invalid store to debug module: %ld bytes at 0x%lx\n", + len, addr); + return false; +} + +void debug_module_t::ram_write32(unsigned int index, uint32_t value) +{ + char* base = raw_page + DEBUG_RAM_START - DEBUG_START + index * 4; + base[0] = value & 0xff; + base[1] = (value >> 8) & 0xff; + base[2] = (value >> 16) & 0xff; + base[3] = (value >> 24) & 0xff; +} + +char* debug_module_t::page(reg_t paddr) +{ + fprintf(stderr, "dm::page(0x%lx)\n", paddr); + + assert(PGSHIFT == 12); + + if (paddr == (DEBUG_START & PGMASK)) { + return raw_page; + } + + fprintf(stderr, "ERROR: invalid page to debug module at 0x%lx\n", paddr); + return NULL; +} diff --git a/riscv/debug_module.h b/riscv/debug_module.h new file mode 100644 index 0000000..10554a8 --- /dev/null +++ b/riscv/debug_module.h @@ -0,0 +1,37 @@ +// See LICENSE for license details. +#ifndef _RISCV_DEBUG_MODULE_H +#define _RISCV_DEBUG_MODULE_H + +#include + +#include "devices.h" + +class debug_module_t : public abstract_device_t +{ + public: + debug_module_t(); + + bool load(reg_t addr, size_t len, uint8_t* bytes); + bool store(reg_t addr, size_t len, const uint8_t* bytes); + char* page(reg_t paddr); + + void ram_write32(unsigned int index, uint32_t value); + + void set_interrupt(uint32_t hartid) { + interrupt.insert(hartid); + } + void clear_interrupt(uint32_t hartid) { + interrupt.erase(hartid); + } + bool get_interrupt(uint32_t hartid) const { + return interrupt.find(hartid) != interrupt.end(); + } + + private: + // Track which interrupts from module to debugger are set. + std::set interrupt; + // TODO: use PGSIZE, which requires solving some circular include dependencies. + char raw_page[4096]; +}; + +#endif diff --git a/riscv/decode.h b/riscv/decode.h index 9b9df5b..5732a0d 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -14,7 +14,6 @@ #include "config.h" #include "common.h" #include -#include "debug_rom/debug_rom.h" typedef int64_t sreg_t; typedef uint64_t reg_t; @@ -238,11 +237,15 @@ private: #define DCSR_CAUSE_HALT 5 #define DEBUG_START 0xfffffffffffff000 -#define DEBUG_RAM_START 0xfffffffffffffc00 // TODO: 0x400 -#define DEBUG_RAM_END (DEBUG_RAM_START + 64) #define DEBUG_ROM_START 0xfffffffffffff800 // TODO: 0x800 +#define DEBUG_ROM_RESUME (DEBUG_ROM_START + 4) #define DEBUG_ROM_END (DEBUG_ROM_START + debug_rom_raw_len) +#define DEBUG_RAM_START 0xfffffffffffffc00 // TODO: 0x400 +#define DEBUG_RAM_SIZE 64 +#define DEBUG_RAM_END (DEBUG_RAM_START + DEBUG_RAM_SIZE) #define DEBUG_END 0xffffffffffffffff +#define DEBUG_CLEARDEBINT 0xfffffffffffffef8 +#define DEBUG_SETHALTNOT 0xffffffffffffff00 #define DEBUG_SIZE (DEBUG_END - DEBUG_START + 1) #endif diff --git a/riscv/devices.cc b/riscv/devices.cc index c7a63b0..e6f5d7d 100644 --- a/riscv/devices.cc +++ b/riscv/devices.cc @@ -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); } + +char* bus_t::page(reg_t paddr) +{ + auto it = devices.lower_bound(-paddr); + if (it == devices.end()) + return NULL; + return it->second->page(paddr); +} diff --git a/riscv/devices.h b/riscv/devices.h index cb3b6d9..8378188 100644 --- a/riscv/devices.h +++ b/riscv/devices.h @@ -11,6 +11,9 @@ 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; + // Return a pointer to the start of the page that addr falls in, or NULL if + // there is no IO device at that address. + virtual char* page(reg_t addr) { return NULL; } virtual ~abstract_device_t() {} }; @@ -18,6 +21,9 @@ 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); + // Return a pointer to the start of the page that addr falls in, or NULL if + // there is no IO device at that address. + char* page(reg_t paddr); void add_device(reg_t addr, abstract_device_t* dev); private: diff --git a/riscv/execute.cc b/riscv/execute.cc index 1796c38..25d1d51 100644 --- a/riscv/execute.cc +++ b/riscv/execute.cc @@ -2,6 +2,7 @@ #include "processor.h" #include "mmu.h" +#include "sim.h" #include @@ -53,10 +54,18 @@ static reg_t execute_insn(processor_t* p, reg_t pc, insn_fetch_t fetch) // fetch/decode/execute loop void processor_t::step(size_t n) { - if (state.dcsr.debugint && state.dcsr.cause == DCSR_CAUSE_NONE) { + // TODO: get_interrupt() isn't super fast. Does that matter? + if (state.dcsr.cause == DCSR_CAUSE_NONE && + sim->debug_module.get_interrupt(id)) { enter_debug_mode(DCSR_CAUSE_DEBUGINT); } + if (state.dcsr.cause != DCSR_CAUSE_NONE) { + // In Debug Mode, just do 100 steps at a time. Otherwise we're going to be + // spinning the rest of the time anyway. + n = std::max(n, (size_t) 100); + } + while (n > 0) { size_t instret = 0; reg_t pc = state.pc; diff --git a/riscv/gdbserver.cc b/riscv/gdbserver.cc index 4d6df08..6840cb7 100644 --- a/riscv/gdbserver.cc +++ b/riscv/gdbserver.cc @@ -23,9 +23,11 @@ // Functions to generate RISC-V opcodes. // TODO: Does this already exist somewhere? +#define S1 3 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; } @@ -36,7 +38,26 @@ static uint32_t jal(unsigned int rd, uint32_t imm) { (bit(imm, 11) << 20) | (bits(imm, 19, 12) << 12) | (rd << 7) | - 0x6f; + MATCH_JAL; +} + +static uint32_t csrsi(unsigned int csr, uint8_t imm) { + return (csr << 20) | + (bits(imm, 4, 0) << 15) | + MATCH_CSRRSI; +} + +static uint32_t csrr(unsigned int rd, unsigned int csr) { + return (csr << 20) | (rd << 15) | MATCH_CSRRS; +} + +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; } template @@ -143,11 +164,20 @@ gdbserver_t::gdbserver_t(uint16_t port, sim_t *sim) : void gdbserver_t::write_debug_ram(unsigned int index, uint32_t value) { - char *ram = sim->debug_ram() + 4 * index; - ram[0] = value & 0xff; - ram[1] = (value >> 8) & 0xff; - ram[2] = (value >> 16) & 0xff; - ram[3] = (value >> 24) & 0xff; + sim->debug_module.ram_write32(index, value); +} + +void gdbserver_t::halt() +{ + processor_t *p = sim->get_core(0); + write_debug_ram(0, csrsi(DCSR_ADDRESS, DCSR_HALT_OFFSET)); + write_debug_ram(1, csrr(S1, DPC_ADDRESS)); + write_debug_ram(2, sw(S1, 0, (uint16_t) DEBUG_RAM_START)); + write_debug_ram(3, csrr(S1, DCSR_ADDRESS)); + write_debug_ram(4, sw(S1, 0, (uint16_t) DEBUG_RAM_START + 8)); + write_debug_ram(5, jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*5)))); + sim->debug_module.set_interrupt(p->id); + state = STATE_HALTING; } void gdbserver_t::accept() @@ -168,9 +198,7 @@ void gdbserver_t::accept() extended_mode = false; // gdb wants the core to be halted when it attaches. - processor_t *p = sim->get_core(0); - write_debug_ram(0, jal(0, (uint32_t) (DEBUG_ROM_START + 4 - DEBUG_RAM_START))); - p->set_debug_int(); + halt(); } } @@ -544,7 +572,7 @@ void gdbserver_t::handle_continue(const std::vector &packet) } // TODO p->set_halted(false, HR_NONE); - running = true; + // TODO running = true; } void gdbserver_t::handle_step(const std::vector &packet) @@ -559,7 +587,7 @@ void gdbserver_t::handle_step(const std::vector &packet) } // TODO: p->set_single_step(true); - running = true; + // TODO running = true; } void gdbserver_t::handle_kill(const std::vector &packet) @@ -724,13 +752,20 @@ void gdbserver_t::handle_interrupt() processor_t *p = sim->get_core(0); // TODO p->set_halted(true, HR_INTERRUPT); send_packet("S02"); // Pretend program received SIGINT. - running = false; + // TODO running = false; } void gdbserver_t::handle() { if (client_fd > 0) { processor_t *p = sim->get_core(0); + + if (state == STATE_HALTING && sim->debug_module.get_interrupt(p->id) == 0) { + // gdb requested a halt and now it's done. + send_packet("T05"); + state = STATE_HALTED; + } + /* TODO if (running && p->halted) { // The core was running, but now it's halted. Better tell gdb. diff --git a/riscv/gdbserver.h b/riscv/gdbserver.h index b75e990..7ac8823 100644 --- a/riscv/gdbserver.h +++ b/riscv/gdbserver.h @@ -82,6 +82,8 @@ public: bool connected() const { return client_fd > 0; } + void halt(); + private: sim_t *sim; int socket_fd; @@ -94,6 +96,12 @@ private: // Used to track whether we think the target is running. If we think it is // but it isn't, we need to tell gdb about it. bool running; + enum { + STATE_UNKNOWN, + STATE_RUNNING, + STATE_HALTING, + STATE_HALTED + } state; std::map breakpoints; diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 5fb72bf..514547c 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -51,16 +51,44 @@ reg_t mmu_t::translate(reg_t addr, access_type type) return walk(addr, type, mode > PRV_U, pum) | (addr & (PGSIZE-1)); } -const uint16_t* mmu_t::fetch_slow_path(reg_t addr) +const char* mmu_t::fill_from_mmio(reg_t vaddr, reg_t paddr) { - reg_t paddr = translate(addr, FETCH); + reg_t rv_start = paddr & PGMASK; + char* spike_start = proc->sim->mmio_page(rv_start); + + if (!spike_start) + return NULL; + + // TODO: refactor with refill_tlb() + reg_t idx = (vaddr >> PGSHIFT) % TLB_ENTRIES; + reg_t expected_tag = vaddr >> PGSHIFT; + + if (tlb_load_tag[idx] != expected_tag) tlb_load_tag[idx] = -1; + if (tlb_store_tag[idx] != expected_tag) tlb_store_tag[idx] = -1; + if (tlb_insn_tag[idx] != expected_tag) tlb_insn_tag[idx] = -1; + + tlb_insn_tag[idx] = expected_tag; + tlb_data[idx] = spike_start - DEBUG_START; + + return spike_start + (paddr & ~PGMASK); +} + +const uint16_t* mmu_t::fetch_slow_path(reg_t vaddr) +{ + reg_t paddr = translate(vaddr, FETCH); + + // mmu_t::walk() returns -1 if it can't find a match. Of course -1 could also + // be a valid address. + if (paddr == ~(reg_t) 0 && vaddr != ~(reg_t) 0) { + throw trap_instruction_access_fault(vaddr); + } if (sim->addr_is_mem(paddr)) { - refill_tlb(addr, paddr, FETCH); + refill_tlb(vaddr, paddr, FETCH); 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); + throw trap_instruction_access_fault(vaddr); return &fetch_temp; } } diff --git a/riscv/mmu.h b/riscv/mmu.h index b6aa2ca..a87b6af 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -16,6 +16,7 @@ // virtual memory configuration #define PGSHIFT 12 const reg_t PGSIZE = 1 << PGSHIFT; +const reg_t PGMASK = ~(PGSIZE-1); struct insn_fetch_t { @@ -153,8 +154,9 @@ private: reg_t tlb_load_tag[TLB_ENTRIES]; reg_t tlb_store_tag[TLB_ENTRIES]; - // finish translation on a TLB miss and upate the TLB + // finish translation on a TLB miss and update the TLB void refill_tlb(reg_t vaddr, reg_t paddr, 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, bool supervisor, bool pum); @@ -172,7 +174,7 @@ private: return (uint16_t*)(tlb_data[vpn % TLB_ENTRIES] + addr); return fetch_slow_path(addr); } - + friend class processor_t; }; diff --git a/riscv/processor.cc b/riscv/processor.cc index 7c5c0fb..3cb2f5a 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -8,6 +8,7 @@ #include "mmu.h" #include "htif.h" #include "disasm.h" +#include "gdbserver.h" #include #include #include @@ -119,11 +120,6 @@ void state_t::reset() load_reservation = -1; } -void processor_t::set_debug_int() -{ - state.dcsr.debugint = true; -} - void processor_t::set_debug(bool value) { debug = value; @@ -481,7 +477,7 @@ reg_t processor_t::get_csr(int which) (0 << DCSR_FULLRESET_OFFSET) | (state.dcsr.prv << DCSR_PRV_OFFSET) | (state.dcsr.step << DCSR_STEP_OFFSET) | - (state.dcsr.debugint << DCSR_DEBUGINT_OFFSET) | + (sim->debug_module.get_interrupt(id) << DCSR_DEBUGINT_OFFSET) | (0 << DCSR_STOPCYCLE_OFFSET) | (0 << DCSR_STOPTIME_OFFSET) | (state.dcsr.ebreakm << DCSR_EBREAKM_OFFSET) | diff --git a/riscv/processor.h b/riscv/processor.h index 1eabee4..3511d30 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -35,7 +35,6 @@ typedef struct { uint8_t prv; bool step; - bool debugint; bool ebreakm; bool ebreakh; bool ebreaks; @@ -97,7 +96,6 @@ public: processor_t(const char* isa, sim_t* sim, uint32_t id); ~processor_t(); - void set_debug_int(); void set_debug(bool value); void set_histogram(bool value); void reset(bool value); diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in index c7d84f7..279fbde 100644 --- a/riscv/riscv.mk.in +++ b/riscv/riscv.mk.in @@ -25,6 +25,7 @@ riscv_hdrs = \ insn_template.h \ mulhi.h \ gdbserver.h \ + debug_module.h \ riscv_precompiled_hdrs = \ insn_template.h \ @@ -47,6 +48,7 @@ riscv_srcs = \ rom.cc \ rtc.cc \ gdbserver.cc \ + debug_module.cc \ $(riscv_gen_srcs) \ riscv_test_srcs = diff --git a/riscv/sim.cc b/riscv/sim.cc index 7c50425..b09e720 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -3,6 +3,7 @@ #include "sim.h" #include "mmu.h" #include "htif.h" +#include "gdbserver.h" #include #include #include @@ -41,13 +42,6 @@ sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, bool halted, fprintf(stderr, "warning: only got %lu bytes of target mem (wanted %lu)\n", (unsigned long)memsz, (unsigned long)memsz0); - /* Copy Debug ROM into the end of the allocated block, because we surely - * didn't succeed in allocating 0xfffffffff800 bytes. */ - /* TODO: Once everything uses the new memory map, just put this at the - * address that it actually belongs at. */ - memcpy(mem + memsz - DEBUG_SIZE + DEBUG_ROM_START - DEBUG_START, - debug_rom_raw, debug_rom_raw_len); - debug_mmu = new mmu_t(this, NULL); for (size_t i = 0; i < procs.size(); i++) { @@ -58,6 +52,8 @@ sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, bool halted, rtc.reset(new rtc_t(procs)); make_config_string(); + + bus.add_device(DEBUG_START, &debug_module); } sim_t::~sim_t() @@ -153,6 +149,11 @@ bool sim_t::mmio_store(reg_t addr, size_t len, const uint8_t* bytes) return bus.store(addr, len, bytes); } +char* sim_t::mmio_page(reg_t addr) +{ + return bus.page(addr); +} + void sim_t::make_config_string() { reg_t rtc_addr = EXT_IO_BASE; diff --git a/riscv/sim.h b/riscv/sim.h index 2e7b214..d3c9a6b 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -8,10 +8,11 @@ #include #include "processor.h" #include "devices.h" -#include "gdbserver.h" +#include "debug_module.h" class htif_isasim_t; class mmu_t; +class gdbserver_t; // this class encapsulates the processors and memory in a RISC-V machine. class sim_t @@ -46,6 +47,7 @@ private: std::unique_ptr boot_rom; std::unique_ptr rtc; bus_t bus; + debug_module_t debug_module; processor_t* get_core(const std::string& i); void step(size_t n); // step through simulation @@ -66,6 +68,9 @@ private: reg_t mem_to_addr(char* x) { return x - mem + DRAM_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); + // Return a pointer to the start of the page that addr falls in, or NULL if + // there is no IO device at that address. + char* mmio_page(reg_t addr); void make_config_string(); // presents a prompt for introspection into the simulation @@ -89,11 +94,6 @@ private: reg_t get_mem(const std::vector& args); reg_t get_pc(const std::vector& args); - // Return a pointer to Debug RAM in spike address space. - char *debug_ram() const { - return mem + memsz - DEBUG_SIZE + DEBUG_RAM_START - DEBUG_START; - } - friend class htif_isasim_t; friend class processor_t; friend class mmu_t; -- 2.30.2