Xilinx
HLS
Block Preview

Introduction

The FIR (programmable coefs) block is identical to Component_FIR (low-pass fixed) except that the coefficient bus is routed out as a top-level input pin. The user is responsible for driving a valid packed coefficient vector on COEFS; the block never latches it internally, so COEFS is an ap_stable bus and can be changed at run time (typically from a register bank filled by the SDK).

      IN_I  ─┐
    IN_Q  ─┤ [ FIR ] ─── OUT_I / OUT_Q
    COEFS ─┘
  

Pin Description

IN_I Input InputSize bit BIT VECTOR
In-phase (I) input sample. Signed, Input Bit Width bits.
Default: Must be connected
IN_Q Input InputSize bit BIT VECTOR
Quadrature (Q) input sample. Signed, Input Bit Width bits. Tie to zero if you only want to filter a real signal.
Default: Must be connected
COEFS Input NumTaps * CoefSize bit BIT VECTOR
Packed coefficient bus, NumTaps * CoefSize bits wide. Bit [(k+1)*CoefSize-1 : k*CoefSize] = signed h[k]. Bus is ap_stable inside the HLS core: value is sampled combinationally every clock, so it can be updated at run time from the fabric.
Default: Must be connected
CLK Input 1 bit BIT
System clock input. Default: Acquisition clock.
Default: Default Board Clock
RESET Input 1 bit BIT
HLS synchronous reset (ap_rst). Default: Global reset.
Default: Default Board Reset
OUT_I Output InputSize + CoefSize + 8 bit BIT VECTOR
In-phase (I) output. Signed, InputSize + CoefSize + 8 bits.
OUT_Q Output InputSize + CoefSize + 8 bit BIT VECTOR
Quadrature (Q) output. Signed, InputSize + CoefSize + 8 bits.

Properties

Property window

Input Bit Width InputSize

Bit width of each I and Q input sample (signed)

Bit width of each I / Q input sample. Range 4 to 32, default 16.

Default: 16

Options: 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

Coefficient Bit Width CoefSize

Bit width of each coefficient (signed). Determines the width of the COEFS bus (NumTaps * CoefSize).

Bit width of each signed coefficient. Sets the width of the COEFS bus together with NumTaps. Default 16.

Default: 16

Options: 8 10 12 14 16 18 20 24

Number of Taps NumTaps

Number of filter taps (filter order = NumTaps - 1). Determines the width of the COEFS bus (NumTaps * CoefSize).

Number of filter taps (filter order = NumTaps - 1). Sets the width of the COEFS bus together with CoefSize. Default 32.

Default: 32

Options: 8 16 24 32 48 64 96 128

Usage

COEFS bus layout

The bus is packed little-endian per tap: bit slice [(k+1)*CoefSize-1 : k*CoefSize] of COEFS holds the signed coefficient h[k], i.e. h[0] is at the LSBs of the bus.

    COEFS bit index:   packedSize-1  ...   CoefSize  CoefSize-1  ...  0
                    +----------+---+------------+---------+ ... +---+
                    | h[N-1]   |...|   h[1]     |          h[0]     |
                    +----------+---+------------+--------------------+
  

where packedSize = NumTaps * CoefSize. Each h[k] is signed two’s complement, CoefSize bits.

Data path

Same as Component_FIR:

    y_c[n] = sum_{k=0..NumTaps-1} h[k] * x_c[n-k]        for c in {I,Q}
  

Same output width InputSize + CoefSize + 8, same II=1 pipeline, same 1-clock latency.

Coefficient design (host side)

The coefficients are the responsibility of the driver / firmware. The easiest recipe for a real low-pass is windowed sinc, DC-normalised and quantised to signed CoefSize bits with a scale of 2^(CoefSize-1)-1 (identical to what Component_FIR does internally). The Python testbench tb/fir/fir_tb.py contains a reference implementation of the coefficient generator that you can copy verbatim.

Typical applications

  • Software-defined channel-select filter: change bandwidth without resynthesising the bitstream.
  • Matched filter whose shape depends on the sample rate at run time.
  • Adaptive equaliser where a small state machine outside the block updates the coefficients.

Resources & Timing

  • Latency: 1 clock cycle

  • Throughput: 1 sample per clock (II=1)

Implemented with Vitis HLS. NumTaps DSP48 slices per channel. Because the coefficients are ap_stable (not compile-time constant) Vivado cannot optimise them away, so DSP usage is deterministic.