name: "Variable-Width Timestamp Delta Encoder"
category: "Cryptography & Compression"
complexity: "Medium"
description: |
  Implement a synchronous streaming encoder for a sequence of 32-bit unsigned
  timestamps.

  INPUT STREAM:
  - One timestamp is accepted on each rising edge of `clk` for which `rst=0`
    and `in_valid=1`.
  - `in_timestamp` is an unsigned 32-bit value.
  - The evaluator will provide a monotonically non-decreasing sequence across
    accepted input samples. Equal consecutive timestamps are allowed.
  - A cycle with `in_valid=0` accepts no input and must not update internal
    state.

  ENCODING RULES:
  - The module must remember the most recent accepted timestamp.
  - For the first accepted timestamp after reset, there is no previous sample.
    In that case, emit the input timestamp itself as a full-width value with
    `out_tag=2'b10`.
  - For each later accepted timestamp, compute the unsigned delta:
    `delta = in_timestamp - previous_timestamp`.
  - Encode that delta using the smallest lossless width class:
      `out_tag=2'b00` when `delta <= 32'd255`
      `out_tag=2'b01` when `32'd256 <= delta <= 32'd65535`
      `out_tag=2'b10` when `delta >= 32'd65536`
  - `out_tag=2'b11` is unused and must never be produced.
  - `previous_timestamp` is updated to the newly accepted input timestamp on
    every accepted input cycle, including the first sample after reset.

  OUTPUT FORMAT:
  - Each accepted input sample must produce exactly one output cycle with
    `out_valid=1`.
  - The output for an accepted input on cycle N must appear on cycle N+1.
  - `out_value` is a 32-bit unsigned bus interpreted according to `out_tag`:
      for `out_tag=2'b00`, `out_value[7:0]` must equal the delta and
      `out_value[31:8]` must be zero
      for `out_tag=2'b01`, `out_value[15:0]` must equal the delta and
      `out_value[31:16]` must be zero
      for `out_tag=2'b10`, `out_value[31:0]` must equal the full 32-bit
      payload for that sample
  - For the first sample after reset, that full-width payload is the input
    timestamp itself.
  - For any later sample classified into the `2'b10` bucket, that full-width
    payload is the 32-bit delta.
  - The module must support back-to-back accepted inputs, which therefore
    produce back-to-back valid outputs one cycle later.
  - Whenever no output is scheduled for a cycle, `out_valid` must be 0,
    `out_tag` must be `2'b00`, and `out_value` must be `32'b0`.

  RESET:
  - `rst` is synchronous and active-high.
  - While `rst=1`, clear all internal state, discard any pending output, and
    drive `out_valid=0`, `out_tag=2'b00`, and `out_value=32'b0`.
  - A cycle with `rst=1` accepts no input even if `in_valid=1`.
  - After reset is deasserted, the next accepted timestamp must again be
    treated as the first sample and emitted with `out_tag=2'b10`.

interface:
  module_name: "timestamp_delta_encoder"
  clocked: true
  ports:
    - name: "clk"
      type: "input"
      width: "1"
      description: "System clock"
    - name: "rst"
      type: "input"
      width: "1"
      description: "Synchronous active-high reset"
    - name: "in_valid"
      type: "input"
      width: "1"
      description: "High when `in_timestamp` contains a timestamp to accept on this cycle"
    - name: "in_timestamp"
      type: "input"
      width: "32"
      description: "Unsigned 32-bit input timestamp"
    - name: "out_valid"
      type: "output"
      width: "1"
      description: "High when the encoder emits one encoded result for the sample accepted on the previous cycle"
    - name: "out_tag"
      type: "output"
      width: "2"
      description: "Width classification tag: 00 for 8-bit delta, 01 for 16-bit delta, 10 for the full-width payload"
    - name: "out_value"
      type: "output"
      width: "32"
      description: "Encoded unsigned payload, zero-extended for 8-bit or 16-bit delta outputs"

target_platform:
  device_family: "AMD Xilinx Zynq-7000"

tasks:
  - name: "Area-Efficient Timestamp Delta Encoder"
    constraints:
      max_lut: 80
      max_ff: 72
      max_bram: 0
      max_dsp: 0
      min_frequency: 250
    objective:
      goal: "minimise"
      target: "LUT"
