URL
https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk
Subversion Repositories open8_urisc
[/] [open8_urisc/] [trunk/] [VHDL/] [o8_mavg_8ch_16b_64d.vhd] - Rev 332
Go to most recent revision | Compare with Previous | Blame | View Log
-- Copyright (c)2023 Jeremy Seth Henry -- All rights reserved. -- -- Redistribution and use in source and binary forms, with or without -- modification, are permitted provided that the following conditions are met: -- * Redistributions of source code must retain the above copyright -- notice, this list of conditions and the following disclaimer. -- * Redistributions in binary form must reproduce the above copyright -- notice, this list of conditions and the following disclaimer in the -- documentation and/or other materials provided with the distribution, -- where applicable (as part of a user interface, debugging port, etc.) -- -- THIS SOFTWARE IS PROVIDED BY JEREMY SETH HENRY ``AS IS'' AND ANY -- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -- DISCLAIMED. IN NO EVENT SHALL JEREMY SETH HENRY BE LIABLE FOR ANY -- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- -- VHDL units : o8_mavg_8ch_16b_64d -- Description: 8-channel moving average calculation for 16-bit unsigned data -- Accumulator depth is 64 elements, using 1 block RAM. -- -- Register Map: -- Offset Bitfield Description Read/Write -- 0x00 AAAAAAAA Raw Data (lower) (RW) -- 0x01 AAAAAAAA Raw Data (upper) (RW) -- 0x02 -----AAA Raw Channel Select (RW) -- 0x03 BA------ Update Accum & Int Enable / Busy (RW*) -- 0x04 AAAAAAAA Avg Data (lower) (RW) -- 0x05 AAAAAAAA Avg Data (upper) (RW) -- 0x06 -----AAA Avg Channel Select (RW) -- 0x07 BA------ Flush Statistics & Int_Enable / Busy (RW*) -- -- Note: Writing bit A high will enable a CPU interrupt for the specified -- operation. Writing a low will disable the interrupt. Bit B indicates -- the operation status in either case. library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use ieee.std_logic_misc.all; library work; use work.open8_pkg.all; entity o8_mavg_8ch_16b_64d is generic( Autoflush_On_Reset : boolean := TRUE; Address : ADDRESS_TYPE ); port( Open8_Bus : in OPEN8_BUS_TYPE; Write_Qual : in std_logic := '1'; Rd_Data : out DATA_TYPE; Interrupt : out std_logic ); end entity; architecture behave of o8_mavg_8ch_16b_64d is alias Clock is Open8_Bus.Clock; alias Reset is Open8_Bus.Reset; constant User_Addr : std_logic_vector(15 downto 3) := Address(15 downto 3); alias Comp_Addr is Open8_Bus.Address(15 downto 3); signal Addr_Match : std_logic := '0'; alias Reg_Sel_d is Open8_Bus.Address(2 downto 0); signal Reg_Sel_q : std_logic_vector(2 downto 0) := "000"; signal Wr_En_d : std_logic := '0'; signal Wr_En_q : std_logic := '0'; alias Wr_Data_d is Open8_Bus.Wr_Data; signal Wr_Data_q : DATA_TYPE := x"00"; signal Rd_En_d : std_logic := '0'; signal Rd_En_q : std_logic := '0'; signal RAW_Data : std_logic_vector(15 downto 0) := (others => '0'); alias RAW_Data_L is RAW_Data(7 downto 0); alias RAW_Data_H is RAW_Data(15 downto 8); signal RAW_Channel : std_logic_vector(2 downto 0) := (others => '0'); signal RAW_Valid : std_logic := '0'; signal Flush_Valid : std_logic := '0'; signal Flush_Busy : std_logic := '0'; type AVG_CTL_STATES is (IDLE, RD_LAST, ADV_PTR, CALC_NEXT, WR_NEW, AVG_DONE, FLUSH_INIT, FLUSH_RAM, FLUSH_DONE); signal AVG_Ctl : AVG_CTL_STATES := FLUSH_INIT; signal Avg_Busy : std_logic := '0'; signal CH_Select : std_logic_vector(2 downto 0) := (others => '0'); signal Data_New : std_logic_vector(15 downto 0) := (others => '0'); signal RAM_Wr_Addr : std_logic_vector(8 downto 0) := (others => '0'); alias RAM_Wr_Chan is RAM_Wr_Addr(8 downto 6); alias RAM_Wr_Ptr is RAM_Wr_Addr(5 downto 0); signal RAM_Wr_Data : std_logic_vector(15 downto 0) := (others => '0'); signal RAM_Wr_En : std_logic := '0'; signal RAM_Rd_Addr : std_logic_vector(8 downto 0) := (others => '0'); alias RAM_Rd_Chan is RAM_Rd_Addr(8 downto 6); alias RAM_Rd_Ptr is RAM_Rd_Addr(5 downto 0); signal RAM_Rd_Data : std_logic_vector(15 downto 0) := (others => '0'); alias Data_Old is RAM_Rd_Data; type PTR_ARRAY is array (0 to 7) of std_logic_vector(5 downto 0); signal SP0_Pointers : PTR_ARRAY; signal SPN_Pointers : PTR_ARRAY; -- Accumulator width is bus_size (16) + log depth (6) type ACCUM_ARRAY is array (0 to 7) of unsigned(21 downto 0); signal Accumulators : ACCUM_ARRAY; signal AVG_Channel : std_logic_vector(2 downto 0) := (others => '0'); signal AVG_Out : std_logic_vector(15 downto 0) := (others => '0'); alias AVG_Out_L is AVG_Out(7 downto 0); alias AVG_Out_H is AVG_Out(15 downto 8); signal AVG_Int_En : std_logic := '0'; signal Flush_Int_En : std_logic := '0'; begin Addr_Match <= '1' when Comp_Addr = User_Addr else '0'; Wr_En_d <= Addr_Match and Write_Qual and Open8_Bus.Wr_En; Rd_En_d <= Addr_Match and Open8_Bus.Rd_En; Register_IF_proc: process( Clock, Reset ) variable i : integer := 0; begin if( Reset = Reset_Level )then Wr_En_q <= '0'; Wr_Data_q <= x"00"; Reg_Sel_q <= (others => '0'); Rd_En_q <= '0'; Rd_Data <= OPEN8_NULLBUS; RAW_Data <= (others => '0'); RAW_Valid <= '0'; RAW_Channel <= (others => '0'); AVG_Out <= (others => '0'); AVG_Channel <= (others => '0'); AVG_Int_En <= '0'; Flush_Int_En <= '0'; elsif( rising_edge(Clock) )then Reg_Sel_q <= Reg_Sel_d; Wr_En_q <= Wr_En_d; Wr_Data_q <= Wr_Data_d; Flush_Valid <= '0'; RAW_Valid <= '0'; if( Wr_En_q = '1' )then case( Reg_Sel_q )is when "000" => RAW_Data_L <= Wr_Data_q; when "001" => RAW_Data_H <= Wr_Data_q; when "010" => RAW_Channel <= Wr_Data_q(2 downto 0); when "011" => AVG_Int_En <= Wr_Data_q(6); RAW_Valid <= not (Flush_Busy or Avg_Busy); when "110" => AVG_Channel <= Wr_Data_q(2 downto 0); when "111" => Flush_Int_En <= Wr_Data_q(6); Flush_Valid <= not (Flush_Busy or Avg_Busy); when others => null; end case; end if; i := conv_integer(AVG_Channel); AVG_Out <= std_logic_vector(Accumulators(i)(21 downto 6)); Rd_Data <= OPEN8_NULLBUS; Rd_En_q <= Rd_En_d; if( Rd_En_q = '1' )then case( Reg_Sel_q )is when "000" => Rd_Data <= RAW_Data_L; when "001" => Rd_Data <= RAW_Data_H; when "010" => Rd_Data <= "00000" & RAW_Channel; when "011" => Rd_Data <= Avg_Busy & AVG_Int_En & "000000"; when "100" => Rd_Data <= AVG_Out_L; when "101" => Rd_Data <= AVG_Out_H; when "110" => Rd_Data <= "00000" & AVG_Channel; when "111" => Rd_Data <= Flush_Busy & Flush_Int_En & "000000"; when others => null; end case; end if; end if; end process; MAVG_Control_proc: process( Clock, Reset ) variable i : integer := 0; begin if( Reset = Reset_Level )then AVG_Ctl <= IDLE; if( Autoflush_On_Reset )then AVG_Ctl <= FLUSH_INIT; end if; CH_Select <= (others => '0'); Data_New <= (others => '0'); Flush_Busy <= '0'; Avg_Busy <= '0'; for i in 0 to 7 loop SP0_Pointers(i) <= (others => '1'); SPN_Pointers(i) <= (others => '0'); Accumulators(i) <= (others => '0'); end loop; RAM_Wr_Addr <= (others => '0'); RAM_Wr_Data <= (others => '0'); RAM_Wr_En <= '0'; RAM_Rd_Addr <= (others => '0'); Interrupt <= '0'; elsif( rising_edge(Clock) )then Interrupt <= '0'; RAM_Wr_En <= '0'; Flush_Busy <= '0'; Avg_Busy <= '0'; i := conv_integer(unsigned(CH_Select)); case( AVG_Ctl )is when IDLE => if( Flush_Valid = '1' )then AVG_Ctl <= FLUSH_INIT; elsif( RAW_Valid = '1' )then Data_New <= RAW_Data; CH_Select <= RAW_Channel; AVG_Ctl <= RD_LAST; end if; -- Data Average Update States when RD_LAST => Avg_Busy <= '1'; RAM_Rd_Chan <= CH_Select; RAM_Rd_Ptr <= SPN_Pointers(i); AVG_Ctl <= ADV_PTR; when ADV_PTR => Avg_Busy <= '1'; SP0_Pointers(i) <= SP0_Pointers(i) + 1; AVG_Ctl <= CALC_NEXT; when CALC_NEXT => Avg_Busy <= '1'; Accumulators(i) <= Accumulators(i) + unsigned( Data_New ) - unsigned( Data_Old ); AVG_Ctl <= WR_NEW; when WR_NEW => Avg_Busy <= '1'; RAM_Wr_Chan <= CH_Select; RAM_Wr_Ptr <= SP0_Pointers(i); RAM_Wr_Data <= Data_New; RAM_Wr_En <= '1'; SPN_Pointers(i) <= SP0_Pointers(i) + 1; AVG_Ctl <= AVG_DONE; when AVG_DONE => Interrupt <= AVG_Int_En; AVG_Ctl <= IDLE; -- Buffer Flush States when FLUSH_INIT => Flush_Busy <= '1'; RAM_Wr_Addr <= (others => '0'); RAM_Wr_Data <= (others => '0'); AVG_Ctl <= FLUSH_RAM; when FLUSH_RAM => Flush_Busy <= '1'; RAM_Wr_Addr <= RAM_Wr_Addr + 1; RAM_Wr_En <= '1'; if( and_reduce(RAM_Wr_Addr) = '1' )then AVG_Ctl <= FLUSH_DONE; end if; when FLUSH_DONE => Interrupt <= Flush_Int_En; AVG_Ctl <= IDLE; when others => null; end case; end if; end process; U_BUFF : entity work.mavg_buffer_16b port map( clock => Clock, data => RAM_Wr_Data, rdaddress => RAM_Rd_Addr, wraddress => RAM_Wr_Addr, wren => RAM_Wr_En, q => RAM_Rd_Data ); end architecture;
Go to most recent revision | Compare with Previous | Blame | View Log