www.gusucode.com > hdlfilter 案例代码 matlab源码程序 > hdlfilter/hdlfirda.m

    %% HDL Distributed Arithmetic for FIR Filters
% This example illustrates how to generate HDL code for a lowpass FIR filter 
% with Distributed Arithmetic (DA) architecture.

% Copyright 2006-2016 The MathWorks, Inc.

%% Distributed Arithmetic
% Distributed Arithmetic is a popular architecture for implementing 
% FIR filters without the use of multipliers. DA realizes the sum of 
% products computation required for FIR filters efficiently using LUTs, 
% shifters and adders. Since these operations map efficiently onto an 
% FPGA, DA is a favored architecture on these devices. 

%% Design the Filter
% Use a sampling rate of 48 kHz, passband edge frequency of
% 9.6 kHz and stop frequency of 12k. Set the allowable peak-to-peak
% passband ripple to 1 dB and the stopband attenuation to -90 dB.
% Then, design the filter using fdesign.lowpass, and create the
% System object filter as a direct form FIR filter.

Fs           = 48e3;         % Sampling Frequency in Hz
Fpass        = 9.6e3;        % Passband Frequency in Hz
Fstop        = 12e3;         % Stopband Frequency in Hz
Apass        = 1;            % Passband Ripple in dB
Astop        = 90;           % Stopband Attenuation in dB

lpSpec = fdesign.lowpass( 'Fp,Fst,Ap,Ast',...
    Fpass, Fstop, Apass, Astop, Fs);

lpFilter = design(lpSpec, 'equiripple', 'filterstructure', 'dffir',...
    'SystemObject', true);

%% Quantize the Filter
% Since DA implements the FIR filter by serializing the input data bits, it
% requires a quantized filter. Assume that 12 bit input and output word lengths 
% with 11 fractional bits are required (due to of fixed data path
% requirements or input ADC/output DAC widths). Apply these fixed point
% settings. 

inputDataType = numerictype(1,12,11);
outputDataType = inputDataType;
coeffsDataType = numerictype(1,16,16);

lpFilter.FullPrecisionOverride = false;
lpFilter.CoefficientsDataType = 'Custom';
lpFilter.CustomCoefficientsDataType = coeffsDataType;
lpFilter.OutputDataType = 'Custom';
lpFilter.CustomOutputDataType = outputDataType;

% Now check the filter response with fvtool.
fvtool(lpFilter,'Fs',Fs,'Arithmetic','fixed');

%% Generate HDL Code with DA Architecture
% To generate HDL Code with DA architecture, invoke the generatehdl command, 
% passing in  a valid value to the 'DALUTPartition' property.
% The 'DALUTPartition' property directs the code generator to use DA architecture,
% and divides the LUT into a specified number of partitions. 
% The 'DALUTPartition' property specifies the number of LUT partitions, 
% and the number of the taps associated with each partition.
% For a filter with many taps it is best to
% divide the taps into a number of LUTs, with each LUT storing the sum of
% coefficients for only the taps associated with it. The sum of the LUT 
% outputs is computed in a tree structure of adders.
%
% Check the filter length by getting the number of coefficients. 

FL = length(lpFilter.Numerator);

%%
% Assume that you have 8 input LUTs;  calculate the value of the
% DALUTPartition property such that you use as many of these LUTs as possible
% per partition.

dalut = [ones(1, floor(FL/8))*8, mod(FL, 8)];

%%
% Generate HDL with DA architecture. By default, VHDL code is generated. 
% To generate Verilog code, pass in the 'TargetLanguage' property with the value
% 'Verilog'.

workingdir = tempname;
generatehdl(lpFilter, 'DALUTPartition', dalut, ...
                'TargetDirectory', workingdir, ...
                'InputDataType', inputDataType);

%% Convert the Filter Structure to 'Direct form symmetric' and Generate HDL
% A symmetrical filter structure offers advantages in hardware, as it
% halves the number of coefficients to work with. This reduces the hardware
% complexity substantially. Create a new FIR filter System object 'lpSymFilter' 
% with a 'Direct form symmetric' structure and the same fixed point
% settings.

lpSymFilter = design(lpSpec, 'equiripple', 'filterstructure', 'dfsymfir',...
    'SystemObject', true);

lpSymFilter.FullPrecisionOverride = false;
lpSymFilter.CoefficientsDataType = 'Custom';
lpSymFilter.CustomCoefficientsDataType = coeffsDataType;
lpSymFilter.OutputDataType = 'Custom';
lpSymFilter.CustomOutputDataType = outputDataType;

% Calculate filter length FL for lpSymFilter for the purpose of calculating 'DALUTPartition'
FL = ceil(length(lpSymFilter.Numerator)/2);

% Generate the  value for 'DALUTPartition' as done previously for lpFilter.
dalut_sym = [ones(1, floor(FL/8))*8, mod(FL, 8)];

% Generate HDL code for default radix of 2
generatehdl(lpSymFilter, 'DALUTPartition', dalut_sym, ...
                   'TargetDirectory', workingdir, ...
                   'InputDataType', inputDataType);

%%
% Notice that a symmetrical filter takes one additional clock cycle before
% the output is obtained. This is because of the carry bit that is added to
% the input word length as the input data from the symmetrical taps are summed
% together. The clock rate for 'lpSymFilter' is 13 times the input sample rate,
% whereas for 'lpFilter' the clock rate was 12 times the input sample rate.

%% DARadix
% The default architecture is a Radix 2 implementation, which operates on one bit of
% input data on each clock cycle. The number of clock cycles elapsed
% before an output is obtained is equal to the number of bits in the input data. 
% Thus DA can potentially limit the throughput. To improve the throughput of DA,
% you can configure DA to process multiple bits in parallel.
% The 'DARadix' property is provided for this purpose.
% For example, you can set 'DARadix' to 2^3 to operate on 3 bits in parallel.
% For a 12 bit input word length, you can specify processing of 
% 1, 2, 3, 4, 6 or 12 bits at a time by specifying corresponding 
% 'DARadix' values of 2^1, 2^2, 2^3, 2^4, 2^6, or 2^12 respectively.

%%
% In selecting different 'DARadix' values, you trade off speed vs. area 
% within the DA architecture. The number of bits operated in parallel
% determines the factor by which the clock rate needs to be increased. This
% is known as folding factor. For example, the default 'DARadix of 2^1,
% implying 1 bit at a time, results in a clock rate 12 times the input
% sample rate or a folding factor of 12. A 'DARadix' of 2^3  results in a 
% clock rate only 4 times the input sample rate, but requires 3 identical
% sets of LUTs, one for each bit being processed in parallel.

%% Information Regarding DA Architecture
% As explained in previous section, DA architecture presents a lot of
% options both in terms of LUT sizes and the folding factor. You can use
% hdlfilterdainfo function to get information regarding various filter
% lengths based on the value of coefficients. This function also displays
% two other tables, one for all possible values of DARadix property with 
% corresponding folding factors. The second table displays details of
% LUT sets with the corresponding values of DALUTPartition property.

hdlfilterdainfo(lpFilter, 'InputDataType', inputDataType);
%%
% You can use optional properties for LUT and folding factors to 
% display specific information. You can choose one of the two LUT
% properties, 'LUTInputs' or 'DALUTPartition' to display all the folding
% factor options available for the specific LUT inputs. 

hdlfilterdainfo(lpFilter, 'InputDataType', inputDataType, ...
                    'LUTInputs', 4);

%% 
% You can also choose one of the two folding factor related properties,
% 'FoldingFactor' or 'DARadix' to display all the LUT options for the
% specific folding factor.

hdlfilterdainfo(lpFilter, 'InputDataType', inputDataType, ...
                    'Foldingfactor', 6);

%%
% Notice that LUT details indicate a factor by which the LUT sets need to be
% replicated to achieve the corresponding folding factor. Also, total LUT
% size is calculated with above factor. 

%% 
% You can use output arguments to return the values of DALUTPartition and 
% DARadix for a specific configuration and use it with generatehdl command.
% Let us assume that you can intend to raise the clock rate by 4 times the
% sample rate and want to use 6 input LUTs. You can verify that the LUT
% details meet your area requirements. 

hdlfilterdainfo(lpFilter, 'InputDataType', inputDataType, ...
                    'FoldingFactor', 4, ...
                    'LUTInputs',  6);

%%
% Now generate HDL with the above constraints by first storing the required
% values of DALUTPartition and DARadix in variables by using the output
% arguments to the hdlfilterdainfo function. You can then invoke
% generatehdl command using these variables.

[dalut, dr] = hdlfilterdainfo(lpFilter, 'InputDataType', inputDataType, ...
                                  'FoldingFactor', 4, ...
                                  'LUTInputs', 6);

generatehdl(lpFilter, 'InputDataType', inputDataType, ...
                'DALUTPartition', dalut, ...
                'DAradix', dr, ...
                'TargetDirectory', workingdir);

%% Conclusion
% You designed a lowpass direct form FIR filter to meet the
% given specification. You then quantized and checked your design. You
% generated VHDL code for DA with various radices and explored speed vs. area
% trade-offs within DA by replicating LUTs and operating on multiple bits in
% parallel. 
%
% You can generate a test bench with a standard stimulus and/or your own defined 
% stimulus, and use an HDL Simulator to verify the generated HDL code for 
% DA architectures. You can use a synthesis tool to compare 
% the area and speed of these architectures.