Browse Source

Convert mip to csr_t family

This changes the commitlog of `csrw sip` so that it only logs a change
to `mip`, instead of both `mip` and `sip`. This is arguably
preferable, since there is no real `sip` register -- it is only a view
into `mip`.

It also adds proper tracing of the modification to `mip` when doing
`csrw` to `hip`, `hvip`, and `vsip`, which were all missing
previously.
pull/796/head
Scott Johnson 5 years ago
committed by Andrew Waterman
parent
commit
7c8ae9ba4d
  1. 10
      riscv/clint.cc
  2. 37
      riscv/csrs.cc
  3. 19
      riscv/csrs.h
  4. 49
      riscv/processor.cc
  5. 4
      riscv/processor.h

10
riscv/clint.cc

@ -33,7 +33,7 @@ bool clint_t::load(reg_t addr, size_t len, uint8_t* bytes)
if (addr >= MSIP_BASE && addr + len <= MSIP_BASE + procs.size()*sizeof(msip_t)) {
std::vector<msip_t> msip(procs.size());
for (size_t i = 0; i < procs.size(); ++i)
msip[i] = !!(procs[i]->state.mip & MIP_MSIP);
msip[i] = !!(procs[i]->state.mip->read() & MIP_MSIP);
memcpy(bytes, (uint8_t*)&msip[0] + addr - MSIP_BASE, len);
} else if (addr >= MTIMECMP_BASE && addr + len <= MTIMECMP_BASE + procs.size()*sizeof(mtimecmp_t)) {
memcpy(bytes, (uint8_t*)&mtimecmp[0] + addr - MTIMECMP_BASE, len);
@ -54,9 +54,9 @@ bool clint_t::store(reg_t addr, size_t len, const uint8_t* bytes)
memset((uint8_t*)&mask[0] + addr - MSIP_BASE, 0xff, len);
for (size_t i = 0; i < procs.size(); ++i) {
if (!(mask[i] & 0xFF)) continue;
procs[i]->state.mip &= ~MIP_MSIP;
procs[i]->state.mip->backdoor_write_with_mask(MIP_MSIP, 0);
if (!!(msip[i] & 1))
procs[i]->state.mip |= MIP_MSIP;
procs[i]->state.mip->backdoor_write_with_mask(MIP_MSIP, MIP_MSIP);
}
} else if (addr >= MTIMECMP_BASE && addr + len <= MTIMECMP_BASE + procs.size()*sizeof(mtimecmp_t)) {
memcpy((uint8_t*)&mtimecmp[0] + addr - MTIMECMP_BASE, bytes, len);
@ -82,8 +82,8 @@ void clint_t::increment(reg_t inc)
mtime += inc;
}
for (size_t i = 0; i < procs.size(); i++) {
procs[i]->state.mip &= ~MIP_MTIP;
procs[i]->state.mip->backdoor_write_with_mask(MIP_MTIP, 0);
if (mtime >= mtimecmp[i])
procs[i]->state.mip |= MIP_MTIP;
procs[i]->state.mip->backdoor_write_with_mask(MIP_MTIP, MIP_MTIP);
}
}

37
riscv/csrs.cc

@ -486,7 +486,7 @@ bool misa_csr_t::unlogged_write(const reg_t val) noexcept {
state->medeleg &= ~hypervisor_exceptions;
state->mstatus->write(state->mstatus->read() & ~(MSTATUS_GVA | MSTATUS_MPV));
state->mie &= ~MIP_HS_MASK; // also takes care of hie, sie
state->mip &= ~MIP_HS_MASK; // also takes care of hip, sip, hvip
state->mip->write_with_mask(MIP_HS_MASK, 0); // also takes care of hip, sip, hvip
proc->set_csr(CSR_HSTATUS, 0);
}
@ -502,3 +502,38 @@ bool misa_csr_t::extension_enabled_const(unsigned char ext) const noexcept {
assert(!(1 & (write_mask >> (ext - 'A'))));
return extension_enabled(ext);
}
// implement class mip_csr_t
mip_csr_t::mip_csr_t(processor_t* const proc, const reg_t addr):
logged_csr_t(proc, addr),
val(0) {
}
reg_t mip_csr_t::read() const noexcept {
return val;
}
void mip_csr_t::write_with_mask(const reg_t mask, const reg_t val) noexcept {
backdoor_write_with_mask(mask, val);
log_write();
}
void mip_csr_t::backdoor_write_with_mask(const reg_t mask, const reg_t val) noexcept {
this->val = (this->val & ~mask) | (val & mask);
}
bool mip_csr_t::unlogged_write(const reg_t val) noexcept {
const reg_t supervisor_ints = proc->extension_enabled('S') ? MIP_SSIP | MIP_STIP | MIP_SEIP : 0;
const reg_t vssip_int = proc->extension_enabled('H') ? MIP_VSSIP : 0;
const reg_t hypervisor_ints = proc->extension_enabled('H') ? MIP_HS_MASK : 0;
// We must mask off sgeip, vstip, and vseip. All three of these
// bits are aliases for the same bits in hip. The hip spec says:
// * sgeip is read-only -- write hgeip instead
// * vseip is read-only -- write hvip instead
// * vstip is read-only -- write hvip instead
const reg_t mask = (supervisor_ints | hypervisor_ints) &
(MIP_SEIP | MIP_SSIP | MIP_STIP | vssip_int);
this->val = (this->val & ~mask) | (val & mask);
return true;
}

19
riscv/csrs.h

@ -270,4 +270,23 @@ class misa_csr_t: public basic_csr_t {
typedef std::shared_ptr<misa_csr_t> misa_csr_t_p;
class mip_csr_t: public logged_csr_t {
public:
mip_csr_t(processor_t* const proc, const reg_t addr);
virtual reg_t read() const noexcept override;
void write_with_mask(const reg_t mask, const reg_t val) noexcept;
// Does not log. Used by external things (clint) that wiggle bits in mip.
void backdoor_write_with_mask(const reg_t mask, const reg_t val) noexcept;
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
private:
reg_t val;
};
typedef std::shared_ptr<mip_csr_t> mip_csr_t_p;
#endif

49
riscv/processor.cc

@ -346,7 +346,7 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
csrmap[CSR_MCAUSE] = mcause = std::make_shared<cause_csr_t>(proc, CSR_MCAUSE);
minstret = 0;
mie = 0;
mip = 0;
csrmap[CSR_MIP] = mip = std::make_shared<mip_csr_t>(proc, CSR_MIP);
medeleg = 0;
mideleg = 0;
mcounteren = 0;
@ -947,17 +947,6 @@ void processor_t::set_csr(int which, reg_t val)
VU.vxsat = (val & VCSR_VXSAT) >> VCSR_VXSAT_SHIFT;
VU.vxrm = (val & VCSR_VXRM) >> VCSR_VXRM_SHIFT;
break;
case CSR_MIP: {
// We must mask off sgeip, vstip, and vseip. All three of these
// bits are aliases for the same bits in hip. The hip spec says:
// * sgeip is read-only -- write hgeip instead
// * vseip is read-only -- write hvip instead
// * vstip is read-only -- write hvip instead
reg_t mask = (supervisor_ints | hypervisor_ints) &
(MIP_SEIP | MIP_SSIP | MIP_STIP | vssip_int);
state.mip = (state.mip & ~mask) | (val & mask);
break;
}
case CSR_MIE:
state.mie = (state.mie & ~all_ints) | (val & all_ints);
break;
@ -1008,8 +997,8 @@ void processor_t::set_csr(int which, reg_t val)
} else {
mask = state.mideleg & MIP_SSIP;
}
state.mip = (state.mip & ~mask) | (val & mask);
break;
state.mip->write_with_mask(mask, val);
return;
}
case CSR_SIE: {
reg_t mask;
@ -1083,13 +1072,13 @@ void processor_t::set_csr(int which, reg_t val)
break;
case CSR_HIP: {
reg_t mask = MIP_VSSIP;
state.mip = (state.mip & ~mask) | (val & mask);
break;
state.mip->write_with_mask(mask, val);
return;
}
case CSR_HVIP: {
reg_t mask = MIP_VS_MASK;
state.mip = (state.mip & ~mask) | (val & mask);
break;
state.mip->write_with_mask(mask, val);
return;
}
case CSR_HTINST:
state.htinst = val;
@ -1120,8 +1109,8 @@ void processor_t::set_csr(int which, reg_t val)
}
case CSR_VSIP: {
reg_t mask = state.hideleg & MIP_VSSIP;
state.mip = (state.mip & ~mask) | ((val << 1) & mask);
break;
state.mip->write_with_mask(mask, val << 1);
return;
}
case CSR_VSATP:
if (!supports_impl(IMPL_MMU))
@ -1230,16 +1219,11 @@ void processor_t::set_csr(int which, reg_t val)
LOG_CSR(CSR_VXRM);
break;
case CSR_SIP:
LOG_CSR(CSR_MIP);
LOG_CSR(CSR_SIP);
break;
case CSR_SIE:
LOG_CSR(CSR_MIE);
LOG_CSR(CSR_SIE);
break;
case CSR_MIP:
case CSR_MIE:
case CSR_MIDELEG:
case CSR_MEDELEG:
@ -1393,9 +1377,9 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek)
case CSR_MCOUNTINHIBIT: ret(0);
case CSR_SIP: {
if (state.v) {
ret((state.mip & state.hideleg & MIP_VS_MASK) >> 1);
ret((state.mip->read() & state.hideleg & MIP_VS_MASK) >> 1);
} else {
ret(state.mip & state.mideleg & ~MIP_HS_MASK);
ret(state.mip->read() & state.mideleg & ~MIP_HS_MASK);
}
}
case CSR_SIE: {
@ -1420,7 +1404,6 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek)
if (xlen == 32)
ret((state.mstatus->read() >> 32) & (MSTATUSH_SBE | MSTATUSH_MBE));
break;
case CSR_MIP: ret(state.mip);
case CSR_MIE: ret(state.mie);
case CSR_MTVAL2:
if (extension_enabled('H'))
@ -1449,8 +1432,8 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek)
case CSR_HCOUNTEREN: ret(state.hcounteren);
case CSR_HGEIE: ret(0);
case CSR_HTVAL: ret(state.htval);
case CSR_HIP: ret(state.mip & MIP_HS_MASK);
case CSR_HVIP: ret(state.mip & MIP_VS_MASK);
case CSR_HIP: ret(state.mip->read() & MIP_HS_MASK);
case CSR_HVIP: ret(state.mip->read() & MIP_VS_MASK);
case CSR_HTINST: ret(state.htinst);
case CSR_HGATP: {
if (!state.v && get_field(state.mstatus->read(), MSTATUS_TVM))
@ -1459,7 +1442,7 @@ reg_t processor_t::get_csr(int which, insn_t insn, bool write, bool peek)
}
case CSR_HGEIP: ret(0);
case CSR_VSIE: ret((state.mie & state.hideleg & MIP_VS_MASK) >> 1);
case CSR_VSIP: ret((state.mip & state.hideleg & MIP_VS_MASK) >> 1);
case CSR_VSIP: ret((state.mip->read() & state.hideleg & MIP_VS_MASK) >> 1);
case CSR_VSATP: ret(state.vsatp);
case CSR_TSELECT: ret(state.tselect);
case CSR_TDATA1:
@ -1691,7 +1674,7 @@ bool processor_t::load(reg_t addr, size_t len, uint8_t* bytes)
case 0:
if (len <= 4) {
memset(bytes, 0, len);
bytes[0] = get_field(state.mip, MIP_MSIP);
bytes[0] = get_field(state.mip->read(), MIP_MSIP);
return true;
}
break;
@ -1706,7 +1689,7 @@ bool processor_t::store(reg_t addr, size_t len, const uint8_t* bytes)
{
case 0:
if (len <= 4) {
state.mip = set_field(state.mip, MIP_MSIP, bytes[0]);
state.mip->write_with_mask(MIP_MSIP, bytes[0] << IRQ_M_SOFT);
return true;
}
break;

4
riscv/processor.h

@ -176,7 +176,7 @@ struct state_t
csr_t_p mcause;
reg_t minstret;
reg_t mie;
reg_t mip;
mip_csr_t_p mip;
reg_t medeleg;
reg_t mideleg;
uint32_t mcounteren;
@ -485,7 +485,7 @@ private:
static const size_t OPCODE_CACHE_SIZE = 8191;
insn_desc_t opcode_cache[OPCODE_CACHE_SIZE];
void take_pending_interrupt() { take_interrupt(state.mip & state.mie); }
void take_pending_interrupt() { take_interrupt(state.mip->read() & state.mie); }
void take_interrupt(reg_t mask); // take first enabled interrupt in mask
void take_trap(trap_t& t, reg_t epc); // take an exception
void disasm(insn_t insn); // disassemble and print an instruction

Loading…
Cancel
Save