--
-- esefir5.vhd
--   5 Tap FIR low-pass filter (cutoff=20000Hz)
--   Revision 1.00
--
-- Copyright (c) 2006 Mitsutaka Okazaki (ESE Artists' factory)
-- All rights reserved.
--
-- Redistribution and use of this source code or any derivative works, are
-- permitted provided that the following conditions are met:
--
-- 1. Redistributions of source code must retain the above copyright notice,
--    this list of conditions and the following disclaimer.
-- 2. 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.
-- 3. Redistributions may not be sold, nor may they be used in a commercial
--    product or activity without specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-- "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 THE COPYRIGHT OWNER OR
-- CONTRIBUTORS 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.
--
--------------------------------------------------------------------------------
-- Description
--------------------------------------------------------------------------------
--   This component is an implementation of 5 tap FIR low-pass
--   simulation circut for ESE-MSX system II.
--   21MHz rate is assumed for an input clock. 3.58MHz is
--   assumed for streaming sample rate of 'wavin' and 'wavout'.
--------------------------------------------------------------------------------

--  修正 t.hara
--  TAP-RAM の読み出し用アドレスと、描き込み用アドレスが共通の FF になっているが
--  この気持ちがずれていて、フィルタ係数の掛かり方がおかしかったのを修正

library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_arith.all;
    use ieee.std_logic_unsigned.all;

entity esefir5 is
    generic (
        msbi    : integer
    );
    port (
        clk     : in    std_logic;
        reset   : in    std_logic;
        wavin   : in    std_logic_vector ( msbi downto 0 );
        wavout  : out   std_logic_vector ( msbi downto 0 )
    );
end esefir5;

architecture rtl of esefir5 is

    component tapram is
        generic (
            msbi : integer
        );
        port(
            clk     : in    std_logic;
            tapidx  : in    integer range 0 to 4;
            wr      : in    std_logic;
            tapin   : in    std_logic_vector( msbi downto 0 );
            tapout  : out   std_logic_vector( msbi downto 0 )
        );
    end component;

    subtype h_type  is std_logic_vector( 7 downto 0 );
    type h_array    is array( 0 to 5 ) of h_type;

    constant h          : h_array := ( X"09", X"3d", X"72", X"3d", X"09", X"00" );
    signal tapout       : std_logic_vector( msbi downto 0 );
    signal ff_state     : std_logic_vector( 2 downto 0 );
    signal ff_tapidx    : integer range 0 to 4;
    signal ff_sum       : std_logic_vector( msbi + 8 downto 0 );
    signal ff_wavout    : std_logic_vector( msbi downto 0 );
    signal w_we         : std_logic;
    signal w_mul        : std_logic_vector( msbi + 8 downto 0 );
begin

    ---------------------------------------------------------------------------
    --  出力
    ---------------------------------------------------------------------------
    wavout  <=  ff_wavout;

    ---------------------------------------------------------------------------
    --  内部ステート
    ---------------------------------------------------------------------------
    process( reset, clk )
    begin
        if( reset = '1' )then
            ff_state <= "000";
        elsif( clk'event and clk = '1' )then
            if( ff_state = "101" )then
                ff_state <= "000";
            else
                ff_state <= ff_state + 1;
            end if;
        end if;
    end process;

    process( reset, clk )
    begin
        if( reset = '1' )then
            ff_tapidx <= 0;
        elsif( clk'event and clk = '1' )then
            if( ff_tapidx = 4 )then
                ff_tapidx <= 0;
            else
                ff_tapidx <= ff_tapidx + 1;
            end if;
        end if;
    end process;

    ---------------------------------------------------------------------------
    --  積分器
    ---------------------------------------------------------------------------
    w_mul <= tapout * h( conv_integer( ff_state ) );

    process( reset, clk )
    begin
        if( reset = '1' )then
            ff_sum <= (others => '0');
        elsif( clk'event and clk = '1' )then
            if( ff_state = "101" )then
                ff_sum <= (others => '0');
            else
                ff_sum <= ff_sum + w_mul;
            end if;
        end if;
    end process;

    process( reset, clk )
    begin
        if( reset = '1' )then
            ff_wavout <= (others => '0');
        elsif( clk'event and clk = '1' )then
            if( ff_state = "101" )then
                ff_wavout <= ff_sum( ff_sum'high downto 8 );
            else
                -- hold
            end if;
        end if;
    end process;

    ---------------------------------------------------------------------------
    --  タップメモリ書き込み制御
    ---------------------------------------------------------------------------
    w_we <= '1' when( ff_state = "101" )else
            '0';

    ---------------------------------------------------------------------------
    --  タップメモリインスタンス
    ---------------------------------------------------------------------------
    u0 : tapram generic map (
        msbi    => msbi
    )
    port map (
        clk     => clk      ,
        tapidx  => ff_tapidx,
        wr      => w_we     ,
        tapin   => wavin    ,
        tapout  => tapout
    );
end rtl;
