name: "8-Entry TCAM Lookup"
category: "Networking & Communications"
complexity: "Medium"
description: |
  Implement a small ternary content-addressable lookup engine with eight
  entries. This style of masked lookup is commonly used in packet
  classification and routing tables.

  STORED TABLE:
  - The module maintains 8 entries indexed 0 through 7.
  - Each entry contains:
      - a valid bit
      - an 8-bit key
      - an 8-bit mask
      - an 8-bit associated value
  - After reset, all 8 entries are invalid.

  WRITE PORT:
  - A write is accepted on each rising edge of `clk` for which `rst=0` and
    `wr_en=1`.
  - `wr_addr` selects which entry is updated.
  - If `wr_clear=0`, then on that rising edge the selected entry becomes valid
    and its key, mask, and value are replaced by `wr_key`, `wr_mask`, and
    `wr_value`.
  - If `wr_clear=1`, then on that rising edge the selected entry becomes
    invalid. In that case `wr_key`, `wr_mask`, and `wr_value` are ignored.
  - At most one entry is written per cycle.

  LOOKUP RULE:
  - `lookup_key` is compared against all currently stored valid entries.
  - For entry `i`, a match occurs if and only if:
      `valid[i] = 1` and `((lookup_key ^ key[i]) & mask[i]) == 8'h00`
  - Mask bit meaning:
      - `mask[i][b] = 1` means bit `b` must match exactly.
      - `mask[i][b] = 0` means bit `b` is don't-care.
  - Therefore, a valid entry with `mask=8'h00` matches every `lookup_key`.

  PRIORITY RULE:
  - If one or more entries match, assert `match=1`.
  - `match_idx` must be the lowest-index matching entry.
  - `match_value` must be the associated value stored in that same selected
    entry.
  - If no entries match, drive `match=0`, `match_idx=3'b000`, and
    `match_value=8'h00`.

  TIMING:
  - `match`, `match_idx`, and `match_value` are combinational outputs derived
    from the current table contents and the current `lookup_key`.
  - There is no extra output register stage.
  - Table state changes only on rising edges of `clk`.
  - A write accepted on a rising edge becomes visible to the lookup outputs
    after that edge.

  RESET:
  - `rst` is synchronous and active-high.
  - While `rst=1`, all entries must be cleared to invalid on the rising edge,
    `wr_en` must be ignored, and the outputs must be forced to
    `match=0`, `match_idx=0`, and `match_value=0`.
  - After `rst` is deasserted, the table is empty until new writes occur.

interface:
  module_name: "tcam8_lookup"
  clocked: true
  ports:
    - name: "clk"
      type: "input"
      width: "1"
      description: "System clock"
    - name: "rst"
      type: "input"
      width: "1"
      description: "Synchronous active-high reset"
    - name: "lookup_key"
      type: "input"
      width: "8"
      description: "8-bit search key presented to all entries"
    - name: "wr_en"
      type: "input"
      width: "1"
      description: "High to update one entry on the current rising edge"
    - name: "wr_addr"
      type: "input"
      width: "3"
      description: "Index of the entry to write or clear"
    - name: "wr_clear"
      type: "input"
      width: "1"
      description: "1 clears the selected entry, 0 writes a valid entry"
    - name: "wr_key"
      type: "input"
      width: "8"
      description: "Key stored into the selected entry when `wr_clear=0`"
    - name: "wr_mask"
      type: "input"
      width: "8"
      description: "Mask stored into the selected entry when `wr_clear=0`; 1 means care, 0 means don't-care"
    - name: "wr_value"
      type: "input"
      width: "8"
      description: "Associated value stored into the selected entry when `wr_clear=0`"
    - name: "match"
      type: "output"
      width: "1"
      description: "High when at least one valid entry matches `lookup_key`"
    - name: "match_idx"
      type: "output"
      width: "3"
      description: "Lowest-index matching entry, or 0 when no entry matches"
    - name: "match_value"
      type: "output"
      width: "8"
      description: "Associated value from the selected matching entry, or 0 when no entry matches"

target_platform:
  device_family: "AMD Xilinx Zynq-7000"

tasks:
  - name: "Area-Efficient 8-Entry TCAM Lookup"
    constraints:
      max_lut: 180
      max_ff: 220
      max_bram: 0
      max_dsp: 0
      min_frequency: 200
    objective:
      goal: "minimise"
      target: "LUT"
