} while(0)
#define set_pc_and_serialize(x) \
- do { reg_t __npc = (x); \
+ do { reg_t __npc = (x) & p->pc_alignment_mask(); \
npc = PC_SERIALIZE_AFTER; \
STATE.pc = __npc; \
} while(0)
case CSR_MCAUSE: state.mcause = val; break;
case CSR_MTVAL: state.mtval = val; break;
case CSR_MISA: {
+ // the write is ignored if increasing IALIGN would misalign the PC
+ if (!(val & (1L << ('C' - 'A'))) && (state.pc & 2))
+ break;
+
if (!(val & (1L << ('F' - 'A'))))
val &= ~(1L << ('D' - 'A'));
}
case CSR_SIP: return state.mip & state.mideleg;
case CSR_SIE: return state.mie & state.mideleg;
- case CSR_SEPC: return state.sepc;
+ case CSR_SEPC: return state.sepc & pc_alignment_mask();
case CSR_STVAL: return state.stval;
case CSR_STVEC: return state.stvec;
case CSR_SCAUSE:
case CSR_MSTATUS: return state.mstatus;
case CSR_MIP: return state.mip;
case CSR_MIE: return state.mie;
- case CSR_MEPC: return state.mepc;
+ case CSR_MEPC: return state.mepc & pc_alignment_mask();
case CSR_MSCRATCH: return state.mscratch;
case CSR_MCAUSE: return state.mcause;
case CSR_MTVAL: return state.mtval;
return v;
}
case CSR_DPC:
- return state.dpc;
+ return state.dpc & pc_alignment_mask();
case CSR_DSCRATCH:
return state.dscratch;
}
if (ext >= 'a' && ext <= 'z') ext += 'A' - 'a';
return ext >= 'A' && ext <= 'Z' && ((state.misa >> (ext - 'A')) & 1);
}
+ reg_t pc_alignment_mask() {
+ return ~(reg_t)(supports_extension('C') ? 0 : 2);
+ }
void check_pc_alignment(reg_t pc) {
- if (unlikely(pc & 2) && !supports_extension('C'))
+ if (unlikely(pc & ~pc_alignment_mask()))
throw trap_instruction_address_misaligned(pc);
}
reg_t legalize_privilege(reg_t);