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 327

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 324 jshamlet
--   0x03  BA------ Update Accum & Int Enable / Busy      (RW*)
34 323 jshamlet
--   0x04  AAAAAAAA Avg Data (lower)                      (RW)
35
--   0x05  AAAAAAAA Avg Data (upper)                      (RW)
36
--   0x06  -----AAA Avg Channel Select                    (RW)
37 324 jshamlet
--   0x07  BA------ Flush Statistics & Int_Enable / Busy  (RW*)
38
--
39
-- Note: Writing bit A high will enable a CPU interrupt for the specified
40
--        operation. Writing a low will disable the interrupt. Bit B indicates
41
--        the operation status in either case.
42 323 jshamlet
 
43
library ieee;
44
use ieee.std_logic_1164.all;
45
use ieee.std_logic_arith.all;
46
use ieee.std_logic_unsigned.all;
47
use ieee.std_logic_misc.all;
48
 
49
library work;
50
  use work.open8_pkg.all;
51
 
52
entity o8_mavg_8ch_16b_64d is
53
generic(
54 324 jshamlet
  Autoflush_On_Reset         : boolean := TRUE;
55 323 jshamlet
  Address                    : ADDRESS_TYPE
56
);
57
port(
58
  Open8_Bus                  : in  OPEN8_BUS_TYPE;
59
  Write_Qual                 : in  std_logic := '1';
60
  Rd_Data                    : out DATA_TYPE;
61
  Interrupt                  : out std_logic
62
);
63
end entity;
64
 
65
architecture behave of o8_mavg_8ch_16b_64d is
66
 
67
  alias Clock                is Open8_Bus.Clock;
68
  alias Reset                is Open8_Bus.Reset;
69
 
70
  constant User_Addr         : std_logic_vector(15 downto 3)
71
                               := Address(15 downto 3);
72
  alias  Comp_Addr           is Open8_Bus.Address(15 downto 3);
73 325 jshamlet
  signal Addr_Match          : std_logic := '0';
74 323 jshamlet
 
75
  alias  Reg_Sel_d           is Open8_Bus.Address(2 downto 0);
76 325 jshamlet
  signal Reg_Sel_q           : std_logic_vector(2 downto 0) := "000";
77 323 jshamlet
  signal Wr_En_d             : std_logic := '0';
78
  signal Wr_En_q             : std_logic := '0';
79
  alias  Wr_Data_d           is Open8_Bus.Wr_Data;
80
  signal Wr_Data_q           : DATA_TYPE := x"00";
81
  signal Rd_En_d             : std_logic := '0';
82
  signal Rd_En_q             : std_logic := '0';
83
 
84
  signal RAW_Data            : std_logic_vector(15 downto 0) := (others => '0');
85
  alias  RAW_Data_L          is RAW_Data(7 downto 0);
86
  alias  RAW_Data_H          is RAW_Data(15 downto 8);
87
 
88
  signal RAW_Channel         : std_logic_vector(2 downto 0) := (others => '0');
89
 
90
  signal RAW_Valid           : std_logic := '0';
91
 
92
  signal Flush_Valid         : std_logic := '0';
93
  signal Flush_Busy          : std_logic := '0';
94
 
95 324 jshamlet
  type AVG_CTL_STATES is (IDLE,
96
                          RD_LAST, ADV_PTR, CALC_NEXT, WR_NEW, AVG_DONE,
97
                          FLUSH_INIT, FLUSH_RAM, FLUSH_DONE);
98
  signal AVG_Ctl             : AVG_CTL_STATES := FLUSH_INIT;
99 323 jshamlet
 
100
  signal Avg_Busy            : std_logic := '0';
101
 
102
  signal CH_Select           : std_logic_vector(2 downto 0) := (others => '0');
103
  signal Data_New            : std_logic_vector(15 downto 0) := (others => '0');
104
 
105
  signal RAM_Wr_Addr         : std_logic_vector(8 downto 0) := (others => '0');
106
  alias  RAM_Wr_Chan         is RAM_Wr_Addr(8 downto 6);
107
  alias  RAM_Wr_Ptr          is RAM_Wr_Addr(5 downto 0);
108
 
109
  signal RAM_Wr_Data         : std_logic_vector(15 downto 0) := (others => '0');
110
 
111
  signal RAM_Wr_En           : std_logic := '0';
112
 
113
  signal RAM_Rd_Addr         : std_logic_vector(8 downto 0) := (others => '0');
114
  alias  RAM_Rd_Chan         is RAM_Rd_Addr(8 downto 6);
115
  alias  RAM_Rd_Ptr          is RAM_Rd_Addr(5 downto 0);
116
 
117
  signal RAM_Rd_Data         : std_logic_vector(15 downto 0) := (others => '0');
118
  alias  Data_Old            is RAM_Rd_Data;
119
 
120
  type PTR_ARRAY is array (0 to 7) of std_logic_vector(5 downto 0);
121
  signal SP0_Pointers        : PTR_ARRAY;
122
  signal SPN_Pointers        : PTR_ARRAY;
123
 
124
  -- Accumulator width is bus_size (16) + log depth (6)
125
  type ACCUM_ARRAY is array (0 to 7) of unsigned(21 downto 0);
126
  signal Accumulators        : ACCUM_ARRAY;
127
 
128
  signal AVG_Channel         : std_logic_vector(2 downto 0) := (others => '0');
129
 
130 325 jshamlet
  signal AVG_Out             : std_logic_vector(15 downto 0) := (others => '0');
131 323 jshamlet
  alias AVG_Out_L            is AVG_Out(7 downto 0);
132 327 jshamlet
  alias AVG_Out_H            is AVG_Out(15 downto 8);
133 323 jshamlet
 
134 324 jshamlet
  signal AVG_Int_En          : std_logic := '0';
135
  signal Flush_Int_En        : std_logic := '0';
136
 
137 323 jshamlet
begin
138
 
139
  Addr_Match                 <= '1' when Comp_Addr = User_Addr else '0';
140
  Wr_En_d                    <= Addr_Match and Write_Qual and Open8_Bus.Wr_En;
141
  Rd_En_d                    <= Addr_Match and Open8_Bus.Rd_En;
142
 
143
  Register_IF_proc: process( Clock, Reset )
144
    variable i : integer := 0;
145
  begin
146
    if( Reset = Reset_Level )then
147
      Wr_En_q                <= '0';
148
      Wr_Data_q              <= x"00";
149
      Reg_Sel_q              <= (others => '0');
150
      Rd_En_q                <= '0';
151
      Rd_Data                <= OPEN8_NULLBUS;
152
 
153
      RAW_Data               <= (others => '0');
154
      RAW_Valid              <= '0';
155
      RAW_Channel            <= (others => '0');
156
 
157
      AVG_Out                <= (others => '0');
158
      AVG_Channel            <= (others => '0');
159
 
160 324 jshamlet
      AVG_Int_En             <= '0';
161
      Flush_Int_En           <= '0';
162 323 jshamlet
 
163
    elsif( rising_edge(Clock) )then
164
      Reg_Sel_q              <= Reg_Sel_d;
165
      Wr_En_q                <= Wr_En_d;
166
      Wr_Data_q              <= Wr_Data_d;
167
 
168 324 jshamlet
      Flush_Valid            <= '0';
169 323 jshamlet
      RAW_Valid              <= '0';
170
 
171
      if( Wr_En_q = '1' )then
172
        case( Reg_Sel_q )is
173
          when "000" =>
174
            RAW_Data_L       <= Wr_Data_q;
175
 
176
          when "001" =>
177
            RAW_Data_H       <= Wr_Data_q;
178
 
179
          when "010" =>
180
            RAW_Channel      <= Wr_Data_q(2 downto 0);
181
 
182
          when "011" =>
183 324 jshamlet
            AVG_Int_En       <= Wr_Data_q(6);
184
            RAW_Valid        <= not (Flush_Busy or Avg_Busy);
185 323 jshamlet
 
186
          when "110" =>
187
            AVG_Channel      <= Wr_Data_q(2 downto 0);
188
 
189
          when "111" =>
190 324 jshamlet
            Flush_Int_En     <= Wr_Data_q(6);
191
            Flush_Valid      <= not (Flush_Busy or Avg_Busy);
192 323 jshamlet
 
193
          when others =>
194
            null;
195
 
196
        end case;
197
      end if;
198
 
199
      i                      := conv_integer(AVG_Channel);
200
      AVG_Out                <= std_logic_vector(Accumulators(i)(21 downto 6));
201
 
202
      Rd_Data                <= OPEN8_NULLBUS;
203
      Rd_En_q                <= Rd_En_d;
204
      if( Rd_En_q = '1' )then
205
        case( Reg_Sel_q )is
206
          when "000" =>
207
            Rd_Data          <= RAW_Data_L;
208
 
209
          when "001" =>
210
            Rd_Data          <= RAW_Data_H;
211
 
212
          when "010" =>
213
            Rd_Data          <= "00000" & RAW_Channel;
214
 
215
          when "011" =>
216 324 jshamlet
            Rd_Data          <= Avg_Busy & AVG_Int_En & "000000";
217 323 jshamlet
 
218
          when "100" =>
219
            Rd_Data          <= AVG_Out_L;
220
 
221
          when "101" =>
222
            Rd_Data          <= AVG_Out_H;
223
 
224
          when "110" =>
225
            Rd_Data          <= "00000" & AVG_Channel;
226
 
227
          when "111" =>
228 324 jshamlet
            Rd_Data          <= Flush_Busy & Flush_Int_En & "000000";
229 323 jshamlet
 
230
          when others =>
231
            null;
232
 
233
        end case;
234
      end if;
235
 
236
    end if;
237
  end process;
238
 
239
  MAVG_Control_proc: process( Clock, Reset )
240
    variable i : integer := 0;
241
  begin
242
    if( Reset = Reset_Level )then
243 324 jshamlet
      AVG_Ctl                <= IDLE;
244
      if( Autoflush_On_Reset )then
245
        AVG_Ctl              <= FLUSH_INIT;
246
      end if;
247 323 jshamlet
 
248
      CH_Select              <= (others => '0');
249
      Data_New               <= (others => '0');
250
 
251
      Flush_Busy             <= '0';
252
      Avg_Busy               <= '0';
253
 
254
      for i in 0 to 7 loop
255
        SP0_Pointers(i)      <= (others => '1');
256
        SPN_Pointers(i)      <= (others => '0');
257
        Accumulators(i)      <= (others => '0');
258
      end loop;
259
 
260
      RAM_Wr_Addr            <= (others => '0');
261
      RAM_Wr_Data            <= (others => '0');
262
      RAM_Wr_En              <= '0';
263
      RAM_Rd_Addr            <= (others => '0');
264
 
265
      Interrupt              <= '0';
266
 
267
    elsif( rising_edge(Clock) )then
268
 
269
      Interrupt              <= '0';
270
 
271
      RAM_Wr_En              <= '0';
272
 
273
      Flush_Busy             <= '0';
274 324 jshamlet
      Avg_Busy               <= '0';
275 323 jshamlet
 
276
      i                      := conv_integer(unsigned(CH_Select));
277
 
278
      case( AVG_Ctl )is
279
        when IDLE =>
280
          if( Flush_Valid = '1' )then
281 324 jshamlet
            AVG_Ctl          <= FLUSH_INIT;
282 323 jshamlet
          elsif( RAW_Valid = '1' )then
283
            Data_New         <= RAW_Data;
284
            CH_Select        <= RAW_Channel;
285
            AVG_Ctl          <= RD_LAST;
286
          end if;
287
 
288 324 jshamlet
        -- Data Average Update States
289 323 jshamlet
        when RD_LAST =>
290 324 jshamlet
          Avg_Busy           <= '1';
291 323 jshamlet
          RAM_Rd_Chan        <= CH_Select;
292
          RAM_Rd_Ptr         <= SPN_Pointers(i);
293
          AVG_Ctl            <= ADV_PTR;
294
 
295
        when ADV_PTR =>
296 324 jshamlet
          Avg_Busy           <= '1';
297 323 jshamlet
          SP0_Pointers(i)    <= SP0_Pointers(i) + 1;
298
          AVG_Ctl            <= CALC_NEXT;
299
 
300
        when CALC_NEXT =>
301 324 jshamlet
          Avg_Busy           <= '1';
302 323 jshamlet
          Accumulators(i)    <= Accumulators(i) +
303
                                unsigned( Data_New ) -
304
                                unsigned( Data_Old );
305
          AVG_Ctl            <= WR_NEW;
306
 
307
        when WR_NEW =>
308 324 jshamlet
          Avg_Busy           <= '1';
309 323 jshamlet
          RAM_Wr_Chan        <= CH_Select;
310
          RAM_Wr_Ptr         <= SP0_Pointers(i);
311
          RAM_Wr_Data        <= Data_New;
312
          RAM_Wr_En          <= '1';
313
          SPN_Pointers(i)    <= SP0_Pointers(i) + 1;
314 324 jshamlet
          AVG_Ctl            <= AVG_DONE;
315
 
316
        when AVG_DONE =>
317
          Interrupt          <= AVG_Int_En;
318 323 jshamlet
          AVG_Ctl            <= IDLE;
319
 
320 324 jshamlet
        -- Buffer Flush States
321
        when FLUSH_INIT =>
322
          Flush_Busy         <= '1';
323
          RAM_Wr_Addr        <= (others => '0');
324
          RAM_Wr_Data        <= (others => '0');
325
          AVG_Ctl            <= FLUSH_RAM;
326
 
327
        when FLUSH_RAM =>
328
          Flush_Busy         <= '1';
329
          RAM_Wr_Addr        <= RAM_Wr_Addr + 1;
330
          RAM_Wr_En          <= '1';
331
          if( and_reduce(RAM_Wr_Addr) = '1' )then
332
            AVG_Ctl          <= FLUSH_DONE;
333
          end if;
334
 
335
        when FLUSH_DONE =>
336
          Interrupt          <= Flush_Int_En;
337
          AVG_Ctl            <= IDLE;
338
 
339 323 jshamlet
        when others =>
340
          null;
341
      end case;
342
 
343
    end if;
344
  end process;
345
 
346
  U_BUFF : entity work.mavg_buffer_16b
347
  port map(
348
    clock               => Clock,
349
    data                => RAM_Wr_Data,
350
    rdaddress           => RAM_Rd_Addr,
351
    wraddress           => RAM_Wr_Addr,
352
    wren                => RAM_Wr_En,
353
    q                   => RAM_Rd_Data
354
  );
355
 
356
end architecture;

powered by: WebSVN 2.1.0

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