/*
+ * Copyright (c) 2010, 2012-2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2009 The Regents of The University of Michigan
* All rights reserved.
*
*/
#ifndef __ARCH_ARM_ISA_HH__
-#define __ARCH_MRM_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
{
- class ISA
+
+ /**
+ * 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;
- public:
- void clear()
+ void
+ updateRegMap(CPSR cpsr)
{
- memset(miscRegs, 0, sizeof(miscRegs));
- CPSR cpsr = 0;
- cpsr.mode = MODE_USER;
- miscRegs[MISCREG_CPSR] = cpsr;
- //XXX We need to initialize the rest of the state.
+ 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");
+ }
+ }
}
- MiscReg
- readMiscRegNoEffect(int misc_reg)
- {
- assert(misc_reg < NumMiscRegs);
- return miscRegs[misc_reg];
+ BaseISADevice &getGenericTimer(ThreadContext *tc);
+
+
+ private:
+ inline void assert32(ThreadContext *tc) {
+ CPSR cpsr M5_VAR_USED = readMiscReg(MISCREG_CPSR, tc);
+ assert(cpsr.width);
}
- MiscReg
- readMiscReg(int misc_reg, ThreadContext *tc)
- {
- assert(misc_reg < NumMiscRegs);
- return miscRegs[misc_reg];
+ inline void assert64(ThreadContext *tc) {
+ CPSR cpsr M5_VAR_USED = readMiscReg(MISCREG_CPSR, tc);
+ assert(!cpsr.width);
}
- void
- setMiscRegNoEffect(int misc_reg, const MiscReg &val)
+ 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);
+ void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
+ void setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc);
+
+ int
+ flattenIntIndex(int reg) const
{
- assert(misc_reg < NumMiscRegs);
- miscRegs[misc_reg] = val;
+ assert(reg >= 0);
+ if (reg < NUM_ARCH_INTREGS) {
+ return intRegMap[reg];
+ } else if (reg < NUM_INTREGS) {
+ return 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("Invalid exception level");
+ break;
+ }
+ } else {
+ return flattenIntRegModeIndex(reg);
+ }
}
- void
- setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
+ int
+ flattenFloatIndex(int reg) const
{
- assert(misc_reg < NumMiscRegs);
- miscRegs[misc_reg] = val;
+ assert(reg >= 0);
+ return reg;
}
int
- flattenIntIndex(int reg)
+ flattenCCIndex(int reg) const
{
+ assert(reg >= 0);
return reg;
}
int
- flattenFloatIndex(int reg)
+ flattenMiscIndex(int reg) const
{
- return reg;
+ assert(reg >= 0);
+ int flat_idx = reg;
+
+ if (reg == MISCREG_SPSR) {
+ 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");
+ flat_idx = MISCREG_SPSR;
+ break;
+ case MODE_FIQ:
+ flat_idx = MISCREG_SPSR_FIQ;
+ break;
+ case MODE_IRQ:
+ flat_idx = MISCREG_SPSR_IRQ;
+ break;
+ case MODE_SVC:
+ flat_idx = MISCREG_SPSR_SVC;
+ break;
+ case MODE_MON:
+ flat_idx = MISCREG_SPSR_MON;
+ break;
+ case MODE_ABORT:
+ flat_idx = MISCREG_SPSR_ABT;
+ break;
+ case MODE_HYP:
+ flat_idx = MISCREG_SPSR_HYP;
+ break;
+ case MODE_UNDEFINED:
+ flat_idx = MISCREG_SPSR_UND;
+ break;
+ default:
+ warn("Trying to access SPSR in an invalid mode: %d\n",
+ cpsr.mode);
+ flat_idx = MISCREG_SPSR;
+ break;
+ }
+ } 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 flat_idx;
}
- void serialize(EventManager *em, std::ostream &os)
- {}
- void unserialize(EventManager *em, Checkpoint *cp,
- const std::string §ion)
- {}
+ void serialize(CheckpointOut &cp) const
+ {
+ DPRINTF(Checkpoint, "Serializing Arm Misc Registers\n");
+ SERIALIZE_ARRAY(miscRegs, NumMiscRegs);
- ISA()
+ SERIALIZE_SCALAR(haveSecurity);
+ SERIALIZE_SCALAR(haveLPAE);
+ SERIALIZE_SCALAR(haveVirtualization);
+ SERIALIZE_SCALAR(haveLargeAsid64);
+ SERIALIZE_SCALAR(physAddrRange64);
+ }
+ void unserialize(CheckpointIn &cp)
{
- clear();
+ 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;
+
+ typedef ArmISAParams Params;
+
+ const Params *params() const;
+
+ ISA(Params *p);
};
}