Browse Source

Fix up interrupt delegation

pull/40/merge
Andrew Waterman 11 years ago
parent
commit
fa1cb289e7
  1. 7
      riscv/encoding.h
  2. 46
      riscv/processor.cc

7
riscv/encoding.h

@ -61,8 +61,11 @@
#define IRQ_S_TIMER 5
#define IRQ_H_TIMER 6
#define IRQ_M_TIMER 7
#define IRQ_COP 8
#define IRQ_HOST 9
#define IRQ_S_DEV 9
#define IRQ_H_DEV 10
#define IRQ_M_DEV 11
#define IRQ_COP 12
#define IRQ_HOST 13
#define DEFAULT_RSTVEC 0x0
#define DEFAULT_NMIVEC 0x4

46
riscv/processor.cc

@ -172,17 +172,18 @@ void processor_t::take_interrupt()
{
check_timer();
reg_t interrupts = state.mip & state.mie;
reg_t pending_interrupts = state.mip & state.mie;
reg_t m_interrupts = interrupts & ~state.mideleg;
reg_t mie = get_field(state.mstatus, MSTATUS_MIE);
if ((state.prv < PRV_M || (state.prv == PRV_M && mie)) && m_interrupts)
raise_interrupt(ctz(m_interrupts));
reg_t m_enabled = state.prv < PRV_M || (state.prv == PRV_M && mie);
reg_t enabled_interrupts = pending_interrupts & ~state.mideleg & -m_enabled;
reg_t s_interrupts = interrupts & state.mideleg;
reg_t sie = get_field(state.mstatus, MSTATUS_SIE);
if ((state.prv < PRV_S || (state.prv == PRV_S && sie)) && s_interrupts)
raise_interrupt(ctz(s_interrupts));
reg_t s_enabled = state.prv < PRV_S || (state.prv == PRV_S && sie);
enabled_interrupts |= pending_interrupts & state.mideleg & -s_enabled;
if (enabled_interrupts)
raise_interrupt(ctz(enabled_interrupts));
}
void processor_t::check_timer()
@ -265,8 +266,8 @@ static bool validate_vm(int max_xlen, reg_t vm)
void processor_t::set_csr(int which, reg_t val)
{
val = zext_xlen(val);
reg_t all_ints = MIP_SSIP | MIP_MSIP | MIP_STIP | MIP_MTIP | (1UL << IRQ_HOST);
reg_t s_ints = MIP_SSIP | MIP_STIP;
reg_t delegable_ints = MIP_SSIP | MIP_STIP | (1 << IRQ_HOST) | (1 << IRQ_COP);
reg_t all_ints = delegable_ints | MIP_MSIP | MIP_MTIP;
switch (which)
{
case CSR_FFLAGS:
@ -311,7 +312,7 @@ void processor_t::set_csr(int which, reg_t val)
break;
}
case CSR_MIP: {
reg_t mask = all_ints &~ MIP_MTIP;
reg_t mask = MIP_SSIP | MIP_STIP | MIP_MSIP;
state.mip = (state.mip & ~mask) | (val & mask);
break;
}
@ -322,7 +323,7 @@ void processor_t::set_csr(int which, reg_t val)
state.mie = (state.mie & ~all_ints) | (val & all_ints);
break;
case CSR_MIDELEG:
state.mideleg = (state.mideleg & ~s_ints) | (val & s_ints);
state.mideleg = (state.mideleg & ~delegable_ints) | (val & delegable_ints);
break;
case CSR_MEDELEG: {
reg_t mask = 0;
@ -341,19 +342,14 @@ void processor_t::set_csr(int which, reg_t val)
case CSR_SSTATUS: {
reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS
| SSTATUS_XS | SSTATUS_PUM;
set_csr(CSR_MSTATUS, (state.mstatus & ~mask) | (val & mask));
break;
}
case CSR_SIP: {
reg_t mask = s_ints &~ MIP_STIP;
state.mip = (state.mip & ~mask) | (val & mask);
break;
}
case CSR_SIE: {
reg_t mask = s_ints;
state.mie = (state.mie & ~mask) | (val & mask);
break;
return set_csr(CSR_MSTATUS, (state.mstatus & ~mask) | (val & mask));
}
case CSR_SIP:
return set_csr(CSR_MIP,
(state.mip & ~state.mideleg) | (val & state.mideleg));
case CSR_SIE:
return set_csr(CSR_MIE,
(state.mie & ~state.mideleg) | (val & state.mideleg));
case CSR_SEPC: state.sepc = val; break;
case CSR_STVEC: state.stvec = val >> 2 << 2; break;
case CSR_SPTBR: state.sptbr = val; break;
@ -439,8 +435,8 @@ reg_t processor_t::get_csr(int which)
sstatus |= (xlen == 32 ? SSTATUS32_SD : SSTATUS64_SD);
return sstatus;
}
case CSR_SIP: return state.mip & (MIP_SSIP | MIP_STIP);
case CSR_SIE: return state.mie & (MIP_SSIP | MIP_STIP);
case CSR_SIP: return state.mip & state.mideleg;
case CSR_SIE: return state.mie & state.mideleg;
case CSR_SEPC: return state.sepc;
case CSR_SBADADDR: return state.sbadaddr;
case CSR_STVEC: return state.stvec;

Loading…
Cancel
Save