name: "Token Bucket Rate Limiter"
category: "Networking & Communications"
complexity: "Medium"
description: |
  Implement a synchronous single-bucket token-bucket rate limiter for an
  order-entry path.

  The module maintains an internal unsigned token count. An incoming
  order request may be accepted only when at least one token is
  available. Each accepted request consumes exactly one token.

  CONFIGURATION:
  - `bucket_capacity` is the maximum token count and is in the range 1 to
    16.
  - `refill_period` is the refill interval in clock cycles and is in the
    range 1 to 256.
  - The evaluator will keep both configuration inputs stable while
    `rst=0`.

  RESET AND INITIAL STATE:
  - `rst` is synchronous and active-high.
  - While `rst=1`, the internal token count must be initialized to
    `bucket_capacity`, the refill timer must be reset to its initial
    phase, and both outputs must be 0.
  - After `rst` is deasserted, the bucket starts full.
  - After `rst` is deasserted, the first refill event must occur after
    exactly `refill_period` cycles with `rst=0`.

  REFILL TIMING:
  - Refill timing runs continuously while `rst=0`, regardless of whether
    `order_req` is 0 or 1.
  - On each refill event, add exactly one token if the current token
    count is below `bucket_capacity`.
  - If the token count is already equal to `bucket_capacity`, the refill
    event must leave the token count unchanged.
  - Refill events must continue to occur every `refill_period` cycles
    even while the bucket is full.

  REQUEST HANDLING:
  - `order_req` is a one-cycle request pulse.
  - `accept` and `reject` must be mutually exclusive.
  - If `order_req=0`, both outputs must be 0.
  - If `order_req=1` and at least one token is available for this cycle,
    assert `accept=1` and `reject=0`.
  - If `order_req=1` and no token is available for this cycle, assert
    `accept=0` and `reject=1`.
  - An accepted request consumes exactly one token.
  - A rejected request consumes no tokens.

  SAME-CYCLE REFILL AND REQUEST:
  - If a refill event and `order_req=1` occur in the same cycle, the
    refill is applied before evaluating whether the request is accepted.
  - Therefore, a request must be accepted on that cycle if the bucket was
    empty at the start of the cycle but the refill event adds one token.
  - In that case, the accepted request consumes that newly added token in
    the same cycle.

  OUTPUT TIMING:
  - `accept` and `reject` must reflect the decision for the current cycle
    with no extra output register stage.
  - State updates occur on the rising edge of `clk` according to that
    same cycle's refill event and request decision.

interface:
  module_name: "order_token_bucket_throttle"
  clocked: true
  ports:
    - name: "clk"
      type: "input"
      width: "1"
      description: "System clock"
    - name: "rst"
      type: "input"
      width: "1"
      description: "Synchronous active-high reset"
    - name: "bucket_capacity"
      type: "input"
      width: "5"
      description: "Maximum token count, guaranteed to be in the range 1 to 16"
    - name: "refill_period"
      type: "input"
      width: "9"
      description: "Refill interval in cycles, guaranteed to be in the range 1 to 256"
    - name: "order_req"
      type: "input"
      width: "1"
      description: "One-cycle order request pulse"
    - name: "accept"
      type: "output"
      width: "1"
      description: "High when the current cycle's request is accepted"
    - name: "reject"
      type: "output"
      width: "1"
      description: "High when the current cycle's request is rejected"

target_platform:
  device_family: "AMD Xilinx Zynq-7000"

tasks:
  - name: "Area-Efficient Single-Bucket Order Throttle"
    constraints:
      max_lut: 48
      max_ff: 24
      max_bram: 0
      max_dsp: 0
      min_frequency: 250
    objective:
      goal: "minimise"
      target: "LUT"
