aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Kamuf <matthias.kamuf@hs-augsburg.de>2022-05-04 14:56:11 +0200
committerMatthias Kamuf <matthias.kamuf@hs-augsburg.de>2022-05-04 14:56:11 +0200
commit1d5a8634e3a54bbcd2e6ac3074e6c38f085feef0 (patch)
tree0e8ccbdac9b3f9486b50d4a97ac8147c19156015
parentf37b864e1b943984739931b0950c45c6f705c679 (diff)
Added source files for simple FIR filter
-rwxr-xr-xmatlab/comms/save_variable.m16
-rwxr-xr-xmatlab/comms/script_verify_fir.m148
-rwxr-xr-xsim/fir/makefile67
-rwxr-xr-xsim/fir/makefile.sources18
-rw-r--r--src/fir_mac_rtl.vhd47
-rw-r--r--src/fir_structure.vhd124
-rw-r--r--src/t_fir_fileio.vhd111
7 files changed, 531 insertions, 0 deletions
diff --git a/matlab/comms/save_variable.m b/matlab/comms/save_variable.m
new file mode 100755
index 0000000..6bc45e6
--- /dev/null
+++ b/matlab/comms/save_variable.m
@@ -0,0 +1,16 @@
+function save_variable (var, format, filename)
+
+% function save_variable (var, format, filename)
+%
+% Saves a variable var to filename using format,
+% e.g., save_variable (x, '%d', 'input.dat');
+
+[fid, message] = fopen(filename, 'w');
+if fid == -1
+ disp('File error. Message returned was:')
+ disp(message)
+ return
+end
+fprintf(fid, [format,'\n'], var);
+fclose(fid);
+return;
diff --git a/matlab/comms/script_verify_fir.m b/matlab/comms/script_verify_fir.m
new file mode 100755
index 0000000..d53842f
--- /dev/null
+++ b/matlab/comms/script_verify_fir.m
@@ -0,0 +1,148 @@
+close all; clear *;
+
+% Whether data shall be written to file or not
+writeDataToFile = 0;
+
+% Filter order
+N = 7;
+% Sampling frequency in <Hz>
+fs = 50e6;
+% Cutoff frequency in <Hz>
+fc = 1e6;
+
+% Design filter (floating-point)
+h = fir1(N, fc/(fs/2));
+
+% Plot frequency response
+figure(1);
+[H, f] = freqz(h, 1, 2^10, fs);
+subplot(211);
+plot(f/1e6, 20*log10(abs(H)), 'LineWidth', 2); grid on; hold on; box off;
+xlabel('f in MHz \rightarrow'); ylabel('|H(f)| in dB \rightarrow');
+subplot(212);
+plot(f/1e6, unwrap(angle(H)), 'LineWidth', 2); grid on; hold on; box off;
+xlabel('f in MHz \rightarrow'); ylabel('arg H(f) in rad \rightarrow');
+
+% Plot impulse response
+figure(2);
+stem(0:N, h, 'LineWidth', 2); hold on;
+xlabel('Coefficient index \rightarrow'); ylabel('Amplitude \rightarrow');
+
+% Wordlength of coefficients
+w_c = 12;
+
+% Convert floating-point coefficients to fixed-point
+hqi = round(h*2^(w_c-1));
+hq = hqi/2^(w_c-1);
+
+% Save integer coefficients to file for later use in VHDL model
+if writeDataToFile == 1
+ fileID = fopen('hqi.txt','w');
+ fprintf(fileID, ['CONSTANT COEFFS : COEFFS_TYPE := (']);
+ for k = 1:N
+ fprintf(fileID, '%d,', hqi(k));
+ end
+ fprintf(fileID, '%d);\n', hqi(N+1));
+ fclose(fileID);
+end
+
+% Plot quantized frequency response
+figure(1);
+[Hq, f] = freqz(hq, 1, 2^10, fs);
+subplot(211);
+plot(f/1e6, 20*log10(abs(Hq)), 'LineWidth', 2);
+title(['Transfer function, N = ' num2str(N), ', fc = ' num2str(fc/1e6) ' MHz']);
+subplot(212);
+plot(f/1e6, unwrap(angle(Hq)), 'LineWidth', 2);
+
+% Plot quantized impulse response
+figure(2);
+stem(0:N, hq, 'x', 'LineWidth', 2); hold off;
+legend('Float', ['Fixed 1.' num2str(w_c-1) 's, normalized']);
+title('Impulse response');
+
+% Create input sample stream
+nofSamples = 2^12;
+sigma = 0.25;
+x = sigma*randn(1, nofSamples);
+
+% Find outliers and saturate to [-1 1-LSB]
+w_in = 14;
+idx = (x >= 1); x(idx) = 1-2^-(w_in-1);
+idx = (x < -1); x(idx) = -1;
+
+% Display histogram
+figure(3);
+histogram(x, 100);
+xlabel('x \rightarrow'); ylabel('Occurences \rightarrow');
+title(['Distribution of input samples, \sigma = ' num2str(sigma)]);
+
+% Quantize input sample stream to w_in bit
+xqi = round(x*2^(w_in-1));
+xq = xqi/2^(w_in-1);
+
+% Save input sample stream to file
+if writeDataToFile == 1
+ save_variable(xqi, '%d', '../../sim/fir/stimuli/fir_stimuli.dat');
+end
+
+% Filter quantized input stream with quantized impulse response
+yq = filter(hq, 1, xq);
+
+% Plot quantized input and output sample streams
+figure(4);
+t = (0:nofSamples-1)/fs;
+plot(t*1e6, xq); hold on; box off;
+plot(t*1e6, yq);
+xlabel('t in microseconds \rightarrow'); ylabel('Amplitude \rightarrow');
+
+% Estimate transfer function given specific outcome of xq
+[Hxyq, f] = tfestimate(xq, yq, [], [], 2^10, fs);
+
+% Plot estimated frequency response
+figure(1);
+subplot(211);
+plot(f/1e6, 20*log10(abs(Hxyq)), 'LineWidth', 2);
+subplot(212);
+plot(f/1e6, unwrap(angle(Hxyq)), 'LineWidth', 2);
+
+% Truncation of output result to w_out bit
+w_out = 14;
+
+% Filter quantized input with quantized impulse response
+yqi = filter(hqi, 1, xqi);
+
+% Determine dynamic wordlength of current result
+w_dyn_cur = ceil(log2(max(abs(yqi)))) + 1;
+disp(['Dynamic wordlength, current result: ' num2str(w_dyn_cur) ' bits']);
+
+% Determine worst-case dynamic wordlength
+w_dyn_wc = w_in + floor(log2(sum(abs(hqi)))) + 1;
+disp(['Dynamic wordlength, worst-case: ' num2str(w_dyn_wc) ' bits']);
+yqit = floor(yqi/2^(w_dyn_wc-w_out));
+
+% Determine dynamic wordlength of current output
+w_dyn_curs = ceil(log2(max(abs(yqit)))) + 1;
+disp(['Dynamic wordlength, current output: ' num2str(w_dyn_curs) ' bits']);
+
+% Plot truncated output sample stream
+figure(4);
+plot(t, yqit / 2^(w_out-1));
+legend('x(t)', 'y(t)', 'y(t), truncated');
+title('Quantized input and output samples');
+
+% Estimate transfer function given specific outcome of xqint
+[Hxyqints, f] = tfestimate(xqi, yqit, [], [], 2^10, fs);
+
+% Plot the estimated frequency response
+figure(1);
+subplot(211);
+plot(f/1e6, 20*log10(abs(Hxyqints)*2^(w_in-w_out)), 'LineWidth', 2);
+legend('Float', ['Fixed 1.' num2str(w_c-1) 's'], 'Estimate', 'Estimate, truncated', 'Location','southwest');
+subplot(212);
+plot(f/1e6, unwrap(angle(Hxyqints)), 'LineWidth', 2);
+
+% Save output sample stream to file
+if writeDataToFile == 1
+ save_variable(yqit, '%d', '../../sim/fir/log/fir_result_ref.dat');
+end \ No newline at end of file
diff --git a/sim/fir/makefile b/sim/fir/makefile
new file mode 100755
index 0000000..bcf8ac0
--- /dev/null
+++ b/sim/fir/makefile
@@ -0,0 +1,67 @@
+## ----------------------------------------------------------------------------
+## Script : makefile
+## ----------------------------------------------------------------------------
+## Author : Johann Faerber, Friedrich Beckmann
+## Company : University of Applied Sciences Augsburg
+## ----------------------------------------------------------------------------
+## Description: This makefile allows automating design flow with ModelSim,
+## it is based on a design directory structure described in
+## ../makefile
+## ----------------------------------------------------------------------------
+
+###################################################################
+# Project Configuration:
+#
+# assign variable PROJECT with the top level project name
+#
+# Prerequisite:
+# - mandatory design directory structure (see end of file)
+# - assumes file name of testbench t_$(PROJECT).vhd
+###################################################################
+
+PROJECT = fir
+
+include ./makefile.sources
+
+# Add here the testbench file
+SOURCE_FILES = $(SYN_SOURCE_FILES) \
+../../src/t_$(PROJECT)_fileio.vhd
+
+include ../makefile
+
+## ----------------------------------------------------------------------------
+## Description:
+## ------------
+## assumes the following design directory structure as prerequisite
+##
+## DigitaltechnikPraktikum
+## |
+## +---src
+## | and2gate_equation.vhd
+## | invgate_equation.vhd
+## | mux2to1_structure.vhd
+## | or2gate_equation.vhd
+## | t_mux2to1.vhd
+## | de1_mux2to1_structure.vhd
+## |
+## +---sim
+## | | makefile
+## | |
+## | \---mux2to1
+## | makefile
+## | makefile.sources
+## |
+## +---pnr
+## | | makefile
+## | |
+## | \---de1_mux2to1
+## | de1_mux2to1_pins.tcl
+## | makefile
+## |
+## \---scripts
+## de1_pin_assignments_minimumio.csv
+## de1_pin_assignments_minimumio.tcl
+## modelsim.ini
+## quartus_project_settings.tcl
+## ----------------------------------------------------------------------------
+
diff --git a/sim/fir/makefile.sources b/sim/fir/makefile.sources
new file mode 100755
index 0000000..575e14f
--- /dev/null
+++ b/sim/fir/makefile.sources
@@ -0,0 +1,18 @@
+## ----------------------------------------------------------------------------
+## Script : makefile.sources
+## ----------------------------------------------------------------------------
+## Author : Johann Faerber
+## Company : University of Applied Sciences Augsburg
+## ----------------------------------------------------------------------------
+## Description: provide all the VHDL source files in the variable SYN_SOURCE_FILES
+## Attention !!!
+## -------------
+## Do not forget a new line after the final source file !
+## ----------------------------------------------------------------------------
+
+SYN_SOURCE_FILES = \
+../../src/fir_mac_rtl.vhd \
+../../src/fir_structure.vhd \
+
+# do not delete this line
+# -----------------------------------------------------------------------------
diff --git a/src/fir_mac_rtl.vhd b/src/fir_mac_rtl.vhd
new file mode 100644
index 0000000..866fa50
--- /dev/null
+++ b/src/fir_mac_rtl.vhd
@@ -0,0 +1,47 @@
+-------------------------------------------------------------------------------
+-- Module : fir_mac
+-------------------------------------------------------------------------------
+-- Author : Matthias Kamuf
+-- Company : University of Applied Sciences Augsburg
+-------------------------------------------------------------------------------
+-- Description: Module fir_mac used as part of fir
+--
+-------------------------------------------------------------------------------
+-- Revisions : see end of file
+-------------------------------------------------------------------------------
+LIBRARY IEEE;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+
+ENTITY fir_mac IS
+ GENERIC (
+ gen_w_in : natural := 14;
+ gen_w_c : natural := 12);
+ PORT (
+ clk_i : IN std_ulogic;
+ rst_ni : IN std_ulogic;
+ hl_i : IN std_ulogic_vector(gen_w_c-1 DOWNTO 0); -- left coefficient
+ hr_i : IN std_ulogic_vector(gen_w_c-1 DOWNTO 0); -- right coefficient
+ d_i : IN std_ulogic_vector(gen_w_in-1 DOWNTO 0); -- data input first register
+ d_o : OUT std_ulogic_vector(gen_w_in-1 DOWNTO 0); -- data output second register
+ sum_o : OUT std_ulogic_vector(gen_w_in+gen_w_c DOWNTO 0)); -- registered output sum_o
+END fir_mac;
+
+ARCHITECTURE rtl OF fir_mac IS
+
+
+BEGIN
+
+ -- shift register at sample rate
+
+ -- products left and right of first register
+
+ -- output sum (registered) at sample rate
+
+END rtl;
+
+-------------------------------------------------------------------------------
+-- Revisions:
+-- ----------
+-- $Id:$
+-------------------------------------------------------------------------------
diff --git a/src/fir_structure.vhd b/src/fir_structure.vhd
new file mode 100644
index 0000000..88364e5
--- /dev/null
+++ b/src/fir_structure.vhd
@@ -0,0 +1,124 @@
+-------------------------------------------------------------------------------
+-- Module : fir
+-------------------------------------------------------------------------------
+-- Author : Matthias Kamuf
+-- Company : University of Applied Sciences Augsburg
+-------------------------------------------------------------------------------
+-- Description: Top-level of module fir
+--
+-------------------------------------------------------------------------------
+-- Revisions : see end of file
+-------------------------------------------------------------------------------
+LIBRARY IEEE;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+
+ENTITY fir IS
+ PORT (
+ clk_i : IN std_ulogic;
+ rst_ni : IN std_ulogic;
+ valid_i : IN std_ulogic;
+ sample_i : IN std_ulogic_vector(13 DOWNTO 0);
+ valid_o : OUT std_ulogic;
+ sample_o : OUT std_ulogic_vector(13 DOWNTO 0));
+END fir;
+
+ARCHITECTURE structure OF fir IS
+
+ -- coefficient wordlength
+ CONSTANT W_C : natural := 12;
+
+ -- type definition for coefficients
+ TYPE COEFFS_TYPE IS ARRAY (0 TO 7) OF integer;
+
+ -- HERE SHALL BE THE CONTENT OF hqi.txt --->
+
+ -- <---
+
+ COMPONENT fir_mac IS
+ GENERIC (
+ gen_w_in : natural := 14;
+ gen_w_c : natural := 12);
+ PORT (
+ clk_i : IN std_ulogic;
+ rst_ni : IN std_ulogic;
+ hl_i : IN std_ulogic_vector(gen_w_c-1 DOWNTO 0); -- left coefficient
+ hr_i : IN std_ulogic_vector(gen_w_c-1 DOWNTO 0); -- right coefficient
+ d_i : IN std_ulogic_vector(gen_w_in-1 DOWNTO 0); -- data input first register
+ d_o : OUT std_ulogic_vector(gen_w_in-1 DOWNTO 0); -- data output second register
+ sum_o : OUT std_ulogic_vector(gen_w_in+gen_w_c DOWNTO 0)); -- registered output sum_o
+ END COMPONENT fir_mac;
+
+ -- dynamic range of sum given coefficients above
+ CONSTANT W_DYN : natural := 1;
+
+BEGIN
+
+ -- component instantiation
+ mac0 : fir_mac
+ GENERIC MAP (
+ gen_w_in => sample_i'length,
+ gen_w_c => W_C)
+ PORT MAP (
+ clk_i => clk_i,
+ rst_ni => rst_ni,
+ hl_i => ,
+ hr_i => ,
+ d_i => ,
+ d_o => ,
+ sum_o => );
+
+ mac1 : fir_mac
+ GENERIC MAP (
+ gen_w_in => sample_i'length,
+ gen_w_c => W_C)
+ PORT MAP (
+ clk_i => clk_i,
+ rst_ni => rst_ni,
+ hl_i => ,
+ hr_i => ,
+ d_i => ,
+ d_o => ,
+ sum_o => );
+
+ mac2 : fir_mac
+ GENERIC MAP (
+ gen_w_in => sample_i'length,
+ gen_w_c => W_C)
+ PORT MAP (
+ clk_i => clk_i,
+ rst_ni => rst_ni,
+ hl_i => ,
+ hr_i => ,
+ d_i => ,
+ d_o => ,
+ sum_o => );
+
+ mac3 : fir_mac
+ GENERIC MAP (
+ gen_w_in => sample_i'length,
+ gen_w_c => W_C)
+ PORT MAP (
+ clk_i => clk_i,
+ rst_ni => rst_ni,
+ hl_i => ,
+ hr_i => ,
+ d_i => ,
+ d_o => ,
+ sum_o => );
+
+ -- combining sums of individual fir_mac
+
+ -- final sum
+
+ -- truncated final sum (registered) at sample rate
+
+ -- (registered and delayed due to pipeline stage in fir_mac) valid signal at sample rate
+
+END structure;
+
+-------------------------------------------------------------------------------
+-- Revisions:
+-- ----------
+-- $Id:$
+-------------------------------------------------------------------------------
diff --git a/src/t_fir_fileio.vhd b/src/t_fir_fileio.vhd
new file mode 100644
index 0000000..3fd8363
--- /dev/null
+++ b/src/t_fir_fileio.vhd
@@ -0,0 +1,111 @@
+-------------------------------------------------------------------------------
+-- Module : t_fir_fileio
+-------------------------------------------------------------------------------
+-- Author : Matthias Kamuf
+-- Company : University of Applied Sciences Augsburg
+-------------------------------------------------------------------------------
+-- Description: Testbench for module fir
+--
+------------------------------------------------------------------------------
+-- Revisions : see end of file
+-------------------------------------------------------------------------------
+LIBRARY IEEE;
+USE IEEE.std_logic_1164.ALL;
+USE IEEE.numeric_std.ALL;
+USE STD.textio.ALL;
+
+ENTITY t_fir IS
+
+END t_fir;
+
+ARCHITECTURE tbench OF t_fir IS
+
+ COMPONENT fir IS
+ PORT (
+ clk_i : IN std_ulogic;
+ rst_ni : IN std_ulogic;
+ valid_i : IN std_ulogic;
+ sample_i : IN std_ulogic_vector(13 DOWNTO 0);
+ valid_o : OUT std_ulogic;
+ sample_o : OUT std_ulogic_vector(13 DOWNTO 0));
+ END COMPONENT fir;
+
+ -- component ports
+ SIGNAL clk : std_ulogic;
+ SIGNAL rst_n : std_ulogic;
+ SIGNAL valid_in : std_ulogic;
+ SIGNAL sample_in : std_ulogic_vector(13 DOWNTO 0);
+ SIGNAL valid_out : std_ulogic;
+ SIGNAL sample_out : std_ulogic_vector(13 DOWNTO 0);
+
+ -- definition of a clock period
+ CONSTANT period : time := 20 ns;
+ -- switch for clock generator
+ SIGNAL clken_p : boolean := true;
+
+BEGIN
+
+ -- component instantiation
+ DUT : fir
+ PORT MAP (
+ clk_i => clk,
+ rst_ni => rst_n,
+ valid_i => valid_in,
+ sample_i => sample_in,
+ valid_o => valid_out,
+ sample_o => sample_out);
+
+ -- clock generation
+ clock_proc : PROCESS
+ BEGIN
+ WHILE clken_p LOOP
+ clk <= '0'; WAIT FOR period/2;
+ clk <= '1'; WAIT FOR period/2;
+ END LOOP;
+ WAIT;
+ END PROCESS;
+
+ reset : rst_n <= '0', '1' AFTER period;
+
+ stimuli_observer : PROCESS
+ VARIABLE Li : line; -- pointer to file input buffer
+ VARIABLE Vi : integer;
+ FILE stimulifile : text OPEN read_mode IS "stimuli/fir_stimuli.dat";
+
+ VARIABLE Lo : line; -- pointer to file output buffer
+ VARIABLE Vo : integer;
+ FILE resultfile : text OPEN write_mode IS "log/fir_result.dat";
+
+ BEGIN
+
+ valid_in <= '1';
+ sample_in <= (OTHERS => '0');
+
+ WAIT UNTIL rst_n = '1'; -- wait for reset
+
+ WHILE (NOT endfile(stimulifile)) LOOP
+ IF valid_in = '1' THEN
+ readline(stimulifile, Li);
+ read(Li, Vi);
+ sample_in <= std_ulogic_vector(to_signed(Vi, sample_in'length));
+ END IF;
+ IF valid_out = '1' THEN
+ Vo := to_integer(signed(sample_out));
+ write(Lo, Vo);
+ writeline(resultfile, Lo);
+ END IF;
+ WAIT UNTIL clk = '1';
+ END LOOP;
+
+ clken_p <= false; -- switch off clock generator
+
+ WAIT;
+ END PROCESS;
+END tbench;
+
+
+-------------------------------------------------------------------------------
+-- Revisions:
+-- ----------
+-- $Id:$
+-------------------------------------------------------------------------------