arch-arm: Add Illegal Execution flag to PCState

This patch moves the detection of the Illegal Execution flag (PSTATE.IL)
from the tlb translation stage (fetch) to the decoding stage.  This is
done by adding the illegalExecution field to the PCState.

Change-Id: I9c1c4e9c6bd5ded905c1d56b3034e4e9322582fa
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/10813
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
diff --git a/src/arch/arm/decoder.cc b/src/arch/arm/decoder.cc
index 1502b06..ce039b7 100644
--- a/src/arch/arm/decoder.cc
+++ b/src/arch/arm/decoder.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014 ARM Limited
+ * Copyright (c) 2012-2014,2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -179,6 +179,8 @@
     if (foundIt)
         pc.nextItstate(itBits);
     this_emi.itstate = pc.itstate();
+    this_emi.illegalExecution = pc.illegalExec() ? 1 : 0;
+
     pc.size(inst_size);
 
     emi = 0;
diff --git a/src/arch/arm/faults.cc b/src/arch/arm/faults.cc
index 676559f..dd4f958 100644
--- a/src/arch/arm/faults.cc
+++ b/src/arch/arm/faults.cc
@@ -601,6 +601,7 @@
     pc.nextJazelle(pc.jazelle());
     pc.aarch64(!cpsr.width);
     pc.nextAArch64(!cpsr.width);
+    pc.illegalExec(false);
     tc->pcState(pc);
 }
 
@@ -684,6 +685,7 @@
     PCState pc(new_pc);
     pc.aarch64(!cpsr.width);
     pc.nextAArch64(!cpsr.width);
+    pc.illegalExec(false);
     tc->pcState(pc);
 
     // If we have a valid instruction then use it to annotate this fault with
diff --git a/src/arch/arm/insts/pseudo.cc b/src/arch/arm/insts/pseudo.cc
index e2504d6..2e8c3f1 100644
--- a/src/arch/arm/insts/pseudo.cc
+++ b/src/arch/arm/insts/pseudo.cc
@@ -249,3 +249,13 @@
 {
     return csprintf("%-10s (implementation defined)", mnemonic);
 }
+
+IllegalExecInst::IllegalExecInst(ExtMachInst _machInst)
+    : ArmStaticInst("Illegal Execution", _machInst, No_OpClass)
+{}
+
+Fault
+IllegalExecInst::execute(ExecContext *xc, Trace::InstRecord *traceData) const
+{
+    return std::make_shared<IllegalInstSetStateFault>();
+}
diff --git a/src/arch/arm/insts/pseudo.hh b/src/arch/arm/insts/pseudo.hh
index ececbbb..9065c62 100644
--- a/src/arch/arm/insts/pseudo.hh
+++ b/src/arch/arm/insts/pseudo.hh
@@ -161,4 +161,19 @@
 
 };
 
+/**
+ * This class is modelling instructions which are not going to be
+ * executed since they are flagged as Illegal Execution Instructions
+ * (PSTATE.IL = 1 or CPSR.IL = 1).
+ * The sole purpose of this instruction is to generate an appropriate
+ * fault when executed.
+ */
+class IllegalExecInst : public ArmStaticInst
+{
+  public:
+    IllegalExecInst(ExtMachInst _machInst);
+
+    Fault execute(ExecContext *xc, Trace::InstRecord *traceData) const;
+};
+
 #endif
diff --git a/src/arch/arm/isa.cc b/src/arch/arm/isa.cc
index aaf209e..9b17927 100644
--- a/src/arch/arm/isa.cc
+++ b/src/arch/arm/isa.cc
@@ -704,6 +704,7 @@
         PCState pc = tc->pcState();
         pc.nextThumb(cpsr.t);
         pc.nextJazelle(cpsr.j);
+        pc.illegalExec(cpsr.il == 1);
 
         // Follow slightly different semantics if a CheckerCPU object
         // is connected
diff --git a/src/arch/arm/isa/bitfields.isa b/src/arch/arm/isa/bitfields.isa
index ba9a39e..ac6989a 100644
--- a/src/arch/arm/isa/bitfields.isa
+++ b/src/arch/arm/isa/bitfields.isa
@@ -1,6 +1,6 @@
 // -*- mode:c++ -*-
 
-// Copyright (c) 2010, 2011 ARM Limited
+// Copyright (c) 2010, 2011, 2018 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -47,6 +47,7 @@
 
 // Opcode fields
 def bitfield DECODERFAULT  decoderFault;
+def bitfield ILLEGALEXEC   illegalExecution;
 
 def bitfield ENCODING      encoding;
 def bitfield OPCODE        opcode;
diff --git a/src/arch/arm/isa/decoder/decoder.isa b/src/arch/arm/isa/decoder/decoder.isa
index c352e08..1c9acbe 100644
--- a/src/arch/arm/isa/decoder/decoder.isa
+++ b/src/arch/arm/isa/decoder/decoder.isa
@@ -1,6 +1,6 @@
 // -*- mode:c++ -*-
 
-// Copyright (c) 2010-2011 ARM Limited
+// Copyright (c) 2010-2011,2018 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -40,15 +40,17 @@
 //
 // Authors: Gabe Black
 
-decode DECODERFAULT default DecoderFault::decoderFault() {
-    0: decode THUMB default Unknown::unknown() {
-        0: decode AARCH64 {
-            0:
-            ##include "arm.isa"
+decode ILLEGALEXEC default IllegalExec::illegalExec() {
+    0: decode DECODERFAULT default DecoderFault::decoderFault() {
+        0: decode THUMB default Unknown::unknown() {
+            0: decode AARCH64 {
+                0:
+                ##include "arm.isa"
+                1:
+                ##include "aarch64.isa"
+            }
             1:
-            ##include "aarch64.isa"
+            ##include "thumb.isa"
         }
-        1:
-        ##include "thumb.isa"
     }
 }
diff --git a/src/arch/arm/isa/formats/pseudo.isa b/src/arch/arm/isa/formats/pseudo.isa
index 30c2320..407b1c8 100644
--- a/src/arch/arm/isa/formats/pseudo.isa
+++ b/src/arch/arm/isa/formats/pseudo.isa
@@ -1,6 +1,6 @@
 // -*- mode:c++ -*-
 
-// Copyright (c) 2014 ARM Limited
+// Copyright (c) 2014, 2018 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -55,6 +55,15 @@
 
 ////////////////////////////////////////////////////////////////////
 //
+// Illegal execution handling
+//
+
+def format IllegalExec() {{
+    decode_block = 'return new IllegalExecInst(machInst);\n'
+}};
+
+////////////////////////////////////////////////////////////////////
+//
 // Unknown instruction handling
 //
 
diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc
index d2153e7..79eef1b 100644
--- a/src/arch/arm/tlb.cc
+++ b/src/arch/arm/tlb.cc
@@ -1145,11 +1145,6 @@
     }
 
     if (fault == NoFault) {
-        // Generate Illegal Inst Set State fault if IL bit is set in CPSR
-        if (aarch64 && is_fetch && cpsr.il == 1) {
-            return std::make_shared<IllegalInstSetStateFault>();
-        }
-
         // Don't try to finalize a physical address unless the
         // translation has completed (i.e., there is a table entry).
         return te ? finalizePhysical(req, tc, mode) : NoFault;
diff --git a/src/arch/arm/types.hh b/src/arch/arm/types.hh
index 84887a1..07cdfad 100644
--- a/src/arch/arm/types.hh
+++ b/src/arch/arm/types.hh
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012-2013, 2017 ARM Limited
+ * Copyright (c) 2010, 2012-2013, 2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -70,6 +70,7 @@
     BitUnion64(ExtMachInst)
         // Decoder state
         Bitfield<63, 62> decoderFault; // See DecoderFault
+        Bitfield<61> illegalExecution;
 
         // ITSTATE bits
         Bitfield<55, 48> itstate;
@@ -218,14 +219,16 @@
             JazelleBit = (1 << 1),
             AArch64Bit = (1 << 2)
         };
+
         uint8_t flags;
         uint8_t nextFlags;
         uint8_t _itstate;
         uint8_t _nextItstate;
         uint8_t _size;
+        bool _illegalExec;
       public:
         PCState() : flags(0), nextFlags(0), _itstate(0), _nextItstate(0),
-                    _size(0)
+                    _size(0), _illegalExec(false)
         {}
 
         void
@@ -236,10 +239,22 @@
         }
 
         PCState(Addr val) : flags(0), nextFlags(0), _itstate(0),
-                            _nextItstate(0), _size(0)
+                            _nextItstate(0), _size(0), _illegalExec(false)
         { set(val); }
 
         bool
+        illegalExec() const
+        {
+            return _illegalExec;
+        }
+
+        void
+        illegalExec(bool val)
+        {
+            _illegalExec = val;
+        }
+
+        bool
         thumb() const
         {
             return flags & ThumbBit;
@@ -472,7 +487,9 @@
         {
             return Base::operator == (opc) &&
                 flags == opc.flags && nextFlags == opc.nextFlags &&
-                _itstate == opc._itstate && _nextItstate == opc._nextItstate;
+                _itstate == opc._itstate &&
+                _nextItstate == opc._nextItstate &&
+                _illegalExec == opc._illegalExec;
         }
 
         bool
@@ -490,6 +507,7 @@
             SERIALIZE_SCALAR(nextFlags);
             SERIALIZE_SCALAR(_itstate);
             SERIALIZE_SCALAR(_nextItstate);
+            SERIALIZE_SCALAR(_illegalExec);
         }
 
         void
@@ -501,6 +519,7 @@
             UNSERIALIZE_SCALAR(nextFlags);
             UNSERIALIZE_SCALAR(_itstate);
             UNSERIALIZE_SCALAR(_nextItstate);
+            UNSERIALIZE_SCALAR(_illegalExec);
         }
     };