diff --git a/src/arch/riscv/RiscvInterrupts.py b/src/arch/riscv/RiscvInterrupts.py index ad64013a2e..7cb0412a69 100644 --- a/src/arch/riscv/RiscvInterrupts.py +++ b/src/arch/riscv/RiscvInterrupts.py @@ -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} + } + """, +) diff --git a/src/arch/riscv/SConscript b/src/arch/riscv/SConscript index d183314af0..78864523c7 100644 --- a/src/arch/riscv/SConscript +++ b/src/arch/riscv/SConscript @@ -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') diff --git a/src/arch/riscv/faults.hh b/src/arch/riscv/faults.hh index fa67e3b34c..36fec182e7 100644 --- a/src/arch/riscv/faults.hh +++ b/src/arch/riscv/faults.hh @@ -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 diff --git a/src/arch/riscv/interrupts.cc b/src/arch/riscv/interrupts.cc new file mode 100644 index 0000000000..29770781ef --- /dev/null +++ b/src/arch/riscv/interrupts.cc @@ -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* pin = + new IntSinkPin(pinName,i, this, interruptID); + localInterruptPins.push_back(pin); + } +} + + +std::bitset +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(mask); +} + +Fault +Interrupts::getInterrupt() +{ + assert(checkInterrupts()); + if (checkNonMaskableInterrupt()) + return std::make_shared(); + std::bitset mask = globalMask(); + if (((ISA*) tc->getIsaPtr())->rvType() == RV64) { + const std::vector 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(id); + } + } + } else if (((ISA*) tc->getIsaPtr())->rvType() == RV32) { + const std::vector 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(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 diff --git a/src/arch/riscv/interrupts.hh b/src/arch/riscv/interrupts.hh index b003b59426..a10479fb65 100644 --- a/src/arch/riscv/interrupts.hh +++ b/src/arch/riscv/interrupts.hh @@ -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 ip; std::bitset ie; + std::vector*> localInterruptPins; public: using Params = RiscvInterruptsParams; - Interrupts(const Params &p) : BaseInterrupts(p), ip(0), ie(0) {} + Interrupts(const Params &p); - std::bitset - 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(mask); - } + std::bitset 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(); - std::bitset mask = globalMask(); - const std::vector 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(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 diff --git a/src/arch/riscv/regs/misc.hh b/src/arch/riscv/regs/misc.hh index 96e88c7438..837cbfacbd 100644 --- a/src/arch/riscv/regs/misc.hh +++ b/src/arch/riscv/regs/misc.hh @@ -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, };