PLIC Block Diagram

---
config:
  layout: dagre
---
flowchart LR

  classDef file fill:#FFFFFF,stroke:#111,stroke-width:3px,color:#111
  classDef source fill:#E9F1FF,stroke:#111,stroke-width:2px,color:#111
  classDef iface fill:#EDE7D4,stroke:#111,stroke-width:2px,color:#111
  classDef backend fill:#F8F8F8,stroke:#111,stroke-width:2px,color:#111

  subgraph DEV["external interrupt sources"]
    direction TB
      UART_HW["UART hardware<br/><br/>UART0_IRQ = 10"]:::source
      VIRTIO_HW["virtio disk hardware<br/><br/>VIRTIO0_IRQ = 1"]:::source
  end

  subgraph SETUP["PLIC setup interface"]
    direction TB
      PLICINIT["plicinit()<br/><br/>set device priorities"]:::iface
      PLICINITHART["plicinithart()<br/><br/>enable device IRQs for this hart<br/>set threshold = 0"]:::iface
  end

  subgraph PLIC_BOX["PLIC hardware state"]
    direction TB
      PLIC_STATE["PLIC<br/><br/>tracks pending external IRQs<br/>checks priority / enable / threshold<br/>routes IRQ to a hart<br/>supports claim + complete"]:::source
  end

  subgraph TRAP["trap-side interface"]
    direction TB
      CPU["RISC-V hart<br/><br/>supervisor external interrupt<br/>scause = external interrupt"]:::process
      DEVINTR["devintr()<br/><br/>classify interrupt<br/>external device / timer / unknown"]:::iface
      CLAIM["plic_claim()<br/><br/>read claimed IRQ number"]:::iface
      COMPLETE["plic_complete(irq)<br/><br/>mark IRQ as handled"]:::iface
  end

  subgraph BACKEND["driver backend after IRQ dispatch"]
    direction TB
      UARTINTR["uartintr()<br/><br/>console interrupt handler"]:::backend
      VIRTIOINTR["virtio_disk_intr()<br/><br/>disk interrupt handler"]:::backend
      UNKNOWN["unexpected irq<br/><br/>print warning"]:::backend
  end

  subgraph NONPLIC["not PLIC path"]
    direction TB
      TIMER["supervisor timer interrupt<br/><br/>clockintr()<br/>does not use PLIC"]:::backend
  end

  PLICINIT -->|"configures priorities"| PLIC_STATE
  PLICINITHART -->|"configures per-hart enables"| PLIC_STATE

  UART_HW -->|"raises IRQ 10"| PLIC_STATE
  VIRTIO_HW -->|"raises IRQ 1"| PLIC_STATE

  PLIC_STATE -->|"delivers external interrupt"| CPU
  CPU -->|"trap enters kernel"| DEVINTR
  DEVINTR -->|"external interrupt branch"| CLAIM

  CLAIM -->|"reads claim register"| PLIC_STATE

  CLAIM -->|"irq == UART0_IRQ"| UARTINTR
  CLAIM -->|"irq == VIRTIO0_IRQ"| VIRTIOINTR
  CLAIM -->|"other nonzero irq"| UNKNOWN

  UARTINTR -->|"handled"| COMPLETE
  VIRTIOINTR -->|"handled"| COMPLETE
  UNKNOWN -->|"handled / reported"| COMPLETE

  COMPLETE -->|"writes completion"| PLIC_STATE

  DEVINTR -.->|"timer branch bypasses PLIC"| TIMER