Xilinx
TM
Block Preview

Introduction

Principle of Operation

This block is FFT Windowed TM with a writable window. The datapath is generated by the same code (Component_FFTWindowedTM.SharedCompileHDL, called with programmable = True), so everything the FFT Windowed TM page says about the transform holds here too:

  • the TM input carries $R$ samples per clock ($R$ = TMFactor, 2 or 4);
  • each lane is multiplied by its own polyphase slice of the window, $\mathrm{WROM}_r[m] = w[mR + r]$;
  • the windowed lanes feed the gapless polyphase FFT engine (one Xilinx xfft core of $M = N/R$ points plus the multiplier-free recombination), and $R$ spectrum bins come out per clock, back to back.

The only difference is where $w[n]$ comes from:

FFT Windowed TM FFT Windowed TM Prog
Window storage VHDL constant ROM VHDL signal RAM
Set by the FFT Windowed designer (double-click) the COEF_* bus, at run time
Value before load the designed window rectangular (0xFFFF in every cell)
Extra pins – COEF_ADDR, COEF_DATA, COEF_WE
Properties FFTLength, TMFactor, InputBits, ScalingMode, Window, WFProject FFTLength, TMFactor, InputBits, ScalingMode

Use it when the window has to change without re-running synthesis: adaptive spectral analysis, a window selected by the operator, or a measurement that sweeps several windows over the same acquisition.

To design a window, place a fixed FFT Windowed block, use its designer to preview the shape, and export the coefficient list; then drive those values into this block’s COEF_* bus from your own loader (a state machine, a register file, a soft core).

Pin Description

DATA_IN Input InputBits bit TM
TM sample stream – $R$ signed samples per clock, InputBits each, packed lane 0 in the least significant field. This is the only data input; samples are consumed every clock (no clock enable, no back-pressure).
Default: Must be connected
COEF_ADDR Input ceil(log2 FFTLength) bit BIT VECTOR
Window coefficient address – the sample index $n$, 0 … N-1, ceil(log2 N) bits. The wrapper derives the polyphase lane ($n \bmod R$) and the RAM index ($\lfloor n/R \rfloor$) internally.
COEF_DATA Input 16 bit BIT VECTOR
Window coefficient value – unsigned Q16, 65535 = 1.0, 0 = 0.0. Negative coefficients are not representable.
COEF_WE Input 1 bit BIT
Write strobe – one clock high writes COEF_DATA at COEF_ADDR. Takes effect on the next sample, with no frame boundary interlock.
CLK Input 1 bit BIT
Clock – everything (window load, multiply, FFT core) is synchronous to it. Defaults to the project acquisition clock.
Default: Default Board Clock
OUT_RE Output outBits bit TM
Spectrum, real part – TM bus, $R$ bins per clock, outBits per bin (see the Output width table). Bins come out in natural order, frames back to back.
OUT_IM Output outBits bit TM
Spectrum, imaginary part – same geometry as OUT_RE.
DV Output 1 bit BIT
Data valid – high on every clock that carries bins. Continuous once the pipeline has filled.
FRAME_START Output 1 bit BIT
Frame start – pulses on the clock carrying the first bins of a frame (bin 0 is in lane 0 of that word).
FRAME_END Output 1 bit BIT
Frame end – pulses on the clock carrying the last bins of a frame.

Properties

Property window

FFT Length FFTLength

Transform length N (power of 2)

Transform length $N$, a power of two. Available values: 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384. The instantiated xfft core is $N/\text{TMFactor}$ points, and the window RAM holds $N$ coefficients spread over TMFactor polyphase banks. Default: 1024

Default: 1024

Options: 64 128 256 512 1024 2048 4096 8192 16384

TM Factor (SSR) TMFactor

Time Multiplexing factor (samples per clock). 2 or 4 (multiplier-free recombination).

Time-multiplexing factor $R$ = samples per clock on DATA_IN and bins per clock on OUT_RE / OUT_IM. Available values: 2, 4 — nothing else compiles (the recombination stage is multiplier-free only for these two). Default: 4

Default: 4

Options: 2 4

Input Data Bits InputBits

Bit width of each input sample (8-24 bits)

Bit width of one input sample, 8 … 24. It is also the input_width of the generated xfft IP and the width the windowed sample is rounded back to. Default: 16

Default: 16

Options: 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

Scaling Mode ScalingMode

No Scaling: full bit growth (InputBits + log2(N) + 1). Grow to Max: saturated to 27 bits. Scale: output divided by N, InputBits wide (saturated).

How the FFT core handles bit growth.

Value Output width Meaning
No Scaling $\min(\text{InputBits}+\lceil\log_2 N\rceil+1, 32)$ full bit growth, no loss
Grow to Max $\min(\text{InputBits}+\lceil\log_2 N\rceil+1, 27)$ grown then saturated to 27 bit
Scale InputBits divided by $N$, saturated back to the input width

Default: No Scaling

Default: No Scaling

Options: No Scaling Grow to Max Scale

⚙️ Loading the window

The load port is a plain synchronous write port on the polyphase RAMs. One coefficient per clock:

  COEF_ADDR <= n                      -- n = SAMPLE index, 0 .. N-1
COEF_DATA <= round(w[n] * 65535)    -- unsigned Q16
COEF_WE   <= '1'                    -- one clock
  

COEF_ADDR is ceil(log2 N) bits wide. The address is split inside the wrapper exactly as the polyphase decomposition requires — you do not have to do that split yourself:

$$ \text{lane } r = n \bmod R \qquad \text{ROM index } m = \left\lfloor n / R \right\rfloor $$

(the low $\log_2 R$ bits of COEF_ADDR select the lane, the remaining bits are the index inside that lane’s RAM). Writing n = 0 … N-1 in natural order therefore loads the window in natural order.

Until the first write the RAMs are initialised to (others => '1'), i.e. 0xFFFF in every cell: the block behaves as an unwindowed (rectangular) gapless FFT.

The window multiplier

Per lane $r$, in two registered stages:

vhdl
  x0(r) <= signed(data_in((r+1)*inBits-1 downto r*inBits));
w0(r) <= WROM_r(to_integer(m_cnt));
p1(r) <= x0(r) * signed('0' & w0(r));
...
core_in((r+1)*inBits-1 downto r*inBits)
      <= std_logic_vector(resize(shift_right(p1(r) + 32768, 16), inBits));
  

so the windowed sample is

$$ x_w[n] ;=; \left\lfloor \frac{x[n],w[n] + 2^{15}}{2^{16}} \right\rfloor $$

— a round-to-nearest back to InputBits, not a truncation. Because $w[n] \le 65535 < 2^{16}$ the magnitude never grows, so the resize cannot overflow and no saturation logic is needed. The cost is one DSP slice per lane.

Window phase

m_cnt is a free-running counter reloaded only by the global reset; its initial value compensates the 2-stage window pipeline against the 3 startup tready drops of the xfft core in pipelined-streaming mode (WINIT = ((2 - 3) mod M + M) mod M, i.e. $M-1$). The consequence for the user is simple:

  • the window is aligned to frames by reset, not by any input signal;
  • there is no START / frame-trigger pin — frames are back to back from reset on, and FRAME_START / FRAME_END tell you where they fall.

The source comments state that this offset was verified in xsim and must be re-verified if the xfft IP version changes.

Output width

OUT_RE / OUT_IM are TM buses of outBits per lane, where

ScalingMode outBits
No Scaling $\min(\text{InputBits} + \lceil\log_2 N\rceil + 1,\ 32)$
Grow to Max $\min(\text{InputBits} + \lceil\log_2 N\rceil + 1,\ 27)$
Scale InputBits (output divided by $N$, saturated)

Generated hardware

CompileHDL writes into the project’s pcores/ folder:

  • xfft_wtmp_<designator>.tcl — one Xilinx xfft IP of transform_length $M = N/R$, pipelined_streaming_io, input_width = InputBits, phase_factor_width 16, scaling_options unscaled, rounding_modes convergent_rounding, output_ordering natural_order, aresetn true;
  • ssr_fft_wtmp_<designator>.vhd — the polyphase gapless wrapper (shared with FFT TM Realtime);
  • fft_wtmp_<designator>.vhd — the top level: window RAMs, the load port, the multiplier stage and the core instance.

The block is declared _ANY_XLX, i.e. Xilinx targets only.

Constraints and failure modes

  • TMFactor must be 2 or 4. Anything else aborts the compile with

      <designator>: FFT Windowed TM supports TM factor 2 or 4 only. Selected: <R>
      
  • FFTLength, TMFactor, InputBits and ScalingMode all have RedesignIfChanged = True: changing any of them re-draws the symbol (pin widths change) and re-generates the IP.

  • The block is not available inside a state machine (AvailableInStateMachine = False); it is available in sub-designs.

  • There is no RESET pin on the symbol: reset is wired automatically to the project global reset, and clk defaults to the project acquisition clock.

Resources & Timing

  • Latency: The symbol declares a latency of N clocks (bxs.Latency = N). The exact cycle-accurate figure is not stated anywhere in the sources; treat N as the figure the compiler uses for automatic delay matching.
  • Xilinx only (SupportedBoard = _ANY_XLX); one xfft core of N/R points.
  • One DSP slice per TM lane for the window multiply.
  • Window RAM: TMFactor banks of N/TMFactor x 16 bit (N coefficients in total).
  • Not available inside a state machine; available in sub-designs.