stats: update stats for mmap() change.
[gem5.git] / src / arch / arm / isa.hh
index c747fc7704eb5b7114e587f3d55b87137f5828ed..ab5c72e6a7c16469b903c464fa79337b7671af49 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010, 2012-2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
 #ifndef __ARCH_ARM_ISA_HH__
 #define __ARCH_ARM_ISA_HH__
 
+#include "arch/arm/isa_device.hh"
 #include "arch/arm/registers.hh"
+#include "arch/arm/system.hh"
 #include "arch/arm/tlb.hh"
 #include "arch/arm/types.hh"
 #include "debug/Checkpoint.hh"
 #include "sim/sim_object.hh"
+#include "enums/DecoderFlavour.hh"
 
 struct ArmISAParams;
+struct DummyArmISADeviceParams;
 class ThreadContext;
 class Checkpoint;
 class EventManager;
 
 namespace ArmISA
 {
+
+    /**
+     * At the moment there are 57 registers which need to be aliased/
+     * translated with other registers in the ISA. This enum helps with that
+     * translation.
+     */
+    enum translateTable {
+        miscRegTranslateCSSELR_EL1,
+        miscRegTranslateSCTLR_EL1,
+        miscRegTranslateSCTLR_EL2,
+        miscRegTranslateACTLR_EL1,
+        miscRegTranslateACTLR_EL2,
+        miscRegTranslateCPACR_EL1,
+        miscRegTranslateCPTR_EL2,
+        miscRegTranslateHCR_EL2,
+        miscRegTranslateMDCR_EL2,
+        miscRegTranslateHSTR_EL2,
+        miscRegTranslateHACR_EL2,
+        miscRegTranslateTTBR0_EL1,
+        miscRegTranslateTTBR1_EL1,
+        miscRegTranslateTTBR0_EL2,
+        miscRegTranslateVTTBR_EL2,
+        miscRegTranslateTCR_EL1,
+        miscRegTranslateTCR_EL2,
+        miscRegTranslateVTCR_EL2,
+        miscRegTranslateAFSR0_EL1,
+        miscRegTranslateAFSR1_EL1,
+        miscRegTranslateAFSR0_EL2,
+        miscRegTranslateAFSR1_EL2,
+        miscRegTranslateESR_EL2,
+        miscRegTranslateFAR_EL1,
+        miscRegTranslateFAR_EL2,
+        miscRegTranslateHPFAR_EL2,
+        miscRegTranslatePAR_EL1,
+        miscRegTranslateMAIR_EL1,
+        miscRegTranslateMAIR_EL2,
+        miscRegTranslateAMAIR_EL1,
+        miscRegTranslateVBAR_EL1,
+        miscRegTranslateVBAR_EL2,
+        miscRegTranslateCONTEXTIDR_EL1,
+        miscRegTranslateTPIDR_EL0,
+        miscRegTranslateTPIDRRO_EL0,
+        miscRegTranslateTPIDR_EL1,
+        miscRegTranslateTPIDR_EL2,
+        miscRegTranslateTEECR32_EL1,
+        miscRegTranslateCNTFRQ_EL0,
+        miscRegTranslateCNTPCT_EL0,
+        miscRegTranslateCNTVCT_EL0,
+        miscRegTranslateCNTVOFF_EL2,
+        miscRegTranslateCNTKCTL_EL1,
+        miscRegTranslateCNTHCTL_EL2,
+        miscRegTranslateCNTP_TVAL_EL0,
+        miscRegTranslateCNTP_CTL_EL0,
+        miscRegTranslateCNTP_CVAL_EL0,
+        miscRegTranslateCNTV_TVAL_EL0,
+        miscRegTranslateCNTV_CTL_EL0,
+        miscRegTranslateCNTV_CVAL_EL0,
+        miscRegTranslateCNTHP_TVAL_EL2,
+        miscRegTranslateCNTHP_CTL_EL2,
+        miscRegTranslateCNTHP_CVAL_EL2,
+        miscRegTranslateDACR32_EL2,
+        miscRegTranslateIFSR32_EL2,
+        miscRegTranslateTEEHBR32_EL1,
+        miscRegTranslateSDER32_EL3,
+        miscRegTranslateMax
+    };
+
     class ISA : public SimObject
     {
       protected:
+        // Parent system
+        ArmSystem *system;
+
+        // Micro Architecture
+        const Enums::DecoderFlavour _decoderFlavour;
+
+        /** Dummy device for to handle non-existing ISA devices */
+        DummyISADevice dummyDevice;
+
+        // PMU belonging to this ISA
+        BaseISADevice *pmu;
+
+        // Generic timer interface belonging to this ISA
+        std::unique_ptr<BaseISADevice> timer;
+
+        // Cached copies of system-level properties
+        bool haveSecurity;
+        bool haveLPAE;
+        bool haveVirtualization;
+        bool haveLargeAsid64;
+        uint8_t physAddrRange64;
+
+        /** Register translation entry used in lookUpMiscReg */
+        struct MiscRegLUTEntry {
+            uint32_t lower;
+            uint32_t upper;
+        };
+
+        struct MiscRegInitializerEntry {
+            uint32_t index;
+            struct MiscRegLUTEntry entry;
+        };
+
+        /** Register table noting all translations */
+        static const struct MiscRegInitializerEntry
+                            MiscRegSwitch[miscRegTranslateMax];
+
+        /** Translation table accessible via the value of the register */
+        std::vector<struct MiscRegLUTEntry> lookUpMiscReg;
+
         MiscReg miscRegs[NumMiscRegs];
         const IntRegIndex *intRegMap;
 
         void
         updateRegMap(CPSR cpsr)
         {
-            switch (cpsr.mode) {
-              case MODE_USER:
-              case MODE_SYSTEM:
-                intRegMap = IntRegUsrMap;
-                break;
-              case MODE_FIQ:
-                intRegMap = IntRegFiqMap;
-                break;
-              case MODE_IRQ:
-                intRegMap = IntRegIrqMap;
-                break;
-              case MODE_SVC:
-                intRegMap = IntRegSvcMap;
-                break;
-              case MODE_MON:
-                intRegMap = IntRegMonMap;
-                break;
-              case MODE_ABORT:
-                intRegMap = IntRegAbtMap;
-                break;
-              case MODE_UNDEFINED:
-                intRegMap = IntRegUndMap;
-                break;
-              default:
-                panic("Unrecognized mode setting in CPSR.\n");
+            if (cpsr.width == 0) {
+                intRegMap = IntReg64Map;
+            } else {
+                switch (cpsr.mode) {
+                  case MODE_USER:
+                  case MODE_SYSTEM:
+                    intRegMap = IntRegUsrMap;
+                    break;
+                  case MODE_FIQ:
+                    intRegMap = IntRegFiqMap;
+                    break;
+                  case MODE_IRQ:
+                    intRegMap = IntRegIrqMap;
+                    break;
+                  case MODE_SVC:
+                    intRegMap = IntRegSvcMap;
+                    break;
+                  case MODE_MON:
+                    intRegMap = IntRegMonMap;
+                    break;
+                  case MODE_ABORT:
+                    intRegMap = IntRegAbtMap;
+                    break;
+                  case MODE_HYP:
+                    intRegMap = IntRegHypMap;
+                    break;
+                  case MODE_UNDEFINED:
+                    intRegMap = IntRegUndMap;
+                    break;
+                  default:
+                    panic("Unrecognized mode setting in CPSR.\n");
+                }
             }
         }
 
+        BaseISADevice &getGenericTimer(ThreadContext *tc);
+
+
+      private:
+        inline void assert32(ThreadContext *tc) {
+            CPSR cpsr M5_VAR_USED = readMiscReg(MISCREG_CPSR, tc);
+            assert(cpsr.width);
+        }
+
+        inline void assert64(ThreadContext *tc) {
+            CPSR cpsr M5_VAR_USED = readMiscReg(MISCREG_CPSR, tc);
+            assert(!cpsr.width);
+        }
+
+        void tlbiVA(ThreadContext *tc, MiscReg newVal, uint16_t asid,
+                    bool secure_lookup, uint8_t target_el);
+
+        void tlbiALL(ThreadContext *tc, bool secure_lookup, uint8_t target_el);
+
+        void tlbiALLN(ThreadContext *tc, bool hyp, uint8_t target_el);
+
+        void tlbiMVA(ThreadContext *tc, MiscReg newVal, bool secure_lookup,
+                     bool hyp, uint8_t target_el);
+
       public:
         void clear();
+        void clear64(const ArmISAParams *p);
 
         MiscReg readMiscRegNoEffect(int misc_reg) const;
         MiscReg readMiscReg(int misc_reg, ThreadContext *tc);
@@ -109,99 +252,189 @@ namespace ArmISA
                 return intRegMap[reg];
             } else if (reg < NUM_INTREGS) {
                 return reg;
-            } else {
-                int mode = reg / intRegsPerMode;
-                reg = reg % intRegsPerMode;
-                switch (mode) {
-                  case MODE_USER:
-                  case MODE_SYSTEM:
-                    return INTREG_USR(reg);
-                  case MODE_FIQ:
-                    return INTREG_FIQ(reg);
-                  case MODE_IRQ:
-                    return INTREG_IRQ(reg);
-                  case MODE_SVC:
-                    return INTREG_SVC(reg);
-                  case MODE_MON:
-                    return INTREG_MON(reg);
-                  case MODE_ABORT:
-                    return INTREG_ABT(reg);
-                  case MODE_UNDEFINED:
-                    return INTREG_UND(reg);
+            } else if (reg == INTREG_SPX) {
+                CPSR cpsr = miscRegs[MISCREG_CPSR];
+                ExceptionLevel el = opModeToEL(
+                    (OperatingMode) (uint8_t) cpsr.mode);
+                if (!cpsr.sp && el != EL0)
+                    return INTREG_SP0;
+                switch (el) {
+                  case EL3:
+                    return INTREG_SP3;
+                  // @todo: uncomment this to enable Virtualization
+                  // case EL2:
+                  //   return INTREG_SP2;
+                  case EL1:
+                    return INTREG_SP1;
+                  case EL0:
+                    return INTREG_SP0;
                   default:
-                    panic("Flattening into an unknown mode.\n");
+                    panic("Invalid exception level");
+                    break;
                 }
+            } else {
+                return flattenIntRegModeIndex(reg);
             }
         }
 
         int
         flattenFloatIndex(int reg) const
         {
+            assert(reg >= 0);
             return reg;
         }
 
-        // dummy
         int
         flattenCCIndex(int reg) const
         {
+            assert(reg >= 0);
             return reg;
         }
 
         int
         flattenMiscIndex(int reg) const
         {
+            assert(reg >= 0);
+            int flat_idx = reg;
+
             if (reg == MISCREG_SPSR) {
-                int spsr_idx = NUM_MISCREGS;
                 CPSR cpsr = miscRegs[MISCREG_CPSR];
                 switch (cpsr.mode) {
+                  case MODE_EL0T:
+                    warn("User mode does not have SPSR\n");
+                    flat_idx = MISCREG_SPSR;
+                    break;
+                  case MODE_EL1T:
+                  case MODE_EL1H:
+                    flat_idx = MISCREG_SPSR_EL1;
+                    break;
+                  case MODE_EL2T:
+                  case MODE_EL2H:
+                    flat_idx = MISCREG_SPSR_EL2;
+                    break;
+                  case MODE_EL3T:
+                  case MODE_EL3H:
+                    flat_idx = MISCREG_SPSR_EL3;
+                    break;
                   case MODE_USER:
                     warn("User mode does not have SPSR\n");
-                    spsr_idx = MISCREG_SPSR;
+                    flat_idx = MISCREG_SPSR;
                     break;
                   case MODE_FIQ:
-                    spsr_idx = MISCREG_SPSR_FIQ;
+                    flat_idx = MISCREG_SPSR_FIQ;
                     break;
                   case MODE_IRQ:
-                    spsr_idx = MISCREG_SPSR_IRQ;
+                    flat_idx = MISCREG_SPSR_IRQ;
                     break;
                   case MODE_SVC:
-                    spsr_idx = MISCREG_SPSR_SVC;
+                    flat_idx = MISCREG_SPSR_SVC;
                     break;
                   case MODE_MON:
-                    spsr_idx = MISCREG_SPSR_MON;
+                    flat_idx = MISCREG_SPSR_MON;
                     break;
                   case MODE_ABORT:
-                    spsr_idx = MISCREG_SPSR_ABT;
+                    flat_idx = MISCREG_SPSR_ABT;
+                    break;
+                  case MODE_HYP:
+                    flat_idx = MISCREG_SPSR_HYP;
                     break;
                   case MODE_UNDEFINED:
-                    spsr_idx = MISCREG_SPSR_UND;
+                    flat_idx = MISCREG_SPSR_UND;
                     break;
                   default:
                     warn("Trying to access SPSR in an invalid mode: %d\n",
                          cpsr.mode);
-                    spsr_idx = MISCREG_SPSR;
+                    flat_idx = MISCREG_SPSR;
                     break;
                 }
-                return spsr_idx;
+            } else if (miscRegInfo[reg][MISCREG_MUTEX]) {
+                // Mutually exclusive CP15 register
+                switch (reg) {
+                  case MISCREG_PRRR_MAIR0:
+                  case MISCREG_PRRR_MAIR0_NS:
+                  case MISCREG_PRRR_MAIR0_S:
+                    {
+                        TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR);
+                        // If the muxed reg has been flattened, work out the
+                        // offset and apply it to the unmuxed reg
+                        int idxOffset = reg - MISCREG_PRRR_MAIR0;
+                        if (ttbcr.eae)
+                            flat_idx = flattenMiscIndex(MISCREG_MAIR0 +
+                                                        idxOffset);
+                        else
+                            flat_idx = flattenMiscIndex(MISCREG_PRRR +
+                                                        idxOffset);
+                    }
+                    break;
+                  case MISCREG_NMRR_MAIR1:
+                  case MISCREG_NMRR_MAIR1_NS:
+                  case MISCREG_NMRR_MAIR1_S:
+                    {
+                        TTBCR ttbcr = readMiscRegNoEffect(MISCREG_TTBCR);
+                        // If the muxed reg has been flattened, work out the
+                        // offset and apply it to the unmuxed reg
+                        int idxOffset = reg - MISCREG_NMRR_MAIR1;
+                        if (ttbcr.eae)
+                            flat_idx = flattenMiscIndex(MISCREG_MAIR1 +
+                                                        idxOffset);
+                        else
+                            flat_idx = flattenMiscIndex(MISCREG_NMRR +
+                                                        idxOffset);
+                    }
+                    break;
+                  case MISCREG_PMXEVTYPER_PMCCFILTR:
+                    {
+                        PMSELR pmselr = miscRegs[MISCREG_PMSELR];
+                        if (pmselr.sel == 31)
+                            flat_idx = flattenMiscIndex(MISCREG_PMCCFILTR);
+                        else
+                            flat_idx = flattenMiscIndex(MISCREG_PMXEVTYPER);
+                    }
+                    break;
+                  default:
+                    panic("Unrecognized misc. register.\n");
+                    break;
+                }
+            } else {
+                if (miscRegInfo[reg][MISCREG_BANKED]) {
+                    bool secureReg = haveSecurity &&
+                                     inSecureState(miscRegs[MISCREG_SCR],
+                                                   miscRegs[MISCREG_CPSR]);
+                    flat_idx += secureReg ? 2 : 1;
+                }
             }
-            return reg;
+            return flat_idx;
         }
 
-        void serialize(std::ostream &os)
+        void serialize(CheckpointOut &cp) const
         {
             DPRINTF(Checkpoint, "Serializing Arm Misc Registers\n");
             SERIALIZE_ARRAY(miscRegs, NumMiscRegs);
+
+            SERIALIZE_SCALAR(haveSecurity);
+            SERIALIZE_SCALAR(haveLPAE);
+            SERIALIZE_SCALAR(haveVirtualization);
+            SERIALIZE_SCALAR(haveLargeAsid64);
+            SERIALIZE_SCALAR(physAddrRange64);
         }
-        void unserialize(Checkpoint *cp, const std::string &section)
+        void unserialize(CheckpointIn &cp)
         {
             DPRINTF(Checkpoint, "Unserializing Arm Misc Registers\n");
             UNSERIALIZE_ARRAY(miscRegs, NumMiscRegs);
             CPSR tmp_cpsr = miscRegs[MISCREG_CPSR];
             updateRegMap(tmp_cpsr);
+
+            UNSERIALIZE_SCALAR(haveSecurity);
+            UNSERIALIZE_SCALAR(haveLPAE);
+            UNSERIALIZE_SCALAR(haveVirtualization);
+            UNSERIALIZE_SCALAR(haveLargeAsid64);
+            UNSERIALIZE_SCALAR(physAddrRange64);
         }
 
         void startup(ThreadContext *tc) {}
 
+        Enums::DecoderFlavour decoderFlavour() const { return _decoderFlavour; }
+
         /// Explicitly import the otherwise hidden startup
         using SimObject::startup;