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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [VHDL/] [o8_mavg_8ch_16b_64d.vhd] - Blame information for rev 323

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 323 jshamlet
-- Copyright (c)2023 Jeremy Seth Henry
2
-- All rights reserved.
3
--
4
-- Redistribution and use in source and binary forms, with or without
5
-- modification, are permitted provided that the following conditions are met:
6
--     * Redistributions of source code must retain the above copyright
7
--       notice, this list of conditions and the following disclaimer.
8
--     * Redistributions in binary form must reproduce the above copyright
9
--       notice, this list of conditions and the following disclaimer in the
10
--       documentation and/or other materials provided with the distribution,
11
--       where applicable (as part of a user interface, debugging port, etc.)
12
--
13
-- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY
14
-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
-- DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY BE LIABLE FOR ANY
17
-- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20
-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22
-- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
--
24
-- VHDL units : o8_mavg_8ch_16b_64d
25
-- Description: 8-channel moving average calculation for 16-bit unsigned data
26
--              Accumulator depth is 64 elements, using 1 block RAM.
27
--
28
-- Register Map:
29
-- Offset  Bitfield Description                        Read/Write
30
--   0x00  AAAAAAAA Raw Data (lower)                      (RW)
31
--   0x01  AAAAAAAA Raw Data (upper)                      (RW)
32
--   0x02  -----AAA Raw Channel Select                    (RW)
33
--   0x03  A------- Update Accum / Busy                   (RW)
34
--   0x04  AAAAAAAA Avg Data (lower)                      (RW)
35
--   0x05  AAAAAAAA Avg Data (upper)                      (RW)
36
--   0x06  -----AAA Avg Channel Select                    (RW)
37
--   0x07  A------- Flush Statistics  / Busy              (RW)
38
 
39
library ieee;
40
use ieee.std_logic_1164.all;
41
use ieee.std_logic_arith.all;
42
use ieee.std_logic_unsigned.all;
43
use ieee.std_logic_misc.all;
44
 
45
library work;
46
  use work.open8_pkg.all;
47
 
48
entity o8_mavg_8ch_16b_64d is
49
generic(
50
  Address                    : ADDRESS_TYPE
51
);
52
port(
53
  Open8_Bus                  : in  OPEN8_BUS_TYPE;
54
  Write_Qual                 : in  std_logic := '1';
55
  Rd_Data                    : out DATA_TYPE;
56
  Interrupt                  : out std_logic
57
);
58
end entity;
59
 
60
architecture behave of o8_mavg_8ch_16b_64d is
61
 
62
  alias Clock                is Open8_Bus.Clock;
63
  alias Reset                is Open8_Bus.Reset;
64
 
65
  constant User_Addr         : std_logic_vector(15 downto 3)
66
                               := Address(15 downto 3);
67
  alias  Comp_Addr           is Open8_Bus.Address(15 downto 3);
68
  signal Addr_Match          : std_logic;
69
 
70
  alias  Reg_Sel_d           is Open8_Bus.Address(2 downto 0);
71
  signal Reg_Sel_q           : std_logic_vector(2 downto 0);
72
  signal Wr_En_d             : std_logic := '0';
73
  signal Wr_En_q             : std_logic := '0';
74
  alias  Wr_Data_d           is Open8_Bus.Wr_Data;
75
  signal Wr_Data_q           : DATA_TYPE := x"00";
76
  signal Rd_En_d             : std_logic := '0';
77
  signal Rd_En_q             : std_logic := '0';
78
 
79
  signal RAW_Data            : std_logic_vector(15 downto 0) := (others => '0');
80
  alias  RAW_Data_L          is RAW_Data(7 downto 0);
81
  alias  RAW_Data_H          is RAW_Data(15 downto 8);
82
 
83
  signal RAW_Channel         : std_logic_vector(2 downto 0) := (others => '0');
84
 
85
  signal RAW_Valid           : std_logic := '0';
86
 
87
  signal Flush_Valid         : std_logic := '0';
88
  signal Flush_Busy          : std_logic := '0';
89
 
90
  type AVG_CTL_STATES is (INIT, CLR_BUFF, IDLE, RD_LAST, ADV_PTR, CALC_NEXT,
91
                          WR_NEW);
92
  signal AVG_Ctl             : AVG_CTL_STATES := INIT;
93
 
94
  signal Avg_Busy            : std_logic := '0';
95
 
96
  signal CH_Select           : std_logic_vector(2 downto 0) := (others => '0');
97
  signal Data_New            : std_logic_vector(15 downto 0) := (others => '0');
98
 
99
  signal RAM_Wr_Addr         : std_logic_vector(8 downto 0) := (others => '0');
100
  alias  RAM_Wr_Chan         is RAM_Wr_Addr(8 downto 6);
101
  alias  RAM_Wr_Ptr          is RAM_Wr_Addr(5 downto 0);
102
 
103
  signal RAM_Wr_Data         : std_logic_vector(15 downto 0) := (others => '0');
104
 
105
  signal RAM_Wr_En           : std_logic := '0';
106
 
107
  signal RAM_Rd_Addr         : std_logic_vector(8 downto 0) := (others => '0');
108
  alias  RAM_Rd_Chan         is RAM_Rd_Addr(8 downto 6);
109
  alias  RAM_Rd_Ptr          is RAM_Rd_Addr(5 downto 0);
110
 
111
  signal RAM_Rd_Data         : std_logic_vector(15 downto 0) := (others => '0');
112
  alias  Data_Old            is RAM_Rd_Data;
113
 
114
  type PTR_ARRAY is array (0 to 7) of std_logic_vector(5 downto 0);
115
  signal SP0_Pointers        : PTR_ARRAY;
116
  signal SPN_Pointers        : PTR_ARRAY;
117
 
118
  -- Accumulator width is bus_size (16) + log depth (6)
119
  type ACCUM_ARRAY is array (0 to 7) of unsigned(21 downto 0);
120
  signal Accumulators        : ACCUM_ARRAY;
121
 
122
  signal AVG_Channel         : std_logic_vector(2 downto 0) := (others => '0');
123
 
124
  signal AVG_Out             : std_logic_vector(15 downto 0);
125
  alias AVG_Out_L            is AVG_Out(7 downto 0);
126
  alias AVG_Out_H            is AVG_Out(7 downto 0);
127
 
128
begin
129
 
130
  Addr_Match                 <= '1' when Comp_Addr = User_Addr else '0';
131
  Wr_En_d                    <= Addr_Match and Write_Qual and Open8_Bus.Wr_En;
132
  Rd_En_d                    <= Addr_Match and Open8_Bus.Rd_En;
133
 
134
  Register_IF_proc: process( Clock, Reset )
135
    variable i : integer := 0;
136
  begin
137
    if( Reset = Reset_Level )then
138
      Wr_En_q                <= '0';
139
      Wr_Data_q              <= x"00";
140
      Reg_Sel_q              <= (others => '0');
141
      Rd_En_q                <= '0';
142
      Rd_Data                <= OPEN8_NULLBUS;
143
 
144
      RAW_Data               <= (others => '0');
145
      RAW_Valid              <= '0';
146
      RAW_Channel            <= (others => '0');
147
 
148
      AVG_Out                <= (others => '0');
149
      AVG_Channel            <= (others => '0');
150
 
151
 
152
    elsif( rising_edge(Clock) )then
153
      Reg_Sel_q              <= Reg_Sel_d;
154
      Wr_En_q                <= Wr_En_d;
155
      Wr_Data_q              <= Wr_Data_d;
156
 
157
      RAW_Valid              <= '0';
158
 
159
      if( Wr_En_q = '1' )then
160
        case( Reg_Sel_q )is
161
          when "000" =>
162
            RAW_Data_L       <= Wr_Data_q;
163
 
164
          when "001" =>
165
            RAW_Data_H       <= Wr_Data_q;
166
 
167
          when "010" =>
168
            RAW_Channel      <= Wr_Data_q(2 downto 0);
169
 
170
          when "011" =>
171
            RAW_Valid        <= not Avg_Busy;
172
 
173
          when "110" =>
174
            AVG_Channel      <= Wr_Data_q(2 downto 0);
175
 
176
          when "111" =>
177
            Flush_Valid      <= not Flush_Busy;
178
 
179
          when others =>
180
            null;
181
 
182
        end case;
183
      end if;
184
 
185
      i                      := conv_integer(AVG_Channel);
186
      AVG_Out                <= std_logic_vector(Accumulators(i)(21 downto 6));
187
 
188
      Rd_Data                <= OPEN8_NULLBUS;
189
      Rd_En_q                <= Rd_En_d;
190
      if( Rd_En_q = '1' )then
191
        case( Reg_Sel_q )is
192
          when "000" =>
193
            Rd_Data          <= RAW_Data_L;
194
 
195
          when "001" =>
196
            Rd_Data          <= RAW_Data_H;
197
 
198
          when "010" =>
199
            Rd_Data          <= "00000" & RAW_Channel;
200
 
201
          when "011" =>
202
            Rd_Data          <= Avg_Busy & "0000000";
203
 
204
          when "100" =>
205
            Rd_Data          <= AVG_Out_L;
206
 
207
          when "101" =>
208
            Rd_Data          <= AVG_Out_H;
209
 
210
          when "110" =>
211
            Rd_Data          <= "00000" & AVG_Channel;
212
 
213
          when "111" =>
214
            Rd_Data          <= Flush_Busy & "0000000";
215
 
216
          when others =>
217
            null;
218
 
219
        end case;
220
      end if;
221
 
222
    end if;
223
  end process;
224
 
225
  MAVG_Control_proc: process( Clock, Reset )
226
    variable i : integer := 0;
227
  begin
228
    if( Reset = Reset_Level )then
229
      AVG_Ctl                <= INIT;
230
 
231
      CH_Select              <= (others => '0');
232
      Data_New               <= (others => '0');
233
 
234
      Flush_Busy             <= '0';
235
      Avg_Busy               <= '0';
236
 
237
      for i in 0 to 7 loop
238
        SP0_Pointers(i)      <= (others => '1');
239
        SPN_Pointers(i)      <= (others => '0');
240
        Accumulators(i)      <= (others => '0');
241
      end loop;
242
 
243
      RAM_Wr_Addr            <= (others => '0');
244
      RAM_Wr_Data            <= (others => '0');
245
      RAM_Wr_En              <= '0';
246
      RAM_Rd_Addr            <= (others => '0');
247
 
248
      Interrupt              <= '0';
249
 
250
    elsif( rising_edge(Clock) )then
251
 
252
      Interrupt              <= '0';
253
 
254
      RAM_Wr_En              <= '0';
255
 
256
      Flush_Busy             <= '0';
257
      Avg_Busy               <= '1';
258
 
259
      i                      := conv_integer(unsigned(CH_Select));
260
 
261
      case( AVG_Ctl )is
262
        when INIT =>
263
           Flush_Busy        <= '1';
264
          RAM_Wr_Addr        <= (others => '0');
265
          RAM_Wr_Data        <= (others => '0');
266
          AVG_Ctl            <= CLR_BUFF;
267
 
268
        when CLR_BUFF =>
269
          Flush_Busy         <= '1';
270
          RAM_Wr_Addr        <= RAM_Wr_Addr + 1;
271
          RAM_Wr_En          <= '1';
272
          if( and_reduce(RAM_Wr_Addr) = '1' )then
273
            AVG_Ctl          <= IDLE;
274
          end if;
275
 
276
        when IDLE =>
277
          Avg_Busy           <= '0';
278
          if( Flush_Valid = '1' )then
279
            AVG_Ctl          <= INIT;
280
          elsif( RAW_Valid = '1' )then
281
            Data_New         <= RAW_Data;
282
            CH_Select        <= RAW_Channel;
283
            AVG_Ctl          <= RD_LAST;
284
          end if;
285
 
286
        when RD_LAST =>
287
          RAM_Rd_Chan        <= CH_Select;
288
          RAM_Rd_Ptr         <= SPN_Pointers(i);
289
          AVG_Ctl            <= ADV_PTR;
290
 
291
        when ADV_PTR =>
292
          SP0_Pointers(i)    <= SP0_Pointers(i) + 1;
293
          AVG_Ctl            <= CALC_NEXT;
294
 
295
        when CALC_NEXT =>
296
          Accumulators(i)    <= Accumulators(i) +
297
                                unsigned( Data_New ) -
298
                                unsigned( Data_Old );
299
          AVG_Ctl            <= WR_NEW;
300
 
301
        when WR_NEW =>
302
          RAM_Wr_Chan        <= CH_Select;
303
          RAM_Wr_Ptr         <= SP0_Pointers(i);
304
          RAM_Wr_Data        <= Data_New;
305
          RAM_Wr_En          <= '1';
306
          SPN_Pointers(i)    <= SP0_Pointers(i) + 1;
307
          Interrupt          <= '1';
308
          AVG_Ctl            <= IDLE;
309
 
310
        when others =>
311
          null;
312
      end case;
313
 
314
    end if;
315
  end process;
316
 
317
  U_BUFF : entity work.mavg_buffer_16b
318
  port map(
319
    clock               => Clock,
320
    data                => RAM_Wr_Data,
321
    rdaddress           => RAM_Rd_Addr,
322
    wraddress           => RAM_Wr_Addr,
323
    wren                => RAM_Wr_En,
324
    q                   => RAM_Rd_Data
325
  );
326
 
327
end architecture;

powered by: WebSVN 2.1.0

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