name: "Runtime-Reconfigurable 8-Tap FIR"
category: "DSP & Numerical Algorithms"
complexity: "Medium"
description: |
  Implement a synchronous 8-tap FIR filter with runtime coefficient updates.

  INPUT SAMPLES:
  - A sample is accepted on each rising edge for which `rst=0` and
    `data_valid=1`.
  - `data_in` is a signed 8-bit two's-complement sample.
  - Let x[n] be the nth accepted sample after reset is deasserted.
  - If `data_valid=0`, no sample is accepted and the frame position does not
    advance.

  FILTER RULE:
  - The filter uses eight signed 16-bit coefficients `h[0]` through `h[7]`.
  - `h[0]` multiplies the newest accepted sample x[n].
  - `h[7]` multiplies x[n-7].
  - For each accepted sample x[n], compute:
      `y[n] = h[0]*x[n] + h[1]*x[n-1] + h[2]*x[n-2] + h[3]*x[n-3] +`
             `h[4]*x[n-4] + h[5]*x[n-5] + h[6]*x[n-6] + h[7]*x[n-7]`
  - Any sample before the start of the post-reset stream is treated as 0.
  - Use exact signed arithmetic. Do not saturate, wrap, round, or truncate.
  - `data_out` must present the exact signed 27-bit two's-complement result.

  COEFFICIENT UPDATE RULE:
  - On each rising edge for which `rst=0` and `coeff_wr_en=1`, write the
    signed 16-bit value on `coeff_data` to coefficient index `coeff_addr`.
  - Coefficient writes may occur on the same cycle as a sample acceptance.
  - Coefficient writes never affect the current frame immediately.
  - Accepted samples are partitioned into frames of exactly 8 accepted
    samples: frame 0 is x[0] through x[7], frame 1 is x[8] through x[15], and
    so on.
  - All samples within one frame must use the same coefficient set.
  - If one or more coefficient writes have occurred since the current frame
    began, those writes take effect together at the first accepted sample of
    the next frame.
  - Coefficient writes that occur before the first post-reset sample may
    affect frame 0.
  - If `coeff_wr_en=1` on the same cycle as the first accepted sample of a
    frame, that write must not affect that frame.
  - If the same coefficient index is written multiple times before a frame
    boundary, the last accepted write wins.
  - After a frame boundary where updates take effect, any later partial update
    must start from the newly active coefficient values.

  OUTPUT TIMING:
  - Each accepted sample must produce exactly one output cycle with
    `data_out_valid=1`.
  - If x[n] is accepted on cycle T, then on cycle T+1 `data_out_valid` must be
    1 and `data_out` must equal y[n].
  - The result must not appear on cycle T and must not be delayed beyond
    cycle T+1.
  - Example timing:
    if x[n] is accepted on cycle 12, then on cycle 12 `data_out_valid` must be
    0, and on cycle 13 `data_out_valid` must be 1 with `data_out = y[n]`.
  - If x[n+1] is accepted on cycle T+1, the module must still output y[n] on
    cycle T+1 while accepting x[n+1] for output on cycle T+2.
  - The module must support one accepted sample per cycle.
  - Whenever no output is scheduled for a cycle, `data_out_valid` must be 0
    and `data_out` must be 0.

  RESET:
  - `rst` is synchronous and active-high.
  - While `rst=1`, do not accept samples or coefficient writes, clear the
    sample history, clear all coefficients to 0, discard any staged updates,
    restart at the beginning of frame 0, and drive `data_out_valid=0` and
    `data_out=0`.
  - After reset is deasserted, the next accepted sample becomes x[0].

interface:
  module_name: "runtime_reconfigurable_fir"
  clocked: true
  ports:
    - name: "clk"
      type: "input"
      width: "1"
      description: "System clock"
    - name: "rst"
      type: "input"
      width: "1"
      description: "Synchronous active-high reset"
    - name: "data_in"
      type: "input"
      width: "8"
      description: "Signed 8-bit two's-complement input sample"
    - name: "data_valid"
      type: "input"
      width: "1"
      description: "High when `data_in` contains an input sample to be accepted on this cycle"
    - name: "coeff_wr_en"
      type: "input"
      width: "1"
      description: "High to write `coeff_data` to coefficient index `coeff_addr` for a future frame update"
    - name: "coeff_addr"
      type: "input"
      width: "3"
      description: "Coefficient tap address: 0 selects the newest-sample coefficient and 7 selects the oldest-history coefficient"
    - name: "coeff_data"
      type: "input"
      width: "16"
      description: "Signed 16-bit two's-complement coefficient value written by the update interface"
    - name: "data_out"
      type: "output"
      width: "27"
      description: "Signed 27-bit two's-complement FIR result for the previously accepted input sample"
    - name: "data_out_valid"
      type: "output"
      width: "1"
      description: "High when `data_out` contains a valid FIR result on this cycle"

target_platform:
  device_family: "AMD Xilinx Zynq-7000"

tasks:
  - name: "Area-Efficient Runtime-Reconfigurable FIR"
    constraints:
      max_lut: 260
      max_ff: 220
      max_bram: 0
      max_dsp: 8
      min_frequency: 180
    objective:
      goal: "minimise"
      target: "LUT"
