OpenCores
URL https://opencores.org/ocsvn/viirf/viirf/trunk

Subversion Repositories viirf

[/] [viirf/] [trunk/] [src/] [sos_core_df1.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 Muraer
--------------------------------------------------------------------------------------------------------------
2
-- MIT License
3
--  
4
-- Copyright (c) 2017 Mario Mauerer
5
--  
6
-- Permission is hereby granted, free of charge, to any person obtaining a copy
7
-- of this software and associated documentation files (the "Software"), to deal
8
-- in the Software without restriction, including without limitation the rights
9
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
-- copies of the Software, and to permit persons to whom the Software is
11
-- furnished to do so, subject to the following conditions:
12
-- 
13
-- The above copyright notice and this permission notice shall be included in all
14
-- copies or substantial portions of the Software.
15
-- 
16
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
-- SOFTWARE.
23
--
24
--------------------------------------------------------------------------------------------------------------
25
-- 
26
-- VHDL Naming Convention:
27
-- http://dz.ee.ethz.ch/en/information/hdl-help/vhdl-naming-conventions.html
28
--------------------------------------------------------------------------------------------------------------
29
--
30
-- VIIRF - Versatile IIR Filter
31
--
32
-- sos_core_df1.vhd
33
--
34
-- This is the implementation of a direct-form 1 SOS/biquad.
35
-- It implements the following difference equation:
36
-- y[n] = g*(b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2])
37
--
38
-- The core is pipelined; there are registers between mayor logic elements in
39
-- order to be able to operate this core at a higher clock rate. This comes at
40
-- the cost of a higher resource utilization, especially multipliers. There is
41
-- a core that reuses the multiplier, at the cost of a lower max.
42
-- clock rate (sos_core_df1_reuse.vhd)
43
--
44
-- The coefficients are provided as signed vectors to this unit.
45
--
46
-- Generics/Configuration:
47
--
48
-- W_DAT:
49
--      Data width (input and output) of the core
50
-- W_COEF:
51
--      Overall coefficient width.
52
-- W_FRAC:
53
--      Fraction length of the coefficients. Together with W_COEF, this defines
54
--      the Q-notation of the quantized coefficients.
55
--      E.g., for Q1.15, set W_COEF=16 and W_FRAC=15.
56
-- SOSGAIN_EN:
57
--      Boolean that indicates whether the output-gain of the section is
58
--      enabled/generated, or not.
59
 
60
library IEEE;
61
use IEEE.STD_LOGIC_1164.all;
62
use IEEE.NUMERIC_STD.all;
63
 
64
entity sos_core_df1 is
65
  generic(
66
    W_DAT      : integer := 25;
67
    W_COEF     : integer := 18;
68
    W_FRAC     : integer := 16;
69
    SOSGAIN_EN : boolean := true
70
    );
71
  port (
72
    ClkxCI  : in  std_logic;
73
    RstxRI  : in  std_logic;
74
    DatxDI  : in  signed(W_DAT-1 downto 0);
75
    StrbxSI : in  std_logic;
76
    DatxDO  : out signed(W_DAT-1 downto 0);
77
    StrbxSO : out std_logic;
78
    b0xDI   : in  signed(W_COEF-1 downto 0);
79
    b1xDI   : in  signed(W_COEF-1 downto 0);
80
    b2xDI   : in  signed(W_COEF-1 downto 0);
81
    a1xDI   : in  signed(W_COEF-1 downto 0);
82
    a2xDI   : in  signed(W_COEF-1 downto 0);
83
    gxDI    : in  signed(W_COEF-1 downto 0)
84
    );
85
end sos_core_df1;
86
 
87
architecture Behavioral of sos_core_df1 is
88
 
89
-----------------------------------------------------------------------------
90
-- Components
91
-----------------------------------------------------------------------------
92
-- No additional components.
93
 
94
-----------------------------------------------------------------------------
95
-- Signal Declarations
96
-----------------------------------------------------------------------------
97
  -------------
98
  -- Constants:
99
  -------------
100
 
101
  -- Data width after multipliers. This is also the width of the adders:
102
  constant W_MUL : integer := W_COEF + W_DAT;
103
 
104
  -- Data width after the right-shift operation:
105
  constant W_RS : integer := W_MUL - W_FRAC;
106
 
107
  -- Values for output saturation. Two's complement min and max values, defined
108
  -- using bit-masks instead of integers, as W_DAT is allowed to be > 32 bit.
109
  constant SAT_OUT_POS : signed(W_DAT-1 downto 0) := (W_DAT-1 => '0', others => '1');
110
  constant SAT_OUT_NEG : signed(W_DAT-1 downto 0) := (W_DAT-1 => '1', others => '0');
111
 
112
  -- Number of cycles for the strobe-output:
113
  constant NUM_CYC_DEL_STRB : integer := 9;
114
 
115
  -----------
116
  -- Signals:
117
  -----------
118
 
119
  -- Main registers for the direct-form 1 implementation:
120
  signal b0RegxDN, b0RegxDP : signed(W_DAT-1 downto 0) := (others => '0');
121
  signal b1RegxDN, b1RegxDP : signed(W_DAT-1 downto 0) := (others => '0');
122
  signal b2RegxDN, b2RegxDP : signed(W_DAT-1 downto 0) := (others => '0');
123
  signal a1RegxDN, a1RegxDP : signed(W_DAT-1 downto 0) := (others => '0');
124
  signal a2RegxDN, a2RegxDP : signed(W_DAT-1 downto 0) := (others => '0');
125
 
126
  -- Pipelining-registers: Between adders/multipliers for better timing:
127
  signal b0MulxDN, b0MulxDP           : signed(W_MUL-1 downto 0) := (others => '0');
128
  signal b1MulxDN, b1MulxDP           : signed(W_MUL-1 downto 0) := (others => '0');
129
  signal b2MulxDN, b2MulxDP           : signed(W_MUL-1 downto 0) := (others => '0');
130
  signal a1MulxDN, a1MulxDP           : signed(W_MUL-1 downto 0) := (others => '0');
131
  signal a2MulxDN, a2MulxDP           : signed(W_MUL-1 downto 0) := (others => '0');
132
  signal Sum1xDN, Sum1xDP             : signed(W_MUL-1 downto 0) := (others => '0');
133
  signal Sum2xDN, Sum2xDP             : signed(W_MUL-1 downto 0) := (others => '0');
134
  signal Sum3xDN, Sum3xDP             : signed(W_MUL-1 downto 0) := (others => '0');
135
  signal Sum4xDN, Sum4xDP             : signed(W_MUL-1 downto 0) := (others => '0');
136
  signal ShiftOutxDN, ShiftOutxDP     : signed(W_MUL-1 downto 0) := (others => '0');
137
  signal ShiftOutRSxDN, ShiftOutRSxDP : signed(W_RS-1 downto 0)  := (others => '0');
138
 
139
  -- Coefficient buffer registers: For reducing routing delay. These registers
140
  -- are ''static'', i.e., don't change during the core's operation.
141
  signal b0xDN, b0xDP : signed(W_COEF-1 downto 0) := (others => '0');
142
  signal b1xDN, b1xDP : signed(W_COEF-1 downto 0) := (others => '0');
143
  signal b2xDN, b2xDP : signed(W_COEF-1 downto 0) := (others => '0');
144
  signal a1xDN, a1xDP : signed(W_COEF-1 downto 0) := (others => '0');
145
  signal a2xDN, a2xDP : signed(W_COEF-1 downto 0) := (others => '0');
146
  signal gxDN, gxDP   : signed(W_COEF-1 downto 0) := (others => '0');
147
 
148
  -- Output and output-gain register/signals:
149
  signal SatRegxDN, SatRegxDP : signed(W_DAT-1 downto 0) := (others => '0');
150
 
151
-----------------------------------------------------------------------------
152
begin  -- Behavioral
153
-----------------------------------------------------------------------------
154
 
155
-----------------------------------------------------------------------------
156
-- Wiring
157
-----------------------------------------------------------------------------
158
  -- Buffer registers for timing relaxation (routing delay):
159
  b0xDN <= b0xDI;
160
  b1xDN <= b1xDI;
161
  b2xDN <= b2xDI;
162
  a1xDN <= a1xDI;
163
  a2xDN <= a2xDI;
164
  gxDN  <= gxDI;
165
 
166
-----------------------------------------------------------------------------
167
-- Processes
168
-----------------------------------------------------------------------------
169
 
170
  -- The main registers of the direct-form 1 are strobed/forwarded here:
171
  RegStrb : process(DatxDI, StrbxSI, a1RegxDP, a2RegxDP, b0RegxDP, b1RegxDP,
172
                    b2RegxDP, satRegxDP)
173
  begin
174
    -- Default assignments:
175
    b0RegxDN <= b0RegxDP;
176
    b1RegxDN <= b1RegxDP;
177
    b2RegxDN <= b2RegxDP;
178
    a1RegxDN <= a1RegxDP;
179
    a2RegxDN <= a2RegxDP;
180
    -- These registers are only updated upon a new input strobe:
181
    if StrbxSI = '1' then
182
      b0RegxDN <= DatxDI;
183
      b1RegxDN <= b0RegxDP;
184
      b2RegxDN <= b1RegxDP;
185
      a1RegxDN <= satRegxDP;
186
      a2RegxDN <= a1RegxDP;
187
    end if;
188
  end process RegStrb;
189
 
190
  -- This calculates the section's new states. It also saturates the output of
191
  -- the core. 
192
  DataCalc : process(ShiftOutRSxDP, Sum1xDP, Sum2xDP, Sum3xDP, Sum4xDP,
193
                     a1MulxDP, a1RegxDP, a1xDP, a2MulxDP, a2RegxDP, a2xDP,
194
                     b0MulxDP, b0RegxDP, b0xDP, b1MulxDP, b1RegxDP, b1xDP,
195
                     b2MulxDP, b2RegxDP, b2xDP, shiftOutxDP)
196
  begin
197
    -- MulAccs of the direct-form 1:
198
    b0MulxDN      <= b0RegxDP * b0xDP;
199
    b1MulxDN      <= b1RegxDP * b1xDP;
200
    b2MulxDN      <= b2RegxDP * b2xDP;
201
    Sum1xDN       <= b0MulxDP + b1MulxDP;
202
    Sum2xDN       <= Sum1xDP + b2MulxDP;
203
    Sum3xDN       <= Sum2xDP - a2MulxDP;
204
    Sum4xDN       <= Sum3xDP - a1MulxDP;
205
    a1MulxDN      <= a1RegxDP * a1xDP;
206
    a2MulxDN      <= a2RegxDP * a2xDP;
207
    -- Output divider: Get rid of the gain due to the integer algebra (2^W_FRAC):
208
    ShiftOutxDN   <= shift_right(Sum4xDP, W_FRAC);
209
    -- Resize to a smaller vector for less routing delay for the upcoming saturation:
210
    ShiftOutRSxDN <= resize(shiftOutxDP, W_RS);
211
 
212
    -- Check for output overflow and saturate, if necessary:
213
    if ShiftOutRSxDP > SAT_OUT_POS then
214
      SatRegxDN <= SAT_OUT_POS;
215
    elsif ShiftOutRSxDP < SAT_OUT_NEG then
216
      SatRegxDN <= SAT_OUT_NEG;
217
    else
218
      SatRegxDN <= resize(ShiftOutRSxDP, W_DAT);
219
    end if;
220
  end process DataCalc;
221
 
222
  -- Only create / generate the output multiplier, if it's actually enabled.
223
  -- This saves DSP-resources and latency.
224
  -- The signals defined in this block are not visible outside this
225
  -- generate-statement, hence there is a clocking-process here, too.
226
  -- The required latency for the strobe-signal is 13
227
  GenerateOutMul : if SOSGAIN_EN = true generate
228
    signal gRegxDN, gRegxDP                     : signed(W_MUL-1 downto 0)                      := (others => '0');
229
    signal ShiftGainOutxDN, ShiftGainOutxDP     : signed(W_MUL-1 downto 0)                      := (others => '0');
230
    signal ShiftGainOutRSxDN, ShiftGainOutRSxDP : signed(W_RS-1 downto 0)                       := (others => '0');
231
    signal OutMulxDN, OutMulxDP                 : signed(W_DAT-1 downto 0)                      := (others => '0');
232
    -- Number of latency-cycles required for the strobe-output, if the output
233
    -- gain is used:
234
    constant NUM_CYC_DEL_STRB                   : integer                                       := 13;
235
    -- Strobe-shift register: The input strobe is shifted "through" this unit:
236
    signal StrbShiftxSN, StrbShiftxSP           : std_logic_vector(NUM_CYC_DEL_STRB-1 downto 0) := (others => '0');
237
  begin
238
 
239
    -- This process manages the section's output gain:
240
    OutGain : process(SatRegxDP, ShiftGainOutxDP, gRegxDP, gxDP,
241
                      shiftGainOutRSxDP)
242
    begin
243
      -- Apply the output gain:
244
      gRegxDN           <= SatRegxDP * gxDP;
245
      -- Output divider: Get rid of the gain due to the integer algebra (2^W_FRAC):
246
      ShiftGainOutxDN   <= shift_right(gRegxDP, W_FRAC);
247
      -- Resize to a smaller vector for less routing delay for the upcoming saturation:
248
      ShiftGainOutRSxDN <= resize(ShiftGainOutxDP, W_RS);
249
 
250
      -- Output Saturation:
251
      if ShiftGainOutRSxDP > SAT_OUT_POS then
252
        OutMulxDN <= SAT_OUT_POS;
253
      elsif ShiftGainOutRSxDP < SAT_OUT_NEG then
254
        OutMulxDN <= SAT_OUT_NEG;
255
      else
256
        OutMulxDN <= resize(shiftGainOutRSxDP, W_DAT);
257
      end if;
258
    end process OutGain;
259
 
260
    -- The core's data output is the one where the output gain has been applied
261
    -- to:
262
    DatxDO <= OutMulxDP;
263
 
264
    -- Delay the input strobe according to the latency of the core:
265
    StrobeShiftOutGain : process(StrbShiftxSP(NUM_CYC_DEL_STRB-2 downto 0),
266
                                 StrbxSI)
267
    begin
268
      StrbShiftxSN(0)                           <= StrbxSI;
269
      StrbShiftxSN(NUM_CYC_DEL_STRB-1 downto 1) <= StrbShiftxSP(NUM_CYC_DEL_STRB-2 downto 0);
270
    end process StrobeShiftOutGain;
271
 
272
    -- Strobe output:
273
    StrbxSO <= StrbShiftxSP(NUM_CYC_DEL_STRB-1);
274
 
275
    --The flip-flops needed if the output gain is deployed:
276
    FF_OutMul : process (ClkxCI)
277
    begin
278
      if ClkxCI'event and ClkxCI = '1' then
279
        if RstxRI = '1' then
280
          gRegxDP           <= (others => '0');
281
          ShiftGainOutxDP   <= (others => '0');
282
          ShiftGainOutRSxDP <= (others => '0');
283
          OutMulxDP         <= (others => '0');
284
          StrbShiftxSP      <= (others => '0');
285
        else
286
          gRegxDP           <= gRegxDN;
287
          ShiftGainOutxDP   <= ShiftGainOutxDN;
288
          ShiftGainOutRSxDP <= ShiftGainOutRSxDN;
289
          OutMulxDP         <= OutMulxDN;
290
          StrbShiftxSP      <= StrbShiftxSn;
291
        end if;
292
      end if;
293
    end process FF_OutMul;
294
 
295
  end generate;
296
 
297
 
298
  -- If the individual section gains are not used: Simply take the
299
  -- saturated output from the direct-form 1 implementation.
300
  -- The required latency for the strobe-signal is 9
301
  GenerateNoOutMul : if SOSGAIN_EN = false generate
302
    -- Number of latency-cycles required for the strobe-output, if the output
303
    -- gain is not used:
304
    constant NUM_CYC_DEL_STRB         : integer                                       := 9;
305
    -- Strobe-shift register: The input strobe is shifted "through" this unit:
306
    signal StrbShiftxSN, StrbShiftxSP : std_logic_vector(NUM_CYC_DEL_STRB-1 downto 0) := (others => '0');
307
  begin
308
    -- The output from the direct-form 1 calculation:
309
    DatxDO <= SatRegxDP;
310
 
311
    -- Delay the input strobe according to the latency of the core:
312
    StrobeShiftNoOutGain : process(StrbShiftxSP(NUM_CYC_DEL_STRB-2 downto 0),
313
                                   StrbxSI)
314
    begin
315
      StrbShiftxSN(0)                           <= StrbxSI;
316
      StrbShiftxSN(NUM_CYC_DEL_STRB-1 downto 1) <= StrbShiftxSP(NUM_CYC_DEL_STRB-2 downto 0);
317
    end process StrobeShiftNoOutGain;
318
 
319
    -- Strobe output:
320
    StrbxSO <= StrbShiftxSP(NUM_CYC_DEL_STRB-1);
321
 
322
    --The flip-flops needed if the output gain is not used:
323
    FF_NoOutMul : process (ClkxCI)
324
    begin
325
      if ClkxCI'event and ClkxCI = '1' then
326
        if RstxRI = '1' then
327
          StrbShiftxSP <= (others => '0');
328
        else
329
          StrbShiftxSP <= StrbShiftxSn;
330
        end if;
331
      end if;
332
    end process FF_NoOutMul;
333
  end generate;
334
 
335
 
336
  -- The flip-flops for the direct-form 1 implementation:
337
  FF : process (ClkxCI)
338
  begin
339
    if ClkxCI'event and ClkxCI = '1' then
340
      if RstxRI = '1' then
341
        b0RegxDP      <= (others => '0');
342
        b1RegxDP      <= (others => '0');
343
        b2RegxDP      <= (others => '0');
344
        a1RegxDP      <= (others => '0');
345
        a2RegxDP      <= (others => '0');
346
        b0MulxDP      <= (others => '0');
347
        b1MulxDP      <= (others => '0');
348
        b2MulxDP      <= (others => '0');
349
        a1MulxDP      <= (others => '0');
350
        a2MulxDP      <= (others => '0');
351
        Sum1xDP       <= (others => '0');
352
        Sum2xDP       <= (others => '0');
353
        Sum3xDP       <= (others => '0');
354
        Sum4xDP       <= (others => '0');
355
        ShiftOutxDP   <= (others => '0');
356
        ShiftOutRSxDP <= (others => '0');
357
        b0xDP         <= (others => '0');
358
        b1xDP         <= (others => '0');
359
        b2xDP         <= (others => '0');
360
        a1xDP         <= (others => '0');
361
        a2xDP         <= (others => '0');
362
        gxDP          <= (others => '0');
363
        SatRegxDP     <= (others => '0');
364
      else
365
        b0RegxDP      <= b0RegxDN;
366
        b1RegxDP      <= b1RegxDN;
367
        b2RegxDP      <= b2RegxDN;
368
        a1RegxDP      <= a1RegxDN;
369
        a2RegxDP      <= a2RegxDN;
370
        b0MulxDP      <= b0MulxDN;
371
        b1MulxDP      <= b1MulxDN;
372
        b2MulxDP      <= b2MulxDN;
373
        a1MulxDP      <= a1MulxDN;
374
        a2MulxDP      <= a2MulxDN;
375
        Sum1xDP       <= Sum1xDN;
376
        Sum2xDP       <= Sum2xDN;
377
        Sum3xDP       <= Sum3xDN;
378
        Sum4xDP       <= Sum4xDN;
379
        ShiftOutxDP   <= ShiftOutxDN;
380
        ShiftOutRSxDP <= ShiftOutRSxDN;
381
        b0xDP         <= b0xDN;
382
        b1xDP         <= b1xDN;
383
        b2xDP         <= b2xDN;
384
        a1xDP         <= a1xDN;
385
        a2xDP         <= a2xDN;
386
        gxDP          <= gxDN;
387
        SatRegxDP     <= SatRegxDN;
388
      end if;
389
    end if;
390
  end process FF;
391
 
392
-----------------------------------------------------------------------------
393
-- Instances
394
-----------------------------------------------------------------------------
395
-- No further instances.
396
 
397
 
398
end Behavioral;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.