Traps and interrupts¶
This page documents how Lince models SPARC V8 trap delivery and how the IRQMP wires external interrupts into trap entries.
SPARC V8 trap basics¶
A trap on SPARC V8 is a synchronous event that:
- Decrements
CWPmoduloNWINDOWS(Lince usesNWINDOWS = 8). - Saves
PSRinto the new window's local registers, setsS=1,ET=0,PS=old_S. - Computes
TBR = (TBA & 0xFFFFF000) | (tt << 4)and setsPC = TBR,nPC = TBR + 4.
If ET == 0 at the moment of the trap, the processor enters
ErrorMode instead.
Where trap types are defined¶
src/core/include/lince/core/trap.hpp enumerates SPARC V8 trap-type
constants and the ExecStatus → tt mapping. The notable entries:
ExecStatus |
tt |
SPARC V8 trap |
|---|---|---|
InsnFetchError |
0x01 |
instruction_access_exception |
IllegalInstruction |
0x02 |
illegal_instruction |
PrivilegedInstruction |
0x03 |
privileged_instruction |
FpDisabled |
0x04 |
fp_disabled |
WinOverflow |
0x05 |
window_overflow |
WinUnderflow |
0x06 |
window_underflow |
MemNotAligned |
0x07 |
mem_address_not_aligned |
BusError |
0x09 |
data_access_exception |
TagOverflow |
0x0a |
tag_overflow |
DivisionByZero |
0x2a |
division_by_zero |
| Hardware IRQ level L | 0x10 + L |
interrupt_level_L |
Tcc software trap |
0x80 + sw_trap_no |
trap_instruction |
status_to_tt(ExecStatus) is the canonical mapping; the step loop
calls it whenever a handler returns a non-Ok status.
The enter_trap and leave_trap API¶
Implemented on CpuState:
enter_trap performs the architectural sequence above. Two
implementation notes:
annul_next_is cleared on entry (SPARC V8 §5.1.2.2 — interrupt cancels a pending annul).- The function does not touch
pending_psr_. The PSR write pipeline continues to drain normally;SandETset byenter_trapgo straight intopsr_because they are written through the immediate path, not the delayed one.
leave_trap is invoked by the RETT handler. It:
- Restores
SfromPS, setsET = 1. - Increments
CWP. - Asks the step loop to branch to the saved return target.
Privileged-instruction pre-checks¶
Per SPARC V8 §B.26, the RETT handler validates in this exact order:
PSR.S == 1(elseprivileged_instruction).PSR.ET == 0(elseillegal_instruction).- The destination window is not invalid (
WIMtest, elsewindow_underflow). - The return address is word-aligned (else
mem_address_not_aligned).
Lince's handlers_regwin.cpp follows the order to the letter; tests
under tests/unit/test_traps.cpp exercise each branch.
Hardware interrupt sampling¶
Before each core executes its quantum, the runtime calls
sample_interrupts(core_idx):
- The IRQMP is queried via
pending_mask(core_idx)for the per-core bitmap of asserted lines. - The highest set bit ≥ 1 is the candidate interrupt level.
- If
level > psr.PILandpsr.ET == 1, a hardware trap is injected withtt = 0x10 + level.
Lower-level interrupts remain pending until either:
- The PIL drops, or
- The handler clears the IRQ at the source (writing
ICR).
ErrorMode¶
If a trap fires while ET == 0, enter_trap aborts and sets
error_mode_ = true. The step loop returns
HaltReason::ErrorMode from the next run_for boundary. The CLI
captures this and prints a complete post-mortem of core 0:
[lince-emu] core0 post-mortem: pc=0x400034a0 npc=0x400034a4
tbr=0x40000020 tt=0x02 psr=0x00000083 wim=0x00000002
[lince-emu] g0-g7: 0 0x00000000 0x00000000 ...
[lince-emu] i0-i7: 0x400fff40 0x00000008 ...
Library users can call emu->core(0) and inspect any of these fields
directly.
Tagged-arithmetic edge case¶
TADDccTV and TSUBccTV (SPARC V8 §B.30) compute the result and
update icc first, then trap if V is set. Lince's handler writes rd
and icc before returning ExecStatus::TagOverflow (Decision 10).
The architectural specification leaves the result as "unpredictable" when the trap fires; deterministically committing it makes test expectations reproducible.
Coprocessor and FPU encoding policy¶
op = 10, op3 ∈ {0x34, 0x35}— FPop1 / FPop2 — decode asInsnKind::FpOpand trap withFpDisabled(tt = 0x04). Decision 8. When the SoftFloat 3e FPU lands in Phase 7, this handler will gain real semantics gated onPSR.EF.op = 10, op3 ∈ {0x36, 0x37}— coprocessor opcodes — decode asInsnKind::Unknownand trap withIllegalInstruction.