name: "Priority Interrupt Controller"
category: "Soft Processors & Memory"
complexity: "Medium"
description: |
  Implement a synchronous interrupt controller for four interrupt sources.

  The controller receives interrupt request pulses on `irq_req[3:0]`. Each
  request sets a corresponding pending bit. A pending interrupt remains set
  until it is acknowledged.

  The input `irq_enable[3:0]` determines which pending interrupts are eligible
  to be delivered. Disabling a source must prevent it from being selected on
  the outputs, but must not clear its pending bit. If a pending source is later
  re-enabled, it must become visible again.

  OUTPUT SELECTION:
  - `irq_valid` must be high whenever at least one enabled pending interrupt
    exists.
  - `irq_id` must encode the highest-priority enabled pending interrupt.
  - Priority is fixed: source 0 is highest priority and source 3 is lowest
    priority.
  - If no enabled pending interrupt exists, `irq_valid` must be low. In that
    case `irq_id` is don't-care and will not be checked.

  REQUEST CAPTURE:
  - A request is captured on a rising clock edge when the corresponding bit of
    `irq_req` is high.
  - Multiple requests may be captured in the same cycle.
  - If a source is already pending, an additional request for that source has no
    further effect.

  ACKNOWLEDGE BEHAVIOUR:
  - `irq_ack` is sampled on the rising clock edge.
  - If `irq_ack` is high and `irq_valid` is high, the controller must clear the
    currently selected interrupt source, meaning the source identified by the
    output priority logic just before that clock edge.
  - If `irq_ack` is high while `irq_valid` is low, it has no effect.
  - If a source is both acknowledged and newly requested in the same cycle, the
    request must remain pending after the clock edge. In other words, request
    capture takes precedence over clearing for that same source.

  TIMING:
  - Pending state updates only on rising clock edges.
  - `irq_valid` and `irq_id` reflect the current pending state and current
    `irq_enable` values with no additional output register stage.
  - After an acknowledge clears the highest-priority pending interrupt, the next
    highest-priority enabled pending interrupt must become visible immediately
    after that same clock edge.

  RESET:
  - `rst` is synchronous and active-high.
  - On reset, clear all pending interrupts and drive `irq_valid` low.

interface:
  module_name: "interrupt_controller_4src"
  clocked: true
  ports:
    - name: "clk"
      type: "input"
      width: "1"
      description: "Clock signal"
    - name: "rst"
      type: "input"
      width: "1"
      description: "Synchronous active-high reset"
    - name: "irq_req"
      type: "input"
      width: "4"
      description: "Interrupt request pulse inputs, one bit per source"
    - name: "irq_enable"
      type: "input"
      width: "4"
      description: "Interrupt enable mask, one bit per source"
    - name: "irq_ack"
      type: "input"
      width: "1"
      description: "Acknowledge the currently selected interrupt"
    - name: "irq_valid"
      type: "output"
      width: "1"
      description: "High when at least one enabled pending interrupt exists"
    - name: "irq_id"
      type: "output"
      width: "2"
      description: "ID of the highest-priority enabled pending interrupt"

target_platform:
  device_family: "AMD Xilinx Zynq-7000"

tasks:
  - name: "Area-Efficient Interrupt Controller"
    constraints:
      max_lut: 40
      max_ff: 16
      max_bram: 0
      max_dsp: 0
      min_frequency: 200
    objective:
      goal: "minimise"
      target: "LUT"
