/*
- * 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_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;
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");
- }
- }
-
- public:
- void clear()
- {
- memset(miscRegs, 0, sizeof(miscRegs));
- CPSR cpsr = 0;
- cpsr.mode = MODE_USER;
- miscRegs[MISCREG_CPSR] = cpsr;
- updateRegMap(cpsr);
-
- SCTLR sctlr = 0;
- sctlr.nmfi = 1;
- sctlr.rao1 = 1;
- sctlr.rao2 = 1;
- sctlr.rao3 = 1;
- sctlr.rao4 = 1;
- miscRegs[MISCREG_SCTLR] = sctlr;
-
- /*
- * Technically this should be 0, but we don't support those
- * settings.
- */
- CPACR cpacr = 0;
- // Enable CP 10, 11
- cpacr.cp10 = 0x3;
- cpacr.cp11 = 0x3;
- miscRegs[MISCREG_CPACR] = cpacr;
-
- /* Start with an event in the mailbox */
- miscRegs[MISCREG_SEV_MAILBOX] = 1;
-
- /*
- * Implemented = '5' from "M5",
- * Variant = 0,
- */
- miscRegs[MISCREG_MIDR] =
- (0x35 << 24) | //Implementor is '5' from "M5"
- (0 << 20) | //Variant
- (0xf << 16) | //Architecture from CPUID scheme
- (0 << 4) | //Primary part number
- (0 << 0) | //Revision
- 0;
-
- // Separate Instruction and Data TLBs.
- miscRegs[MISCREG_TLBTR] = 1;
-
- MVFR0 mvfr0 = 0;
- mvfr0.advSimdRegisters = 2;
- mvfr0.singlePrecision = 2;
- mvfr0.doublePrecision = 2;
- mvfr0.vfpExceptionTrapping = 0;
- mvfr0.divide = 1;
- mvfr0.squareRoot = 1;
- mvfr0.shortVectors = 1;
- mvfr0.roundingModes = 1;
- miscRegs[MISCREG_MVFR0] = mvfr0;
-
- MVFR1 mvfr1 = 0;
- mvfr1.flushToZero = 1;
- mvfr1.defaultNaN = 1;
- mvfr1.advSimdLoadStore = 1;
- mvfr1.advSimdInteger = 1;
- mvfr1.advSimdSinglePrecision = 1;
- mvfr1.advSimdHalfPrecision = 1;
- mvfr1.vfpHalfPrecision = 1;
- miscRegs[MISCREG_MVFR1] = mvfr1;
-
- miscRegs[MISCREG_MPIDR] = 0;
-
- //XXX We need to initialize the rest of the state.
- }
-
- MiscReg
- readMiscRegNoEffect(int misc_reg)
- {
- assert(misc_reg < NumMiscRegs);
- if (misc_reg == MISCREG_SPSR) {
- CPSR cpsr = miscRegs[MISCREG_CPSR];
+ if (cpsr.width == 0) {
+ intRegMap = IntReg64Map;
+ } else {
switch (cpsr.mode) {
case MODE_USER:
- return miscRegs[MISCREG_SPSR];
+ case MODE_SYSTEM:
+ intRegMap = IntRegUsrMap;
+ break;
case MODE_FIQ:
- return miscRegs[MISCREG_SPSR_FIQ];
+ intRegMap = IntRegFiqMap;
+ break;
case MODE_IRQ:
- return miscRegs[MISCREG_SPSR_IRQ];
+ intRegMap = IntRegIrqMap;
+ break;
case MODE_SVC:
- return miscRegs[MISCREG_SPSR_SVC];
+ intRegMap = IntRegSvcMap;
+ break;
case MODE_MON:
- return miscRegs[MISCREG_SPSR_MON];
+ intRegMap = IntRegMonMap;
+ break;
case MODE_ABORT:
- return miscRegs[MISCREG_SPSR_ABT];
+ intRegMap = IntRegAbtMap;
+ break;
+ case MODE_HYP:
+ intRegMap = IntRegHypMap;
+ break;
case MODE_UNDEFINED:
- return miscRegs[MISCREG_SPSR_UND];
+ intRegMap = IntRegUndMap;
+ break;
default:
- return miscRegs[MISCREG_SPSR];
+ panic("Unrecognized mode setting in CPSR.\n");
}
}
- return miscRegs[misc_reg];
}
- MiscReg
- readMiscReg(int misc_reg, ThreadContext *tc)
- {
- if (misc_reg == MISCREG_CPSR) {
- CPSR cpsr = miscRegs[misc_reg];
- Addr pc = tc->readPC();
- if (pc & (ULL(1) << PcJBitShift))
- cpsr.j = 1;
- else
- cpsr.j = 0;
- if (pc & (ULL(1) << PcTBitShift))
- cpsr.t = 1;
- else
- cpsr.t = 0;
- return cpsr;
- }
- if (misc_reg >= MISCREG_CP15_UNIMP_START &&
- misc_reg < MISCREG_CP15_END) {
- panic("Unimplemented CP15 register %s read.\n",
- miscRegName[misc_reg]);
- }
- switch (misc_reg) {
- case MISCREG_CLIDR:
- warn("The clidr register always reports 0 caches.\n");
- break;
- case MISCREG_CCSIDR:
- warn("The ccsidr register isn't implemented and "
- "always reads as 0.\n");
- break;
- }
- return readMiscRegNoEffect(misc_reg);
+ BaseISADevice &getGenericTimer(ThreadContext *tc);
+
+
+ private:
+ inline void assert32(ThreadContext *tc) {
+ CPSR cpsr M5_VAR_USED = readMiscReg(MISCREG_CPSR, tc);
+ assert(cpsr.width);
}
- void
- setMiscRegNoEffect(int misc_reg, const MiscReg &val)
+ 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);
+ 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);
- if (misc_reg == MISCREG_SPSR) {
+ 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];
- switch (cpsr.mode) {
- case MODE_USER:
- miscRegs[MISCREG_SPSR] = val;
- return;
- case MODE_FIQ:
- miscRegs[MISCREG_SPSR_FIQ] = val;
- return;
- case MODE_IRQ:
- miscRegs[MISCREG_SPSR_IRQ] = val;
- return;
- case MODE_SVC:
- miscRegs[MISCREG_SPSR_SVC] = val;
- return;
- case MODE_MON:
- miscRegs[MISCREG_SPSR_MON] = val;
- return;
- case MODE_ABORT:
- miscRegs[MISCREG_SPSR_ABT] = val;
- return;
- case MODE_UNDEFINED:
- miscRegs[MISCREG_SPSR_UND] = val;
- return;
+ 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:
- miscRegs[MISCREG_SPSR] = val;
- return;
+ panic("Invalid exception level");
+ break;
}
+ } else {
+ return flattenIntRegModeIndex(reg);
}
- miscRegs[misc_reg] = val;
}
- void
- setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
+ int
+ flattenFloatIndex(int reg) const
{
- MiscReg newVal = val;
- if (misc_reg == MISCREG_CPSR) {
- updateRegMap(val);
- CPSR cpsr = val;
- DPRINTF(Arm, "Updating CPSR to %#x f:%d i:%d a:%d mode:%#x\n",
- cpsr, cpsr.f, cpsr.i, cpsr.a, cpsr.mode);
- Addr npc = tc->readNextPC() & ~PcModeMask;
- if (cpsr.j)
- npc = npc | (ULL(1) << PcJBitShift);
- if (cpsr.t)
- npc = npc | (ULL(1) << PcTBitShift);
-
- tc->setNextPC(npc);
- }
- if (misc_reg >= MISCREG_CP15_UNIMP_START &&
- misc_reg < MISCREG_CP15_END) {
- panic("Unimplemented CP15 register %s wrote with %#x.\n",
- miscRegName[misc_reg], val);
- }
- switch (misc_reg) {
- case MISCREG_CPACR:
- {
- CPACR newCpacr = 0;
- CPACR valCpacr = val;
- newCpacr.cp10 = valCpacr.cp10;
- newCpacr.cp11 = valCpacr.cp11;
- if (newCpacr.cp10 != 0x3 || newCpacr.cp11 != 3) {
- panic("Disabling coprocessors isn't implemented.\n");
- }
- newVal = newCpacr;
- }
- break;
- case MISCREG_CSSELR:
- warn("The csselr register isn't implemented.\n");
- break;
- case MISCREG_FPSCR:
- {
- const uint32_t ones = (uint32_t)(-1);
- FPSCR fpscrMask = 0;
- fpscrMask.ioc = ones;
- fpscrMask.dzc = ones;
- fpscrMask.ofc = ones;
- fpscrMask.ufc = ones;
- fpscrMask.ixc = ones;
- fpscrMask.idc = ones;
- fpscrMask.len = ones;
- fpscrMask.stride = ones;
- fpscrMask.rMode = ones;
- fpscrMask.fz = ones;
- fpscrMask.dn = ones;
- fpscrMask.ahp = ones;
- fpscrMask.qc = ones;
- fpscrMask.v = ones;
- fpscrMask.c = ones;
- fpscrMask.z = ones;
- fpscrMask.n = ones;
- newVal = (newVal & (uint32_t)fpscrMask) |
- (miscRegs[MISCREG_FPSCR] & ~(uint32_t)fpscrMask);
- }
- break;
- case MISCREG_FPEXC:
- {
- const uint32_t fpexcMask = 0x60000000;
- newVal = (newVal & fpexcMask) |
- (miscRegs[MISCREG_FPEXC] & ~fpexcMask);
- }
- break;
- case MISCREG_TLBTR:
- case MISCREG_MVFR0:
- case MISCREG_MVFR1:
- case MISCREG_MPIDR:
- case MISCREG_FPSID:
- return;
- }
- return setMiscRegNoEffect(misc_reg, newVal);
+ assert(reg >= 0);
+ return reg;
}
int
- flattenIntIndex(int reg)
+ flattenCCIndex(int reg) const
{
assert(reg >= 0);
- if (reg < NUM_ARCH_INTREGS) {
- return intRegMap[reg];
- } else if (reg < NUM_INTREGS) {
- return reg;
- } else {
- int mode = reg / intRegsPerMode;
- reg = reg % intRegsPerMode;
- switch (mode) {
+ return reg;
+ }
+
+ int
+ flattenMiscIndex(int reg) const
+ {
+ 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:
- case MODE_SYSTEM:
- return INTREG_USR(reg);
+ warn("User mode does not have SPSR\n");
+ flat_idx = MISCREG_SPSR;
+ break;
case MODE_FIQ:
- return INTREG_FIQ(reg);
+ flat_idx = MISCREG_SPSR_FIQ;
+ break;
case MODE_IRQ:
- return INTREG_IRQ(reg);
+ flat_idx = MISCREG_SPSR_IRQ;
+ break;
case MODE_SVC:
- return INTREG_SVC(reg);
+ flat_idx = MISCREG_SPSR_SVC;
+ break;
case MODE_MON:
- return INTREG_MON(reg);
+ flat_idx = MISCREG_SPSR_MON;
+ break;
case MODE_ABORT:
- return INTREG_ABT(reg);
+ flat_idx = MISCREG_SPSR_ABT;
+ break;
+ case MODE_HYP:
+ flat_idx = MISCREG_SPSR_HYP;
+ break;
case MODE_UNDEFINED:
- return INTREG_UND(reg);
+ flat_idx = MISCREG_SPSR_UND;
+ break;
default:
- panic("Flattening into an unknown mode.\n");
+ 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;
}
- int
- flattenFloatIndex(int reg)
+ void serialize(CheckpointOut &cp) const
{
- return reg;
- }
+ DPRINTF(Checkpoint, "Serializing Arm Misc Registers\n");
+ SERIALIZE_ARRAY(miscRegs, NumMiscRegs);
- void serialize(EventManager *em, std::ostream &os)
- {}
- void unserialize(EventManager *em, Checkpoint *cp,
- const std::string §ion)
- {}
-
- 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);
};
}