Livt packages
Livt.Signal
Version 0.1.1
Q1.15 sample streams, filters, windows, rate conversion, FFTs, oscillators, and mixers for Livt.
Published files (80)
src/transform/SequentialFftQ15Primitive.vhd.in
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.livt_lang_icontext_package.all;
use work.livt_lang_package.all;
entity livt_signal_transform_sequentialfftq15primitive is
port (
ctor_lvt_context_in : in t_icontext_in;
ctor_sampleshape : in std_logic_vector;
ctor_stageshape : in std_logic_vector;
ctor_stageshiftmask : in signed(31 downto 0);
ctor_inverse : in boolean;
ctor_inputbitreversed : in boolean;
ctor_outputbitreversed : in boolean;
ctor_inputvalid : in boolean;
ctor_inputready : out boolean;
ctor_inputreal : in std_logic_vector(15 downto 0);
ctor_inputimag : in std_logic_vector(15 downto 0);
ctor_inputfirst : in boolean;
ctor_inputlast : in boolean;
ctor_outputvalid : out boolean;
ctor_outputready : in boolean;
ctor_outputreal : out std_logic_vector(15 downto 0);
ctor_outputimag : out std_logic_vector(15 downto 0);
ctor_outputfirst : out boolean;
ctor_outputlast : out boolean;
ctor_framelengtherror : out boolean
);
end;
architecture rtl of livt_signal_transform_sequentialfftq15primitive is
constant SAMPLES : positive := ctor_sampleshape'length;
constant STAGES : positive := ctor_stageshape'length;
constant MASTER_SAMPLES : positive := 4096;
subtype complex_word_t is std_logic_vector(31 downto 0);
subtype q15_t is signed(15 downto 0);
subtype product_t is signed(31 downto 0);
subtype complex_product_t is signed(32 downto 0);
subtype butterfly_t is signed(33 downto 0);
type sample_memory_t is array (0 to SAMPLES - 1) of complex_word_t;
type phase_t is (load_frame, compute_read, compute_write,
emit_read, emit_hold);
function supported_size(value : positive) return boolean is
begin
return value = 8 or value = 16 or value = 32 or value = 64 or
value = 128 or value = 256 or value = 512 or value = 1024 or
value = 2048 or value = 4096;
end;
function reverse_bits(value : natural; width : positive) return natural is
variable remaining : natural := value;
variable result : natural := 0;
begin
for bit_index in 0 to width - 1 loop
result := result * 2 + remaining mod 2;
remaining := remaining / 2;
end loop;
return result;
end;
function pack_complex(real_part, imag_part : q15_t)
return complex_word_t is
begin
return std_logic_vector(real_part) & std_logic_vector(imag_part);
end;
function quantize_q15(value : butterfly_t; stage_shift : natural)
return q15_t is
constant TOTAL_SHIFT : natural := 15 + stage_shift;
variable extended : signed(34 downto 0);
variable magnitude, rounded : unsigned(34 downto 0);
variable sticky : boolean := false;
variable raw : integer;
begin
extended := resize(value, extended'length);
if extended(extended'high) = '1' then
magnitude := unsigned(-extended);
else
magnitude := unsigned(extended);
end if;
rounded := shift_right(magnitude, TOTAL_SHIFT);
if magnitude(TOTAL_SHIFT - 1) = '1' then
for bit_index in 0 to TOTAL_SHIFT - 2 loop
if magnitude(bit_index) = '1' then sticky := true; end if;
end loop;
if sticky or rounded(0) = '1' then rounded := rounded + 1; end if;
end if;
if extended(extended'high) = '1' then
if rounded >= resize(to_unsigned(32768, 16), rounded'length) then
return to_signed(-32768, 16);
end if;
raw := to_integer(rounded(15 downto 0));
return to_signed(-raw, 16);
end if;
if rounded > resize(to_unsigned(32767, 15), rounded'length) then
return to_signed(32767, 16);
end if;
return signed(rounded(15 downto 0));
end;
function twiddle(master_index : natural; inverse : boolean)
return complex_word_t is
variable real_part, imag_part : integer;
begin
case master_index is
-- GENERATED_TWIDDLE_CASE
when others => real_part := 0; imag_part := 0;
end case;
if inverse then
if imag_part = -32768 then imag_part := 32767;
else imag_part := -imag_part; end if;
end if;
return pack_complex(to_signed(real_part, 16), to_signed(imag_part, 16));
end;
signal sample_memory : sample_memory_t := (others => (others => '0'));
attribute ram_style : string;
attribute ram_style of sample_memory : signal is "block";
signal phase : phase_t := load_frame;
signal frame_active : boolean := false;
signal load_count : natural range 0 to SAMPLES - 1 := 0;
signal stage_index : natural range 0 to STAGES - 1 := 0;
signal group_base : natural range 0 to SAMPLES - 1 := 0;
signal group_size : natural range 2 to SAMPLES := 2;
signal half_size : natural range 1 to SAMPLES / 2 := 1;
signal position : natural range 0 to SAMPLES / 2 - 1 := 0;
signal twiddle_stride : natural range 1 to SAMPLES / 2 := SAMPLES / 2;
signal twiddle_index : natural range 0 to SAMPLES / 2 - 1 := 0;
signal address_a, address_b : natural range 0 to SAMPLES - 1 := 0;
signal operand_a, operand_b, operand_twiddle : complex_word_t :=
(others => '0');
signal emit_index : natural range 0 to SAMPLES - 1 := 0;
signal output_word : complex_word_t := (others => '0');
signal frame_length_error : boolean := false;
begin
ctor_inputready <= ctor_lvt_context_in.rst = '0' and phase = load_frame;
ctor_outputvalid <= ctor_lvt_context_in.rst = '0' and phase = emit_hold;
ctor_outputreal <= output_word(31 downto 16);
ctor_outputimag <= output_word(15 downto 0);
ctor_outputfirst <= emit_index = 0;
ctor_outputlast <= emit_index = SAMPLES - 1;
ctor_framelengtherror <= frame_length_error;
process (ctor_lvt_context_in.clk)
variable logical_index, memory_address : natural;
variable next_address_a, next_address_b : natural;
variable master_twiddle_index : natural;
variable ar, ai, br, bi, wr, wi : q15_t;
variable product_rr, product_ii, product_ri, product_ir : product_t;
variable twiddle_real, twiddle_imag : complex_product_t;
variable aligned_real, aligned_imag : complex_product_t;
variable sum_real, sum_imag, difference_real, difference_imag : butterfly_t;
variable result_a_real, result_a_imag : q15_t;
variable result_b_real, result_b_imag : q15_t;
variable selected_shift : natural range 0 to 1;
begin
if rising_edge(ctor_lvt_context_in.clk) then
if ctor_lvt_context_in.rst = '1' then
phase <= load_frame;
frame_active <= false;
load_count <= 0;
stage_index <= 0;
group_base <= 0;
group_size <= 2;
half_size <= 1;
position <= 0;
twiddle_stride <= SAMPLES / 2;
twiddle_index <= 0;
emit_index <= 0;
output_word <= (others => '0');
frame_length_error <= false;
else
assert supported_size(SAMPLES)
report "sequential FFT length must be in 8..4096" severity failure;
assert 2 ** STAGES = SAMPLES
report "sequential FFT length must be a power of two" severity failure;
assert to_integer(ctor_stageshiftmask) >= -1 and
to_integer(ctor_stageshiftmask) <= 4095
report "invalid FFT stage shift mask" severity failure;
frame_length_error <= false;
case phase is
when load_frame =>
if ctor_inputvalid then
if ctor_inputfirst then
if frame_active then frame_length_error <= true; end if;
logical_index := 0;
if ctor_inputbitreversed then
memory_address := logical_index;
else
memory_address := reverse_bits(logical_index, STAGES);
end if;
sample_memory(memory_address) <= pack_complex(
signed(ctor_inputreal), signed(ctor_inputimag));
load_count <= 1;
frame_active <= true;
if ctor_inputlast then
frame_length_error <= true;
frame_active <= false;
load_count <= 0;
end if;
elsif frame_active then
logical_index := load_count;
if ctor_inputbitreversed then
memory_address := logical_index;
else
memory_address := reverse_bits(logical_index, STAGES);
end if;
sample_memory(memory_address) <= pack_complex(
signed(ctor_inputreal), signed(ctor_inputimag));
if ctor_inputlast then
if load_count = SAMPLES - 1 then
frame_active <= false;
load_count <= 0;
stage_index <= 0;
group_base <= 0;
group_size <= 2;
half_size <= 1;
position <= 0;
twiddle_stride <= SAMPLES / 2;
twiddle_index <= 0;
phase <= compute_read;
else
frame_length_error <= true;
frame_active <= false;
load_count <= 0;
end if;
elsif load_count = SAMPLES - 1 then
frame_length_error <= true;
frame_active <= false;
load_count <= 0;
else
load_count <= load_count + 1;
end if;
else
frame_length_error <= true;
end if;
end if;
when compute_read =>
next_address_a := group_base + position;
next_address_b := next_address_a + half_size;
address_a <= next_address_a;
address_b <= next_address_b;
operand_a <= sample_memory(next_address_a);
operand_b <= sample_memory(next_address_b);
master_twiddle_index := twiddle_index
* (MASTER_SAMPLES / SAMPLES);
operand_twiddle <= twiddle(master_twiddle_index,
ctor_inverse);
phase <= compute_write;
when compute_write =>
ar := signed(operand_a(31 downto 16));
ai := signed(operand_a(15 downto 0));
br := signed(operand_b(31 downto 16));
bi := signed(operand_b(15 downto 0));
wr := signed(operand_twiddle(31 downto 16));
wi := signed(operand_twiddle(15 downto 0));
product_rr := br * wr;
product_ii := bi * wi;
product_ri := br * wi;
product_ir := bi * wr;
twiddle_real := resize(product_rr, 33)
- resize(product_ii, 33);
twiddle_imag := resize(product_ri, 33)
+ resize(product_ir, 33);
aligned_real := shift_left(resize(ar, 33), 15);
aligned_imag := shift_left(resize(ai, 33), 15);
sum_real := resize(aligned_real, 34)
+ resize(twiddle_real, 34);
sum_imag := resize(aligned_imag, 34)
+ resize(twiddle_imag, 34);
difference_real := resize(aligned_real, 34)
- resize(twiddle_real, 34);
difference_imag := resize(aligned_imag, 34)
- resize(twiddle_imag, 34);
if ctor_stageshiftmask(stage_index) = '1' then
selected_shift := 1;
else
selected_shift := 0;
end if;
result_a_real := quantize_q15(sum_real, selected_shift);
result_a_imag := quantize_q15(sum_imag, selected_shift);
result_b_real := quantize_q15(difference_real, selected_shift);
result_b_imag := quantize_q15(difference_imag, selected_shift);
sample_memory(address_a) <= pack_complex(
result_a_real, result_a_imag);
sample_memory(address_b) <= pack_complex(
result_b_real, result_b_imag);
if position + 1 < half_size then
position <= position + 1;
twiddle_index <= twiddle_index + twiddle_stride;
phase <= compute_read;
elsif group_base + group_size < SAMPLES then
group_base <= group_base + group_size;
position <= 0;
twiddle_index <= 0;
phase <= compute_read;
elsif stage_index + 1 < STAGES then
stage_index <= stage_index + 1;
group_base <= 0;
group_size <= group_size * 2;
half_size <= half_size * 2;
position <= 0;
twiddle_stride <= twiddle_stride / 2;
twiddle_index <= 0;
phase <= compute_read;
else
emit_index <= 0;
phase <= emit_read;
end if;
when emit_read =>
if ctor_outputbitreversed then
memory_address := reverse_bits(emit_index, STAGES);
else
memory_address := emit_index;
end if;
output_word <= sample_memory(memory_address);
phase <= emit_hold;
when emit_hold =>
if ctor_outputready then
if emit_index = SAMPLES - 1 then
emit_index <= 0;
phase <= load_frame;
else
emit_index <= emit_index + 1;
phase <= emit_read;
end if;
end if;
end case;
end if;
end if;
end process;
end;