arch-riscv: adding support for local interrupts (#813)
Besides the standard RISC-V interrupts software, timer, and external interrupt, the RISC-V specification also offers the possibility to implement local interrupts. With this patch, we contribute an extension of RiscvInterrupts that enables connecting interrupt sources to the local interrupt controller. We assigned the local interrupts to machine-level and gave them the highest priority. If two local interrupts are pending, there exception code will be the tie-breaker (higher ID > lower ID). 32 Bit systems only recognize the local interrupts 16 to 31, 64 Bit systems 16 to 63. Change-Id: Iff8d34e740b925dce351c0c6f54f4bd37a647e0c --------- Co-authored-by: Robert Hauser <robert.hauser@uni-rostock.de>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
# Copyright (c) 2014 Sven Karlsson
|
||||
# Copyright (c) 2016 RISC-V Foundation
|
||||
# Copyright (c) 2016 The University of Virginia
|
||||
# Copyright (c) 2024 University of Rostock
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
@@ -27,10 +28,35 @@
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from m5.citations import add_citation
|
||||
from m5.objects.BaseInterrupts import BaseInterrupts
|
||||
from m5.objects.IntPin import VectorIntSinkPin
|
||||
from m5.params import VectorParam
|
||||
|
||||
|
||||
class RiscvInterrupts(BaseInterrupts):
|
||||
type = "RiscvInterrupts"
|
||||
cxx_class = "gem5::RiscvISA::Interrupts"
|
||||
cxx_header = "arch/riscv/interrupts.hh"
|
||||
|
||||
local_interrupt_pins = VectorIntSinkPin("Pins for local interrupts")
|
||||
local_interrupt_ids = VectorParam.Unsigned(
|
||||
[], "list of local interrupt ids"
|
||||
)
|
||||
|
||||
|
||||
add_citation(
|
||||
RiscvInterrupts,
|
||||
r"""@inproceedings{Hauser:2024:LocalRiscvInterrupts,
|
||||
author = {Robert Hauser and
|
||||
Lukas Steffen and
|
||||
Florian Grützmacher and
|
||||
Christian Haubelt},
|
||||
title = {Analyzing Local RISC-V Interrupt Latencies with Virtual Prototyping},
|
||||
booktitle = {Workshop Methoden und Beschreibungssprachen zur Modellierung und Verifikation von Schaltungen und Systemen (MBMV24)},
|
||||
pages = {1-7},
|
||||
year = {2024},
|
||||
month = {2}
|
||||
}
|
||||
""",
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
# Copyright (c) 2014 Sven Karlsson
|
||||
# Copyright (c) 2020 Barkhausen Institut
|
||||
# Copyright (c) 2021 Huawei International
|
||||
# Copyright (c) 2024 University of Rostock
|
||||
# All rights reserved
|
||||
#
|
||||
# The license below extends only to copyright in the software and shall
|
||||
@@ -48,6 +49,7 @@ if env['CONF']['USE_RISCV_ISA']:
|
||||
|
||||
Source('decoder.cc', tags='riscv isa')
|
||||
Source('faults.cc', tags='riscv isa')
|
||||
Source('interrupts.cc', tags='riscv isa')
|
||||
Source('isa.cc', tags='riscv isa')
|
||||
Source('process.cc', tags='riscv isa')
|
||||
Source('pagetable.cc', tags='riscv isa')
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Copyright (c) 2016 RISC-V Foundation
|
||||
* Copyright (c) 2016 The University of Virginia
|
||||
* Copyright (c) 2018 TU Dresden
|
||||
* Copyright (c) 2024 University of Rostock
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -93,6 +94,54 @@ enum ExceptionCode : uint64_t
|
||||
INT_EXT_USER = 8,
|
||||
INT_EXT_SUPER = 9,
|
||||
INT_EXT_MACHINE = 11,
|
||||
INT_LOCAL_0 = 16,
|
||||
INT_LOCAL_1 = 17,
|
||||
INT_LOCAL_2 = 18,
|
||||
INT_LOCAL_3 = 19,
|
||||
INT_LOCAL_4 = 20,
|
||||
INT_LOCAL_5 = 21,
|
||||
INT_LOCAL_6 = 22,
|
||||
INT_LOCAL_7 = 23,
|
||||
INT_LOCAL_8 = 24,
|
||||
INT_LOCAL_9 = 25,
|
||||
INT_LOCAL_10 = 26,
|
||||
INT_LOCAL_11 = 27,
|
||||
INT_LOCAL_12 = 28,
|
||||
INT_LOCAL_13 = 29,
|
||||
INT_LOCAL_14 = 30,
|
||||
INT_LOCAL_15 = 31,
|
||||
INT_LOCAL_16 = 32,
|
||||
INT_LOCAL_17 = 33,
|
||||
INT_LOCAL_18 = 34,
|
||||
INT_LOCAL_19 = 35,
|
||||
INT_LOCAL_20 = 36,
|
||||
INT_LOCAL_21 = 37,
|
||||
INT_LOCAL_22 = 38,
|
||||
INT_LOCAL_23 = 39,
|
||||
INT_LOCAL_24 = 40,
|
||||
INT_LOCAL_25 = 41,
|
||||
INT_LOCAL_26 = 42,
|
||||
INT_LOCAL_27 = 43,
|
||||
INT_LOCAL_28 = 44,
|
||||
INT_LOCAL_29 = 45,
|
||||
INT_LOCAL_30 = 46,
|
||||
INT_LOCAL_31 = 47,
|
||||
INT_LOCAL_32 = 48,
|
||||
INT_LOCAL_33 = 49,
|
||||
INT_LOCAL_34 = 50,
|
||||
INT_LOCAL_35 = 51,
|
||||
INT_LOCAL_36 = 52,
|
||||
INT_LOCAL_37 = 53,
|
||||
INT_LOCAL_38 = 54,
|
||||
INT_LOCAL_39 = 55,
|
||||
INT_LOCAL_40 = 56,
|
||||
INT_LOCAL_41 = 57,
|
||||
INT_LOCAL_42 = 58,
|
||||
INT_LOCAL_43 = 59,
|
||||
INT_LOCAL_44 = 60,
|
||||
INT_LOCAL_45 = 61,
|
||||
INT_LOCAL_46 = 62,
|
||||
INT_LOCAL_47 = 63,
|
||||
NumInterruptTypes,
|
||||
// INT_NMI does not exist in the spec, it's a modeling artifact for NMI. We
|
||||
// intentionally set it to be NumInterruptTypes so it can never conflict
|
||||
|
||||
248
src/arch/riscv/interrupts.cc
Normal file
248
src/arch/riscv/interrupts.cc
Normal file
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Google
|
||||
* Copyright (c) 2024 University of Rostock
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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
|
||||
* notice, this list of conditions and the following disclaimer;
|
||||
* redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution;
|
||||
* neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "arch/riscv/interrupts.hh"
|
||||
|
||||
namespace gem5
|
||||
{
|
||||
|
||||
namespace RiscvISA
|
||||
{
|
||||
|
||||
Interrupts::Interrupts(const Params &p) : BaseInterrupts(p),
|
||||
ip(0),
|
||||
ie(0)
|
||||
{
|
||||
for (uint8_t i = 0;
|
||||
i < p.port_local_interrupt_pins_connection_count;
|
||||
++i) {
|
||||
uint8_t interruptID = p.local_interrupt_ids[i];
|
||||
assert(interruptID >= 0);
|
||||
assert(interruptID <= 47);
|
||||
std::string pinName =
|
||||
csprintf("%s.local_interrupt_pins[%d]", p.name, i);
|
||||
IntSinkPin<Interrupts>* pin =
|
||||
new IntSinkPin<Interrupts>(pinName,i, this, interruptID);
|
||||
localInterruptPins.push_back(pin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::bitset<NumInterruptTypes>
|
||||
Interrupts::globalMask() const
|
||||
{
|
||||
INTERRUPT mask = 0;
|
||||
STATUS status = tc->readMiscReg(MISCREG_STATUS);
|
||||
MISA misa = tc->readMiscRegNoEffect(MISCREG_ISA);
|
||||
INTERRUPT mideleg = 0;
|
||||
if (misa.rvs || misa.rvn) {
|
||||
mideleg = tc->readMiscReg(MISCREG_MIDELEG);
|
||||
}
|
||||
INTERRUPT sideleg = 0;
|
||||
if (misa.rvs && misa.rvn) {
|
||||
sideleg = tc->readMiscReg(MISCREG_SIDELEG);
|
||||
}
|
||||
PrivilegeMode prv = (PrivilegeMode)tc->readMiscReg(MISCREG_PRV);
|
||||
switch (prv) {
|
||||
case PRV_U:
|
||||
// status.uie is always 0 if misa.rvn is disabled
|
||||
if (misa.rvs) {
|
||||
mask.local = ~sideleg.local;
|
||||
if (status.uie)
|
||||
mask.local = mask.local | sideleg.local;
|
||||
mask.mei = (!sideleg.mei) | (sideleg.mei & status.uie);
|
||||
mask.mti = (!sideleg.mti) | (sideleg.mti & status.uie);
|
||||
mask.msi = (!sideleg.msi) | (sideleg.msi & status.uie);
|
||||
mask.sei = (!sideleg.sei) | (sideleg.sei & status.uie);
|
||||
mask.sti = (!sideleg.sti) | (sideleg.sti & status.uie);
|
||||
mask.ssi = (!sideleg.ssi) | (sideleg.ssi & status.uie);
|
||||
} else {
|
||||
// According to the RISC-V privilege spec v1.10, if the
|
||||
// S privilege mode is not implemented and user-trap
|
||||
// support, setting mideleg/medeleg bits will delegate the
|
||||
// trap to U-mode trap handler
|
||||
mask.local = ~mideleg.local;
|
||||
if (status.uie)
|
||||
mask.local = mask.local | mideleg.local;
|
||||
mask.mei = (!mideleg.mei) | (mideleg.mei & status.uie);
|
||||
mask.mti = (!mideleg.mti) | (mideleg.mti & status.uie);
|
||||
mask.msi = (!mideleg.msi) | (mideleg.msi & status.uie);
|
||||
mask.sei = mask.sti = mask.ssi = 0;
|
||||
}
|
||||
if (status.uie)
|
||||
mask.uei = mask.uti = mask.usi = 1;
|
||||
break;
|
||||
case PRV_S:
|
||||
mask.local = ~mideleg.local;
|
||||
mask.mei = (!mideleg.mei) | (mideleg.mei & status.sie);
|
||||
mask.mti = (!mideleg.mti) | (mideleg.mti & status.sie);
|
||||
mask.msi = (!mideleg.msi) | (mideleg.msi & status.sie);
|
||||
if (status.sie) {
|
||||
mask.sei = mask.sti = mask.ssi = 1;
|
||||
mask.local = mask.local | mideleg.local;
|
||||
}
|
||||
mask.uei = mask.uti = mask.usi = 0;
|
||||
break;
|
||||
case PRV_M:
|
||||
|
||||
if (status.mie) {
|
||||
mask.local = gem5::mask(48);
|
||||
mask.mei = mask.mti = mask.msi = 1;
|
||||
}
|
||||
mask.sei = mask.sti = mask.ssi = 0;
|
||||
mask.uei = mask.uti = mask.usi = 0;
|
||||
break;
|
||||
default:
|
||||
panic("Unknown privilege mode %d.", prv);
|
||||
break;
|
||||
}
|
||||
|
||||
return std::bitset<NumInterruptTypes>(mask);
|
||||
}
|
||||
|
||||
Fault
|
||||
Interrupts::getInterrupt()
|
||||
{
|
||||
assert(checkInterrupts());
|
||||
if (checkNonMaskableInterrupt())
|
||||
return std::make_shared<NonMaskableInterruptFault>();
|
||||
std::bitset<NumInterruptTypes> mask = globalMask();
|
||||
if (((ISA*) tc->getIsaPtr())->rvType() == RV64) {
|
||||
const std::vector<int> interrupt_order {
|
||||
INT_LOCAL_47, INT_LOCAL_46, INT_LOCAL_45, INT_LOCAL_44,
|
||||
INT_LOCAL_43, INT_LOCAL_42, INT_LOCAL_41, INT_LOCAL_40,
|
||||
INT_LOCAL_39, INT_LOCAL_38, INT_LOCAL_37, INT_LOCAL_36,
|
||||
INT_LOCAL_35, INT_LOCAL_34, INT_LOCAL_33, INT_LOCAL_32,
|
||||
INT_LOCAL_31, INT_LOCAL_30, INT_LOCAL_29, INT_LOCAL_28,
|
||||
INT_LOCAL_27, INT_LOCAL_26, INT_LOCAL_25, INT_LOCAL_24,
|
||||
INT_LOCAL_23, INT_LOCAL_22, INT_LOCAL_21, INT_LOCAL_20,
|
||||
INT_LOCAL_19, INT_LOCAL_18, INT_LOCAL_17, INT_LOCAL_16,
|
||||
INT_LOCAL_15, INT_LOCAL_14, INT_LOCAL_13, INT_LOCAL_12,
|
||||
INT_LOCAL_11, INT_LOCAL_10, INT_LOCAL_9, INT_LOCAL_8,
|
||||
INT_LOCAL_7, INT_LOCAL_6, INT_LOCAL_5, INT_LOCAL_4,
|
||||
INT_LOCAL_3, INT_LOCAL_2, INT_LOCAL_1, INT_LOCAL_0,
|
||||
INT_EXT_MACHINE, INT_SOFTWARE_MACHINE, INT_TIMER_MACHINE,
|
||||
INT_EXT_SUPER, INT_SOFTWARE_SUPER, INT_TIMER_SUPER,
|
||||
INT_EXT_USER, INT_SOFTWARE_USER, INT_TIMER_USER
|
||||
};
|
||||
for (const int &id : interrupt_order) {
|
||||
if (checkInterrupt(id) && mask[id]) {
|
||||
return std::make_shared<InterruptFault>(id);
|
||||
}
|
||||
}
|
||||
} else if (((ISA*) tc->getIsaPtr())->rvType() == RV32) {
|
||||
const std::vector<int> interrupt_order {
|
||||
INT_LOCAL_15, INT_LOCAL_14, INT_LOCAL_13, INT_LOCAL_12,
|
||||
INT_LOCAL_11, INT_LOCAL_10, INT_LOCAL_9, INT_LOCAL_8,
|
||||
INT_LOCAL_7, INT_LOCAL_6, INT_LOCAL_5, INT_LOCAL_4,
|
||||
INT_LOCAL_3, INT_LOCAL_2, INT_LOCAL_1, INT_LOCAL_0,
|
||||
INT_EXT_MACHINE, INT_SOFTWARE_MACHINE, INT_TIMER_MACHINE,
|
||||
INT_EXT_SUPER, INT_SOFTWARE_SUPER, INT_TIMER_SUPER,
|
||||
INT_EXT_USER, INT_SOFTWARE_USER, INT_TIMER_USER
|
||||
};
|
||||
for (const int &id : interrupt_order) {
|
||||
if (checkInterrupt(id) && mask[id]) {
|
||||
return std::make_shared<InterruptFault>(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NoFault;
|
||||
}
|
||||
|
||||
void
|
||||
Interrupts::post(int int_num, int index)
|
||||
{
|
||||
DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
|
||||
if (int_num != INT_NMI) {
|
||||
ip[int_num] = true;
|
||||
} else {
|
||||
postNMI();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Interrupts::clear(int int_num, int index)
|
||||
{
|
||||
DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
|
||||
if (int_num != INT_NMI) {
|
||||
ip[int_num] = false;
|
||||
} else {
|
||||
clearNMI();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Interrupts::clearAll()
|
||||
{
|
||||
DPRINTF(Interrupt, "All interrupts cleared\n");
|
||||
ip = 0;
|
||||
clearNMI();
|
||||
}
|
||||
|
||||
void
|
||||
Interrupts::raiseInterruptPin(uint32_t num)
|
||||
{
|
||||
tc->getCpuPtr()->postInterrupt(tc->threadId(), num + 16, 0);
|
||||
}
|
||||
|
||||
void
|
||||
Interrupts::serialize(CheckpointOut &cp) const
|
||||
{
|
||||
unsigned long ip_ulong = ip.to_ulong();
|
||||
unsigned long ie_ulong = ie.to_ulong();
|
||||
SERIALIZE_SCALAR(ip_ulong);
|
||||
SERIALIZE_SCALAR(ie_ulong);
|
||||
}
|
||||
|
||||
void
|
||||
Interrupts::unserialize(CheckpointIn &cp)
|
||||
{
|
||||
unsigned long ip_ulong;
|
||||
unsigned long ie_ulong;
|
||||
UNSERIALIZE_SCALAR(ip_ulong);
|
||||
ip = ip_ulong;
|
||||
UNSERIALIZE_SCALAR(ie_ulong);
|
||||
ie = ie_ulong;
|
||||
}
|
||||
|
||||
Port &
|
||||
Interrupts::getPort(const std::string &if_name, PortID idx)
|
||||
{
|
||||
|
||||
if (if_name == "local_interrupt_pins" && idx < localInterruptPins.size()) {
|
||||
return *localInterruptPins[idx];
|
||||
} else {
|
||||
return BaseInterrupts::getPort(if_name, idx);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace RiscvISA
|
||||
|
||||
} // namespace gem5
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Google
|
||||
* Copyright (c) 2024 University of Rostock
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -36,8 +37,10 @@
|
||||
#include "arch/riscv/faults.hh"
|
||||
#include "arch/riscv/regs/misc.hh"
|
||||
#include "base/logging.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "debug/Interrupt.hh"
|
||||
#include "dev/intpin.hh"
|
||||
#include "params/RiscvInterrupts.hh"
|
||||
#include "sim/sim_object.hh"
|
||||
|
||||
@@ -59,71 +62,13 @@ class Interrupts : public BaseInterrupts
|
||||
std::bitset<NumInterruptTypes> ip;
|
||||
std::bitset<NumInterruptTypes> ie;
|
||||
|
||||
std::vector<gem5::IntSinkPin<Interrupts>*> localInterruptPins;
|
||||
public:
|
||||
using Params = RiscvInterruptsParams;
|
||||
|
||||
Interrupts(const Params &p) : BaseInterrupts(p), ip(0), ie(0) {}
|
||||
Interrupts(const Params &p);
|
||||
|
||||
std::bitset<NumInterruptTypes>
|
||||
globalMask() const
|
||||
{
|
||||
INTERRUPT mask = 0;
|
||||
STATUS status = tc->readMiscReg(MISCREG_STATUS);
|
||||
MISA misa = tc->readMiscRegNoEffect(MISCREG_ISA);
|
||||
INTERRUPT mideleg = 0;
|
||||
if (misa.rvs || misa.rvn) {
|
||||
mideleg = tc->readMiscReg(MISCREG_MIDELEG);
|
||||
}
|
||||
INTERRUPT sideleg = 0;
|
||||
if (misa.rvs && misa.rvn) {
|
||||
sideleg = tc->readMiscReg(MISCREG_SIDELEG);
|
||||
}
|
||||
PrivilegeMode prv = (PrivilegeMode)tc->readMiscReg(MISCREG_PRV);
|
||||
switch (prv) {
|
||||
case PRV_U:
|
||||
// status.uie is always 0 if misa.rvn is disabled
|
||||
if (misa.rvs) {
|
||||
mask.mei = (!sideleg.mei) | (sideleg.mei & status.uie);
|
||||
mask.mti = (!sideleg.mti) | (sideleg.mti & status.uie);
|
||||
mask.msi = (!sideleg.msi) | (sideleg.msi & status.uie);
|
||||
mask.sei = (!sideleg.sei) | (sideleg.sei & status.uie);
|
||||
mask.sti = (!sideleg.sti) | (sideleg.sti & status.uie);
|
||||
mask.ssi = (!sideleg.ssi) | (sideleg.ssi & status.uie);
|
||||
} else {
|
||||
// According to the RISC-V privilege spec v1.10, if the
|
||||
// S privilege mode is not implemented and user-trap
|
||||
// support, setting mideleg/medeleg bits will delegate the
|
||||
// trap to U-mode trap handler
|
||||
mask.mei = (!mideleg.mei) | (mideleg.mei & status.uie);
|
||||
mask.mti = (!mideleg.mti) | (mideleg.mti & status.uie);
|
||||
mask.msi = (!mideleg.msi) | (mideleg.msi & status.uie);
|
||||
mask.sei = mask.sti = mask.ssi = 0;
|
||||
}
|
||||
if (status.uie)
|
||||
mask.uei = mask.uti = mask.usi = 1;
|
||||
break;
|
||||
case PRV_S:
|
||||
// status.sie is always 0 if misa.rvn is disabled
|
||||
mask.mei = (!mideleg.mei) | (mideleg.mei & status.sie);
|
||||
mask.mti = (!mideleg.mti) | (mideleg.mti & status.sie);
|
||||
mask.msi = (!mideleg.msi) | (mideleg.msi & status.sie);
|
||||
if (status.sie)
|
||||
mask.sei = mask.sti = mask.ssi = 1;
|
||||
mask.uei = mask.uti = mask.usi = 0;
|
||||
break;
|
||||
case PRV_M:
|
||||
if (status.mie)
|
||||
mask.mei = mask.mti = mask.msi = 1;
|
||||
mask.sei = mask.sti = mask.ssi = 0;
|
||||
mask.uei = mask.uti = mask.usi = 0;
|
||||
break;
|
||||
default:
|
||||
panic("Unknown privilege mode %d.", prv);
|
||||
break;
|
||||
}
|
||||
|
||||
return std::bitset<NumInterruptTypes>(mask);
|
||||
}
|
||||
std::bitset<NumInterruptTypes> globalMask() const;
|
||||
|
||||
bool
|
||||
checkNonMaskableInterrupt() const
|
||||
@@ -137,83 +82,32 @@ class Interrupts : public BaseInterrupts
|
||||
return checkNonMaskableInterrupt() || (ip & ie & globalMask()).any();
|
||||
}
|
||||
|
||||
Fault
|
||||
getInterrupt() override
|
||||
{
|
||||
assert(checkInterrupts());
|
||||
if (checkNonMaskableInterrupt())
|
||||
return std::make_shared<NonMaskableInterruptFault>();
|
||||
std::bitset<NumInterruptTypes> mask = globalMask();
|
||||
const std::vector<int> interrupt_order {
|
||||
INT_EXT_MACHINE, INT_SOFTWARE_MACHINE, INT_TIMER_MACHINE,
|
||||
INT_EXT_SUPER, INT_SOFTWARE_SUPER, INT_TIMER_SUPER,
|
||||
INT_EXT_USER, INT_SOFTWARE_USER, INT_TIMER_USER
|
||||
};
|
||||
for (const int &id : interrupt_order)
|
||||
if (checkInterrupt(id) && mask[id])
|
||||
return std::make_shared<InterruptFault>(id);
|
||||
return NoFault;
|
||||
}
|
||||
Fault getInterrupt() override;
|
||||
|
||||
void updateIntrInfo() override {}
|
||||
|
||||
void
|
||||
post(int int_num, int index) override
|
||||
{
|
||||
DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
|
||||
if (int_num != INT_NMI) {
|
||||
ip[int_num] = true;
|
||||
} else {
|
||||
postNMI();
|
||||
}
|
||||
}
|
||||
void post(int int_num, int index) override;
|
||||
|
||||
void
|
||||
clear(int int_num, int index) override
|
||||
{
|
||||
DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
|
||||
if (int_num != INT_NMI) {
|
||||
ip[int_num] = false;
|
||||
} else {
|
||||
clearNMI();
|
||||
}
|
||||
}
|
||||
void clear(int int_num, int index) override;
|
||||
|
||||
void postNMI() { tc->setMiscReg(MISCREG_NMIP, 1); }
|
||||
void clearNMI() { tc->setMiscReg(MISCREG_NMIP, 0); }
|
||||
|
||||
void
|
||||
clearAll() override
|
||||
{
|
||||
DPRINTF(Interrupt, "All interrupts cleared\n");
|
||||
ip = 0;
|
||||
clearNMI();
|
||||
}
|
||||
void clearAll() override;
|
||||
|
||||
uint64_t readIP() const { return (uint64_t)ip.to_ulong(); }
|
||||
uint64_t readIE() const { return (uint64_t)ie.to_ulong(); }
|
||||
void setIP(const uint64_t& val) { ip = val; }
|
||||
void setIE(const uint64_t& val) { ie = val; }
|
||||
|
||||
void
|
||||
serialize(CheckpointOut &cp) const override
|
||||
{
|
||||
unsigned long ip_ulong = ip.to_ulong();
|
||||
unsigned long ie_ulong = ie.to_ulong();
|
||||
SERIALIZE_SCALAR(ip_ulong);
|
||||
SERIALIZE_SCALAR(ie_ulong);
|
||||
}
|
||||
void serialize(CheckpointOut &cp) const override;
|
||||
|
||||
void
|
||||
unserialize(CheckpointIn &cp) override
|
||||
{
|
||||
unsigned long ip_ulong;
|
||||
unsigned long ie_ulong;
|
||||
UNSERIALIZE_SCALAR(ip_ulong);
|
||||
ip = ip_ulong;
|
||||
UNSERIALIZE_SCALAR(ie_ulong);
|
||||
ie = ie_ulong;
|
||||
}
|
||||
void unserialize(CheckpointIn &cp) override;
|
||||
|
||||
Port &getPort(const std::string &if_name, PortID idx) override;
|
||||
|
||||
void raiseInterruptPin(uint32_t num);
|
||||
void lowerInterruptPin(uint32_t num) {};
|
||||
};
|
||||
|
||||
} // namespace RiscvISA
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*
|
||||
* Copyright (c) 2016 RISC-V Foundation
|
||||
* Copyright (c) 2016 The University of Virginia
|
||||
* Copyright (c) 2024 University of Rostock
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -1233,6 +1234,7 @@ EndBitUnion(MISA)
|
||||
* this bit union.
|
||||
*/
|
||||
BitUnion64(INTERRUPT)
|
||||
Bitfield<63,16> local;
|
||||
Bitfield<11> mei;
|
||||
Bitfield<9> sei;
|
||||
Bitfield<8> uei;
|
||||
@@ -1438,6 +1440,7 @@ USTATUS_MASKS[enums::Num_RiscvType][enums::Num_PrivilegeModeSet] = {
|
||||
},
|
||||
};
|
||||
|
||||
const RegVal LOCAL_MASK = mask(63,16);
|
||||
const RegVal MEI_MASK = 1ULL << 11;
|
||||
const RegVal SEI_MASK = 1ULL << 9;
|
||||
const RegVal UEI_MASK = 1ULL << 8;
|
||||
@@ -1448,13 +1451,13 @@ const RegVal MSI_MASK = 1ULL << 3;
|
||||
const RegVal SSI_MASK = 1ULL << 1;
|
||||
const RegVal USI_MASK = 1ULL << 0;
|
||||
const RegVal MI_MASK[enums::Num_PrivilegeModeSet] = {
|
||||
[enums::M] = MEI_MASK| MTI_MASK | MSI_MASK,
|
||||
[enums::MU] = MEI_MASK| MTI_MASK | MSI_MASK,
|
||||
[enums::MNU] = MEI_MASK | UEI_MASK | MTI_MASK | UTI_MASK |
|
||||
[enums::M] = LOCAL_MASK | MEI_MASK| MTI_MASK | MSI_MASK,
|
||||
[enums::MU] = LOCAL_MASK | MEI_MASK| MTI_MASK | MSI_MASK,
|
||||
[enums::MNU] = LOCAL_MASK | MEI_MASK | UEI_MASK | MTI_MASK | UTI_MASK |
|
||||
MSI_MASK | USI_MASK,
|
||||
[enums::MSU] = MEI_MASK | SEI_MASK | MTI_MASK | STI_MASK |
|
||||
[enums::MSU] = LOCAL_MASK | MEI_MASK | SEI_MASK | MTI_MASK | STI_MASK |
|
||||
MSI_MASK | SSI_MASK,
|
||||
[enums::MNSU] = MEI_MASK | SEI_MASK | UEI_MASK |
|
||||
[enums::MNSU] = LOCAL_MASK | MEI_MASK | SEI_MASK | UEI_MASK |
|
||||
MTI_MASK | STI_MASK | UTI_MASK |
|
||||
MSI_MASK | SSI_MASK | USI_MASK,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user