isa,cpu: Add support for FS SMT Interrupts

Adds per-thread interrupt controllers and thread/context logic
so that interrupts properly get routed in SMT systems.
This commit is contained in:
Mitch Hayenga 2015-09-30 11:14:19 -05:00
parent e255fa053f
commit a5c4eb3de9
23 changed files with 129 additions and 102 deletions

View file

@ -176,9 +176,9 @@ def build_test_system(np):
cpu.itb.walker.port = test_sys.ruby._cpu_ports[i].slave cpu.itb.walker.port = test_sys.ruby._cpu_ports[i].slave
cpu.dtb.walker.port = test_sys.ruby._cpu_ports[i].slave cpu.dtb.walker.port = test_sys.ruby._cpu_ports[i].slave
cpu.interrupts.pio = test_sys.ruby._cpu_ports[i].master cpu.interrupts[0].pio = test_sys.ruby._cpu_ports[i].master
cpu.interrupts.int_master = test_sys.ruby._cpu_ports[i].slave cpu.interrupts[0].int_master = test_sys.ruby._cpu_ports[i].slave
cpu.interrupts.int_slave = test_sys.ruby._cpu_ports[i].master cpu.interrupts[0].int_slave = test_sys.ruby._cpu_ports[i].master
else: else:
if options.caches or options.l2cache: if options.caches or options.l2cache:

View file

@ -265,9 +265,9 @@ if options.ruby:
system.cpu[i].icache_port = ruby_port.slave system.cpu[i].icache_port = ruby_port.slave
system.cpu[i].dcache_port = ruby_port.slave system.cpu[i].dcache_port = ruby_port.slave
if buildEnv['TARGET_ISA'] == 'x86': if buildEnv['TARGET_ISA'] == 'x86':
system.cpu[i].interrupts.pio = ruby_port.master system.cpu[i].interrupts[0].pio = ruby_port.master
system.cpu[i].interrupts.int_master = ruby_port.slave system.cpu[i].interrupts[0].int_master = ruby_port.slave
system.cpu[i].interrupts.int_slave = ruby_port.master system.cpu[i].interrupts[0].int_slave = ruby_port.master
system.cpu[i].itb.walker.port = ruby_port.slave system.cpu[i].itb.walker.port = ruby_port.slave
system.cpu[i].dtb.walker.port = ruby_port.slave system.cpu[i].dtb.walker.port = ruby_port.slave
else: else:

View file

@ -943,7 +943,7 @@ decode OPCODE default Unknown::unknown() {
0x01: quiesce({{ 0x01: quiesce({{
// Don't sleep if (unmasked) interrupts are pending // Don't sleep if (unmasked) interrupts are pending
Interrupts* interrupts = Interrupts* interrupts =
xc->tcBase()->getCpuPtr()->getInterruptController(); xc->tcBase()->getCpuPtr()->getInterruptController(0);
if (interrupts->checkInterrupts(xc->tcBase())) { if (interrupts->checkInterrupts(xc->tcBase())) {
PseudoInst::quiesceSkip(xc->tcBase()); PseudoInst::quiesceSkip(xc->tcBase());
} else { } else {

View file

@ -681,7 +681,7 @@ void
Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst) Reset::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{ {
if (FullSystem) { if (FullSystem) {
tc->getCpuPtr()->clearInterrupts(); tc->getCpuPtr()->clearInterrupts(tc->threadId());
tc->clearArchRegs(); tc->clearArchRegs();
} }
if (!ArmSystem::highestELIs64(tc)) { if (!ArmSystem::highestELIs64(tc)) {
@ -938,7 +938,7 @@ AbortFault<T>::invoke(ThreadContext *tc, const StaticInstPtr &inst)
} }
if (source == ArmFault::AsynchronousExternalAbort) { if (source == ArmFault::AsynchronousExternalAbort) {
tc->getCpuPtr()->clearInterrupt(INT_ABT, 0); tc->getCpuPtr()->clearInterrupt(tc->threadId(), INT_ABT, 0);
} }
// Get effective fault source encoding // Get effective fault source encoding
CPSR cpsr = tc->readMiscReg(MISCREG_CPSR); CPSR cpsr = tc->readMiscReg(MISCREG_CPSR);
@ -1353,7 +1353,7 @@ SystemError::SystemError()
void void
SystemError::invoke(ThreadContext *tc, const StaticInstPtr &inst) SystemError::invoke(ThreadContext *tc, const StaticInstPtr &inst)
{ {
tc->getCpuPtr()->clearInterrupt(INT_ABT, 0); tc->getCpuPtr()->clearInterrupt(tc->threadId(), INT_ABT, 0);
ArmFault::invoke(tc, inst); ArmFault::invoke(tc, inst);
} }
@ -1404,7 +1404,7 @@ ArmSev::invoke(ThreadContext *tc, const StaticInstPtr &inst) {
// SEV execution and let pipeline continue as pcState is still // SEV execution and let pipeline continue as pcState is still
// valid. // valid.
tc->setMiscReg(MISCREG_SEV_MAILBOX, 1); tc->setMiscReg(MISCREG_SEV_MAILBOX, 1);
tc->getCpuPtr()->clearInterrupt(INT_SEV, 0); tc->getCpuPtr()->clearInterrupt(tc->threadId(), INT_SEV, 0);
} }
// Instantiate all the templates to make the linker happy // Instantiate all the templates to make the linker happy

View file

@ -668,12 +668,12 @@ ISA::readMiscReg(int misc_reg, ThreadContext *tc)
case MISCREG_DBGDSCRint: case MISCREG_DBGDSCRint:
return 0; return 0;
case MISCREG_ISR: case MISCREG_ISR:
return tc->getCpuPtr()->getInterruptController()->getISR( return tc->getCpuPtr()->getInterruptController(tc->threadId())->getISR(
readMiscRegNoEffect(MISCREG_HCR), readMiscRegNoEffect(MISCREG_HCR),
readMiscRegNoEffect(MISCREG_CPSR), readMiscRegNoEffect(MISCREG_CPSR),
readMiscRegNoEffect(MISCREG_SCR)); readMiscRegNoEffect(MISCREG_SCR));
case MISCREG_ISR_EL1: case MISCREG_ISR_EL1:
return tc->getCpuPtr()->getInterruptController()->getISR( return tc->getCpuPtr()->getInterruptController(tc->threadId())->getISR(
readMiscRegNoEffect(MISCREG_HCR_EL2), readMiscRegNoEffect(MISCREG_HCR_EL2),
readMiscRegNoEffect(MISCREG_CPSR), readMiscRegNoEffect(MISCREG_CPSR),
readMiscRegNoEffect(MISCREG_SCR_EL3)); readMiscRegNoEffect(MISCREG_SCR_EL3));
@ -1929,7 +1929,7 @@ ISA::getGenericTimer(ThreadContext *tc)
"been configured to use a generic timer.\n"); "been configured to use a generic timer.\n");
} }
timer.reset(new GenericTimerISA(*generic_timer, tc->cpuId())); timer.reset(new GenericTimerISA(*generic_timer, tc->contextId()));
return *timer.get(); return *timer.get();
} }

View file

@ -649,7 +649,8 @@ let {{
if (SevMailbox == 1) { if (SevMailbox == 1) {
SevMailbox = 0; SevMailbox = 0;
PseudoInst::quiesceSkip(tc); PseudoInst::quiesceSkip(tc);
} else if (tc->getCpuPtr()->getInterruptController()->checkInterrupts(tc)) { } else if (tc->getCpuPtr()->getInterruptController(
tc->threadId())->checkInterrupts(tc)) {
PseudoInst::quiesceSkip(tc); PseudoInst::quiesceSkip(tc);
} else if (cpsr.el == EL0 && !sctlr.ntwe) { } else if (cpsr.el == EL0 && !sctlr.ntwe) {
PseudoInst::quiesceSkip(tc); PseudoInst::quiesceSkip(tc);
@ -692,8 +693,8 @@ let {{
// WFI doesn't sleep if interrupts are pending (masked or not) // WFI doesn't sleep if interrupts are pending (masked or not)
ThreadContext *tc = xc->tcBase(); ThreadContext *tc = xc->tcBase();
if (tc->getCpuPtr()->getInterruptController()->checkWfiWake(hcr, cpsr, if (tc->getCpuPtr()->getInterruptController(
scr)) { tc->threadId())->checkWfiWake(hcr, cpsr, scr)) {
PseudoInst::quiesceSkip(tc); PseudoInst::quiesceSkip(tc);
} else if (cpsr.el == EL0 && !sctlr.ntwi) { } else if (cpsr.el == EL0 && !sctlr.ntwi) {
PseudoInst::quiesceSkip(tc); PseudoInst::quiesceSkip(tc);
@ -711,7 +712,7 @@ let {{
} else { } else {
PseudoInst::quiesce(tc); PseudoInst::quiesce(tc);
} }
tc->getCpuPtr()->clearInterrupt(INT_ABT, 0); tc->getCpuPtr()->clearInterrupt(tc->threadId(), INT_ABT, 0);
''' '''
wfiIop = InstObjParams("wfi", "WfiInst", "PredOp", \ wfiIop = InstObjParams("wfi", "WfiInst", "PredOp", \
{ "code" : wfiCode, "predicate_test" : predicateTest }, { "code" : wfiCode, "predicate_test" : predicateTest },
@ -731,7 +732,7 @@ let {{
// Wake CPU with interrupt if they were sleeping // Wake CPU with interrupt if they were sleeping
if (oc->readMiscReg(MISCREG_SEV_MAILBOX) == 0) { if (oc->readMiscReg(MISCREG_SEV_MAILBOX) == 0) {
// Post Interrupt and wake cpu if needed // Post Interrupt and wake cpu if needed
oc->getCpuPtr()->postInterrupt(INT_SEV, 0); oc->getCpuPtr()->postInterrupt(oc->threadId(), INT_SEV, 0);
} }
} }
''' '''

View file

@ -591,9 +591,9 @@ ISA::setMiscReg(int miscReg, MiscReg val, ThreadContext * tc)
{ {
tl = val; tl = val;
if (hpstate.tlz && tl == 0 && !hpstate.hpriv) if (hpstate.tlz && tl == 0 && !hpstate.hpriv)
tc->getCpuPtr()->postInterrupt(IT_TRAP_LEVEL_ZERO, 0); tc->getCpuPtr()->postInterrupt(0, IT_TRAP_LEVEL_ZERO, 0);
else else
tc->getCpuPtr()->clearInterrupt(IT_TRAP_LEVEL_ZERO, 0); tc->getCpuPtr()->clearInterrupt(0, IT_TRAP_LEVEL_ZERO, 0);
return; return;
} }
case MISCREG_CWP: case MISCREG_CWP:

View file

@ -1022,7 +1022,7 @@ TLB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
{ {
SparcISA::Interrupts * interrupts = SparcISA::Interrupts * interrupts =
dynamic_cast<SparcISA::Interrupts *>( dynamic_cast<SparcISA::Interrupts *>(
tc->getCpuPtr()->getInterruptController()); tc->getCpuPtr()->getInterruptController(0));
pkt->set(interrupts->get_vec(IT_INT_VEC)); pkt->set(interrupts->get_vec(IT_INT_VEC));
} }
break; break;
@ -1030,9 +1030,9 @@ TLB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
{ {
SparcISA::Interrupts * interrupts = SparcISA::Interrupts * interrupts =
dynamic_cast<SparcISA::Interrupts *>( dynamic_cast<SparcISA::Interrupts *>(
tc->getCpuPtr()->getInterruptController()); tc->getCpuPtr()->getInterruptController(0));
temp = findMsbSet(interrupts->get_vec(IT_INT_VEC)); temp = findMsbSet(interrupts->get_vec(IT_INT_VEC));
tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, temp); tc->getCpuPtr()->clearInterrupt(0, IT_INT_VEC, temp);
pkt->set(temp); pkt->set(temp);
} }
break; break;
@ -1278,16 +1278,16 @@ TLB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
// clear all the interrupts that aren't set in the write // clear all the interrupts that aren't set in the write
SparcISA::Interrupts * interrupts = SparcISA::Interrupts * interrupts =
dynamic_cast<SparcISA::Interrupts *>( dynamic_cast<SparcISA::Interrupts *>(
tc->getCpuPtr()->getInterruptController()); tc->getCpuPtr()->getInterruptController(0));
while (interrupts->get_vec(IT_INT_VEC) & data) { while (interrupts->get_vec(IT_INT_VEC) & data) {
msb = findMsbSet(interrupts->get_vec(IT_INT_VEC) & data); msb = findMsbSet(interrupts->get_vec(IT_INT_VEC) & data);
tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, msb); tc->getCpuPtr()->clearInterrupt(0, IT_INT_VEC, msb);
} }
} }
break; break;
case ASI_SWVR_UDB_INTR_W: case ASI_SWVR_UDB_INTR_W:
tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()-> tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()->
postInterrupt(bits(data, 5, 0), 0); postInterrupt(0, bits(data, 5, 0), 0);
break; break;
default: default:
doMmuWriteError: doMmuWriteError:

View file

@ -49,20 +49,20 @@ ISA::checkSoftInt(ThreadContext *tc)
// If PIL < 14, copy over the tm and sm bits // If PIL < 14, copy over the tm and sm bits
if (pil < 14 && softint & 0x10000) if (pil < 14 && softint & 0x10000)
cpu->postInterrupt(IT_SOFT_INT, 16); cpu->postInterrupt(0, IT_SOFT_INT, 16);
else else
cpu->clearInterrupt(IT_SOFT_INT, 16); cpu->clearInterrupt(0, IT_SOFT_INT, 16);
if (pil < 14 && softint & 0x1) if (pil < 14 && softint & 0x1)
cpu->postInterrupt(IT_SOFT_INT, 0); cpu->postInterrupt(0, IT_SOFT_INT, 0);
else else
cpu->clearInterrupt(IT_SOFT_INT, 0); cpu->clearInterrupt(0, IT_SOFT_INT, 0);
// Copy over any of the other bits that are set // Copy over any of the other bits that are set
for (int bit = 15; bit > 0; --bit) { for (int bit = 15; bit > 0; --bit) {
if (1 << bit & softint && bit > pil) if (1 << bit & softint && bit > pil)
cpu->postInterrupt(IT_SOFT_INT, bit); cpu->postInterrupt(0, IT_SOFT_INT, bit);
else else
cpu->clearInterrupt(IT_SOFT_INT, bit); cpu->clearInterrupt(0, IT_SOFT_INT, bit);
} }
} }
@ -149,9 +149,9 @@ ISA::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
case MISCREG_HINTP: case MISCREG_HINTP:
setMiscRegNoEffect(miscReg, val); setMiscRegNoEffect(miscReg, val);
if (hintp) if (hintp)
cpu->postInterrupt(IT_HINTP, 0); cpu->postInterrupt(0, IT_HINTP, 0);
else else
cpu->clearInterrupt(IT_HINTP, 0); cpu->clearInterrupt(0, IT_HINTP, 0);
break; break;
case MISCREG_HTBA: case MISCREG_HTBA:
@ -163,25 +163,25 @@ ISA::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
case MISCREG_QUEUE_CPU_MONDO_TAIL: case MISCREG_QUEUE_CPU_MONDO_TAIL:
setMiscRegNoEffect(miscReg, val); setMiscRegNoEffect(miscReg, val);
if (cpu_mondo_head != cpu_mondo_tail) if (cpu_mondo_head != cpu_mondo_tail)
cpu->postInterrupt(IT_CPU_MONDO, 0); cpu->postInterrupt(0, IT_CPU_MONDO, 0);
else else
cpu->clearInterrupt(IT_CPU_MONDO, 0); cpu->clearInterrupt(0, IT_CPU_MONDO, 0);
break; break;
case MISCREG_QUEUE_DEV_MONDO_HEAD: case MISCREG_QUEUE_DEV_MONDO_HEAD:
case MISCREG_QUEUE_DEV_MONDO_TAIL: case MISCREG_QUEUE_DEV_MONDO_TAIL:
setMiscRegNoEffect(miscReg, val); setMiscRegNoEffect(miscReg, val);
if (dev_mondo_head != dev_mondo_tail) if (dev_mondo_head != dev_mondo_tail)
cpu->postInterrupt(IT_DEV_MONDO, 0); cpu->postInterrupt(0, IT_DEV_MONDO, 0);
else else
cpu->clearInterrupt(IT_DEV_MONDO, 0); cpu->clearInterrupt(0, IT_DEV_MONDO, 0);
break; break;
case MISCREG_QUEUE_RES_ERROR_HEAD: case MISCREG_QUEUE_RES_ERROR_HEAD:
case MISCREG_QUEUE_RES_ERROR_TAIL: case MISCREG_QUEUE_RES_ERROR_TAIL:
setMiscRegNoEffect(miscReg, val); setMiscRegNoEffect(miscReg, val);
if (res_error_head != res_error_tail) if (res_error_head != res_error_tail)
cpu->postInterrupt(IT_RES_ERROR, 0); cpu->postInterrupt(0, IT_RES_ERROR, 0);
else else
cpu->clearInterrupt(IT_RES_ERROR, 0); cpu->clearInterrupt(0, IT_RES_ERROR, 0);
break; break;
case MISCREG_QUEUE_NRES_ERROR_HEAD: case MISCREG_QUEUE_NRES_ERROR_HEAD:
case MISCREG_QUEUE_NRES_ERROR_TAIL: case MISCREG_QUEUE_NRES_ERROR_TAIL:
@ -213,9 +213,9 @@ ISA::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
setMiscRegNoEffect(miscReg, newVal); setMiscRegNoEffect(miscReg, newVal);
newVal = hpstate; newVal = hpstate;
if (newVal.tlz && tl == 0 && !newVal.hpriv) if (newVal.tlz && tl == 0 && !newVal.hpriv)
cpu->postInterrupt(IT_TRAP_LEVEL_ZERO, 0); cpu->postInterrupt(0, IT_TRAP_LEVEL_ZERO, 0);
else else
cpu->clearInterrupt(IT_TRAP_LEVEL_ZERO, 0); cpu->clearInterrupt(0, IT_TRAP_LEVEL_ZERO, 0);
break; break;
} }
case MISCREG_HTSTATE: case MISCREG_HTSTATE:

View file

@ -183,7 +183,7 @@ void initCPU(ThreadContext *tc, int cpuId)
tc->setMiscReg(MISCREG_APIC_BASE, lApicBase); tc->setMiscReg(MISCREG_APIC_BASE, lApicBase);
Interrupts * interrupts = dynamic_cast<Interrupts *>( Interrupts * interrupts = dynamic_cast<Interrupts *>(
tc->getCpuPtr()->getInterruptController()); tc->getCpuPtr()->getInterruptController(0));
assert(interrupts); assert(interrupts);
interrupts->setRegNoEffect(APIC_ID, cpuId << 24); interrupts->setRegNoEffect(APIC_ID, cpuId << 24);

View file

@ -149,40 +149,40 @@ class BaseCPU(MemObject):
if buildEnv['TARGET_ISA'] == 'sparc': if buildEnv['TARGET_ISA'] == 'sparc':
dtb = Param.SparcTLB(SparcTLB(), "Data TLB") dtb = Param.SparcTLB(SparcTLB(), "Data TLB")
itb = Param.SparcTLB(SparcTLB(), "Instruction TLB") itb = Param.SparcTLB(SparcTLB(), "Instruction TLB")
interrupts = Param.SparcInterrupts( interrupts = VectorParam.SparcInterrupts(
NULL, "Interrupt Controller") [], "Interrupt Controller")
isa = VectorParam.SparcISA([ isa_class() ], "ISA instance") isa = VectorParam.SparcISA([ isa_class() ], "ISA instance")
elif buildEnv['TARGET_ISA'] == 'alpha': elif buildEnv['TARGET_ISA'] == 'alpha':
dtb = Param.AlphaTLB(AlphaDTB(), "Data TLB") dtb = Param.AlphaTLB(AlphaDTB(), "Data TLB")
itb = Param.AlphaTLB(AlphaITB(), "Instruction TLB") itb = Param.AlphaTLB(AlphaITB(), "Instruction TLB")
interrupts = Param.AlphaInterrupts( interrupts = VectorParam.AlphaInterrupts(
NULL, "Interrupt Controller") [], "Interrupt Controller")
isa = VectorParam.AlphaISA([ isa_class() ], "ISA instance") isa = VectorParam.AlphaISA([ isa_class() ], "ISA instance")
elif buildEnv['TARGET_ISA'] == 'x86': elif buildEnv['TARGET_ISA'] == 'x86':
dtb = Param.X86TLB(X86TLB(), "Data TLB") dtb = Param.X86TLB(X86TLB(), "Data TLB")
itb = Param.X86TLB(X86TLB(), "Instruction TLB") itb = Param.X86TLB(X86TLB(), "Instruction TLB")
interrupts = Param.X86LocalApic(NULL, "Interrupt Controller") interrupts = VectorParam.X86LocalApic([], "Interrupt Controller")
isa = VectorParam.X86ISA([ isa_class() ], "ISA instance") isa = VectorParam.X86ISA([ isa_class() ], "ISA instance")
elif buildEnv['TARGET_ISA'] == 'mips': elif buildEnv['TARGET_ISA'] == 'mips':
dtb = Param.MipsTLB(MipsTLB(), "Data TLB") dtb = Param.MipsTLB(MipsTLB(), "Data TLB")
itb = Param.MipsTLB(MipsTLB(), "Instruction TLB") itb = Param.MipsTLB(MipsTLB(), "Instruction TLB")
interrupts = Param.MipsInterrupts( interrupts = VectorParam.MipsInterrupts(
NULL, "Interrupt Controller") [], "Interrupt Controller")
isa = VectorParam.MipsISA([ isa_class() ], "ISA instance") isa = VectorParam.MipsISA([ isa_class() ], "ISA instance")
elif buildEnv['TARGET_ISA'] == 'arm': elif buildEnv['TARGET_ISA'] == 'arm':
dtb = Param.ArmTLB(ArmTLB(), "Data TLB") dtb = Param.ArmTLB(ArmTLB(), "Data TLB")
itb = Param.ArmTLB(ArmTLB(), "Instruction TLB") itb = Param.ArmTLB(ArmTLB(), "Instruction TLB")
istage2_mmu = Param.ArmStage2MMU(ArmStage2IMMU(), "Stage 2 trans") istage2_mmu = Param.ArmStage2MMU(ArmStage2IMMU(), "Stage 2 trans")
dstage2_mmu = Param.ArmStage2MMU(ArmStage2DMMU(), "Stage 2 trans") dstage2_mmu = Param.ArmStage2MMU(ArmStage2DMMU(), "Stage 2 trans")
interrupts = Param.ArmInterrupts( interrupts = VectorParam.ArmInterrupts(
NULL, "Interrupt Controller") [], "Interrupt Controller")
isa = VectorParam.ArmISA([ isa_class() ], "ISA instance") isa = VectorParam.ArmISA([ isa_class() ], "ISA instance")
elif buildEnv['TARGET_ISA'] == 'power': elif buildEnv['TARGET_ISA'] == 'power':
UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?") UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
dtb = Param.PowerTLB(PowerTLB(), "Data TLB") dtb = Param.PowerTLB(PowerTLB(), "Data TLB")
itb = Param.PowerTLB(PowerTLB(), "Instruction TLB") itb = Param.PowerTLB(PowerTLB(), "Instruction TLB")
interrupts = Param.PowerInterrupts( interrupts = VectorParam.PowerInterrupts(
NULL, "Interrupt Controller") [], "Interrupt Controller")
isa = VectorParam.PowerISA([ isa_class() ], "ISA instance") isa = VectorParam.PowerISA([ isa_class() ], "ISA instance")
else: else:
print "Don't know what TLB to use for ISA %s" % \ print "Don't know what TLB to use for ISA %s" % \
@ -218,27 +218,29 @@ class BaseCPU(MemObject):
_uncached_slave_ports = [] _uncached_slave_ports = []
_uncached_master_ports = [] _uncached_master_ports = []
if buildEnv['TARGET_ISA'] == 'x86': if buildEnv['TARGET_ISA'] == 'x86':
_uncached_slave_ports += ["interrupts.pio", "interrupts.int_slave"] _uncached_slave_ports += ["interrupts[0].pio",
_uncached_master_ports += ["interrupts.int_master"] "interrupts[0].int_slave"]
_uncached_master_ports += ["interrupts[0].int_master"]
def createInterruptController(self): def createInterruptController(self):
if buildEnv['TARGET_ISA'] == 'sparc': if buildEnv['TARGET_ISA'] == 'sparc':
self.interrupts = SparcInterrupts() self.interrupts = [SparcInterrupts() for i in xrange(self.numThreads)]
elif buildEnv['TARGET_ISA'] == 'alpha': elif buildEnv['TARGET_ISA'] == 'alpha':
self.interrupts = AlphaInterrupts() self.interrupts = [AlphaInterrupts() for i in xrange(self.numThreads)]
elif buildEnv['TARGET_ISA'] == 'x86': elif buildEnv['TARGET_ISA'] == 'x86':
self.apic_clk_domain = DerivedClockDomain(clk_domain = self.apic_clk_domain = DerivedClockDomain(clk_domain =
Parent.clk_domain, Parent.clk_domain,
clk_divider = 16) clk_divider = 16)
self.interrupts = X86LocalApic(clk_domain = self.apic_clk_domain, self.interrupts = [X86LocalApic(clk_domain = self.apic_clk_domain,
pio_addr=0x2000000000000000) pio_addr=0x2000000000000000)
for i in xrange(self.numThreads)]
_localApic = self.interrupts _localApic = self.interrupts
elif buildEnv['TARGET_ISA'] == 'mips': elif buildEnv['TARGET_ISA'] == 'mips':
self.interrupts = MipsInterrupts() self.interrupts = [MipsInterrupts() for i in xrange(self.numThreads)]
elif buildEnv['TARGET_ISA'] == 'arm': elif buildEnv['TARGET_ISA'] == 'arm':
self.interrupts = ArmInterrupts() self.interrupts = [ArmInterrupts() for i in xrange(self.numThreads)]
elif buildEnv['TARGET_ISA'] == 'power': elif buildEnv['TARGET_ISA'] == 'power':
self.interrupts = PowerInterrupts() self.interrupts = [PowerInterrupts() for i in xrange(self.numThreads)]
else: else:
print "Don't know what Interrupt Controller to use for ISA %s" % \ print "Don't know what Interrupt Controller to use for ISA %s" % \
buildEnv['TARGET_ISA'] buildEnv['TARGET_ISA']

View file

@ -237,8 +237,10 @@ BaseCPU::BaseCPU(Params *p, bool is_checker)
// The interrupts should always be present unless this CPU is // The interrupts should always be present unless this CPU is
// switched in later or in case it is a checker CPU // switched in later or in case it is a checker CPU
if (!params()->switched_out && !is_checker) { if (!params()->switched_out && !is_checker) {
if (interrupts) { if (!interrupts.empty()) {
interrupts->setCPU(this); for (ThreadID tid = 0; tid < numThreads; tid++) {
interrupts[tid]->setCPU(this);
}
} else { } else {
fatal("CPU %s has no interrupt controller.\n" fatal("CPU %s has no interrupt controller.\n"
"Ensure createInterruptController() is called.\n", name()); "Ensure createInterruptController() is called.\n", name());
@ -583,8 +585,10 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
} }
interrupts = oldCPU->interrupts; interrupts = oldCPU->interrupts;
interrupts->setCPU(this); for (ThreadID tid = 0; tid < numThreads; tid++) {
oldCPU->interrupts = NULL; interrupts[tid]->setCPU(this);
}
oldCPU->interrupts.clear();
if (FullSystem) { if (FullSystem) {
for (ThreadID i = 0; i < size; ++i) for (ThreadID i = 0; i < size; ++i)
@ -656,11 +660,10 @@ BaseCPU::serialize(CheckpointOut &cp) const
* system. */ * system. */
SERIALIZE_SCALAR(_pid); SERIALIZE_SCALAR(_pid);
interrupts->serialize(cp);
// Serialize the threads, this is done by the CPU implementation. // Serialize the threads, this is done by the CPU implementation.
for (ThreadID i = 0; i < numThreads; ++i) { for (ThreadID i = 0; i < numThreads; ++i) {
ScopedCheckpointSection sec(cp, csprintf("xc.%i", i)); ScopedCheckpointSection sec(cp, csprintf("xc.%i", i));
interrupts[i]->serialize(cp);
serializeThread(cp, i); serializeThread(cp, i);
} }
} }
@ -673,11 +676,11 @@ BaseCPU::unserialize(CheckpointIn &cp)
if (!_switchedOut) { if (!_switchedOut) {
UNSERIALIZE_SCALAR(_pid); UNSERIALIZE_SCALAR(_pid);
interrupts->unserialize(cp);
// Unserialize the threads, this is done by the CPU implementation. // Unserialize the threads, this is done by the CPU implementation.
for (ThreadID i = 0; i < numThreads; ++i) { for (ThreadID i = 0; i < numThreads; ++i) {
ScopedCheckpointSection sec(cp, csprintf("xc.%i", i)); ScopedCheckpointSection sec(cp, csprintf("xc.%i", i));
interrupts[i]->unserialize(cp);
unserializeThread(cp, i); unserializeThread(cp, i);
} }
} }

View file

@ -207,41 +207,45 @@ class BaseCPU : public MemObject
TheISA::MicrocodeRom microcodeRom; TheISA::MicrocodeRom microcodeRom;
protected: protected:
TheISA::Interrupts *interrupts; std::vector<TheISA::Interrupts*> interrupts;
public: public:
TheISA::Interrupts * TheISA::Interrupts *
getInterruptController() getInterruptController(ThreadID tid)
{ {
return interrupts; if (interrupts.empty())
return NULL;
assert(interrupts.size() > tid);
return interrupts[tid];
} }
virtual void wakeup() = 0; virtual void wakeup() = 0;
void void
postInterrupt(int int_num, int index) postInterrupt(ThreadID tid, int int_num, int index)
{ {
interrupts->post(int_num, index); interrupts[tid]->post(int_num, index);
if (FullSystem) if (FullSystem)
wakeup(); wakeup();
} }
void void
clearInterrupt(int int_num, int index) clearInterrupt(ThreadID tid, int int_num, int index)
{ {
interrupts->clear(int_num, index); interrupts[tid]->clear(int_num, index);
} }
void void
clearInterrupts() clearInterrupts(ThreadID tid)
{ {
interrupts->clearAll(); interrupts[tid]->clearAll();
} }
bool bool
checkInterrupts(ThreadContext *tc) const checkInterrupts(ThreadContext *tc) const
{ {
return FullSystem && interrupts->checkInterrupts(tc); return FullSystem && interrupts[tc->threadId()]->checkInterrupts(tc);
} }
class ProfileEvent : public Event class ProfileEvent : public Event

View file

@ -73,7 +73,6 @@ DummyCheckerParams::create()
params->system = system; params->system = system;
params->cpu_id = cpu_id; params->cpu_id = cpu_id;
params->profile = profile; params->profile = profile;
params->interrupts = NULL;
params->workload = workload; params->workload = workload;
DummyChecker *cpu = new DummyChecker(params); DummyChecker *cpu = new DummyChecker(params);

View file

@ -51,7 +51,7 @@ IntrControl::post(int cpu_id, int int_num, int index)
DPRINTF(IntrControl, "post %d:%d (cpu %d)\n", int_num, index, cpu_id); DPRINTF(IntrControl, "post %d:%d (cpu %d)\n", int_num, index, cpu_id);
std::vector<ThreadContext *> &tcvec = sys->threadContexts; std::vector<ThreadContext *> &tcvec = sys->threadContexts;
BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr(); BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr();
cpu->postInterrupt(int_num, index); cpu->postInterrupt(tcvec[cpu_id]->threadId(), int_num, index);
} }
void void
@ -60,7 +60,7 @@ IntrControl::clear(int cpu_id, int int_num, int index)
DPRINTF(IntrControl, "clear %d:%d (cpu %d)\n", int_num, index, cpu_id); DPRINTF(IntrControl, "clear %d:%d (cpu %d)\n", int_num, index, cpu_id);
std::vector<ThreadContext *> &tcvec = sys->threadContexts; std::vector<ThreadContext *> &tcvec = sys->threadContexts;
BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr(); BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr();
cpu->clearInterrupt(int_num, index); cpu->clearInterrupt(tcvec[cpu_id]->threadId(), int_num, index);
} }
IntrControl * IntrControl *

View file

@ -1142,9 +1142,9 @@ X86KvmCPU::deliverInterrupts()
// call across threads, we might still lose interrupts unless // call across threads, we might still lose interrupts unless
// they are getInterrupt() and updateIntrInfo() are called // they are getInterrupt() and updateIntrInfo() are called
// atomically. // atomically.
EventQueue::ScopedMigration migrate(interrupts->eventQueue()); EventQueue::ScopedMigration migrate(interrupts[0]->eventQueue());
fault = interrupts->getInterrupt(tc); fault = interrupts[0]->getInterrupt(tc);
interrupts->updateIntrInfo(tc); interrupts[0]->updateIntrInfo(tc);
} }
X86Interrupt *x86int(dynamic_cast<X86Interrupt *>(fault.get())); X86Interrupt *x86int(dynamic_cast<X86Interrupt *>(fault.get()));
@ -1187,8 +1187,8 @@ X86KvmCPU::kvmRun(Tick ticks)
{ {
struct kvm_run &kvm_run(*getKvmRunState()); struct kvm_run &kvm_run(*getKvmRunState());
if (interrupts->checkInterruptsRaw()) { if (interrupts[0]->checkInterruptsRaw()) {
if (interrupts->hasPendingUnmaskable()) { if (interrupts[0]->hasPendingUnmaskable()) {
DPRINTF(KvmInt, DPRINTF(KvmInt,
"Delivering unmaskable interrupt.\n"); "Delivering unmaskable interrupt.\n");
syncThreadContext(); syncThreadContext();
@ -1200,7 +1200,7 @@ X86KvmCPU::kvmRun(Tick ticks)
// the thread context and check if there are /really/ // the thread context and check if there are /really/
// interrupts that should be delivered now. // interrupts that should be delivered now.
syncThreadContext(); syncThreadContext();
if (interrupts->checkInterrupts(tc)) { if (interrupts[0]->checkInterrupts(tc)) {
DPRINTF(KvmInt, DPRINTF(KvmInt,
"M5 has pending interrupts, delivering interrupt.\n"); "M5 has pending interrupts, delivering interrupt.\n");

View file

@ -403,12 +403,12 @@ Execute::takeInterrupt(ThreadID thread_id, BranchData &branch)
DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n", DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n",
cpu.getContext(thread_id)->pcState()); cpu.getContext(thread_id)->pcState());
Fault interrupt = cpu.getInterruptController()->getInterrupt Fault interrupt = cpu.getInterruptController(thread_id)->getInterrupt
(cpu.getContext(thread_id)); (cpu.getContext(thread_id));
if (interrupt != NoFault) { if (interrupt != NoFault) {
/* The interrupt *must* set pcState */ /* The interrupt *must* set pcState */
cpu.getInterruptController()->updateIntrInfo cpu.getInterruptController(thread_id)->updateIntrInfo
(cpu.getContext(thread_id)); (cpu.getContext(thread_id));
interrupt->invoke(cpu.getContext(thread_id)); interrupt->invoke(cpu.getContext(thread_id));
@ -1391,7 +1391,7 @@ Execute::evaluate()
/* If there was an interrupt signalled, was it acted on now? */ /* If there was an interrupt signalled, was it acted on now? */
bool took_interrupt = false; bool took_interrupt = false;
if (cpu.getInterruptController()) { if (cpu.getInterruptController(0)) {
/* This is here because it seems that after drainResume the /* This is here because it seems that after drainResume the
* interrupt controller isn't always set */ * interrupt controller isn't always set */
interrupted = drainState == NotDraining && isInterrupted(0); interrupted = drainState == NotDraining && isInterrupted(0);

View file

@ -86,7 +86,6 @@ O3CheckerParams::create()
params->system = system; params->system = system;
params->cpu_id = cpu_id; params->cpu_id = cpu_id;
params->profile = profile; params->profile = profile;
params->interrupts = NULL;
params->workload = workload; params->workload = workload;
O3Checker *cpu = new O3Checker(params); O3Checker *cpu = new O3Checker(params);

View file

@ -392,7 +392,7 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
} }
// FullO3CPU always requires an interrupt controller. // FullO3CPU always requires an interrupt controller.
if (!params->switched_out && !interrupts) { if (!params->switched_out && interrupts.empty()) {
fatal("FullO3CPU %s has no interrupt controller.\n" fatal("FullO3CPU %s has no interrupt controller.\n"
"Ensure createInterruptController() is called.\n", name()); "Ensure createInterruptController() is called.\n", name());
} }
@ -935,7 +935,7 @@ Fault
FullO3CPU<Impl>::getInterrupts() FullO3CPU<Impl>::getInterrupts()
{ {
// Check if there are any outstanding interrupts // Check if there are any outstanding interrupts
return this->interrupts->getInterrupt(this->threadContexts[0]); return this->interrupts[0]->getInterrupt(this->threadContexts[0]);
} }
template <class Impl> template <class Impl>
@ -949,7 +949,7 @@ FullO3CPU<Impl>::processInterrupts(const Fault &interrupt)
// @todo: Allow other threads to handle interrupts. // @todo: Allow other threads to handle interrupts.
assert(interrupt != NoFault); assert(interrupt != NoFault);
this->interrupts->updateIntrInfo(this->threadContexts[0]); this->interrupts[0]->updateIntrInfo(this->threadContexts[0]);
DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
this->trap(interrupt, 0, nullptr); this->trap(interrupt, 0, nullptr);

View file

@ -435,11 +435,11 @@ BaseSimpleCPU::checkForInterrupts()
ThreadContext* tc = thread->getTC(); ThreadContext* tc = thread->getTC();
if (checkInterrupts(tc)) { if (checkInterrupts(tc)) {
Fault interrupt = interrupts->getInterrupt(tc); Fault interrupt = interrupts[curThread]->getInterrupt(tc);
if (interrupt != NoFault) { if (interrupt != NoFault) {
t_info.fetchOffset = 0; t_info.fetchOffset = 0;
interrupts->updateIntrInfo(tc); interrupts[curThread]->updateIntrInfo(tc);
interrupt->invoke(tc); interrupt->invoke(tc);
thread->decoder.reset(); thread->decoder.reset();
} }

View file

@ -224,7 +224,7 @@ X86ISA::I82094AA::signalInterrupt(int line)
} else { } else {
for (int i = 0; i < numContexts; i++) { for (int i = 0; i < numContexts; i++) {
Interrupts *localApic = sys->getThreadContext(i)-> Interrupts *localApic = sys->getThreadContext(i)->
getCpuPtr()->getInterruptController(); getCpuPtr()->getInterruptController(0);
if ((localApic->readReg(APIC_LOGICAL_DESTINATION) >> 24) & if ((localApic->readReg(APIC_LOGICAL_DESTINATION) >> 24) &
message.destination) { message.destination) {
apics.push_back(localApic->getInitialApicId()); apics.push_back(localApic->getInitialApicId());

View file

@ -87,9 +87,9 @@ for (i, cpu) in enumerate(system.cpu):
cpu.itb.walker.port = system.ruby._cpu_ports[i].slave cpu.itb.walker.port = system.ruby._cpu_ports[i].slave
cpu.dtb.walker.port = system.ruby._cpu_ports[i].slave cpu.dtb.walker.port = system.ruby._cpu_ports[i].slave
cpu.interrupts.pio = system.ruby._cpu_ports[i].master cpu.interrupts[0].pio = system.ruby._cpu_ports[i].master
cpu.interrupts.int_master = system.ruby._cpu_ports[i].slave cpu.interrupts[0].int_master = system.ruby._cpu_ports[i].slave
cpu.interrupts.int_slave = system.ruby._cpu_ports[i].master cpu.interrupts[0].int_slave = system.ruby._cpu_ports[i].master
root = Root(full_system = True, system = system) root = Root(full_system = True, system = system)
m5.ticks.setGlobalFrequency('1THz') m5.ticks.setGlobalFrequency('1THz')

View file

@ -0,0 +1,19 @@
# Upgrade single-threaded checkpoints to be properly supported with SMT.
# SMT adds per-thread interrupts. Thus we must move the interrupt status
# from the CPU and into the execution context.
def upgrader(cpt):
for sec in cpt.sections():
import re
re_cpu_match = re.match('^(.*sys.*\.cpu[^._]*)$', sec)
if re_cpu_match != None:
interrupts = cpt.get(sec, 'interrupts')
intStatus = cpt.get(sec, 'intStatus')
cpu_name = re_cpu_match.group(1)
cpt.set(cpu_name + ".xc.0", 'interrupts', interrupts)
cpt.set(cpu_name + ".xc.0", 'intStatus', intStatus)
cpt.remove_option(sec, 'interrupts')
cpt.remove_option(sec, 'intStatus')