Merge "Fixup ecall/mret and associated CSRs"
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