Simple Interrupt Generator
April 22, 2026 ยท View on GitHub
This model includes a very simple MMIO device that allows setting interrupts that are difficult to set via other means (through software or CLINT). This is intended for testing purposes.
This describes version 1.0 of the device. Future versions may add additional features but will be backwards compatible.
Memory Layout
The device consists only of 4-byte registers, and it must be 4-byte aligned. Only naturally aligned 4-byte accesses succeed. Other accesses raise an access fault.
| Offset (Bytes) | Size (Bytes) | Register | Read | Write |
|---|---|---|---|---|
| 0 | 4 | version | Version | ignored |
| 4 | 4 | platform | zeros | Set/clear interrupts |
| 8 | 24 | reserved | fault | fault |
version: reads as as the current version (0x00010000 currently). The version is split into major/minor 16-bit integers, so the current version is 1.0. Versioning follows semver, so minor version updates are backwards compatible with existing software, major version updates are not. Writes to version are ignored.
platform: reads as 0. Writes can be used to set or clear platform-generated interrupts as follows:
| Offset (Bits) | Meaning |
|---|---|
| 0 | reserved |
| 1 | SSI |
| 2 | reserved |
| 3 | MSI |
| 4-8 | reserved |
| 9 | SEI |
| 10 | reserved |
| 11 | MEI |
| 12-30 | reserved |
| 31 | 1=set, 0=clear |
Reserved bits must be written with 0 otherwise an access fault is raised. In future versions writing 1 may be allowed and have an effect, but writing 0 will have no effect so writing 0 is forwards compatible (with minor version number changes).
Bit 31 controls whether the relevant interrupts are set or cleared.
MEI and MSI control the platform interrupt inputs to the hart, which directly control the corresponding bits in mip (there is no way for software running on the hart to set these bits directly). SEI and SSI are slightly more subtle because software on the hart can also write to these bits.
SEI controls the supervisor external platform interrupt input, which is distinct from the software-writable mip[SEI] bit. These two values are ORed together when reading mip (or sip) for CSR reads and to dispatch interrupts, but NOT when reading mip/sip for the CSR read-modify-write process.
Setting or clearing SSI updates the value in mip[SSI], but in this case there is only one bit of state.
Note that if the target hart does not support supervisor mode then mip[SSI] and mip[SEI] must be read-only zero. Attempts to set mip[SSI] will be ignored. Attempts to set SEI will set the external platform interrupt input, but it will not be visible in mip while supervisor mode is not supported. If the hart supports mutable misa[S] so that supervisor mode can be dynamically enabled, then setting SEI to 1 here and then enabling misa[S] will result in the interrupt becoming visible.
Space for other registers is reserved for future use. In version 1.0, accessing them raises an access fault.
Example C++ Code
constexpr uint32_t SIG_SSI = (1 << 1);
constexpr uint32_t SIG_MSI = (1 << 3);
constexpr uint32_t SIG_SEI = (1 << 9);
constexpr uint32_t SIG_MEI = (1 << 11);
constexpr uint32_t SIG_SET = (1 << 31);
struct SimpleInterruptGenerator {
uint32_t version;
uint32_t platform;
uint32_t reserved[6];
};
void set_meip(volatile SimpleInterruptGenerator* sig) {
uint32_t version = sig->version;
uint32_t minor = version & 0xFFFF;
uint32_t major = version >> 16;
assert(major == 1 && minor >= 0);
sig->platform = SIG_SET | SIG_MEI;
}
// etc.
Example Assembly Code
.set SIG_SSI, (1 << 1)
.set SIG_MSI, (1 << 3)
.set SIG_SEI, (1 << 9)
.set SIG_MEI, (1 << 11)
.set SIG_SET, (1 << 31)
.set SIG_REG_OFFSET_VERSION, 0
.set SIG_REG_OFFSET_PLATFORM, 4
.set SIG_REQUIRED_MAJOR_VERSION, 1
.set SIG_MINIMUM_MINOR_VERSION, 0
# void set_meip(volatile SimpleInterruptGenerator* sig)
set_meip:
# Load version.
lw t0, SIG_REG_OFFSET_VERSION(a0)
# t1 = major version
srl t1, t0, 16
# t0 = minor version.
li t2, 0xFFFF
and t0, t0, t2
# Check major version matches exactly.
li t2, SIG_REQUIRED_MAJOR_VERSION
bne t1, t2, 1f
# Check minor version matches minimum.
li t2, SIG_MINIMUM_MINOR_VERSION
bltu t0, t2, 1f
li t0, SIG_SET
li t1, SIG_MEI
# t0 = SIG_SET | SIG_MEI
or t0, t0, t1
# Set interrupt.
sw t0, SIG_REG_OFFSET_PLATFORM(a0)
ret
1:
# Assertion failed.
ebreak