x86: Turn the local APIC Interrupts class into a SimObject.
It will no longer be a PioDevice or a ClockedObject, but will carry forward the little bits and pieces of those classes that it was using. Those are a PIO port for memory mapped register accesses, and a clock domain parameter for setting the apic tick frequency. This brings the x86 Interrupts class in line with the Interrupts of the other ISAs so that they can inherit from a standard base class. Change-Id: I6b25fa21911b39a756e0cf9408c5489a81d6ca56 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/20829 Reviewed-by: Jason Lowe-Power <jason@lowepower.com> Reviewed-by: Brandon Potter <Brandon.Potter@amd.com> Maintainer: Jason Lowe-Power <jason@lowepower.com> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
@@ -42,10 +42,10 @@ from m5.defines import buildEnv
|
||||
from m5.params import *
|
||||
from m5.proxy import *
|
||||
|
||||
from m5.objects.Device import PioDevice
|
||||
from m5.objects.ClockDomain import DerivedClockDomain
|
||||
from m5.SimObject import SimObject
|
||||
|
||||
class X86LocalApic(PioDevice):
|
||||
class X86LocalApic(SimObject):
|
||||
type = 'X86LocalApic'
|
||||
cxx_class = 'X86ISA::Interrupts'
|
||||
cxx_header = 'arch/x86/interrupts.hh'
|
||||
@@ -53,6 +53,8 @@ class X86LocalApic(PioDevice):
|
||||
int_slave = SlavePort("Port for receiving interrupt messages")
|
||||
int_latency = Param.Latency('1ns', \
|
||||
"Latency for an interrupt to propagate through this device.")
|
||||
pio = SlavePort("Programmed I/O port")
|
||||
system = Param.System(Parent.any, "System this device is part of")
|
||||
|
||||
pio_latency = Param.Latency('100ns', 'Programmed IO latency')
|
||||
|
||||
@@ -60,5 +62,6 @@ class X86LocalApic(PioDevice):
|
||||
# which we assume is 1/16th the rate of the CPU clock. I don't think this
|
||||
# is a hard rule, but seems to be true in practice. This can be overriden
|
||||
# in configs that use it.
|
||||
clk_domain = DerivedClockDomain(
|
||||
clk_domain=Parent.clk_domain, clk_divider=16)
|
||||
clk_domain = Param.DerivedClockDomain(
|
||||
DerivedClockDomain(clk_domain=Parent.clk_domain, clk_divider=16),
|
||||
"The clock for the local APIC. Should not be modified.")
|
||||
|
||||
@@ -290,16 +290,13 @@ X86ISA::Interrupts::setCPU(BaseCPU * newCPU)
|
||||
void
|
||||
X86ISA::Interrupts::init()
|
||||
{
|
||||
//
|
||||
// The local apic must register its address ranges on its pio
|
||||
// port via the basicpiodevice(piodevice) init() function.
|
||||
PioDevice::init();
|
||||
|
||||
// The slave port has a range, so inform the connected master.
|
||||
intSlavePort.sendRangeChange();
|
||||
// If the master port isn't connected, we can't send interrupts anywhere.
|
||||
panic_if(!intMasterPort.isConnected(),
|
||||
"Int port not connected to anything!");
|
||||
panic_if(!pioPort.isConnected(),
|
||||
"Pio port of %s not connected to anything!", name());
|
||||
|
||||
intSlavePort.sendRangeChange();
|
||||
pioPort.sendRangeChange();
|
||||
}
|
||||
|
||||
|
||||
@@ -599,7 +596,7 @@ X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
|
||||
|
||||
|
||||
X86ISA::Interrupts::Interrupts(Params * p)
|
||||
: PioDevice(p),
|
||||
: SimObject(p), sys(p->system), clockDomain(*p->clk_domain),
|
||||
apicTimerEvent([this]{ processApicTimerEvent(); }, name()),
|
||||
pendingSmi(false), smiVector(0),
|
||||
pendingNmi(false), nmiVector(0),
|
||||
@@ -610,7 +607,7 @@ X86ISA::Interrupts::Interrupts(Params * p)
|
||||
pendingIPIs(0), cpu(NULL),
|
||||
intSlavePort(name() + ".int_slave", this, this),
|
||||
intMasterPort(name() + ".int_master", this, this, p->int_latency),
|
||||
pioDelay(p->pio_latency)
|
||||
pioPort(this), pioDelay(p->pio_latency)
|
||||
{
|
||||
memset(regs, 0, sizeof(regs));
|
||||
//Set the local apic DFR to the flat model.
|
||||
|
||||
@@ -72,9 +72,12 @@ namespace X86ISA {
|
||||
|
||||
ApicRegIndex decodeAddr(Addr paddr);
|
||||
|
||||
class Interrupts : public PioDevice
|
||||
class Interrupts : public SimObject
|
||||
{
|
||||
protected:
|
||||
System *sys;
|
||||
ClockDomain &clockDomain;
|
||||
|
||||
// Storage for the APIC registers
|
||||
uint32_t regs[NUM_APIC_REGS];
|
||||
|
||||
@@ -165,6 +168,8 @@ class Interrupts : public PioDevice
|
||||
return bits(regs[base + (vector / 32)], vector % 32);
|
||||
}
|
||||
|
||||
Tick clockPeriod() const { return clockDomain.clockPeriod(); }
|
||||
|
||||
void requestInterrupt(uint8_t vector, uint8_t deliveryMode, bool level);
|
||||
|
||||
BaseCPU *cpu;
|
||||
@@ -175,6 +180,9 @@ class Interrupts : public PioDevice
|
||||
IntSlavePort<Interrupts> intSlavePort;
|
||||
IntMasterPort<Interrupts> intMasterPort;
|
||||
|
||||
// Port for memory mapped register accesses.
|
||||
PioPort<Interrupts> pioPort;
|
||||
|
||||
Tick pioDelay;
|
||||
Addr pioAddr = MaxAddr;
|
||||
|
||||
@@ -203,8 +211,8 @@ class Interrupts : public PioDevice
|
||||
/*
|
||||
* Functions to interact with the interrupt port.
|
||||
*/
|
||||
Tick read(PacketPtr pkt) override;
|
||||
Tick write(PacketPtr pkt) override;
|
||||
Tick read(PacketPtr pkt);
|
||||
Tick write(PacketPtr pkt);
|
||||
Tick recvMessage(PacketPtr pkt);
|
||||
void completeIPI(PacketPtr pkt);
|
||||
|
||||
@@ -217,7 +225,7 @@ class Interrupts : public PioDevice
|
||||
return entry.periodic;
|
||||
}
|
||||
|
||||
AddrRangeList getAddrRanges() const override;
|
||||
AddrRangeList getAddrRanges() const;
|
||||
AddrRangeList getIntAddrRange() const;
|
||||
|
||||
Port &getPort(const std::string &if_name,
|
||||
@@ -227,8 +235,10 @@ class Interrupts : public PioDevice
|
||||
return intMasterPort;
|
||||
} else if (if_name == "int_slave") {
|
||||
return intSlavePort;
|
||||
} else if (if_name == "pio") {
|
||||
return pioPort;
|
||||
}
|
||||
return PioDevice::getPort(if_name, idx);
|
||||
return SimObject::getPort(if_name, idx);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user