Interrupts transfer execution to a handler when an event needs attention. ivss checks pending events after instruction execution and saves a return frame before changing the program counter:
GPR[SP] -= 4; Mem_WriteRawWord(GPR[SP], GPR[PC]); GPR[SP] -= 4; Mem_WriteRawWord(GPR[SP], CSR[STATUS]); GPR[SP] -= 4; Mem_WriteRawWord(GPR[SP], GPR[ADR]); GPR[SP] -= 4; Mem_WriteRawWord(GPR[SP], GPR[IDX]); CSR[CAUSE] = cause; CSR[STATUS] = status; GPR[PC] = CSR[HANDLER];
The frame preserves the next instruction address, previous status, and the assembler's two helper registers. %cause identifies the event; %handler supplies the destination. Delivery requires a nonzero handler address and the emulator's internal interrupt-enable state.
Pending-event priority follows the implementation's order: invalid instruction, software request, terminal, then timer. Timer and terminal delivery also consult status masks. Once one event is delivered, its pending flag is cleared.
The handler must preserve any additional registers it changes and finish with `iret`. Ordinary ret does not consume this larger frame. Pending flags represent requests, not an unbounded queue of every event.
Source: emulator.c.