name: "Fixed-Ladder Top-of-Book Builder"
category: "Networking & Communications"
complexity: "Medium"
description: |
  Implement a synchronous market-data accelerator that maintains the
  top of book for a small limit-order book represented as aggregated
  quantity at fixed price levels.

  BOOK MODEL:
  - The module stores two independent ladders: one bid ladder and one ask
    ladder.
  - Each ladder has 16 price levels addressed by `price_idx` in the range
    0 to 15.
  - A larger `price_idx` means a higher absolute price.
  - Each stored quantity is an unsigned 16-bit aggregate size.
  - A stored quantity of 0 means that price level is empty.

  UPDATE STREAM:
  - An update is accepted on each rising edge of `clk` for which `rst=0`
    and `upd_valid=1`.
  - `upd_side=0` selects the bid ladder and `upd_side=1` selects the ask
    ladder.
  - The accepted update replaces the quantity at the selected side and
    `price_idx` with `upd_qty`.
  - This is a full replacement update, not an increment or decrement.
  - If `upd_qty=0`, the addressed level becomes empty.
  - If `upd_valid=0`, the stored book state must not change.

  TOP-OF-BOOK DEFINITION:
  - The best bid is the highest `price_idx` in the bid ladder whose stored
    quantity is nonzero.
  - The best ask is the lowest `price_idx` in the ask ladder whose stored
    quantity is nonzero.
  - `book_valid` must be 1 if and only if both a best bid and a best ask
    exist in the stored book state.
  - When `book_valid=1`, the outputs `best_bid_idx`, `best_bid_qty`,
    `best_ask_idx`, `best_ask_qty`, and `spread_ticks` must describe that
    current stored top of book.
  - `spread_ticks` must equal `best_ask_idx - best_bid_idx`.
  - When `book_valid=0`, all five outputs above must be 0.

  OUTPUT TIMING:
  - The outputs must update with exactly one clock cycle of latency from
    the accepted update stream.
  - If an update is accepted on cycle N, then on cycle N+1 the outputs
    must reflect the stored book state after applying that update.
  - If no update is accepted on cycle N, then on cycle N+1 the outputs
    must remain unchanged from cycle N, except for reset behaviour.
  - Back-to-back updates may be accepted on consecutive cycles.

  INPUT GUARANTEE:
  - The evaluator will never present a sequence of accepted updates that
    creates a locked or crossed book. Whenever `book_valid=1`, the stored
    best ask price will be strictly greater than the stored best bid price.

  RESET:
  - `rst` is synchronous and active-high.
  - While `rst=1`, clear the entire stored book, drive `book_valid=0`,
    and drive all other outputs to 0.
  - A cycle with `rst=1` must not accept an update.
  - After reset is deasserted, the next accepted update starts from an
    empty book.

interface:
  module_name: "top_of_book_builder"
  clocked: true
  ports:
    - name: "clk"
      type: "input"
      width: "1"
      description: "System clock"
    - name: "rst"
      type: "input"
      width: "1"
      description: "Synchronous active-high reset"
    - name: "upd_valid"
      type: "input"
      width: "1"
      description: "High when the update fields are valid and must be accepted this cycle"
    - name: "upd_side"
      type: "input"
      width: "1"
      description: "0 selects the bid ladder, 1 selects the ask ladder"
    - name: "price_idx"
      type: "input"
      width: "4"
      description: "Unsigned fixed-ladder price index in the range 0 to 15"
    - name: "upd_qty"
      type: "input"
      width: "16"
      description: "Replacement aggregate quantity for the selected side and price level; 0 clears the level"
    - name: "book_valid"
      type: "output"
      width: "1"
      description: "High when both a non-empty best bid and a non-empty best ask exist"
    - name: "best_bid_idx"
      type: "output"
      width: "4"
      description: "Highest non-empty bid price index, or 0 when `book_valid=0`"
    - name: "best_bid_qty"
      type: "output"
      width: "16"
      description: "Aggregate quantity at the best bid level, or 0 when `book_valid=0`"
    - name: "best_ask_idx"
      type: "output"
      width: "4"
      description: "Lowest non-empty ask price index, or 0 when `book_valid=0`"
    - name: "best_ask_qty"
      type: "output"
      width: "16"
      description: "Aggregate quantity at the best ask level, or 0 when `book_valid=0`"
    - name: "spread_ticks"
      type: "output"
      width: "4"
      description: "Unsigned best-ask minus best-bid distance in price ticks, or 0 when `book_valid=0`"

target_platform:
  device_family: "AMD Xilinx Zynq-7000"

tasks:
  - name: "Low-Latency Fixed-Ladder Top-of-Book Builder"
    constraints:
      max_lut: 320
      max_ff: 640
      max_bram: 0
      max_dsp: 0
      min_frequency: 200
    objective:
      goal: "maximise"
      target: "Fmax"
