Fixup ecall/mret and associated CSRs - Adjust ecall to be callable from any mode, and to jump to `mtvec`, with the LSB cleared. - Have ecall set the `mepc` register to the calling instruction address. - Align `mcause` with the spec. Change-Id: Ia520451306362a895c8c6317a034fd6d58718cfd
diff --git a/hdl/chisel/src/kelvin/scalar/Bru.scala b/hdl/chisel/src/kelvin/scalar/Bru.scala index bc4e7b4..9a3d624 100644 --- a/hdl/chisel/src/kelvin/scalar/Bru.scala +++ b/hdl/chisel/src/kelvin/scalar/Bru.scala
@@ -111,8 +111,9 @@ val pc4De = io.req.bits.pc + 4.U val mret = (io.req.bits.op === BruOp.MRET) && mode === CsrMode.Machine + val ecall = io.req.bits.op === BruOp.ECALL val call = ((io.req.bits.op === BruOp.MRET) && mode === CsrMode.User) || - io.req.bits.op.isOneOf(BruOp.EBREAK, BruOp.ECALL, BruOp.EEXIT, + io.req.bits.op.isOneOf(BruOp.EBREAK, BruOp.EEXIT, BruOp.EYIELD, BruOp.ECTXSW, BruOp.MPAUSE) val stateReg = RegInit(MakeValid(false.B, BranchState.default(p))) @@ -129,6 +130,7 @@ nextState.target := MuxCase(io.req.bits.target, Seq( mret -> io.csr.out.mepc, + ecall -> Cat(io.csr.out.mtvec(31,1), 0.U(1.W)), call -> io.csr.out.mepc, (io.req.bits.fwd || (io.req.bits.op === BruOp.FENCEI)) -> pc4De, (io.req.bits.op === BruOp.JALR) -> io.target.data, @@ -153,7 +155,8 @@ io.taken.valid := stateReg.valid && MuxLookup(op, false.B)(Seq( BruOp.EBREAK -> (mode === CsrMode.User), - BruOp.ECALL -> (mode === CsrMode.User), + // Any mode can execute `ecall`, but the value of `mcause` will be different. + BruOp.ECALL -> true.B, BruOp.EEXIT -> (mode === CsrMode.User), BruOp.EYIELD -> (mode === CsrMode.User), BruOp.ECTXSW -> (mode === CsrMode.User), @@ -182,7 +185,7 @@ val usageFault = stateReg.valid && Mux( (mode === CsrMode.User), op.isOneOf(BruOp.MPAUSE, BruOp.MRET), - op.isOneOf(BruOp.EBREAK, BruOp.ECALL, BruOp.EEXIT, BruOp.EYIELD, + op.isOneOf(BruOp.EBREAK, BruOp.EEXIT, BruOp.EYIELD, BruOp.ECTXSW)) io.csr.in.mode.valid := stateReg.valid && Mux( @@ -191,25 +194,29 @@ (op === BruOp.MRET)) io.csr.in.mode.bits := Mux(((op === BruOp.MRET) && (mode === CsrMode.Machine)), CsrMode.Machine, CsrMode.User) - io.csr.in.mepc.valid := stateReg.valid && (mode === CsrMode.User) && - op.isOneOf(BruOp.EBREAK, BruOp.ECALL, BruOp.EEXIT, BruOp.EYIELD, - BruOp.ECTXSW, BruOp.MPAUSE, BruOp.MRET) - io.csr.in.mepc.bits := Mux(op === BruOp.EYIELD, stateReg.bits.linkData, - stateReg.bits.pcEx) + io.csr.in.mepc.valid := stateReg.valid && op === BruOp.ECALL + io.csr.in.mepc.bits := stateReg.bits.pcEx io.csr.in.mcause.valid := stateReg.valid && (undefFault || usageFault || - ((mode === CsrMode.User) && op.isOneOf(BruOp.EBREAK, BruOp.ECALL, BruOp.EEXIT, BruOp.EYIELD, - BruOp.ECTXSW))) + op.isOneOf(BruOp.ECALL) || + ((mode === CsrMode.User) && + /* user mode mcause triggers */ + op.isOneOf(BruOp.EBREAK, + BruOp.EEXIT, BruOp.EYIELD, + BruOp.ECTXSW), + ) + ) - val faultMsb = 1.U << 31 io.csr.in.mcause.bits := MuxCase(0.U, Seq( - undefFault -> (2.U | faultMsb), - usageFault -> (16.U | faultMsb), - (op === BruOp.EBREAK) -> 1.U, - (op === BruOp.ECALL) -> 2.U, - (op === BruOp.EEXIT) -> 3.U, - (op === BruOp.EYIELD) -> 4.U, - (op === BruOp.ECTXSW) -> 5.U, + (op === BruOp.EBREAK) -> 3.U, + (op === BruOp.ECALL && mode === CsrMode.Machine) -> 11.U, + (op === BruOp.ECALL && mode === CsrMode.User) -> 8.U, + // Kelvin-specific things, use the custom reserved region of the encoding space. + undefFault -> (24 + 0).U, + usageFault -> (24 + 1).U, + (op === BruOp.EEXIT) -> (24 + 2).U, + (op === BruOp.EYIELD) -> (24 + 3).U, + (op === BruOp.ECTXSW) -> (24 + 4).U, )) io.csr.in.mtval.valid := stateReg.valid && (undefFault || usageFault)
diff --git a/hdl/chisel/src/kelvin/scalar/Csr.scala b/hdl/chisel/src/kelvin/scalar/Csr.scala index 465c57b..02e5e67 100644 --- a/hdl/chisel/src/kelvin/scalar/Csr.scala +++ b/hdl/chisel/src/kelvin/scalar/Csr.scala
@@ -301,13 +301,14 @@ mode := io.bru.in.mode.bits } - val firstFault = !mcause(31) + // High bit of mcause is set for an external interrupt. + val interrupt = mcause(31) - when (io.bru.in.mcause.valid && firstFault) { + when (io.bru.in.mcause.valid) { mcause := io.bru.in.mcause.bits } - when (io.bru.in.mtval.valid && firstFault) { + when (io.bru.in.mtval.valid) { mtval := io.bru.in.mtval.bits } @@ -333,8 +334,8 @@ // Forwarding. io.bru.out.mode := mode - io.bru.out.mepc := Mux(mepcEn, wdata, mepc) - io.bru.out.mtvec := Mux(mtvecEn, wdata, mtvec) + io.bru.out.mepc := Mux(mepcEn && req.valid, wdata, mepc) + io.bru.out.mtvec := Mux(mtvecEn && req.valid, wdata, mtvec) io.csr.out.value(0) := mpc io.csr.out.value(1) := msp