diff --git a/U4_FSM/Makefile b/U4_FSM/Makefile index 1d8289a..5b7add9 100644 --- a/U4_FSM/Makefile +++ b/U4_FSM/Makefile @@ -1,9 +1,10 @@ -vhdl_srcs = down_counter_int.vhd \ - top_entity.vhd \ - test_top_entity.vhd \ +vhdl_srcs = ../scripts/test_utility.vhd \ + squareRoot_pipe.vhd \ + fft_magnitude_calc.vhd \ + test_fsm.vhd \ -main = test_top_entity +main = tb_fft_magnitude_calc CHECK_RESULTS = true diff --git a/U4_FSM/Zustandsmaschine.pdf b/U4_FSM/Zustandsmaschine.pdf new file mode 100644 index 0000000..c23045e Binary files /dev/null and b/U4_FSM/Zustandsmaschine.pdf differ diff --git a/U4_FSM/fft_magnitude_calc.vhd b/U4_FSM/fft_magnitude_calc.vhd new file mode 100644 index 0000000..b4fe6b1 --- /dev/null +++ b/U4_FSM/fft_magnitude_calc.vhd @@ -0,0 +1,153 @@ +------------------------------------------------------------------------ +-- fft_magnitude_calc +-- +-- calculation of FFT magnitude sqrt(real_part²+im_part²) +-- Inputs: +-- input_re in: +-1 signed Fixpoint (0.5=0x40000000, -0.5=0xC0000000 (negative numbers in 2K) +-- input_im in: +-1 signed Fixpoint (0.5=0x40000000, -0.5=0xC0000000 (negative numbers in 2K) +-- input_valid: high = inputs are valid for data processing +-- Outputs +-- output_magnitude: Fixpoint 0.5=0x40000000 (always positive) +-- output_valid: high = magnitude data is valid +----------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity fft_magnitude_calc is + port ( + clk : in std_logic; -- Takt + reset : in std_logic; -- Reset + input_valid: in std_logic; -- Eingangsdaten gueltig + input_re : in std_logic_vector( 31 downto 0 ); -- Realteil in Fixpoint + input_im : in std_logic_vector( 31 downto 0 ); -- Imaginaerteil in Fixpoint + output_valid : out std_logic; -- Ausgangsdaten gueltig + output_magnitude : out std_logic_vector( 31 downto 0 ) -- Berechnete magnitude + ); +end entity fft_magnitude_calc; + +architecture rtl of fft_magnitude_calc is + + + -- Zustaende fuer die Zustandsmaschine fuer die Berechnung + type CalcState is ( + CALC_IDLE, -- Zustand Leerlauf + CALC_MULTIPLY, -- Zustand Berechnung real_part² und im_part² + CALC_ADD, -- Zustand Berecnung Addition real_part²+im_part² + CALC_SQRT, -- Zustand Berechnung der sqrt(real_part²+im_part²) + CALC_STORE_RESULT -- Zustand Setzen von output_valid und output_magnitude + ); + + -- Legen Sie die Signale current_calc_state und next_calc_state fuer die Zustandsmaschine CalcState an + + -- Legen Sie die Signale re_multiply_re und im_multiply_im als signed (63 downto 0) an + + -- Legen Sie die Signal re2_add_im2 als signed (63 downto 0) an + + -- Legen Sie die Signal output_sqrt als std_logic_vector (31 downto 0) an + + -- Legen Sie die Signal output_sqrt als std_logic_vector (15 downto 0) an + + -- Legen Sie das Signal start_sqrt_calc als std_logic an + + -- Legen Sie das Signal sqrt_out_valid_flag als std_logic an + + +begin + + -- uebergangsschaltnetz der Zustandsmaschine fuer die Berechnung (Strukturvariante 2 Process Zustandsmaschine) + -- Beschreiben Sie den Prozess fuer das uebergangsschaltnetz (Case-Anweisung) + -- CALC_IDLE -> CALC_MULTIPLY wenn input_valid = 1 + -- CALC_MULTIPLY -> CALC_ADD + -- CALC_ADD -> CALC_SQRT + -- CALC_SQRT -> CALC_STORE_RESULT wenn sqrt_out_valid_flag = 1 + -- CALC_STORE_RESULT -> CALC_IDLE + calc_state_transitions : process ( all ) is + begin + + end process calc_state_transitions; + + -- Zustandsspeicher und Ausgangsschaltnetz zu der Steuerung der Berechnung (Strukturvariante 2 Process Zustandsmaschine) + sync : process ( clk, reset ) is + begin + -- Der Prozess steuert folgende Signale setzen Sie fuer alle passende Resetwerte + -- current_calc_state + -- re_multiply_re + -- im_multiply_im + -- re2_add_im2 + -- input_sqrt + -- start_sqrt_calc + -- output_valid + -- output_magnitude + if ( reset = '1' ) then + + elsif ( rising_edge( clk ) ) then + + -- Machen Sie Anweisungen um start_sqrt_calc und output_valid auf 0 zu setzen + + -- Realisieren Sie den Zustandsspeicher current_calc_state + + -- Vervollstaendigen Sie das Ausgangsschaltnetz + case next_calc_state is + when CALC_IDLE=> null; + + -- calculation of real_part² and im_part² + -- Anweisung fuer die Berechnung von re_multiply_re = input_re² (Datentypen beachten) + -- Anweisung fuer die Berechnung von im_multiply_im = input_im² (Datentypen beachten) + when CALC_MULTIPLY => + + -- calculation of real_part²*+im_part² + -- Anweisung fuer die Berechnung von re2_add_im2 = re_multiply_re + im_multiply_im + when CALC_ADD => + + -- calculation of sqrt(real_part²+im_part²) + -- Anweisung um input_sqrt mit den obersten 32-Bit von re2_add_im2 zu belegen (Datentypen beachten) + -- Anweisung um start_sqrt_calc mit 1 zu setzen + when CALC_SQRT => + + -- Setzen der Entity-Ausgaenge + -- Anweisung um die obersten 16 bit von output_magnitude mit output_sqrt zu setzen und die untern 16 Bit mit 0 + -- Anweisung um output_valid mit 1 zu setzen + when CALC_STORE_RESULT => + + when others => NUll; + end case; + end if; + end process sync; + + + -- Instanziierung des SQRT Moduls fuer die Berechnung der Quardratwurzel + -- Weisen Sie die Signale output_sqrt, reset, input_sqrt und clk richtig zu + sqrt_module : entity work.squareRoot_pipe + generic map ( + G_DATA_W => 32 + ) + port map ( + clk => , + rst => , + iv_data => , + ov_res => + ); + + -- Dieser Prozess sorgt dafuer, dass 16 Takte nachdem start_sqrt_calc 1 geworden ist sqrt_out_valid_flag zu 1 wird + -- Wird benoetigt um die Berechnungsdauer des sqrt_module anzueigen + -- Hier muss nichts veraendert werden + p_sqrt_out_valid_flag: process ( clk, reset ) is + variable delay_sqrt_out_valid_flag : std_logic_vector(14 downto 0); + begin + if ( reset = '1' ) then + sqrt_out_valid_flag <= '0'; + delay_sqrt_out_valid_flag := (others => '0'); + elsif ( rising_edge( clk ) ) then + sqrt_out_valid_flag <= delay_sqrt_out_valid_flag(14); + delay_sqrt_out_valid_flag := delay_sqrt_out_valid_flag(13 downto 0) & start_sqrt_calc; + if sqrt_out_valid_flag = '1' then + delay_sqrt_out_valid_flag := (others => '0'); + end if; + end if; + end process p_sqrt_out_valid_flag; + + +end architecture rtl; + diff --git a/U4_FSM/squareRoot_pipe.vhd b/U4_FSM/squareRoot_pipe.vhd new file mode 100644 index 0000000..2562e0f --- /dev/null +++ b/U4_FSM/squareRoot_pipe.vhd @@ -0,0 +1,119 @@ +---------------------------------------------------------------------------------------------------- +-- Component : squareRoot_pipe +-- Author : pwkolas +---------------------------------------------------------------------------------------------------- +-- File : squareRoot_pipe.vhd +-- Mod. Date : XX.XX.XXXX +-- Version : 1.00 +---------------------------------------------------------------------------------------------------- +-- Description : Square root calculator. +-- Based on +-- "A New Non-Restoring Square Root Algorithm and Its VLSI Implementations" +-- +---------------------------------------------------------------------------------------------------- +-- Modification History : +-- +---------------------------------------------------------------------------------------------------- +-- Comments : +-- +---------------------------------------------------------------------------------------------------- + +library ieee; + +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity squareRoot_pipe is + generic ( + G_DATA_W : integer := 32 + ); + port ( + clk : in std_logic; + rst : in std_logic; + iv_data : in std_logic_vector(G_DATA_W-1 downto 0); + ov_res : out std_logic_vector((G_DATA_W/2)-1 downto 0) + ); +end entity squareRoot_pipe; + +architecture squareRoot_pipe_rtl of squareRoot_pipe is + + constant C_ALU_W : integer := ((G_DATA_W/2) + 2); + constant C_PIPE_L : integer := G_DATA_W/2; + constant C_OFFSET : integer := 3; -- width of start vectors going to ALU + + type t_arr_pipe_x_data is array (C_PIPE_L-1 downto 0) of unsigned(G_DATA_W-1 downto 0); + signal a_data : t_arr_pipe_x_data; -- (D) + signal a_R : t_arr_pipe_x_data; -- (R) + + type t_arr_pipe_x_alu is array (C_PIPE_L-1 downto 0) of unsigned(C_ALU_W-1 downto 0); + + type t_arr_pipe_x_res is array (C_PIPE_L-1 downto 0) of unsigned(G_DATA_W/2-1 downto 0); + signal a_Q : t_arr_pipe_x_res; -- (ALU Q out) + + signal nextOp : std_logic_vector(C_PIPE_L-1 downto 0); + +begin + sqrt_p : process (clk, rst) + variable va_AluInR : t_arr_pipe_x_alu; -- (ALU R in) + variable va_AluInQ : t_arr_pipe_x_alu; -- (ALU Q in) + variable va_AluOut : t_arr_pipe_x_alu; -- (ALU Q out) + begin + if (rst = '1') then + a_data <= (others => (others => '0')); + a_R <= (others => (others => '0')); + a_Q <= (others => (others => '0')); + va_AluInR := (others => (others => '0')); + va_AluInQ := (others => (others => '0')); + va_AluOut := (others => (others => '0')); + nextOp <= (others => '0'); + elsif rising_edge(clk) then + -- stage 0 start conditions, ALU inputs + va_AluInR(0) := (others => '0'); + va_AluInR(0)(1 downto 0) := unsigned(iv_data(G_DATA_W-1 downto G_DATA_W-1-1)); + va_AluInQ(0) := (others => '0'); + va_AluInQ(0)(0) := '1'; + + -- stage 0 calculations + va_AluOut(0) := va_AluInR(0) - va_AluInQ(0); + + -- stage 0 result registers, ALU output + a_data(0) <= shift_left(unsigned(iv_data), 2); + a_R(0) <= (others => '0'); + a_R(0)(G_DATA_W-1 downto G_DATA_W-1-1) <= va_AluOut(0)(1 downto 0); + a_Q(0) <= (others => '0'); + a_Q(0)(0) <= not va_AluOut(0)(2); + nextOp(0) <= not va_AluOut(0)(2); + + -- next stages + for i in 1 to C_PIPE_L-1 loop + -- prepare inputs for next stage + va_AluInR(i) := (others => '0'); + va_AluInR(i)(C_OFFSET+i-1 downto 2) := a_R(i-1)(G_DATA_W-(i-1)-1 downto G_DATA_W-(2*i)); + va_AluInR(i)(2-1 downto 0) := a_data(i-1)(G_DATA_W-1 downto G_DATA_W-1-1); + va_AluInQ(i) := (others => '0'); + va_AluInQ(i)(C_OFFSET+(i-1)-1 downto 2) := a_Q(i-1)(i-1 downto 0); + va_AluInQ(i)(1) := not a_Q(i-1)(0); + va_AluInQ(i)(0) := '1'; + + -- ALU ADD/SUB + if (nextOp(i-1) = '1') then + va_AluOut(i) := va_AluInR(i) - va_AluInQ(i); + else + va_AluOut(i) := va_AluInR(i) + va_AluInQ(i); + end if; + + -- result registers + a_data(i) <= shift_left(unsigned(a_data(i-1)), 2); + a_R(i) <= (others => '0'); + a_R(i)(G_DATA_W-i-1 downto G_DATA_W-2*(i+1)) <= va_AluOut(i)(i+1 downto 0); + a_Q(i) <= shift_left(unsigned(a_Q(i-1)), 1); + a_Q(i)(0) <= not va_AluOut(i)(i+2); + nextOp(i) <= not va_AluOut(i)(i+2); + + end loop; + end if; + end process; + + ov_res <= std_logic_vector(a_Q(C_PIPE_L-1)); + +end architecture squareRoot_pipe_rtl; diff --git a/U4_FSM/test_fsm.vhd b/U4_FSM/test_fsm.vhd new file mode 100644 index 0000000..998225f --- /dev/null +++ b/U4_FSM/test_fsm.vhd @@ -0,0 +1,89 @@ +------------------------------------------------------------------------ +-- fft_magnitude_calc +-- +-- calculation of FFT magnitude sqrt(real_part²+im_part²) +-- Inputs: +-- input_re in: +-1 signed Fixpoint (0.5=0x40000000, -0.5=0xC0000000 (negative numbers in 2K) +-- input_im in: +-1 signed Fixpoint (0.5=0x40000000, -0.5=0xC0000000 (negative numbers in 2K) +-- input_valid: high = inputs are valid for data processing +-- Outputs +-- output_magnitude: Fixpoint 0.5=0x40000000 (always positive) +-- output_valid: high = magnitude data is valid +----------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity tb_fft_magnitude_calc is + generic( GUI_MODE : boolean; CHECK_RESULTS : boolean ); +end entity tb_fft_magnitude_calc; + + +architecture rtl of tb_fft_magnitude_calc is + + + signal clk : std_logic := '0'; -- Takt + signal reset : std_logic := '1'; -- Reset + signal input_valid: std_logic := '0'; -- Eingangsdaten gültig + signal input_re : std_logic_vector( 31 downto 0 ) := X"40000000"; -- Realteil in Fixpoint + signal input_im : std_logic_vector( 31 downto 0 ):= X"40000000"; -- Imaginärteil in Fixpoint + signal output_valid : std_logic; -- Ausgangsdaten gültig + signal output_magnitude : std_logic_vector( 31 downto 0 ); + +begin + + clk <= not clk after 10 ns; + + reset_release : process is + begin + wait for 435 ns; + reset <= '0'; + wait; + end process reset_release; + + -- Instanziierung des SQRT Moduls für die Berechnung der Quardratwurzel + -- Weisen Sie die Signale output_sqrt, reset, input_sqrt und clk richtig zu + fft_magnitude_calc_module : entity work.fft_magnitude_calc + port map ( + clk => clk, + reset => reset, + input_valid => input_valid, -- Eingangsdaten gültig + input_re => input_re, -- Realteil in Fixpoint + input_im => input_im, -- Imaginärteil in Fixpoint + output_valid => output_valid, -- Ausgangsdaten gültig + output_magnitude => output_magnitude -- Berechnete magnitude + ); + + stimulus: process is + begin + wait until falling_edge( reset ); + wait until falling_edge( clk ); + input_valid <= '1'; + wait until falling_edge( clk ); + input_valid <= '0'; + + wait until falling_edge( output_valid ); + + wait for 200 ns; + + wait until falling_edge( clk ); + input_valid <= '1'; + input_re <= X"20000000"; + input_im <= X"20000000"; + wait until falling_edge( clk ); + input_valid <= '0'; + + wait until falling_edge( output_valid ); + + + wait until falling_edge( clk ); + if ( GUI_MODE ) then + std.env.stop; + else + std.env.finish; + end if; + + end process stimulus; + +end architecture rtl; diff --git a/U4_FSM/vsim.wave b/U4_FSM/vsim.wave new file mode 100644 index 0000000..ea235ec --- /dev/null +++ b/U4_FSM/vsim.wave @@ -0,0 +1,3 @@ +onerror {resume} +quietly WaveActivateNextPane {} 0 +add wave -noupdate /tb_fft_magnitude_calc/fft_magnitude_calc_module/*