-------------------------------------------------------------------------------
--
-- Memory controller state machine
--
-- Arbitrates between requests from the processor and video system
-- The video system gets priority
-- Also handles 32- to 16-bit datapath width conversion (sequencing)
--
-- Cristian Soviani, Dennis Lim, and Stephen A. Edwards
--
-------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity memoryctrl is
  port (
    rst : in std_logic;
    clk : in std_logic;
    cs : in std_logic;                  -- chip select (address valid)
    select0 : in std_logic;             -- select (true through whole cycle)
    rnw : in std_logic;                 -- read/write'
    vreq : in std_logic;                -- video request
    onecycle : in std_logic;            -- one- or two-byte access (not four)
    
    videocycle : out std_logic;         -- acknowledges vreq
    hihalf : out std_logic;             -- doing bytes 2,3 of 32-bit access
    pb_wr : out std_logic;              -- Write request to off-chip memory
    pb_rd : out std_logic;              -- Read request to off-chip memory
    xfer : out std_logic;               -- Transfer acknowledge for OPB
    
    ce0 : out std_logic;                -- lower 16 bit OPB data latch enable
    ce1 : out std_logic;                -- upper 16 bit OPB data latch enable
    rres : out std_logic;               -- clear OPB data output latches
    
    video_ce : out std_logic);          -- video buffer latch enable
end memoryctrl;

architecture Behavioral of memoryctrl is
  -- State machine bits
  -- largely one-hot, but one ra and one rb bit can be true simultaneously
  signal r_idle : std_logic;
  signal r_common : std_logic;
  signal r_ra1 : std_logic;
  signal r_ra2 : std_logic;
  signal r_rb1 : std_logic;
  signal r_rb2 : std_logic;
  signal r_rb3 : std_logic;
  signal r_w : std_logic;
  signal r_xfer : std_logic;
  
  signal vcycle_1 : std_logic;
  signal vcycle_2 : std_logic;

  signal r_idle_next_state : std_logic;
  signal r_common_next_state : std_logic;
  signal r_ra1_next_state : std_logic;
  signal r_ra2_next_state : std_logic;
  signal r_rb1_next_state : std_logic;
  signal r_rb2_next_state : std_logic;
  signal r_rb3_next_state : std_logic;
  signal r_w_next_state : std_logic;
  signal r_xfer_next_state : std_logic;

begin
  
  -- Sequential process for the state machine
  
  process (clk, rst)
  begin
    if rst = '1' then
      r_idle <= '1';
      r_common <= '0';
      r_ra1 <= '0';
      r_ra2 <= '0';
      r_rb1 <= '0';
      r_rb2 <= '0';
      r_rb3 <= '0';
      r_w <= '0';
      r_xfer <= '0';
    elsif clk'event and clk='1' then
      r_idle <= r_idle_next_state;
      r_common <= r_common_next_state;
      r_ra1 <= r_ra1_next_state;
      r_ra2 <= r_ra2_next_state;
      r_rb1 <= r_rb1_next_state;
      r_rb2 <= r_rb2_next_state;
      r_rb3 <= r_rb3_next_state;
      r_w <= r_w_next_state;
      r_xfer <= r_xfer_next_state;     
    end if;
  end process;

  -- Combinational next-state logic

  r_idle_next_state <= (r_idle and (not cs)) or r_xfer or (not select0);
  r_common_next_state <= select0 and
                         ((r_idle and cs) or (r_common and vreq));
  r_ra1_next_state <= select0 and
                      r_common and (not vreq) and rnw;
  r_ra2_next_state <= select0 and
                      r_ra1;
  r_rb1_next_state <= select0 and
                      ((r_common and not onecycle and not vreq and rnw) or
                       (r_rb1 and vreq));
  r_rb2_next_state <= select0 and
                      (r_rb1 and (not vreq));
  r_rb3_next_state <= select0 and
                      r_rb2;      
  r_w_next_state <= select0 and
                    ((r_common and (not rnw) and (not vreq) and
                      (not onecycle)) or
                     (r_w and vreq));
  r_xfer_next_state <= select0 and
                       ((r_common and onecycle and
                         (not rnw) and (not vreq)) or
                        (r_w and (not vreq)) or (r_ra2 and onecycle) or r_rb3);

  -- Combinational output logic

  pb_wr <= (r_common and (not rnw) and (not vreq)) or (r_w and (not vreq));
  pb_rd <= vreq or (r_common and (not vreq) and rnw) or (r_rb1 and (not vreq));
  
  hihalf <= (r_w and (not vreq)) or (r_rb1 and (not vreq));

  ce0 <= r_ra2;
  ce1 <= r_rb3;
  rres <= r_xfer;
  xfer <= r_xfer;

  -- Two-cycle delay of video request
  -- (implicitly assumes video cycles always succeed) 
  process (clk, rst)
  begin
    if(rst = '1') then
      vcycle_1 <= '0';
      vcycle_2 <= '0';
    elsif clk'event and clk='1' then
      vcycle_1 <= vreq;
      vcycle_2 <= vcycle_1;
    end if;    
  end process;

  videocycle <= vreq;
  video_ce <= vcycle_2;
  
end Behavioral;
