ARM: Implement ARM CPU interrupts
This commit is contained in:
parent
3aea20d143
commit
b8ec214553
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 §ion)
|
||||
{
|
||||
UNSERIALIZE_ARRAY(interrupts, NumInterruptTypes);
|
||||
UNSERIALIZE_SCALAR(intStatus);
|
||||
}
|
||||
};
|
||||
} // namespace ARM_ISA
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}});
|
||||
|
|
|
@ -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;
|
||||
'''
|
||||
|
|
|
@ -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;
|
||||
'''
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue