name: "8-Port Round-Robin Arbiter"
category: "Networking & Communications"
complexity: "Medium"
description: |
  Implement a synchronous round-robin arbiter for eight input queues
  competing for access to one shared output port.

  The input `req[7:0]` is a level-sensitive request vector. Bit `i`
  being high means requester `i` currently needs service.

  OUTPUT SELECTION:
  - If one or more request bits are high, assert `grant_valid` and drive
    `grant_idx` with the ID of the selected requester.
  - The selected requester must be the first active requester found in
    round-robin order, starting from the current highest-priority
    requester and wrapping around from 7 back to 0.
  - After reset, the priority order starts at requester 0, then 1, 2,
    3, 4, 5, 6, 7, then wraps.

  ACCEPTED GRANTS:
  - A grant is accepted on a rising clock edge when both `grant_valid`
    and `grant_ready` are high.
  - If requester `k` is granted in an accepted cycle, then on
    subsequent cycles the round-robin search must start from requester
    `(k + 1) mod 8`.
  - If no grant is accepted in a cycle, the current priority order must
    remain unchanged.

  REQUEST AND STALL BEHAVIOUR:
  - Requests are level-sensitive, not pulses.
  - A requester may remain asserted across multiple cycles until it is
    serviced.
  - If `grant_ready` is low, no grant is accepted and the fairness order
    must not advance.
  - If only one requester is active, it may be selected on every
    accepted cycle.

  IDLE AND RESET:
  - If all request bits are low, `grant_valid` must be low. In that
    case, `grant_idx` is don't-care and will not be checked.
  - `rst` is synchronous and active-high.
  - While `rst` is high, `grant_valid` must be low regardless of the
    value of `req`.
  - While `rst` is high, `grant_idx` is don't-care and will not be
    checked.
  - On reset, restore the initial round-robin priority.
  - On the first cycle after `rst` is deasserted, arbitration resumes
    from requester 0 using the current `req` vector.

  TIMING:
  - Arbitration state updates only on rising clock edges.
  - `grant_valid` and `grant_idx` must reflect the current request
    vector and the current round-robin priority with no extra output
    register stage.

interface:
  module_name: "round_robin_arbiter"
  clocked: true
  ports:
    - name: "clk"
      type: "input"
      width: "1"
      description: "Clock signal"
    - name: "rst"
      type: "input"
      width: "1"
      description: "Synchronous active-high reset"
    - name: "req"
      type: "input"
      width: "8"
      description: "Request vector from the eight input queues"
    - name: "grant_ready"
      type: "input"
      width: "1"
      description: "High when the downstream path accepts the selected requester this cycle"
    - name: "grant_valid"
      type: "output"
      width: "1"
      description: "High when at least one requester is currently eligible for service"
    - name: "grant_idx"
      type: "output"
      width: "3"
      description: "ID of the selected requester"

target_platform:
  device_family: "AMD Xilinx Zynq-7000"

tasks:
  - name: "Area-Efficient 8-Input Round-Robin Arbiter"
    constraints:
      max_lut: 60
      max_ff: 8
      max_bram: 0
      max_dsp: 0
      min_frequency: 200
    objective:
      goal: "minimise"
      target: "LUT"
