-------------------------------------------------------------------------------
-- CSEE 4840 Embedded System Design
-- Jaycam
-- Yaniv Schiller - yhs2001@columbia.edu
-- Avrum Tilman - amt77@columbia.edu
-- Josh Weinberg - jmw211@columbia.edu
-------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

--  Uncomment the following lines to use the declarations that are
--  provided for instantiating Xilinx primitive components.
--library UNISIM;
--use UNISIM.VComponents.all;

entity memoryctrl is
    Port ( rst : in std_logic;
           clk : in std_logic;
           cs : in std_logic; -- any of my devices selected
           opb_select : in std_logic; -- original select
			  
           rnw : in std_logic;

           eth_io : in std_logic;
           fullword : in std_logic;
 	   read_early : out std_logic;
 	   write_early : out std_logic;
           bus_req : out std_logic;
           
           videocycle : out std_logic;
           hihalf : out std_logic;
           wr_req : out std_logic;
           rd_req : out std_logic;
           xfer : out std_logic;
           ce0 : out std_logic;
           ce1 : out std_logic;
           rres : out std_logic;

	   ram_output_enable : out std_logic;
	   ram_WE : out std_logic;
	   sram_ce : in std_logic
			  );
end memoryctrl;

architecture Behavioral of memoryctrl is

signal r_idle, r_common, r_w32, r_ra, r_rb, r_rc, r_rd, r_xfer : std_logic;
signal r_weth1, r_weth2, r_weth3 : std_logic;
signal r_v1, r_v0, r_v2 : std_logic;
signal wr_req_i, rd_req_i, videocycle_i : std_logic;
signal sram_rst : std_logic;

  signal WE : std_logic;
  signal output_enable : std_logic;

  constant STATE_BITS : integer := 3;
  constant Idle     : std_logic_vector(0 to 2) := "000";
  constant Selected : std_logic_vector(0 to 2) := "001";
  constant Read     : std_logic_vector(0 to 2) := "011";
  constant Xfer1     : std_logic_vector(0 to 2) := "111";
  constant Xfer2     : std_logic_vector(0 to 2) := "110";

  signal present_state, next_state : std_logic_vector(0 to 2);


begin

process(rst, clk)
begin
	if rst = '1' or cs='0' then
          r_idle <= '1';
          r_common <= '0';
          r_w32 <= '0';
          r_ra <= '0'; r_rb <= '0'; r_rc <= '0'; r_xfer <= '0'; r_weth1 <= '0';
          r_weth2 <= '0'; r_weth3 <= '0';

	elsif clk'event and clk='1' then

	r_idle <= (r_idle and not cs) or (r_xfer) or (not opb_select);
	r_common <= opb_select and (r_idle and cs);

        r_weth1 <= opb_select and (r_common and not rnw and eth_io);
        r_weth2 <= opb_select and (r_weth1); 
        r_weth3 <= opb_select and (r_weth2); 
--	r_w32 <= opb_select and (r_common and not rnw and fullword);

	r_ra <= opb_select and (r_common and rnw);
	r_rb  <= opb_select and (r_ra);
        r_rc <= opb_select and r_rb and (fullword or eth_io);
	        
	r_xfer <= opb_select and ( (r_common and not rnw and not fullword and not eth_io)                                  
--		 or (r_w32) 
		 or (r_ra and not fullword and not eth_io) --b
		 or (r_rb) --c
                 or (r_weth1));

	end if;
end process;




  fsm_seq : process(clk, sram_rst)
  begin
   if (sram_ce='1') then

    if sram_rst = '1' then
      present_state <= Idle;
    elsif clk'event and clk = '1' then
      present_state <= next_state;
    end if;

	xfer <= present_state(0);
   	rres <= present_state(0);
	
	read_early <= '1'; -- hmmm   -- r_ra and eth_io;
	write_early <= '1';
	hihalf <= '0';

	wr_req_i <= not WE;
	rd_req_i <= WE;
	wr_req <= wr_req_i;
	rd_req <= rd_req_i;
	bus_req <= rd_req_i or wr_req_i or r_common;

	ce0 <= '1';
	ce1 <= '1';


   else
	xfer <= r_xfer;
	rres <= r_xfer;
	
	read_early <= r_ra and eth_io;
	write_early <= not ((r_common and not rnw and eth_io) or (r_weth1) or r_weth2);
	hihalf <= r_w32 or (r_ra and fullword);

	wr_req_i <= (r_common and not rnw and not eth_io) or (r_w32) or (r_weth1) or (r_weth2) or (r_weth3);
	rd_req_i <= (r_common and rnw) or (r_ra and (fullword or eth_io));
	wr_req <= wr_req_i;
	rd_req <= rd_req_i;
	bus_req <= rd_req_i or wr_req_i or r_common;

	ce0 <= r_rb or (r_rc and eth_io);
	ce1 <= r_rb or r_rc;
   end if;
--   end if;
  
  end process fsm_seq;


  fsm_comb : process(sram_rst, present_state, sram_ce, OPB_Select, rnw)
  begin   
--  if (sram_ce = '1') then 
    sram_rst <= '1';
    WE <= '1';
    output_enable <= '1';
    if rst = '1' then
      next_state <= Idle;
    else
      case present_state is
        when Idle =>
          if sram_ce = '1' then
            next_state <= Selected;
          else
            next_state <= Idle;
            WE <= '1';
	    output_enable <= '1';
          end if;

        when Selected =>
          if OPB_Select = '1' then
            if RNW = '1' then
              sram_rst <= '0';
              next_state <= Read;
            else
              WE <= '0';
              next_state <= Xfer1;
            end if;
          else
            next_state <= Idle;
          end if;

        when Read =>
--          if OPB_Select = '1' then
            output_enable <= '0';
            next_state <= Xfer1;
--          else
--            next_state <= Idle;
--          end if;

        -- State encoding is critical here: xfer must only be true here
        when Xfer1 =>
          next_state <= Idle;

          
        when others =>
          next_state <= Idle;
      end case;
--    end if;

ram_output_enable <= output_enable;
ram_we <= we;


    end if;
  end process fsm_comb;




end Behavioral;
