Skip to content

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:

  1. Decrements CWP modulo NWINDOWS (Lince uses NWINDOWS = 8).
  2. Saves PSR into the new window's local registers, sets S=1, ET=0, PS=old_S.
  3. Computes TBR = (TBA & 0xFFFFF000) | (tt << 4) and sets PC = 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:

void enter_trap(uint8_t tt);   // SPARC V8 §7.1
void leave_trap();             // RETT semantics

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; S and ET set by enter_trap go straight into psr_ because they are written through the immediate path, not the delayed one.

leave_trap is invoked by the RETT handler. It:

  • Restores S from PS, sets ET = 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:

  1. PSR.S == 1 (else privileged_instruction).
  2. PSR.ET == 0 (else illegal_instruction).
  3. The destination window is not invalid (WIM test, else window_underflow).
  4. 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):

  1. The IRQMP is queried via pending_mask(core_idx) for the per-core bitmap of asserted lines.
  2. The highest set bit ≥ 1 is the candidate interrupt level.
  3. If level > psr.PIL and psr.ET == 1, a hardware trap is injected with tt = 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 as InsnKind::FpOp and trap with FpDisabled (tt = 0x04). Decision 8. When the SoftFloat 3e FPU lands in Phase 7, this handler will gain real semantics gated on PSR.EF.
  • op = 10, op3 ∈ {0x36, 0x37} — coprocessor opcodes — decode as InsnKind::Unknown and trap with IllegalInstruction.