arch-riscv: Add support for trap value register
authorAlec Roelke <ar4jc@virginia.edu>
Mon, 19 Feb 2018 03:28:44 +0000 (22:28 -0500)
committerAlec Roelke <alec.roelke@gmail.com>
Sat, 28 Jul 2018 18:48:30 +0000 (18:48 +0000)
RISC-V has a set of CSRs that contain information about a trap that was
taken into each privilegel level, such as illegal instruction bytes or
faulting address.  This patch adds that register, modifies existing
faults to make use of it, and adds a new fault for future use with
handling page faults and bad addresses.

Change-Id: I3004bd7b907e7dc75e5f1a8452a1d74796a7a551
Reviewed-on: https://gem5-review.googlesource.com/11135
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Alec Roelke <alec.roelke@gmail.com>

src/arch/riscv/faults.cc
src/arch/riscv/faults.hh
src/arch/riscv/insts/unknown.hh
src/arch/riscv/isa/decoder.isa
src/arch/riscv/isa/formats/fp.isa
src/arch/riscv/isa/formats/standard.isa

index efab6c4448f40aad87b6f1488102058c5da1903f..b5f3d078bfed27222c0e5ae0ec2504b380889a44 100644 (file)
@@ -71,12 +71,13 @@ RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
         }
 
         // Set fault registers and status
-        MiscRegIndex cause, epc, tvec;
+        MiscRegIndex cause, epc, tvec, tval;
         switch (prv) {
           case PRV_U:
             cause = MISCREG_UCAUSE;
             epc = MISCREG_UEPC;
             tvec = MISCREG_UTVEC;
+            tval = MISCREG_UTVAL;
 
             status.upie = status.uie;
             status.uie = 0;
@@ -85,6 +86,7 @@ RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
             cause = MISCREG_SCAUSE;
             epc = MISCREG_SEPC;
             tvec = MISCREG_STVEC;
+            tval = MISCREG_STVAL;
 
             status.spp = pp;
             status.spie = status.sie;
@@ -94,6 +96,7 @@ RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
             cause = MISCREG_MCAUSE;
             epc = MISCREG_MEPC;
             tvec = MISCREG_MTVEC;
+            tval = MISCREG_MTVAL;
 
             status.mpp = pp;
             status.mpie = status.sie;
@@ -108,6 +111,7 @@ RiscvFault::invoke(ThreadContext *tc, const StaticInstPtr &inst)
         tc->setMiscReg(cause,
                        (isInterrupt() << (sizeof(MiscReg) * 4 - 1)) | _code);
         tc->setMiscReg(epc, tc->instAddr());
+        tc->setMiscReg(tval, trap_value());
         tc->setMiscReg(MISCREG_PRV, prv);
         tc->setMiscReg(MISCREG_STATUS, status);
 
index ef0fdb6e3206eeb25e2d2296aeeff8d03ad99d26..6d3fdebbea0db4fd73f7190c2fddfc2b3505b9e0 100644 (file)
@@ -129,9 +129,10 @@ class RiscvFault : public FaultBase
         : _name(n), _interrupt(i), _code(c)
     {}
 
-    FaultName name() const { return _name; }
+    FaultName name() const override { return _name; }
     bool isInterrupt() const { return _interrupt; }
     ExceptionCode exception() const { return _code; }
+    virtual MiscReg trap_value() const { return 0; }
 
     virtual void invokeSE(ThreadContext *tc, const StaticInstPtr &inst);
     void invoke(ThreadContext *tc, const StaticInstPtr &inst) override;
@@ -159,61 +160,94 @@ class Reset : public FaultBase
         const FaultName _name;
 };
 
-class UnknownInstFault : public RiscvFault
+class InstFault : public RiscvFault
+{
+  protected:
+    const ExtMachInst _inst;
+
+  public:
+    InstFault(FaultName n, const ExtMachInst inst)
+        : RiscvFault(n, false, INST_ILLEGAL), _inst(inst)
+    {}
+
+    MiscReg trap_value() const override { return _inst; }
+};
+
+class UnknownInstFault : public InstFault
 {
   public:
-    UnknownInstFault() : RiscvFault("Unknown instruction", false, INST_ILLEGAL)
+    UnknownInstFault(const ExtMachInst inst)
+        : InstFault("Unknown instruction", inst)
     {}
 
     void invokeSE(ThreadContext *tc, const StaticInstPtr &inst) override;
 };
 
-class IllegalInstFault : public RiscvFault
+class IllegalInstFault : public InstFault
 {
   private:
     const std::string reason;
 
   public:
-    IllegalInstFault(std::string r)
-        : RiscvFault("Illegal instruction", false, INST_ILLEGAL)
+    IllegalInstFault(std::string r, const ExtMachInst inst)
+        : InstFault("Illegal instruction", inst)
     {}
 
     void invokeSE(ThreadContext *tc, const StaticInstPtr &inst) override;
 };
 
-class UnimplementedFault : public RiscvFault
+class UnimplementedFault : public InstFault
 {
   private:
     const std::string instName;
 
   public:
-    UnimplementedFault(std::string name)
-        : RiscvFault("Unimplemented instruction", false, INST_ILLEGAL),
+    UnimplementedFault(std::string name, const ExtMachInst inst)
+        : InstFault("Unimplemented instruction", inst),
           instName(name)
     {}
 
     void invokeSE(ThreadContext *tc, const StaticInstPtr &inst) override;
 };
 
-class IllegalFrmFault: public RiscvFault
+class IllegalFrmFault: public InstFault
 {
   private:
     const uint8_t frm;
 
   public:
-    IllegalFrmFault(uint8_t r)
-        : RiscvFault("Illegal floating-point rounding mode", false,
-                     INST_ILLEGAL),
+    IllegalFrmFault(uint8_t r, const ExtMachInst inst)
+        : InstFault("Illegal floating-point rounding mode", inst),
           frm(r)
     {}
 
     void invokeSE(ThreadContext *tc, const StaticInstPtr &inst) override;
 };
 
+class AddressFault : public RiscvFault
+{
+  private:
+    const Addr _addr;
+
+  public:
+    AddressFault(const Addr addr, ExceptionCode code)
+        : RiscvFault("Address", false, code), _addr(addr)
+    {}
+
+    MiscReg trap_value() const override { return _addr; }
+};
+
 class BreakpointFault : public RiscvFault
 {
+  private:
+    const PCState pcState;
+
   public:
-    BreakpointFault() : RiscvFault("Breakpoint", false, BREAKPOINT) {}
+    BreakpointFault(const PCState &pc)
+        : RiscvFault("Breakpoint", false, BREAKPOINT), pcState(pc)
+    {}
+
+    MiscReg trap_value() const override { return pcState.pc(); }
     void invokeSE(ThreadContext *tc, const StaticInstPtr &inst) override;
 };
 
@@ -228,4 +262,4 @@ class SyscallFault : public RiscvFault
 
 } // namespace RiscvISA
 
-#endif // __ARCH_RISCV_FAULTS_HH__
+#endif // __ARCH_RISCV_FAULTS_HH__
\ No newline at end of file
index 049f879de46bb29e6609954a42e3cbda288479e7..a96474aecbdf348b6b0c96388cbd185d9ee7a3e5 100644 (file)
@@ -59,7 +59,7 @@ class Unknown : public RiscvStaticInst
     Fault
     execute(ExecContext *, Trace::InstRecord *) const override
     {
-        return std::make_shared<UnknownInstFault>();
+        return std::make_shared<UnknownInstFault>(machInst);
     }
 
     std::string
index b4bf3854b165bf6e9d74492ef7eaaac025ebcb98..a0e3ad19d06f28c1cfe5c6351176c918b89a84ef 100644 (file)
@@ -43,7 +43,8 @@ decode QUADRANT default Unknown::unknown() {
                   CIMM8<5:2> << 6;
         }}, {{
             if (machInst == 0)
-                fault = make_shared<IllegalInstFault>("zero instruction");
+                fault = make_shared<IllegalInstFault>("zero instruction",
+                                                      machInst);
             Rp2 = sp + imm;
         }}, uint64_t);
         format CompressedLoad {
@@ -106,9 +107,11 @@ decode QUADRANT default Unknown::unknown() {
             }}, {{
                 if ((RC1 == 0) != (imm == 0)) {
                     if (RC1 == 0) {
-                        fault = make_shared<IllegalInstFault>("source reg x0");
+                        fault = make_shared<IllegalInstFault>("source reg x0",
+                                                              machInst);
                     } else // imm == 0
-                        fault = make_shared<IllegalInstFault>("immediate = 0");
+                        fault = make_shared<IllegalInstFault>("immediate = 0",
+                                                              machInst);
                 }
                 Rc1_sd = Rc1_sd + imm;
             }});
@@ -118,7 +121,8 @@ decode QUADRANT default Unknown::unknown() {
                     imm |= ~((uint64_t)0x1F);
             }}, {{
                 if (RC1 == 0) {
-                    fault = make_shared<IllegalInstFault>("source reg x0");
+                    fault = make_shared<IllegalInstFault>("source reg x0",
+                                                          machInst);
                 }
                 Rc1_sd = (int32_t)Rc1_sd + imm;
             }});
@@ -128,7 +132,8 @@ decode QUADRANT default Unknown::unknown() {
                     imm |= ~((uint64_t)0x1F);
             }}, {{
                 if (RC1 == 0) {
-                    fault = make_shared<IllegalInstFault>("source reg x0");
+                    fault = make_shared<IllegalInstFault>("source reg x0",
+                                                          machInst);
                 }
                 Rc1_sd = imm;
             }});
@@ -142,7 +147,8 @@ decode QUADRANT default Unknown::unknown() {
                         imm |= ~((int64_t)0x1FF);
                 }}, {{
                     if (imm == 0) {
-                        fault = make_shared<IllegalInstFault>("immediate = 0");
+                        fault = make_shared<IllegalInstFault>("immediate = 0",
+                                                              machInst);
                     }
                     sp_sd = sp_sd + imm;
                 }});
@@ -152,10 +158,12 @@ decode QUADRANT default Unknown::unknown() {
                         imm |= ~((uint64_t)0x1FFFF);
                 }}, {{
                     if (RC1 == 0 || RC1 == 2) {
-                        fault = make_shared<IllegalInstFault>("source reg x0");
+                        fault = make_shared<IllegalInstFault>("source reg x0",
+                                                              machInst);
                     }
                     if (imm == 0) {
-                        fault = make_shared<IllegalInstFault>("immediate = 0");
+                        fault = make_shared<IllegalInstFault>("immediate = 0",
+                                                              machInst);
                     }
                     Rc1_sd = imm;
                 }});
@@ -167,7 +175,8 @@ decode QUADRANT default Unknown::unknown() {
                     imm = CIMM5 | (CIMM1 << 5);
                 }}, {{
                     if (imm == 0) {
-                        fault = make_shared<IllegalInstFault>("immediate = 0");
+                        fault = make_shared<IllegalInstFault>("immediate = 0",
+                                                              machInst);
                     }
                     Rp1 = Rp1 >> imm;
                 }}, uint64_t);
@@ -175,7 +184,8 @@ decode QUADRANT default Unknown::unknown() {
                     imm = CIMM5 | (CIMM1 << 5);
                 }}, {{
                     if (imm == 0) {
-                        fault = make_shared<IllegalInstFault>("immediate = 0");
+                        fault = make_shared<IllegalInstFault>("immediate = 0",
+                                                              machInst);
                     }
                     Rp1_sd = Rp1_sd >> imm;
                 }}, uint64_t);
@@ -246,10 +256,12 @@ decode QUADRANT default Unknown::unknown() {
             imm = CIMM5 | (CIMM1 << 5);
         }}, {{
             if (imm == 0) {
-                fault = make_shared<IllegalInstFault>("immediate = 0");
+                fault = make_shared<IllegalInstFault>("immediate = 0",
+                                                      machInst);
             }
             if (RC1 == 0) {
-                fault = make_shared<IllegalInstFault>("source reg x0");
+                fault = make_shared<IllegalInstFault>("source reg x0",
+                                                      machInst);
             }
             Rc1 = Rc1 << imm;
         }}, uint64_t);
@@ -269,7 +281,8 @@ decode QUADRANT default Unknown::unknown() {
                          CIMM5<1:0> << 6;
             }}, {{
                 if (RC1 == 0) {
-                    fault = make_shared<IllegalInstFault>("source reg x0");
+                    fault = make_shared<IllegalInstFault>("source reg x0",
+                                                          machInst);
                 }
                 Rc1_sd = Mem_sw;
             }}, {{
@@ -281,7 +294,8 @@ decode QUADRANT default Unknown::unknown() {
                          CIMM5<2:0> << 6;
             }}, {{
                 if (RC1 == 0) {
-                    fault = make_shared<IllegalInstFault>("source reg x0");
+                    fault = make_shared<IllegalInstFault>("source reg x0",
+                                                          machInst);
                 }
                 Rc1_sd = Mem_sd;
             }}, {{
@@ -292,13 +306,15 @@ decode QUADRANT default Unknown::unknown() {
             0x0: decode RC2 {
                 0x0: Jump::c_jr({{
                     if (RC1 == 0) {
-                        fault = make_shared<IllegalInstFault>("source reg x0");
+                        fault = make_shared<IllegalInstFault>("source reg x0",
+                                                              machInst);
                     }
                     NPC = Rc1;
                 }}, IsIndirectControl, IsUncondControl, IsCall);
                 default: CROp::c_mv({{
                     if (RC1 == 0) {
-                        fault = make_shared<IllegalInstFault>("source reg x0");
+                        fault = make_shared<IllegalInstFault>("source reg x0",
+                                                              machInst);
                     }
                     Rc1 = Rc2;
                 }});
@@ -306,15 +322,17 @@ decode QUADRANT default Unknown::unknown() {
             0x1: decode RC1 {
                 0x0: SystemOp::c_ebreak({{
                     if (RC2 != 0) {
-                        fault = make_shared<IllegalInstFault>("source reg x1");
+                        fault = make_shared<IllegalInstFault>("source reg x1",
+                                                              machInst);
                     }
-                    fault = make_shared<BreakpointFault>();
+                    fault = make_shared<BreakpointFault>(xc->pcState());
                 }}, IsSerializeAfter, IsNonSpeculative, No_OpClass);
                 default: decode RC2 {
                     0x0: Jump::c_jalr({{
                         if (RC1 == 0) {
                             fault = make_shared<IllegalInstFault>
-                                                        ("source reg x0");
+                                                        ("source reg x0",
+                                                         machInst);
                         }
                         ra = NPC;
                         NPC = Rc1;
@@ -1250,7 +1268,8 @@ decode QUADRANT default Unknown::unknown() {
                 }
                 0x20: fcvt_s_d({{
                     if (CONV_SGN != 1) {
-                        fault = make_shared<IllegalInstFault>("CONV_SGN != 1");
+                        fault = make_shared<IllegalInstFault>("CONV_SGN != 1",
+                                                              machInst);
                     }
                     float fd;
                     if (issignalingnan(Fs1)) {
@@ -1263,7 +1282,8 @@ decode QUADRANT default Unknown::unknown() {
                 }}, FloatCvtOp);
                 0x21: fcvt_d_s({{
                     if (CONV_SGN != 0) {
-                        fault = make_shared<IllegalInstFault>("CONV_SGN != 0");
+                        fault = make_shared<IllegalInstFault>("CONV_SGN != 0",
+                                                              machInst);
                     }
                     uint32_t temp;
                     float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
@@ -1277,7 +1297,8 @@ decode QUADRANT default Unknown::unknown() {
                 }}, FloatCvtOp);
                 0x2c: fsqrt_s({{
                     if (RS2 != 0) {
-                        fault = make_shared<IllegalInstFault>("source reg x1");
+                        fault = make_shared<IllegalInstFault>("source reg x1",
+                                                              machInst);
                     }
                     uint32_t temp;
                     float fs1 = reinterpret_cast<float&>(temp = Fs1_bits);
@@ -1291,7 +1312,8 @@ decode QUADRANT default Unknown::unknown() {
                 }}, FloatSqrtOp);
                 0x2d: fsqrt_d({{
                     if (RS2 != 0) {
-                        fault = make_shared<IllegalInstFault>("source reg x1");
+                        fault = make_shared<IllegalInstFault>("source reg x1",
+                                                              machInst);
                     }
                     Fd = sqrt(Fs1);
                 }}, FloatSqrtOp);
@@ -1690,10 +1712,11 @@ decode QUADRANT default Unknown::unknown() {
                     }}, IsSerializeAfter, IsNonSpeculative, IsSyscall,
                         No_OpClass);
                     0x1: ebreak({{
-                        fault = make_shared<BreakpointFault>();
+                        fault = make_shared<BreakpointFault>(xc->pcState());
                     }}, IsSerializeAfter, IsNonSpeculative, No_OpClass);
                     0x100: eret({{
-                        fault = make_shared<UnimplementedFault>("eret");
+                        fault = make_shared<UnimplementedFault>("eret",
+                                                                machInst);
                     }}, No_OpClass);
                 }
             }
index 1f08ca51214a9e6b7477fff4d661c52a2204d729..5f067218c0d2465a7bb9ee7c5344208303e7f7ec 100644 (file)
@@ -57,7 +57,7 @@ def template FloatExecute {{
                 break;
             case 0x4:
                 // Round to nearest, ties to max magnitude not implemented
-                fault = make_shared<IllegalFrmFault>(ROUND_MODE);
+                fault = make_shared<IllegalFrmFault>(ROUND_MODE, machInst);
                 break;
             case 0x7: {
                 uint8_t frm = xc->readMiscReg(MISCREG_FRM);
@@ -76,16 +76,17 @@ def template FloatExecute {{
                     break;
                 case 0x4:
                     // Round to nearest, ties to max magnitude not implemented
-                    fault = make_shared<IllegalFrmFault>(ROUND_MODE);
+                    fault = make_shared<IllegalFrmFault>(ROUND_MODE, machInst);
                     break;
                 default:
-                    fault = std::make_shared<IllegalFrmFault>(frm);
+                    fault = std::make_shared<IllegalFrmFault>(frm, machInst);
                     break;
                 }
                 break;
             }
             default:
-                fault = std::make_shared<IllegalFrmFault>(ROUND_MODE);
+                fault = std::make_shared<IllegalFrmFault>(ROUND_MODE,
+                                                          machInst);
                 break;
             }
 
index e69ad7ee5c848f21ea7c2494b21edcd255af5d04..e9539fe529c8eba12963de5d103389cc052c75e4 100644 (file)
@@ -231,7 +231,7 @@ def template CSRExecute {{
                 olddata = xc->readMiscReg(CSRData.at(csr).physIndex);
             } else {
                 std::string error = csprintf("Illegal CSR index %#x\n", csr);
-                fault = make_shared<IllegalInstFault>(error);
+                fault = make_shared<IllegalInstFault>(error, machInst);
                 olddata = 0;
             }
             break;
@@ -252,7 +252,7 @@ def template CSRExecute {{
                     if (bits(csr, 11, 10) == 0x3) {
                         std::string error = csprintf("CSR %s is read-only\n",
                                                      CSRData.at(csr).name);
-                        fault = make_shared<IllegalInstFault>(error);
+                        fault = make_shared<IllegalInstFault>(error, machInst);
                     } else {
                         DPRINTF(RiscvMisc, "Writing %#x to CSR %s.\n", data,
                                 CSRData.at(csr).name);