/*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
*/
#include "arch/arm/isa.hh"
+#include "config/use_checker.hh"
+#include "debug/Arm.hh"
+#include "debug/MiscRegs.hh"
#include "sim/faults.hh"
+#include "sim/stat_control.hh"
+#include "sim/system.hh"
+
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
namespace ArmISA
{
ISA::clear()
{
SCTLR sctlr_rst = miscRegs[MISCREG_SCTLR_RST];
-
+ uint32_t midr = miscRegs[MISCREG_MIDR];
memset(miscRegs, 0, sizeof(miscRegs));
CPSR cpsr = 0;
cpsr.mode = MODE_USER;
miscRegs[MISCREG_SCTLR] = sctlr;
miscRegs[MISCREG_SCTLR_RST] = sctlr_rst;
+ // Preserve MIDR accross reset
+ miscRegs[MISCREG_MIDR] = midr;
+
/* 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
- (0xf00 << 4) | // Primary part number
- (0 << 0) | // Revision
- 0;
-
// Separate Instruction and Data TLBs.
miscRegs[MISCREG_TLBTR] = 1;
miscRegs[MISCREG_CPACR] = 0;
miscRegs[MISCREG_FPSID] = 0x410430A0;
+
+ // See section B4.1.84 of ARM ARM
+ // All values are latest for ARMv7-A profile
+ miscRegs[MISCREG_ID_ISAR0] = 0x02101111;
+ miscRegs[MISCREG_ID_ISAR1] = 0x02112111;
+ miscRegs[MISCREG_ID_ISAR2] = 0x21232141;
+ miscRegs[MISCREG_ID_ISAR3] = 0x01112131;
+ miscRegs[MISCREG_ID_ISAR4] = 0x10010142;
+ miscRegs[MISCREG_ID_ISAR5] = 0x00000000;
+
//XXX We need to initialize the rest of the state.
}
cpsr.t = pc.thumb() ? 1 : 0;
return cpsr;
}
- if (misc_reg >= MISCREG_CP15_UNIMP_START &&
- misc_reg < MISCREG_CP15_END) {
+ if (misc_reg >= MISCREG_CP15_UNIMP_START)
panic("Unimplemented CP15 register %s read.\n",
miscRegName[misc_reg]);
- }
+
switch (misc_reg) {
+ case MISCREG_MPIDR:
+
+ return 0x80000000 | // multiprocessor extensions available
+ tc->cpuId();
+ break;
+ case MISCREG_ID_MMFR0:
+ return 0x03; // VMSAv7 support
+ case MISCREG_ID_MMFR2:
+ return 0x01230000; // no HW access | WFI stalling | ISB and DSB
+ // | all TLB maintenance | no Harvard
+ case MISCREG_ID_MMFR3:
+ return 0xF0102211; // SuperSec | Coherent TLB | Bcast Maint |
+ // BP Maint | Cache Maint Set/way | Cache Maint MVA
case MISCREG_CLIDR:
warn_once("The clidr register always reports 0 caches.\n");
- break;
+ warn_once("clidr LoUIS field of 0b001 to match current "
+ "ARM implementations.\n");
+ return 0x00200000;
case MISCREG_CCSIDR:
warn_once("The ccsidr register isn't implemented and "
"always reads as 0.\n");
warn("Returning thumbEE disabled for now since we don't support CP14"
"config registers and jumping to ThumbEE vectors\n");
return 0x0031; // !ThumbEE | !Jazelle | Thumb | ARM
- case MISCREG_ID_MMFR0:
- return 0x03; //VMSAz7
+ case MISCREG_ID_PFR1:
+ return 0x00001; // !Timer | !Virti | !M Profile | !TrustZone | ARMv4
case MISCREG_CTR:
return 0x86468006; // V7, 64 byte cache line, load/exclusive is exact
case MISCREG_ACTLR:
case MISCREG_PMCR:
case MISCREG_PMCCNTR:
case MISCREG_PMSELR:
- warn("Not doing anyhting for read to miscreg %s\n",
+ warn("Not doing anything for read to miscreg %s\n",
miscRegName[misc_reg]);
break;
-
+ case MISCREG_CPSR_Q:
+ panic("shouldn't be reading this register seperately\n");
+ case MISCREG_FPSCR_QC:
+ return readMiscRegNoEffect(MISCREG_FPSCR) & ~FpscrQcMask;
+ case MISCREG_FPSCR_EXC:
+ return readMiscRegNoEffect(MISCREG_FPSCR) & ~FpscrExcMask;
+ case MISCREG_L2CTLR:
+ {
+ // mostly unimplemented, just set NumCPUs field from sim and return
+ L2CTLR l2ctlr = 0;
+ // b00:1CPU to b11:4CPUs
+ l2ctlr.numCPUs = tc->getSystemPtr()->numContexts() - 1;
+ return l2ctlr;
+ }
+ case MISCREG_DBGDIDR:
+ /* For now just implement the version number.
+ * Return 0 as we don't support debug architecture yet.
+ */
+ return 0;
+ case MISCREG_DBGDSCR_INT:
+ return 0;
}
return readMiscRegNoEffect(misc_reg);
}
void
ISA::setMiscReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
{
+
MiscReg newVal = val;
+ int x;
+ System *sys;
+ ThreadContext *oc;
+
if (misc_reg == MISCREG_CPSR) {
updateRegMap(val);
+
+
+ CPSR old_cpsr = miscRegs[MISCREG_CPSR];
+ int old_mode = old_cpsr.mode;
CPSR cpsr = val;
+ if (old_mode != cpsr.mode) {
+ tc->getITBPtr()->invalidateMiscReg();
+ tc->getDTBPtr()->invalidateMiscReg();
+ }
+
DPRINTF(Arm, "Updating CPSR from %#x to %#x f:%d i:%d a:%d mode:%#x\n",
miscRegs[misc_reg], cpsr, cpsr.f, cpsr.i, cpsr.a, cpsr.mode);
PCState pc = tc->pcState();
pc.nextThumb(cpsr.t);
pc.nextJazelle(cpsr.j);
+#if USE_CHECKER
+ tc->pcStateNoRecord(pc);
+#else
tc->pcState(pc);
+#endif //USE_CHECKER
} else 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);
} else {
switch (misc_reg) {
- case MISCREG_ITSTATE:
- {
- ITSTATE itstate = newVal;
- CPSR cpsr = miscRegs[MISCREG_CPSR];
- cpsr.it1 = itstate.bottom2;
- cpsr.it2 = itstate.top6;
- miscRegs[MISCREG_CPSR] = cpsr;
- DPRINTF(MiscRegs,
- "Updating ITSTATE -> %#x in CPSR -> %#x.\n",
- (uint8_t)itstate, (uint32_t)cpsr);
- }
- break;
case MISCREG_CPACR:
{
- CPACR newCpacr = 0;
- CPACR valCpacr = val;
- newCpacr.cp10 = valCpacr.cp10;
- newCpacr.cp11 = valCpacr.cp11;
- //XXX d32dis isn't implemented. The manual says whether or not
- //it works is implementation defined.
- newCpacr.asedis = valCpacr.asedis;
- newVal = newCpacr;
+
+ const uint32_t ones = (uint32_t)(-1);
+ CPACR cpacrMask = 0;
+ // Only cp10, cp11, and ase are implemented, nothing else should
+ // be writable
+ cpacrMask.cp10 = ones;
+ cpacrMask.cp11 = ones;
+ cpacrMask.asedis = ones;
+ newVal &= cpacrMask;
+ DPRINTF(MiscRegs, "Writing misc reg %s: %#x\n",
+ miscRegName[misc_reg], newVal);
}
break;
case MISCREG_CSSELR:
warn_once("The csselr register isn't implemented.\n");
- break;
+ return;
case MISCREG_FPSCR:
{
const uint32_t ones = (uint32_t)(-1);
(miscRegs[MISCREG_FPSCR] & ~(uint32_t)fpscrMask);
}
break;
+ case MISCREG_CPSR_Q:
+ {
+ assert(!(newVal & ~CpsrMaskQ));
+ newVal = miscRegs[MISCREG_CPSR] | newVal;
+ misc_reg = MISCREG_CPSR;
+ }
+ break;
+ case MISCREG_FPSCR_QC:
+ {
+ newVal = miscRegs[MISCREG_FPSCR] | (newVal & FpscrQcMask);
+ misc_reg = MISCREG_FPSCR;
+ }
+ break;
+ case MISCREG_FPSCR_EXC:
+ {
+ newVal = miscRegs[MISCREG_FPSCR] | (newVal & FpscrExcMask);
+ misc_reg = MISCREG_FPSCR;
+ }
+ break;
case MISCREG_FPEXC:
{
+ // vfpv3 architecture, section B.6.1 of DDI04068
+ // bit 29 - valid only if fpexc[31] is 0
const uint32_t fpexcMask = 0x60000000;
newVal = (newVal & fpexcMask) |
(miscRegs[MISCREG_FPEXC] & ~fpexcMask);
SCTLR new_sctlr = newVal;
new_sctlr.nmfi = (bool)sctlr.nmfi;
miscRegs[MISCREG_SCTLR] = (MiscReg)new_sctlr;
+ tc->getITBPtr()->invalidateMiscReg();
+ tc->getDTBPtr()->invalidateMiscReg();
+
+ // Check if all CPUs are booted with caches enabled
+ // so we can stop enforcing coherency of some kernel
+ // structures manually.
+ sys = tc->getSystemPtr();
+ for (x = 0; x < sys->numContexts(); x++) {
+ oc = sys->getThreadContext(x);
+ SCTLR other_sctlr = oc->readMiscRegNoEffect(MISCREG_SCTLR);
+ if (!other_sctlr.c && oc->status() != ThreadContext::Halted)
+ return;
+ }
+
+ for (x = 0; x < sys->numContexts(); x++) {
+ oc = sys->getThreadContext(x);
+ oc->getDTBPtr()->allCpusCaching();
+ oc->getITBPtr()->allCpusCaching();
+#if USE_CHECKER
+ CheckerCPU *checker =
+ dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+ if (checker) {
+ checker->getDTBPtr()->allCpusCaching();
+ checker->getITBPtr()->allCpusCaching();
+ }
+#endif
+ }
return;
}
case MISCREG_TLBTR:
return;
case MISCREG_TLBIALLIS:
case MISCREG_TLBIALL:
- warn_once("Need to flush all TLBs in MP\n");
- tc->getITBPtr()->flushAll();
- tc->getDTBPtr()->flushAll();
+ sys = tc->getSystemPtr();
+ for (x = 0; x < sys->numContexts(); x++) {
+ oc = sys->getThreadContext(x);
+ assert(oc->getITBPtr() && oc->getDTBPtr());
+ oc->getITBPtr()->flushAll();
+ oc->getDTBPtr()->flushAll();
+#if USE_CHECKER
+ CheckerCPU *checker =
+ dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+ if (checker) {
+ checker->getITBPtr()->flushAll();
+ checker->getDTBPtr()->flushAll();
+ }
+#endif
+ }
return;
case MISCREG_ITLBIALL:
tc->getITBPtr()->flushAll();
return;
case MISCREG_TLBIMVAIS:
case MISCREG_TLBIMVA:
- warn_once("Need to flush all TLBs in MP\n");
- tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
- bits(newVal, 7,0));
- tc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
- bits(newVal, 7,0));
+ sys = tc->getSystemPtr();
+ for (x = 0; x < sys->numContexts(); x++) {
+ oc = sys->getThreadContext(x);
+ assert(oc->getITBPtr() && oc->getDTBPtr());
+ oc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+ bits(newVal, 7,0));
+ oc->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+ bits(newVal, 7,0));
+#if USE_CHECKER
+ CheckerCPU *checker =
+ dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+ if (checker) {
+ checker->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+ bits(newVal, 7,0));
+ checker->getDTBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
+ bits(newVal, 7,0));
+ }
+#endif
+ }
return;
case MISCREG_TLBIASIDIS:
case MISCREG_TLBIASID:
- warn_once("Need to flush all TLBs in MP\n");
- tc->getITBPtr()->flushAsid(bits(newVal, 7,0));
- tc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
+ sys = tc->getSystemPtr();
+ for (x = 0; x < sys->numContexts(); x++) {
+ oc = sys->getThreadContext(x);
+ assert(oc->getITBPtr() && oc->getDTBPtr());
+ oc->getITBPtr()->flushAsid(bits(newVal, 7,0));
+ oc->getDTBPtr()->flushAsid(bits(newVal, 7,0));
+#if USE_CHECKER
+ CheckerCPU *checker =
+ dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+ if (checker) {
+ checker->getITBPtr()->flushAsid(bits(newVal, 7,0));
+ checker->getDTBPtr()->flushAsid(bits(newVal, 7,0));
+ }
+#endif
+ }
return;
case MISCREG_TLBIMVAAIS:
case MISCREG_TLBIMVAA:
- warn_once("Need to flush all TLBs in MP\n");
- tc->getITBPtr()->flushMva(mbits(newVal, 31,12));
- tc->getDTBPtr()->flushMva(mbits(newVal, 31,12));
+ sys = tc->getSystemPtr();
+ for (x = 0; x < sys->numContexts(); x++) {
+ oc = sys->getThreadContext(x);
+ assert(oc->getITBPtr() && oc->getDTBPtr());
+ oc->getITBPtr()->flushMva(mbits(newVal, 31,12));
+ oc->getDTBPtr()->flushMva(mbits(newVal, 31,12));
+#if USE_CHECKER
+ CheckerCPU *checker =
+ dynamic_cast<CheckerCPU*>(oc->getCheckerCpuPtr());
+ if (checker) {
+ checker->getITBPtr()->flushMva(mbits(newVal, 31,12));
+ checker->getDTBPtr()->flushMva(mbits(newVal, 31,12));
+ }
+#endif
+ }
return;
case MISCREG_ITLBIMVA:
tc->getITBPtr()->flushMvaAsid(mbits(newVal, 31, 12),
warn("Not doing anything for write of miscreg ACTLR\n");
break;
case MISCREG_PMCR:
+ {
+ // Performance counters not implemented. Instead, interpret
+ // a reset command to this register to reset the simulator
+ // statistics.
+ // PMCR_E | PMCR_P | PMCR_C
+ const int ResetAndEnableCounters = 0x7;
+ if (newVal == ResetAndEnableCounters) {
+ inform("Resetting all simobject stats\n");
+ Stats::schedStatEvent(false, true);
+ break;
+ }
+ }
case MISCREG_PMCCNTR:
case MISCREG_PMSELR:
warn("Not doing anything for write to miscreg %s\n",
default:
panic("Security Extensions not implemented!");
}
- req->setVirt(0, val, 1, flags, tc->pcState().pc());
+ warn("Translating via MISCREG in atomic mode! Fix Me!\n");
+ req->setVirt(0, val, 1, flags, tc->pcState().pc(),
+ Request::funcMasterId);
fault = tc->getDTBPtr()->translateAtomic(req, tc, mode);
if (fault == NoFault) {
miscRegs[MISCREG_PAR] =
}
return;
}
+ case MISCREG_CONTEXTIDR:
+ case MISCREG_PRRR:
+ case MISCREG_NMRR:
+ case MISCREG_DACR:
+ tc->getITBPtr()->invalidateMiscReg();
+ tc->getDTBPtr()->invalidateMiscReg();
+ break;
+ case MISCREG_CPSR_MODE:
+ // This miscreg is used by copy*Regs to set the CPSR mode
+ // without updating other CPSR variables. It's used to
+ // make sure the register map is in such a state that we can
+ // see all of the registers for the copy.
+ updateRegMap(val);
+ return;
+ case MISCREG_L2CTLR:
+ warn("miscreg L2CTLR (%s) written with %#x. ignored...\n",
+ miscRegName[misc_reg], uint32_t(val));
}
}
setMiscRegNoEffect(misc_reg, newVal);