diff options
| -rwxr-xr-x | matlab/comms/save_variable.m | 16 | ||||
| -rwxr-xr-x | matlab/comms/script_verify_fir.m | 148 | ||||
| -rwxr-xr-x | sim/fir/makefile | 67 | ||||
| -rwxr-xr-x | sim/fir/makefile.sources | 18 | ||||
| -rw-r--r-- | src/fir_mac_rtl.vhd | 47 | ||||
| -rw-r--r-- | src/fir_structure.vhd | 124 | ||||
| -rw-r--r-- | src/t_fir_fileio.vhd | 111 | 
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:$ +------------------------------------------------------------------------------- | 
