summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAli Saidi <Ali.Saidi@ARM.com>2010-06-02 12:58:16 -0500
committerAli Saidi <Ali.Saidi@ARM.com>2010-06-02 12:58:16 -0500
commitb8ec21455382c3b5e0e9bc8c0dbcd38b07c567e3 (patch)
tree273490f7ecbdbf3dc6f89d3ef46c46c7f07bc24c /src
parent3aea20d143ee27e0562f6f9ea3d4c1b4bbfd20f3 (diff)
downloadgem5-b8ec21455382c3b5e0e9bc8c0dbcd38b07c567e3.tar.xz
ARM: Implement ARM CPU interrupts
Diffstat (limited to 'src')
-rw-r--r--src/arch/arm/faults.cc16
-rw-r--r--src/arch/arm/faults.hh11
-rw-r--r--src/arch/arm/insts/static_inst.hh8
-rw-r--r--src/arch/arm/interrupts.cc9
-rw-r--r--src/arch/arm/interrupts.hh72
-rw-r--r--src/arch/arm/isa.hh22
-rw-r--r--src/arch/arm/isa/decoder/arm.isa3
-rw-r--r--src/arch/arm/isa/insts/data.isa3
-rw-r--r--src/arch/arm/isa/insts/ldr.isa3
-rw-r--r--src/arch/arm/isa/insts/macromem.isa3
-rw-r--r--src/arch/arm/isa/insts/misc.isa9
-rw-r--r--src/arch/arm/isa_traits.hh10
-rw-r--r--src/arch/arm/miscregs.hh3
-rw-r--r--src/cpu/simple_thread.hh1
14 files changed, 150 insertions, 23 deletions
diff --git a/src/arch/arm/faults.cc b/src/arch/arm/faults.cc
index f1ecd31b9..0de5db527 100644
--- a/src/arch/arm/faults.cc
+++ b/src/arch/arm/faults.cc
@@ -77,11 +77,11 @@ ArmFault::getVector(ThreadContext *tc)
// ARM ARM B1-3
SCTLR sctlr = tc->readMiscReg(MISCREG_SCTLR);
-
+
// panic if SCTLR.VE because I have no idea what to do with vectored
// interrupts
assert(!sctlr.ve);
-
+
if (!sctlr.v)
return offset();
return offset() + HighVecs;
@@ -137,14 +137,22 @@ ArmFault::invoke(ThreadContext *tc)
}
Addr pc = tc->readPC();
- DPRINTF(Faults, "Invoking Fault: %s cpsr: %#x PC: %#x lr: %#x\n",
- name(), cpsr, pc, tc->readIntReg(INTREG_LR));
Addr newPc = getVector(tc) | (sctlr.te ? (ULL(1) << PcTBitShift) : 0);
+ DPRINTF(Faults, "Invoking Fault: %s cpsr: %#x PC: %#x lr: %#x newVector: %#x\n",
+ name(), cpsr, pc, tc->readIntReg(INTREG_LR), newPc);
tc->setPC(newPc);
tc->setNextPC(newPc + cpsr.t ? 2 : 4 );
tc->setMicroPC(0);
}
+void
+Reset::invoke(ThreadContext *tc)
+{
+ tc->getCpuPtr()->clearInterrupts();
+ tc->clearArchRegs();
+ ArmFault::invoke(tc);
+}
+
#else
void
diff --git a/src/arch/arm/faults.hh b/src/arch/arm/faults.hh
index 7339e0e63..7e4013a85 100644
--- a/src/arch/arm/faults.hh
+++ b/src/arch/arm/faults.hh
@@ -128,8 +128,15 @@ class ArmFaultVals : public ArmFault
bool fiqDisable() { return vals.fiqDisable; }
};
-
-class Reset : public ArmFaultVals<Reset> {};
+class Reset : public ArmFaultVals<Reset>
+#if FULL_SYSTEM
+{
+ public:
+ void invoke(ThreadContext *tc);
+};
+#else
+{};
+#endif //FULL_SYSTEM
class UndefinedInstruction : public ArmFaultVals<UndefinedInstruction>
{
diff --git a/src/arch/arm/insts/static_inst.hh b/src/arch/arm/insts/static_inst.hh
index 33453bec6..b0eb1a6e9 100644
--- a/src/arch/arm/insts/static_inst.hh
+++ b/src/arch/arm/insts/static_inst.hh
@@ -156,7 +156,7 @@ class ArmStaticInst : public StaticInst
static uint32_t
cpsrWriteByInstr(CPSR cpsr, uint32_t val,
- uint8_t byteMask, bool affectState)
+ uint8_t byteMask, bool affectState, bool nmfi)
{
bool privileged = (cpsr.mode != MODE_USER);
@@ -187,7 +187,11 @@ class ArmStaticInst : public StaticInst
bitMask = bitMask | (1 << 5);
}
- return ((uint32_t)cpsr & ~bitMask) | (val & bitMask);
+ bool cpsr_f = cpsr.f;
+ uint32_t new_cpsr = ((uint32_t)cpsr & ~bitMask) | (val & bitMask);
+ if (nmfi && !cpsr_f)
+ new_cpsr &= ~(1 << 6);
+ return new_cpsr;
}
static uint32_t
diff --git a/src/arch/arm/interrupts.cc b/src/arch/arm/interrupts.cc
index a47ebc75d..c05ae984e 100644
--- a/src/arch/arm/interrupts.cc
+++ b/src/arch/arm/interrupts.cc
@@ -2,6 +2,15 @@
* Copyright (c) 2009 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.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
diff --git a/src/arch/arm/interrupts.hh b/src/arch/arm/interrupts.hh
index 189341d6b..5870034c3 100644
--- a/src/arch/arm/interrupts.hh
+++ b/src/arch/arm/interrupts.hh
@@ -1,6 +1,17 @@
/*
+ * Copyright (c) 2010 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) 2006 The Regents of The University of Michigan
- * Copyright (c) 2009 ARM Limited
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,6 +45,7 @@
#include "arch/arm/faults.hh"
#include "arch/arm/isa_traits.hh"
+#include "arch/arm/miscregs.hh"
#include "arch/arm/registers.hh"
#include "cpu/thread_context.hh"
#include "params/ArmInterrupts.hh"
@@ -47,6 +59,7 @@ class Interrupts : public SimObject
private:
BaseCPU * cpu;
+ bool interrupts[NumInterruptTypes];
uint64_t intStatus;
public:
@@ -74,46 +87,95 @@ class Interrupts : public SimObject
void
post(int int_num, int index)
{
+ DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
+
+ if (int_num < 0 || int_num >= NumInterruptTypes)
+ panic("int_num out of bounds\n");
+
+ if (index != 0)
+ panic("No support for other interrupt indexes\n");
+
+ interrupts[int_num] = true;
+ intStatus |= ULL(1) << int_num;
}
void
clear(int int_num, int index)
{
+ DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
+
+ if (int_num < 0 || int_num >= NumInterruptTypes)
+ panic("int_num out of bounds\n");
+
+ if (index != 0)
+ panic("No support for other interrupt indexes\n");
+
+ interrupts[int_num] = false;
+ intStatus &= ~(ULL(1) << int_num);
+
}
void
clearAll()
{
+ DPRINTF(Interrupt, "Interrupts all cleared\n");
intStatus = 0;
+ memset(interrupts, 0, sizeof(interrupts));
}
bool
checkInterrupts(ThreadContext *tc) const
{
- return intStatus;
+ if (!intStatus)
+ return false;
+
+ CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
+
+ return ((interrupts[INT_IRQ] && !cpsr.i) ||
+ (interrupts[INT_FIQ] && !cpsr.f) ||
+ (interrupts[INT_ABT] && !cpsr.a) ||
+ (interrupts[INT_RST]));
}
Fault
getInterrupt(ThreadContext *tc)
{
- warn_once("ARM Interrupts not handled\n");
- return NoFault;
+ if (!intStatus)
+ return NoFault;
+
+ CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
+
+ if (interrupts[INT_IRQ] && !cpsr.i)
+ return new Interrupt;
+ if (interrupts[INT_FIQ] && !cpsr.f)
+ return new FastInterrupt;
+ if (interrupts[INT_ABT] && !cpsr.a)
+ return new DataAbort(0, false, 0,
+ ArmFault::AsynchronousExternalAbort);
+ if (interrupts[INT_RST])
+ return new Reset;
+
+ panic("intStatus and interrupts not in sync\n");
}
void
updateIntrInfo(ThreadContext *tc)
{
-
+ ; // nothing to do
}
void
serialize(std::ostream &os)
{
+ SERIALIZE_ARRAY(interrupts, NumInterruptTypes);
+ SERIALIZE_SCALAR(intStatus);
}
void
unserialize(Checkpoint *cp, const std::string &section)
{
+ UNSERIALIZE_ARRAY(interrupts, NumInterruptTypes);
+ UNSERIALIZE_SCALAR(intStatus);
}
};
} // namespace ARM_ISA
diff --git a/src/arch/arm/isa.hh b/src/arch/arm/isa.hh
index f2d913ac4..c9c237946 100644
--- a/src/arch/arm/isa.hh
+++ b/src/arch/arm/isa.hh
@@ -92,6 +92,8 @@ namespace ArmISA
public:
void clear()
{
+ SCTLR sctlr_rst = miscRegs[MISCREG_SCTLR_RST];
+
memset(miscRegs, 0, sizeof(miscRegs));
CPSR cpsr = 0;
cpsr.mode = MODE_USER;
@@ -99,12 +101,16 @@ namespace ArmISA
updateRegMap(cpsr);
SCTLR sctlr = 0;
- sctlr.nmfi = 1;
+ sctlr.nmfi = (bool)sctlr_rst.nmfi;
+ sctlr.v = (bool)sctlr_rst.v;
+ sctlr.u = 1;
sctlr.rao1 = 1;
sctlr.rao2 = 1;
sctlr.rao3 = 1;
sctlr.rao4 = 1;
miscRegs[MISCREG_SCTLR] = sctlr;
+ miscRegs[MISCREG_SCTLR_RST] = sctlr_rst;
+
/*
* Technically this should be 0, but we don't support those
@@ -327,6 +333,14 @@ namespace ArmISA
(miscRegs[MISCREG_FPEXC] & ~fpexcMask);
}
break;
+ case MISCREG_SCTLR:
+ {
+ SCTLR sctlr = miscRegs[MISCREG_SCTLR];
+ SCTLR new_sctlr = newVal;
+ new_sctlr.nmfi = (bool)sctlr.nmfi;
+ miscRegs[MISCREG_SCTLR] = (MiscReg)new_sctlr;
+ return;
+ }
case MISCREG_TLBTR:
case MISCREG_MVFR0:
case MISCREG_MVFR1:
@@ -334,7 +348,7 @@ namespace ArmISA
case MISCREG_FPSID:
return;
}
- return setMiscRegNoEffect(misc_reg, newVal);
+ setMiscRegNoEffect(misc_reg, newVal);
}
int
@@ -384,6 +398,10 @@ namespace ArmISA
ISA()
{
+ SCTLR sctlr;
+ sctlr = 0;
+ miscRegs[MISCREG_SCTLR_RST] = sctlr;
+
clear();
}
};
diff --git a/src/arch/arm/isa/decoder/arm.isa b/src/arch/arm/isa/decoder/arm.isa
index 163da5ca0..467b98eaa 100644
--- a/src/arch/arm/isa/decoder/arm.isa
+++ b/src/arch/arm/isa/decoder/arm.isa
@@ -109,9 +109,10 @@ format DataOp {
#endif
}
default: PredImmOp::msr_i_cpsr({{
+ SCTLR sctlr = Sctlr;
uint32_t newCpsr =
cpsrWriteByInstr(Cpsr | CondCodes,
- rotated_imm, RN, false);
+ rotated_imm, RN, false, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
CondCodes = CondCodesMask & newCpsr;
}});
diff --git a/src/arch/arm/isa/insts/data.isa b/src/arch/arm/isa/insts/data.isa
index 474bd8c4e..09019d0f4 100644
--- a/src/arch/arm/isa/insts/data.isa
+++ b/src/arch/arm/isa/insts/data.isa
@@ -233,8 +233,9 @@ let {{
buildRegRegDataInst(mnem, regRegCode, flagType)
if subsPcLr:
code += '''
+ SCTLR sctlr = Sctlr;
uint32_t newCpsr =
- cpsrWriteByInstr(Cpsr | CondCodes, Spsr, 0xF, true);
+ cpsrWriteByInstr(Cpsr | CondCodes, Spsr, 0xF, true, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
CondCodes = CondCodesMask & newCpsr;
'''
diff --git a/src/arch/arm/isa/insts/ldr.isa b/src/arch/arm/isa/insts/ldr.isa
index f5ea53b72..40d9147df 100644
--- a/src/arch/arm/isa/insts/ldr.isa
+++ b/src/arch/arm/isa/insts/ldr.isa
@@ -137,11 +137,12 @@ let {{
wbDiff = 8
accCode = '''
CPSR cpsr = Cpsr;
+ SCTLR sctlr = Sctlr;
NPC = cSwap<uint32_t>(Mem.ud, cpsr.e);
uint32_t newCpsr =
cpsrWriteByInstr(cpsr | CondCodes,
cSwap<uint32_t>(Mem.ud >> 32, cpsr.e),
- 0xF, true);
+ 0xF, true, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
CondCodes = CondCodesMask & newCpsr;
'''
diff --git a/src/arch/arm/isa/insts/macromem.isa b/src/arch/arm/isa/insts/macromem.isa
index 0870a966f..82e9d9842 100644
--- a/src/arch/arm/isa/insts/macromem.isa
+++ b/src/arch/arm/isa/insts/macromem.isa
@@ -69,8 +69,9 @@ let {{
microLdrRetUopCode = '''
CPSR cpsr = Cpsr;
+ SCTLR sctlr = Sctlr;
uint32_t newCpsr =
- cpsrWriteByInstr(cpsr | CondCodes, Spsr, 0xF, true);
+ cpsrWriteByInstr(cpsr | CondCodes, Spsr, 0xF, true, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
CondCodes = CondCodesMask & newCpsr;
IWNPC = cSwap(Mem.uw, cpsr.e) | ((Spsr & 0x20) ? 1 : 0);
diff --git a/src/arch/arm/isa/insts/misc.isa b/src/arch/arm/isa/insts/misc.isa
index 6cd4437d0..722b05eac 100644
--- a/src/arch/arm/isa/insts/misc.isa
+++ b/src/arch/arm/isa/insts/misc.isa
@@ -77,8 +77,9 @@ let {{
exec_output += PredOpExecute.subst(mrsSpsrIop)
msrCpsrRegCode = '''
+ SCTLR sctlr = Sctlr;
uint32_t newCpsr =
- cpsrWriteByInstr(Cpsr | CondCodes, Op1, byteMask, false);
+ cpsrWriteByInstr(Cpsr | CondCodes, Op1, byteMask, false, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
CondCodes = CondCodesMask & newCpsr;
'''
@@ -98,8 +99,9 @@ let {{
exec_output += PredOpExecute.subst(msrSpsrRegIop)
msrCpsrImmCode = '''
+ SCTLR sctlr = Sctlr;
uint32_t newCpsr =
- cpsrWriteByInstr(Cpsr | CondCodes, imm, byteMask, false);
+ cpsrWriteByInstr(Cpsr | CondCodes, imm, byteMask, false, sctlr.nmfi);
Cpsr = ~CondCodesMask & newCpsr;
CondCodes = CondCodesMask & newCpsr;
'''
@@ -577,13 +579,14 @@ let {{
bool setMode = bits(imm, 8);
bool enable = bits(imm, 9);
CPSR cpsr = Cpsr;
+ SCTLR sctlr = Sctlr;
if (cpsr.mode != MODE_USER) {
if (enable) {
if (f) cpsr.f = 0;
if (i) cpsr.i = 0;
if (a) cpsr.a = 0;
} else {
- if (f) cpsr.f = 1;
+ if (f && !sctlr.nmfi) cpsr.f = 1;
if (i) cpsr.i = 1;
if (a) cpsr.a = 1;
}
diff --git a/src/arch/arm/isa_traits.hh b/src/arch/arm/isa_traits.hh
index 4cffe3bec..d81981ff7 100644
--- a/src/arch/arm/isa_traits.hh
+++ b/src/arch/arm/isa_traits.hh
@@ -110,6 +110,7 @@ namespace ArmISA
const int LogVMPageSize = 12; // 4K bytes
const int VMPageSize = (1 << LogVMPageSize);
+ // Shouldn't this be 1 because of Thumb?! Dynamic? --Ali
const int BranchPredAddrShiftAmt = 2; // instructions are 4-byte aligned
const int MachineBytes = 4;
@@ -122,6 +123,15 @@ namespace ArmISA
// Memory accesses cannot be unaligned
const bool HasUnalignedMemAcc = false;
+ enum InterruptTypes
+ {
+ INT_RST,
+ INT_ABT,
+ INT_IRQ,
+ INT_FIQ,
+ NumInterruptTypes
+ };
+
// These otherwise unused bits of the PC are used to select a mode
// like the J and T bits of the CPSR.
static const Addr PcJBitShift = 33;
diff --git a/src/arch/arm/miscregs.hh b/src/arch/arm/miscregs.hh
index 27f12c3b2..cdead8710 100644
--- a/src/arch/arm/miscregs.hh
+++ b/src/arch/arm/miscregs.hh
@@ -80,6 +80,7 @@ namespace ArmISA
MISCREG_FPEXC,
MISCREG_MVFR0,
MISCREG_MVFR1,
+ MISCREG_SCTLR_RST,
MISCREG_SEV_MAILBOX,
// CP15 registers
@@ -191,7 +192,7 @@ namespace ArmISA
"cpsr", "spsr", "spsr_fiq", "spsr_irq", "spsr_svc",
"spsr_mon", "spsr_und", "spsr_abt",
"fpsr", "fpsid", "fpscr", "fpexc", "mvfr0", "mvfr1",
- "sev_mailbox",
+ "sctlr_rst", "sev_mailbox",
"sctlr", "dccisw", "dccimvac", "dccmvac",
"contextidr", "tpidrurw", "tpidruro", "tpidrprw",
"cp15isb", "cp15dsb", "cp15dmb", "cpacr",
diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh
index 74f01bfba..bc8588041 100644
--- a/src/cpu/simple_thread.hh
+++ b/src/cpu/simple_thread.hh
@@ -254,6 +254,7 @@ class SimpleThread : public ThreadState
PC = nextPC = nextNPC = 0;
memset(intRegs, 0, sizeof(intRegs));
memset(floatRegs.i, 0, sizeof(floatRegs.i));
+ isa.clear();
}
//