From d643e43dca834fcb2e40504f65d5043d9f2b018b Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Thu, 4 Dec 2014 23:10:33 -0800 Subject: [PATCH] Support 2/4/6/8-byte instructions Most of the complexity is in instruction address translation, since instructions may span page boundaries. --- hwacha/insns/vf.h | 4 ++-- riscv/decode.h | 40 +++++++++++++++++++++------------------- riscv/mmu.h | 45 ++++++++++++++++++++++++++++++++------------- riscv/processor.cc | 18 +++++++++--------- spike/riscv-dis.cc | 6 ++---- 5 files changed, 66 insertions(+), 47 deletions(-) diff --git a/hwacha/insns/vf.h b/hwacha/insns/vf.h index fafb8b9..395ef1e 100644 --- a/hwacha/insns/vf.h +++ b/hwacha/insns/vf.h @@ -10,7 +10,7 @@ vf_loop: if (VF_PC & 3) h->take_exception(HWACHA_CAUSE_VF_MISALIGNED_FETCH, VF_PC); - insn_t ut_insn = p->get_mmu()->load_insn(VF_PC).insn.insn; + insn_t ut_insn = p->get_mmu()->load_insn(VF_PC).insn; bool matched = false; @@ -30,7 +30,7 @@ vf_loop: if (h->vf_active()) goto vf_loop; } else { - fprintf(stderr, "vf block: 0x%016" PRIx64 " (0x%08" PRIx32 ") %s\n", + fprintf(stderr, "vf block: 0x%016" PRIx64 " (0x%08" PRIx64 ") %s\n", VF_PC, ut_insn.bits(), h->get_ut_disassembler()->disassemble(ut_insn).c_str()); if (h->vf_active()) npc = pc; diff --git a/riscv/decode.h b/riscv/decode.h index 543080d..b325c59 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -44,26 +44,29 @@ const int NFPR = 32; #define FSR_NXA (FPEXC_NX << FSR_AEXC_SHIFT) #define FSR_AEXC (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA) +typedef uint64_t insn_bits_t; class insn_t { public: - uint32_t bits() { return b; } - int32_t i_imm() { return int32_t(b) >> 20; } - int32_t s_imm() { return x(7, 5) + (xs(25, 7) << 5); } - int32_t sb_imm() { return (x(8, 4) << 1) + (x(25,6) << 5) + (x(7,1) << 11) + (imm_sign() << 12); } - int32_t u_imm() { return int32_t(b) >> 12 << 12; } - int32_t uj_imm() { return (x(21, 10) << 1) + (x(20, 1) << 11) + (x(12, 8) << 12) + (imm_sign() << 20); } - uint32_t rd() { return x(7, 5); } - uint32_t rs1() { return x(15, 5); } - uint32_t rs2() { return x(20, 5); } - uint32_t rs3() { return x(27, 5); } - uint32_t rm() { return x(12, 3); } - uint32_t csr() { return x(20, 12); } + insn_t() = default; + insn_t(insn_bits_t bits) : b(bits) {} + insn_bits_t bits() { return b; } + int64_t i_imm() { return int64_t(b) >> 20; } + int64_t s_imm() { return x(7, 5) + (xs(25, 7) << 5); } + int64_t sb_imm() { return (x(8, 4) << 1) + (x(25,6) << 5) + (x(7,1) << 11) + (imm_sign() << 12); } + int64_t u_imm() { return int64_t(b) >> 12 << 12; } + int64_t uj_imm() { return (x(21, 10) << 1) + (x(20, 1) << 11) + (x(12, 8) << 12) + (imm_sign() << 20); } + uint64_t rd() { return x(7, 5); } + uint64_t rs1() { return x(15, 5); } + uint64_t rs2() { return x(20, 5); } + uint64_t rs3() { return x(27, 5); } + uint64_t rm() { return x(12, 3); } + uint64_t csr() { return x(20, 12); } private: - uint32_t b; - uint32_t x(int lo, int len) { return b << (32-lo-len) >> (32-len); } - uint32_t xs(int lo, int len) { return int32_t(b) << (32-lo-len) >> (32-len); } - uint32_t imm_sign() { return xs(31, 1); } + insn_bits_t b; + uint64_t x(int lo, int len) { return (b >> lo) & ((insn_bits_t(1) << len)-1); } + uint64_t xs(int lo, int len) { return int64_t(b) << (64-lo-len) >> (64-len); } + uint64_t imm_sign() { return xs(63, 1); } }; template @@ -76,9 +79,8 @@ public: } void write(size_t i, T value) { - data[i] = value; - if (zero_reg) - data[0] = 0; + if (!zero_reg || i != 0) + data[i] = value; } const T& operator [] (size_t i) const { diff --git a/riscv/mmu.h b/riscv/mmu.h index c3d8f41..778e5fa 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -25,10 +25,7 @@ const reg_t VA_BITS = VPN_BITS + PGSHIFT; struct insn_fetch_t { insn_func_t func; - union { - insn_t insn; - uint_fast32_t pad; - } insn; + insn_t insn; }; struct icache_entry_t { @@ -77,27 +74,49 @@ public: store_func(uint32) store_func(uint64) + inline size_t icache_index(reg_t addr) + { + // for instruction sizes != 4, this hash still works but is suboptimal + return (addr / 4) % ICACHE_SIZE; + } + // load instruction from memory at aligned address. - inline icache_entry_t* access_icache(reg_t addr) + icache_entry_t* access_icache(reg_t addr) __attribute__((always_inline)) { - reg_t idx = (addr / sizeof(insn_t)) % ICACHE_SIZE; + reg_t idx = icache_index(addr); icache_entry_t* entry = &icache[idx]; if (likely(entry->tag == addr)) return entry; - void* iaddr = translate(addr, sizeof(insn_t), false, true); - insn_fetch_t fetch; - fetch.insn.pad = *(decltype(fetch.insn.insn.bits())*)iaddr; - fetch.func = proc->decode_insn(fetch.insn.insn); + char* iaddr = (char*)translate(addr, 2, false, true); + insn_bits_t insn = *(uint16_t*)iaddr; + + if (unlikely(insn_length(insn) == 2)) { + insn = (int16_t)insn; + } else if (likely(insn_length(insn) == 4)) { + if (likely((addr & (PGSIZE-1)) < PGSIZE-2)) + insn |= (insn_bits_t)*(int16_t*)(iaddr + 2) << 16; + else + insn |= (insn_bits_t)*(int16_t*)translate(addr + 2, 2, false, true) << 16; + } else if (insn_length(insn) == 6) { + insn |= (insn_bits_t)*(int16_t*)translate(addr + 4, 2, false, true) << 32; + insn |= (insn_bits_t)*(uint16_t*)translate(addr + 2, 2, false, true) << 16; + } else { + static_assert(sizeof(insn_bits_t) == 8, "insn_bits_t must be uint64_t"); + insn |= (insn_bits_t)*(int16_t*)translate(addr + 6, 2, false, true) << 48; + insn |= (insn_bits_t)*(uint16_t*)translate(addr + 4, 2, false, true) << 32; + insn |= (insn_bits_t)*(uint16_t*)translate(addr + 2, 2, false, true) << 16; + } + insn_fetch_t fetch = {proc->decode_insn(insn), insn}; icache[idx].tag = addr; icache[idx].data = fetch; - reg_t paddr = (char*)iaddr - mem; - if (!tracer.empty() && tracer.interested_in_range(paddr, paddr + sizeof(insn_t), false, true)) + reg_t paddr = iaddr - mem; + if (!tracer.empty() && tracer.interested_in_range(paddr, paddr + 1, false, true)) { icache[idx].tag = -1; - tracer.trace(paddr, sizeof(insn_t), false, true); + tracer.trace(paddr, 1, false, true); } return &icache[idx]; } diff --git a/riscv/processor.cc b/riscv/processor.cc index 956b2d3..08ec2b7 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -129,13 +129,13 @@ static void commit_log(state_t* state, insn_t insn) #ifdef RISCV_ENABLE_COMMITLOG if (state->sr & SR_EI) { if (state->log_reg_write.addr) { - fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx32 ") %c%2u 0x%016" PRIx64 "\n", + fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ") %c%2u 0x%016" PRIx64 "\n", state->pc, insn.bits(), state->log_reg_write.addr & 1 ? 'f' : 'x', state->log_reg_write.addr >> 1, state->log_reg_write.data); } else { - fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx32 ")\n", + fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ")\n", state->pc, insn.bits()); } } @@ -153,8 +153,8 @@ inline void processor_t::update_histogram(size_t pc) static reg_t execute_insn(processor_t* p, reg_t pc, insn_fetch_t fetch) { - reg_t npc = fetch.func(p, fetch.insn.insn, pc); - commit_log(p->get_state(), fetch.insn.insn); + reg_t npc = fetch.func(p, fetch.insn, pc); + commit_log(p->get_state(), fetch.insn); p->update_histogram(pc); return npc; } @@ -192,13 +192,13 @@ void processor_t::step(size_t n) while (instret++ < n) { insn_fetch_t fetch = mmu->load_insn(pc); - disasm(fetch.insn.insn); + disasm(fetch.insn); pc = execute_insn(this, pc, fetch); } } else while (instret < n) { - size_t idx = (pc / sizeof(insn_t)) % ICACHE_SIZE; + size_t idx = _mmu->icache_index(pc); auto ic_entry = _mmu->access_icache(pc); #define ICACHE_ACCESS(idx) { \ @@ -251,9 +251,9 @@ void processor_t::deliver_ipi() void processor_t::disasm(insn_t insn) { - // the disassembler is stateless, so we share it - fprintf(stderr, "core %3d: 0x%016" PRIx64 " (0x%08" PRIx32 ") %s\n", - id, state.pc, insn.bits(), disassembler->disassemble(insn).c_str()); + uint64_t bits = insn.bits() & ((1ULL << (8 * insn_length(insn.bits()))) - 1); + fprintf(stderr, "core %3d: 0x%016" PRIx64 " (0x%08" PRIx64 ") %s\n", + id, state.pc, bits, disassembler->disassemble(insn).c_str()); } void processor_t::set_pcr(int which, reg_t val) diff --git a/spike/riscv-dis.cc b/spike/riscv-dis.cc index 89c4b74..d0af451 100644 --- a/spike/riscv-dis.cc +++ b/spike/riscv-dis.cc @@ -32,10 +32,8 @@ int main(int argc, char** argv) break; size_t numstart = start + strlen("DASM("); - uint32_t n = strtoul(&s[numstart], NULL, 16); - - string dis = d.disassemble(*(insn_t*)&n); - + insn_bits_t bits = strtoull(&s[numstart], NULL, 16); + string dis = d.disassemble(bits); s = s.substr(0, start) + dis + s.substr(end+1); start += dis.length(); } -- 2.30.2