"""IRQ routing seam. Evidence kind: **hardware register/field header + observed access pattern.** The GSP boot handshake sets the falcon ``IRQSSET`` HALT bit (bit 4) after writing MAILBOX0/DEBUGINFO, and the boot code reads ``FALCON_IRQSTAT``; the libos kernel owns the RISC-V-local ``RISCV_IRQMSET``/``IRQMCLR``/``IRQMASK`` group. This module aggregates those two sources behind one object so a future core-interrupt model can consume a single ``pending()`` surface. It does **not** deliver interrupts to the machine's hart: mstatus/mie/mip/ mtvec trap entry is not modelled (documented unknown). It only makes the routing state explicit and serialisable. """ from __future__ import annotations # Falcon IRQSSET/IRQSCLR bit positions used by the boot handshake (header # field list; only the ones with proven firmware use are named). FALCON_IRQ_GPTMR = 1 << 0 FALCON_IRQ_WDTMR = 1 << 1 FALCON_IRQ_MTHD = 1 << 2 FALCON_IRQ_CTXSW = 1 << 3 FALCON_IRQ_HALT = 1 << 4 FALCON_IRQ_EXTERR = 1 << 5 FALCON_IRQ_SWGEN0 = 1 << 6 FALCON_IRQ_SWGEN1 = 1 << 7 FALCON_IRQ_DMA = 1 << 16 FALCON_IRQ_SHA = 1 << 17 class IrqRouter: """Aggregate falcon + RISC-V-local interrupt state.""" name = "irq" def __init__(self, *, falcon=None, priscv=None): self.falcon = falcon self.priscv = priscv def falcon_status(self) -> int: return self.falcon.irq_status if self.falcon is not None else 0 def riscv_mask(self) -> int: return self.priscv.irq_mask if self.priscv is not None else 0 def pending(self) -> dict: """Raw pending state; delivery is deliberately not modelled.""" return { "falcon_irq_status": self.falcon_status(), "falcon_halt": bool(self.falcon_status() & FALCON_IRQ_HALT), "riscv_irq_mask": self.riscv_mask(), } def state(self) -> dict: return self.pending() def reset(self) -> None: pass