library ieee;
use IEEE.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;

-- Since effects are involved with delays, we use SRAM to RW delay data.
-- We exploit the ideas of circular buffer to store data.
-- Here, it is performed with counters.

entity SRAM_FX is
  port (
		clk:in std_logic; --50Mhz system clk
		rst:in std_logic;

		feedback: in std_logic;
		effect_sel: in std_logic;
    		delay_len: in std_logic_vector(17 downto 0);  --must be in 2's comp negative, this reduce unnessessary computation in vhdl
		trigger: in std_logic;
		done: out std_logic;

		snd_in: in std_logic_vector(15 downto 0);
		snd_out:out std_logic_vector(15 downto 0);

    --SRAM should always assume to be enabled
    --and it is controlled by RNW and Address
		sram_rnw: out std_logic;
		sram_addr: out std_logic_vector(17 downto 0);
		sram_dt_wr: out std_logic_vector(15 downto 0);
		sram_dt_rd: in std_logic_vector(15 downto 0)

		);
end SRAM_FX;

architecture Behavioral of SRAM_FX is
  signal s_done: std_logic;
  signal dt_in: std_logic_vector(15 downto 0);  --input latch
  signal dt_out: std_logic_vector(15 downto 0);  --output latch
  signal sr_rnw, readram_dt: std_logic;
  signal sr_addr: std_logic_vector(17 downto 0);  --address latch
  signal sr_dt_rd: std_logic_vector(15 downto 0); --sram latch

  signal c_addr: std_logic_vector(17 downto 0):="000000000000000000";
  signal delay_addr: std_logic_vector(17 downto 0);--:="111010001001000000";

  signal dt_mux: std_logic;
  signal mux_dt,temp_sum,accum: std_logic_vector(15 downto 0);

  signal up:std_logic:='1';
  signal lrcnt: std_logic_vector(9 downto 0);
  signal lrclk:std_logic;
  signal cnt: std_logic_vector(6 downto 0):="0000000";
  signal d_cnt: std_logic_vector(11 downto 0):=x"000";
  signal fxdelay:std_logic_vector(17 downto 0):="000000000000000000";
  signal flgclk:std_logic;

  constant idling : std_logic_vector(1 downto 0):="00";
  constant s1: std_logic_vector(1 downto 0):="01";
  constant s2 : std_logic_vector(1 downto 0):="10";
  --constant s3 : std_logic_vector(1 downto 0):="11";
  signal c_state,n_state: std_logic_vector(1 downto 0) :="00";

begin
		done<=s_done;
		snd_out<=dt_out(15 downto 0);
		sram_rnw<=sr_rnw;
    sram_addr(17 downto 0)<=sr_addr(17 downto 0);

    sram_dt_wr<= dt_in(15 downto 0) when feedback='0' else
                 temp_sum(15 downto 0);


  process(clk,rst)
	begin
		if rst='1' then
      lrcnt<=(others=>'0');
    elsif clk'event and clk='1' then
      lrcnt<=lrcnt+1;
      lrclk<=lrcnt(9);
    end if;
  end process;

  process(lrclk,rst)
	begin
		if rst='1' then
      cnt<="0000000";
    elsif lrclk'event and lrclk='1' then
      cnt<=cnt+1;
      flgclk<=cnt(6);
    end if;
  end process;

  --variation from 0 to .003sec, with rate=128/48000 per step
  process(flgclk,rst)
  begin
    if rst='1' then
      d_cnt<="000000000000";
      up<='1';
    elsif flgclk'event and flgclk='1' then
      if up='1' then
        d_cnt<=d_cnt+1;
        if d_cnt="000010001111" then
          up<='0';
        end if;
      else
        d_cnt<=d_cnt-1;
        if d_cnt="000000000001" then
          up<='1';
        end if;
      end if;
    end if;
  end process;

  fxdelay<= delay_len when effect_sel='0' else
            "000000" & d_cnt;

----latch sound input------------
--data input is divided by 2 to avoid saturation
--at first we divide data ip by 4 but get nothing!
	process(clk,rst)
	begin
		if rst='1' then
			dt_in<=X"0000";
		elsif clk'event and clk='1' then
      dt_in(15)<=snd_in(15);
      dt_in(14)<=snd_in(15);
      dt_in(13)<=snd_in(14);
      dt_in(12)<=snd_in(13);
      dt_in(11)<=snd_in(12);
      dt_in(10)<=snd_in(11);
      dt_in(9)<=snd_in(10);
      dt_in(8)<=snd_in(9);
      dt_in(7)<=snd_in(8);
      dt_in(6)<=snd_in(7);
      dt_in(5)<=snd_in(6);
      dt_in(4)<=snd_in(5);
      dt_in(3)<=snd_in(4);
      dt_in(2)<=snd_in(3);
      dt_in(1)<=snd_in(2);
      dt_in(0)<=snd_in(1);
			--dt_in(14 downto 0)<=snd_in(15 downto 1);
		end if;
	end process;

	--generate delay and current addresses
	process(clk,rst)
	begin
		if rst='1' then
      sr_addr<="000000000000000000";
		elsif clk'event and clk='1' then
      if c_state=s1 then
        sr_addr<=c_addr;
      else
        sr_addr<=delay_addr;
      end if;
		end if;
	end process;

    delay_addr<=c_addr-fxdelay;


	--latch sram output------------
  --data input is divided by 4 to avoid saturation
	process(clk,rst)
	begin
		if rst='1' then
			sr_dt_rd<=X"0000";
		elsif clk'event and clk='1' then
      if readram_dt<='1' then
        sr_dt_rd(15)<=sram_dt_rd(15);
        sr_dt_rd(14)<=sram_dt_rd(15);
        sr_dt_rd(13)<=sram_dt_rd(14);
        sr_dt_rd(12)<=sram_dt_rd(13);
        sr_dt_rd(11)<=sram_dt_rd(12);
        sr_dt_rd(10)<=sram_dt_rd(11);
        sr_dt_rd(9)<=sram_dt_rd(10);
        sr_dt_rd(8)<=sram_dt_rd(9);
        sr_dt_rd(7)<=sram_dt_rd(8);
        sr_dt_rd(6)<=sram_dt_rd(7);
        sr_dt_rd(5)<=sram_dt_rd(6);
        sr_dt_rd(4)<=sram_dt_rd(5);
        sr_dt_rd(3)<=sram_dt_rd(4);
        sr_dt_rd(2)<=sram_dt_rd(3);
        sr_dt_rd(1)<=sram_dt_rd(2);
        sr_dt_rd(0)<=sram_dt_rd(1);
        --sr_dt_rd(14 downto 0)<=sram_dt_rd(15 downto 1);
      end if;
		end if;
	end process;

  --fsm of delay process-----
	process(clk,rst)
	begin
		if rst='1' then
			c_state<=idling;
		elsif clk'event and clk='1' then
			c_state<=n_state;
		end if;
	end process;

	--state machine combinational logic
	FSM_Comb: process(rst,trigger,c_state)
	begin
    sr_rnw<='1';  --always reading
    s_done<='0';
    readram_dt<='0';

    if rst='1' then
      n_state <= idling;
    else
      case c_state is
      when idling =>
        if trigger='1' then
          readram_dt<='1';
          n_state<=s1;
        else
          n_state<=idling;
        end if;
      when s1 =>
        --wait for calculation to be done
        n_state<=s2;
      when s2 =>
        --store new data to SRAM
        sr_rnw<='0';  --write to sram
        s_done<='1';
        n_state<=idling;
      when others =>
        n_state<=idling;
      end case;
    end if;
	end process;


	--latch output-------
	process(clk, rst)
	begin
		if rst='1' then
			dt_out<=X"0000";
		elsif clk'event and clk='1' then
      if c_state=s1 then
        dt_out<=temp_sum(15 downto 0);
      end if;
		end if;
	end process;

  --update current SRAM address-----------
	process(clk,rst)
	begin
	if rst='1' then
		c_addr<="000000000000000000";
	elsif clk'event and clk='1' then
        if c_state=s2 then
          c_addr<=c_addr+1;
        end if;
		end if;
	end process;


----delay calculation--------
--temp_sum is floating at c_state=2
  temp_sum<=dt_in + sr_dt_rd;


end Behavioral;


