# -----------------------------------------------------------------------------
# (C) Bibix
# The content below includes confidential, proprietary information of
# Bibix. All use, disclosure, and/or reproduction is prohibited
# unless authorized in writing. All rights reserved.
# -----------------------------------------------------------------------------
# File : fft_r8_64p.arx
# Description : 64-point decimation-in-frequency FFT pipeline based on
# two radix-2^3 butterfly stages
# Author : Sabih Gerez, Bibix
# based on work by Rene Moll (DSE) &
# David van Kampen (UT, 2006)
# Creation date: November 18, 2011
# -----------------------------------------------------------------------------
# $Rev: 182 $
# $Author: sabih $
# $Date: 2011-11-22 20:27:04 +0100 (Tue, 22 Nov 2011) $
# $Log$
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# This file implements a 64 point R2^3 FFT consisting of
# - Two R2^3 butterflies
# - A complex multiplier for applying intermediate twiddle factors
# - Control logic
#
# The structure is as follows:
#
# twiddle -----------------+
# |
# +------+ +---+ +------+
# data_in -> | BF 1 | -> | * | -> | BF 2 | -> data_out
# +------+ +---+ +------+
#
# The control is created by two counters, one for each butterfly.
#
# The external twiddle factors need to be fed when the first butterfly
# is outputting valid results. This is at cycle 59 (32 + 16 + 8 + 3)
# due to the FIFO sizes and pipelining.
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# Radix-2 butterfly (Stage 1)
#
# The butterfly stage has two operation modes:
# - Butterfly operation (select_s1 = 1)
# - Bypass (select_s1 = 0)
# Used to bypass the operation and route the FIFO to I/O
# -----------------------------------------------------------------------------
component bf23_s1
T : generic type
x_in_real : in T
x_in_imag : in T
y_in_real : in T
y_in_imag : in T
select_s1 : in bit
x_out_real : out T
x_out_imag : out T
y_out_real : out T
y_out_imag : out T
begin
if (select_s1 == 1)
x_out_real = convert(T, x_in_real - y_in_real)
x_out_imag = convert(T, x_in_imag - y_in_imag)
y_out_real = convert(T, x_in_real + y_in_real)
y_out_imag = convert(T, x_in_imag + y_in_imag)
else
x_out_real = y_in_real
x_out_imag = y_in_imag
y_out_real = x_in_real
y_out_imag = x_in_imag
end
end
# -----------------------------------------------------------------------------
# Radix-2 butterfly (Stage 2)
#
# This butterfly stage implements the previous stage preceded by an
# optional twiddle factor at the y input:
# - Apply a twiddle factor (-j) (select_s2 = 1)
# - Bypass twiddle (-j) (select_s2 = 0)
#
# From the previous stage:
# - Butterfly operation (select_s1 = 1)
# - Bypass (select_s1 = 0)
# Used to bypass the operation and route the FIFO to I/O
# -----------------------------------------------------------------------------
component bf23_s2
T : generic type
x_in_real : in T
x_in_imag : in T
y_in_real : in T
y_in_imag : in T
select_s1 : in bit
select_s2 : in bit
x_out_real : out T
x_out_imag : out T
y_out_real : out T
y_out_imag : out T
variable
# Variables for the input mux
mux_real : T
mux_imag : T
generate
bf_int : bf23_s1
T = T
x_in_real => x_in_real
x_in_imag => x_in_imag
y_in_real => mux_real
y_in_imag => mux_imag
select_s1 => select_s1
x_out_real => x_out_real
x_out_imag => x_out_imag
y_out_real => y_out_real
y_out_imag => y_out_imag
begin
if (select_s2 == 1)
mux_real = y_in_imag
mux_imag = -y_in_real
else
mux_real = y_in_real
mux_imag = y_in_imag
end
end
# -----------------------------------------------------------------------------
# Radix-2 butterfly (Stage 3)
#
# This butterfly stage implements the previous stage preceded by yet
# another optional twiddle factor at the y input:
#
# - Apply a twiddle factor (-W8) (select_s3 = 1)
# - Bypass twiddle (-W8) (select_s3 = 0)
#
# From the previous stages:
# - Butterfly operation (select_s1 = 1)
# - Bypass (select_s1 = 0)
# Used to bypass the operation and route the FIFO to I/O
# - Apply a twiddle factor (-j) (select_s2 = 1)
# - Bypass twiddle (-j) (select_s2 = 0)
# -----------------------------------------------------------------------------
component bf23_s3
T : generic type
x_in_real : in T
x_in_imag : in T
y_in_real : in T
y_in_imag : in T
select_s1 : in bit
select_s2 : in bit
select_s3 : in bit
x_out_real : out T
x_out_imag : out T
y_out_real : out T
y_out_imag : out T
variable
y_sum : T
y_sub : T
# Variables for the input mux
mux_real : T
mux_imag : T
constant
W8 : T = 0.707106781
generate
bf_int : bf23_s2
T = T
x_in_real => x_in_real
x_in_imag => x_in_imag
y_in_real => mux_real
y_in_imag => mux_imag
select_s1 => select_s1
select_s2 => select_s2
x_out_real => x_out_real
x_out_imag => x_out_imag
y_out_real => y_out_real
y_out_imag => y_out_imag
begin
# Complex multiplication:
# (a+jb)*(c+jd) = (ac - bd) + j(ad + bc)
# Since c = -d
# c(a + b) + jc(a - b)
y_sum = convert(T, y_in_real + y_in_imag)
y_sub = convert(T, y_in_imag - y_in_real)
if (select_s3 == 1)
mux_real = convert(T, y_sum * W8)
mux_imag = convert(T, y_sub * W8)
else
mux_real = y_in_real
mux_imag = y_in_imag
end
end
# -----------------------------------------------------------------------------
# Radix-2^3 butterfly
#
# Generics:
# - N: order number corresponding to the butterfly position; N=64 for
# the first stage, and N=8 for the second. It is used to compute the
# FIFO sizes.
#
# - COUNT_RATE: the number of LSBs discarded from counters on behalf
# of control. COUNT_RATE = log2(N) - 3, but the current version of
# Arx has some troubles to parameterize the component with a single
# generic.
# -----------------------------------------------------------------------------
component bf23
T : generic type
N : generic integer = 8
COUNT_RATE : generic integer = 0
data_in_real : in T
data_in_imag : in T
data_out_real : out T
data_out_imag : out T
# Control input for the muxes
counter : in unsigned(COUNT_RATE+3)
register
# Internal registers (Used as FIFO)
#
# Note: An additional buffer is added for stage 3 to avoid an array
# of 1 This register is never used however implemented to avoid a
# VHDL generation bug
reg_s1_real : array[(N/2)] of T = 0
reg_s1_imag : array[(N/2)] of T = 0
reg_s2_real : array[(N/4)] of T = 0
reg_s2_imag : array[(N/4)] of T = 0
reg_s3_real : array[(N/8)+1] of T = 0
reg_s3_imag : array[(N/8)+1] of T = 0
variable
# Mux control wires
bf1_select_s1 : bit
bf2_select_s1 : bit
bf2_select_s2 : bit
bf3_select_s1 : bit
bf3_select_s2 : bit
bf3_select_s3 : bit
# Control wires
counter_bf1 : unsigned(COUNT_RATE+3)
counter_bf2 : unsigned(COUNT_RATE+3)
counter_bf3 : unsigned(COUNT_RATE+3)
# Wires to the FIFO for stage 1
reg_s1_in_real : T
reg_s1_in_imag : T
reg_s1_out_real : T
reg_s1_out_imag : T
# Wires to the FIFO for stage 2
reg_s2_in_real : T
reg_s2_in_imag : T
reg_s2_out_real : T
reg_s2_out_imag : T
# Wires to the FIFO for stage 3
reg_s3_in_real : T
reg_s3_in_imag : T
reg_s3_out_real : T
reg_s3_out_imag : T
# Storage for butterfly outputs
register
bf1_out_real : T = 0
bf1_out_imag : T = 0
bf2_out_real : T = 0
bf2_out_imag : T = 0
bf3_out_real : T = 0
bf3_out_imag : T = 0
generate
# instantiate butterflies
# note that the FIFO inputs connect to butterfly outputs and vice
# versa
bf1 : bf23_s1
T = T
x_in_real => reg_s1_out_real
x_in_imag => reg_s1_out_imag
y_in_real => data_in_real
y_in_imag => data_in_imag
select_s1 => bf1_select_s1
x_out_real => reg_s1_in_real
x_out_imag => reg_s1_in_imag
y_out_real => bf1_out_real
y_out_imag => bf1_out_imag
bf2 : bf23_s2
T = T
x_in_real => reg_s2_out_real
x_in_imag => reg_s2_out_imag
y_in_real => bf1_out_real
y_in_imag => bf1_out_imag
select_s1 => bf2_select_s1
select_s2 => bf2_select_s2
x_out_real => reg_s2_in_real
x_out_imag => reg_s2_in_imag
y_out_real => bf2_out_real
y_out_imag => bf2_out_imag
bf3 : bf23_s3
T = T
x_in_real => reg_s3_out_real
x_in_imag => reg_s3_out_imag
y_in_real => bf2_out_real
y_in_imag => bf2_out_imag
select_s1 => bf3_select_s1
select_s2 => bf3_select_s2
select_s3 => bf3_select_s3
x_out_real => reg_s3_in_real
x_out_imag => reg_s3_in_imag
y_out_real => bf3_out_real
y_out_imag => bf3_out_imag
begin
# Derive the control signals for each stage from the incoming counter.
counter_bf1 = counter >> COUNT_RATE
counter_bf2 = counter - 1 >> COUNT_RATE
counter_bf3 = counter - 2 >> COUNT_RATE
# Control R23BF by setting the muxes for each stage
case counter_bf1
when 0
bf1_select_s1 = 0
when 1
bf1_select_s1 = 0
when 2
bf1_select_s1 = 0
when 3
bf1_select_s1 = 0
when 4
bf1_select_s1 = 1
when 5
bf1_select_s1 = 1
when 6
bf1_select_s1 = 1
else
bf1_select_s1 = 1
end
case counter_bf2
when 0
bf2_select_s2 = 0
bf2_select_s1 = 0
when 1
bf2_select_s2 = 0
bf2_select_s1 = 0
when 2
bf2_select_s2 = 1
bf2_select_s1 = 1
when 3
bf2_select_s2 = 1
bf2_select_s1 = 1
when 4
bf2_select_s2 = 0
bf2_select_s1 = 0
when 5
bf2_select_s2 = 0
bf2_select_s1 = 0
when 6
bf2_select_s2 = 0
bf2_select_s1 = 1
else
bf2_select_s2 = 0
bf2_select_s1 = 1
end
case counter_bf3
when 0
bf3_select_s3 = 0
bf3_select_s2 = 0
bf3_select_s1 = 0
when 1
bf3_select_s3 = 0
bf3_select_s2 = 1
bf3_select_s1 = 1
when 2
bf3_select_s3 = 0
bf3_select_s2 = 0
bf3_select_s1 = 0
when 3
bf3_select_s3 = 1
bf3_select_s2 = 0
bf3_select_s1 = 1
when 4
bf3_select_s3 = 0
bf3_select_s2 = 0
bf3_select_s1 = 0
when 5
bf3_select_s3 = 1
bf3_select_s2 = 1
bf3_select_s1 = 1
when 6
bf3_select_s3 = 0
bf3_select_s2 = 0
bf3_select_s1 = 0
else
bf3_select_s3 = 0
bf3_select_s2 = 0
bf3_select_s1 = 1
end
# Update registers (stage 1)
reg_s1_out_real = reg_s1_real[(N/2)-1]
reg_s1_out_imag = reg_s1_imag[(N/2)-1]
reg_s1_real[0] = reg_s1_in_real
reg_s1_imag[0] = reg_s1_in_imag
for i in 1:((N/2)-1)
reg_s1_real[i] = reg_s1_real[i-1]
reg_s1_imag[i] = reg_s1_imag[i-1]
end
# Update registers (stage 2)
reg_s2_out_real = reg_s2_real[(N/4)-1]
reg_s2_out_imag = reg_s2_imag[(N/4)-1]
reg_s2_real[0] = reg_s2_in_real
reg_s2_imag[0] = reg_s2_in_imag
for i in 1:((N/4)-1)
reg_s2_real[i] = reg_s2_real[i-1]
reg_s2_imag[i] = reg_s2_imag[i-1]
end
# Update registers (stage 3)
reg_s3_out_real = reg_s3_real[(N/8)-1]
reg_s3_out_imag = reg_s3_imag[(N/8)-1]
reg_s3_real[0] = reg_s3_in_real
reg_s3_imag[0] = reg_s3_in_imag
for i in 1:((N/8)-1)
reg_s3_real[i] = reg_s3_real[i-1]
reg_s3_imag[i] = reg_s3_imag[i-1]
end
# Connect outputs
data_out_real = bf3_out_real
data_out_imag = bf3_out_imag
end
# -----------------------------------------------------------------------------
# Complex multiplier
# -----------------------------------------------------------------------------
component complex_mult
# Generic - settings
IO_WL : generic integer = 10 # Word length
IO_IWL : generic integer = 2 # Integer word length
# Generic - types
T_IO : generic type = signed(IO_WL, IO_IWL)
T_MULT : generic type = signed(2*IO_WL+1, 2*IO_IWL)
# Ports
x_real : in T_IO
x_imag : in T_IO
y_real : in T_IO
y_imag : in T_IO
z_real : out T_IO
z_imag : out T_IO
variable
m1 : T_MULT
m2 : T_MULT
m3 : T_MULT
m4 : T_MULT
begin
m1 = convert(T_MULT, x_real * y_real)
m2 = convert(T_MULT, x_imag * y_imag)
m3 = convert(T_MULT, x_real * y_imag)
m4 = convert(T_MULT, x_imag * y_real)
z_real = convert(T_IO, m1 - m2)
z_imag = convert(T_IO, m3 + m4)
end
# -----------------------------------------------------------------------------
# Top component
# -----------------------------------------------------------------------------
component top
IO_WL : generic integer = 16 # Word length
IO_IWL : generic integer = 8 # Integer word length
T : generic type = signed(IO_WL, IO_IWL)
T_MULT : generic type = signed(2*IO_WL+1, 2*IO_IWL)
x_real : in T
x_imag : in T
twiddle_real : in T
twiddle_imag : in T
y_real : out T
y_imag : out T
variable
bf1_out_real : T
bf1_out_imag : T
bf2_in_real : T
bf2_in_imag : T
bf1_control : unsigned(6)
bf2_control : unsigned(3)
register
# Control counters for both stages.
# The second stage is initialized with 5, to compensate
# for the pipeline of the first stage.
bf1_counter : unsigned(6) = 0
bf2_counter : unsigned(3) = 5
generate
bf1 : bf23
T = T
N = 64
COUNT_RATE = 3
data_in_real => x_real
data_in_imag => x_imag
data_out_real => bf1_out_real
data_out_imag => bf1_out_imag
counter => bf1_control
cmult : complex_mult
T_IO = T
T_MULT = T_MULT
x_real => bf1_out_real
x_imag => bf1_out_imag
y_real => twiddle_real
y_imag => twiddle_imag
z_real => bf2_in_real
z_imag => bf2_in_imag
bf2 : bf23
T = T
N = 8
COUNT_RATE = 0
data_in_real => bf2_in_real
data_in_imag => bf2_in_imag
data_out_real => y_real
data_out_imag => y_imag
counter => bf2_control
begin
# Counter 1 for the control of butterfly 1
if (bf1_counter == 63)
bf1_counter = 0
else
bf1_counter = bf1_counter + 1
end
bf1_control = bf1_counter
# Counter 2 for the control of butterfly 2
if (bf2_counter == 7)
bf2_counter = 0
else
bf2_counter = bf2_counter + 1
end
bf2_control = bf2_counter
end