-------------------------------------------------------------------------------
--
-- FILENAME: video_emc_controller.vhd
--
-- COMPONENTS: video_controller, video_buf, 
--             opb2emc_master_select, emc_controller
--
-- NOTES: 
-- 1 - Two clock domains are divided by a small buffer video_buf.
--     Timing is interleaved for write in OPB_Clk domain and
--     for read in Pixel_Clock domain, so no conflict in timing. 
--
-------------------------------------------------------------------------------

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

entity video_emc_controller is
  
  generic (
    C_OPB_AWIDTH : integer         := 32;
    C_OPB_DWIDTH : integer         := 32;
    C_OPB_CLK_PERIOD_PS  : integer := 20000;
    C_NUM_BANKS_MEM  : integer     := 1;
    C_DEV_MIR_ENABLE  : integer    := 0;
    C_READ_ADDR_TO_OUT_SLOW_PS_0  : integer   := 10000;
    C_WRITE_ADDR_TO_OUT_SLOW_PS_0  : integer  := 8000;
    C_WRITE_MIN_PULSE_WIDTH_PS_0  : integer   := 8000;
    C_READ_ADDR_TO_OUT_FAST_PS_0  : integer   := 10000;
    C_WRITE_ADDR_TO_OUT_FAST_PS_0  : integer  := 8000;
    C_BASEADDR   : std_logic_vector(31 downto 0) := X"b0000000";
    C_HIGHADDR   : std_logic_vector(31 downto 0) := X"b0001fff";
    C_MEM0_BASEADDR    : std_logic_vector(31 downto 0) := X"c0000000";
    C_MEM0_HIGHADDR    : std_logic_vector(31 downto 0) := X"c00fffff"); -- in reality
    
  port (
    OPB_Clk        : in std_logic;
    OPB_Rst        : in std_logic;

    -- OPB signals interfacing with uB
    OPB_ABus       : in std_logic_vector (31 downto 0);
    OPB_BE         : in std_logic_vector (3 downto 0); -- not used
    OPB_DBus       : in std_logic_vector (31 downto 0);
    OPB_RNW        : in std_logic;
    OPB_select     : in std_logic;
    OPB_seqAddr    : in std_logic; -- not used

    -- OPB signals interfacing with external SRAM
    EMC_DBus       : out std_logic_vector (31 downto 0);
    EMC_errAck     : out std_logic;
    EMC_retry      : out std_logic;
    EMC_toutSup    : out std_logic;
    EMC_xferAck    : out std_logic;

    Pixel_Clock_2x : in std_logic;

    -- Video signals
    VIDOUT_CLK     : out std_logic;
    VIDOUT_RED     : out std_logic;
    VIDOUT_GREEN   : out std_logic;
    VIDOUT_BLUE    : out std_logic;
    VIDOUT_HSYNC : out std_logic;
    VIDOUT_VSYNC : out std_logic;

    -- Off-chip SRAM signals
    Mem_A   : out   std_logic_vector(0 to 31);
    Mem_DQ_I  : in    std_logic_vector(0 to 31);
    Mem_DQ_O  : out   std_logic_vector(0 to 31);
    Mem_DQ_T  : out   std_logic_vector(0 to 31);
    --Mem_DQ    : inout std_logic_vector(0 to 31);
    Mem_OEN : out std_logic;
    Mem_CEN : out std_logic;
    Mem_WEN : out std_logic;
    Mem_BEN : out std_logic_vector(0 to 3));

end video_emc_controller;

architecture Behavioral of video_emc_controller is

  constant C_MEM_BASEADDR : std_logic_vector(31 downto 0) := X"C0000003";

  -------------------------------------
  -- video_controller							
  -------------------------------------

  constant HTOTAL : integer := 800;
  constant HSYNC : integer := 96;
  constant HBACK_PORCH : integer := 48;
  constant HACTIVE : integer := 640;
  constant HFRONT_PORCH : integer := 16;
  constant HVidBuf_start : integer := 135;
  constant HVidBuf_stop : integer := 775;
  
  constant VTOTAL : integer := 525;
  constant VSYNC : integer := 2;
  constant VBACK_PORCH : integer := 33;
  constant VACTIVE : integer := 480;
  constant VFRONT_PORCH : integer := 10;			 
  constant VVidBuf_start : integer := 35;			 
  constant VVidBuf_stop : integer := 515;			 

  -------------------------------------
  -- video_controller
  -------------------------------------

  -- Signals for the video controller
  signal Pixel_Clock : std_logic;       -- 25 MHz clock divided from 50 MHz
  signal LoadNShift : std_logic;        -- Shift register control
  signal ShiftData : std_logic_vector(31 downto 0); -- Shift register data
  signal VideoData : std_logic_vector(3 downto 0); -- Serial out ANDed with blanking

  signal Hcount : std_logic_vector(9 downto 0);  -- Horizontal position (0-800)
  signal Vcount : std_logic_vector(9 downto 0);  -- Vertical position (0-524)
  signal HBLANK_N, VBLANK_N : std_logic;   -- Blanking signals 
  signal EndOfLine, EndOfField : std_logic;

  signal HVidBuf_valid, VVidBuf_valid : std_logic;
  signal VidBuf_Load_valid, VidBuf_Data_valid : std_logic;

  signal HVidBuf_count_X8 : std_logic_vector(9 downto 0);
  signal HVidBuf_count : std_logic_vector(6 downto 0);
  signal VVidBuf_count : std_logic_vector(9 downto 0);

  -------------------------------------
  -- video_buf
  -------------------------------------

  -- Signals for the OPB-mapped RAM			
  signal Vid2Emc_Ena_pixel : std_logic;
  signal Vid2Emc_Ena0, Vid2Emc_Ena1, Vid2Emc_Ena2 : std_logic;
  signal VidBuf_Data : std_logic_vector(31 downto 0); -- data in video buffer 

  signal VidBuf_ABus : std_logic_vector(15 downto 0);	 
  signal VidBuf_count : std_logic_vector(15 downto 0);	 

  signal Vid2Emc_ABus       : std_logic_vector (31 downto 0);
  signal Vid2Emc_BE         : std_logic_vector (3 downto 0); -- not used
  signal Vid2Emc_DBus       : std_logic_vector (31 downto 0);
  signal Vid2Emc_RNW        : std_logic;
  signal Vid2Emc_select     : std_logic;
  signal Vid2Emc_seqAddr    : std_logic; -- not used

  signal Emc2Vid_xferAck : std_logic;										
  signal Emc2Vid_DBus    : std_logic_vector (31 downto 0);

  -------------------------------------
  -- opb2emc_master_select
  -------------------------------------

  -- Latched input signals from OPB
  signal OPB2Emc_Abus, OPB2Emc_Dbus : std_logic_vector(31 downto 0);
  signal OPB2Emc_RNW, OPB2Emc_select : std_logic;
  signal OPB2Emc_BE : std_logic_vector(3 downto 0);
  signal OPB2Emc_seqAddr : std_logic;

  -- Written from uB C-code via OPB
  signal MasterSelect2Emc : std_logic_vector(2 downto 0);
  signal MasterSelect2Emc0 : std_logic_vector(2 downto 0);
  signal MasterSelect2Emc_INT : std_logic_vector(2 downto 0);
  signal MOD_Rst, OPBorMOD_Rst : std_logic; -- reset controller state whenever mode changes
  signal Emc2OPB_DBus       : std_logic_vector (31 downto 0);
  signal Emc2OPB_xferAck    : std_logic;
  
  -- Latched input signals into EMC
  signal EMC_Abus_in, EMC_Dbus_in : std_logic_vector(31 downto 0);
  signal EMC_RNW_in, EMC_select_in : std_logic;
  signal EMC_BE_in : std_logic_vector(3 downto 0);
  signal EMC_seqAddr_in : std_logic;

  -- Latched output signals from EMC
  signal EMC_DBus_out : std_logic_vector (31 downto 0);
  signal EMC_xferAck_out : std_logic;
  signal OPB_SRAMselect : std_logic;
  signal Vid2Emc_SRAMselect : std_logic;
  
  -------------------------------------
  -- emc_controller
  -------------------------------------

  signal current_state, next_state : std_ulogic_vector(1 downto 0);
  constant SRAM_RW_0 	: std_ulogic_vector := "00";
  constant SRAM_RW_1 	: std_ulogic_vector := "01";
  constant SRAM_RW_2 	: std_ulogic_vector := "10";
  constant SRAM_RW_3 	: std_ulogic_vector := "11";
  
  signal Mem_DQ_T0 	: std_logic;
  signal SRAM_RW_active : std_logic;
  
begin  -- Behavioral

  -------------------------------------
  -- video_buf
  -------------------------------------

  -- get Vid2Emc_Ena0/1/2 from Pixel_Clock domain (cross-clock domain)
  Vid2Emc_Ena_GEN: process (OPB_Clk, OPB_Rst)
  begin
    if OPB_Rst = '1' then
      Vid2Emc_Ena0 <= '0';
      Vid2Emc_Ena1 <= '0';
      Vid2Emc_Ena2 <= '0';
    elsif OPB_Clk'event and OPB_Clk = '1' then
      Vid2Emc_Ena0 <= Vid2Emc_Ena_pixel;
      Vid2Emc_Ena1 <= Vid2Emc_Ena0;
      Vid2Emc_Ena2 <= Vid2Emc_Ena1;
    end if;
  end process Vid2Emc_Ena_GEN;

  Vid2Emc_select_GEN: process (OPB_Clk, OPB_Rst)
  begin
    if OPB_Rst = '1' then
      Vid2Emc_ABus <= X"00000000";     
      Vid2Emc_select <= '0';
    elsif OPB_Clk'event and OPB_Clk = '1' then
      if Vid2Emc_Ena1 = '1' and Vid2Emc_Ena2 = '0' and VidBuf_Load_valid = '1' then
        Vid2Emc_select <= '1';
        Vid2Emc_ABus <= C_MEM_BASEADDR + ("00000000000000" & VidBuf_ABus & "00");     
      elsif Emc2Vid_xferAck = '1' and VidBuf_Load_valid = '1' then
        Vid2Emc_select <= '0';
        Vid2Emc_ABus <= X"00000000";
      end if;
    end if;
  end process Vid2Emc_select_GEN;

  Vid2Emc_BE <= "1111"; -- always enable all 4 bytes
  Vid2Emc_DBus <= X"00000000"; -- not used
  Vid2Emc_RNW <= '1'; -- always read
  Vid2Emc_seqAddr <= '0'; -- not used
 
  VidBuf_Data_GEN: process (OPB_Clk, OPB_Rst)
  begin
    if OPB_Rst = '1' then
      VidBuf_Data <= X"00000000";
    elsif OPB_Clk'event and OPB_Clk = '1' then
	   if (Emc2Vid_xferAck = '1' and VidBuf_Load_valid = '1' ) then
              VidBuf_Data <= Emc2Vid_DBus;
           elsif (Emc2Vid_xferAck = '0' and (VidBuf_Load_valid = '1' or VidBuf_Data_valid = '1')) then
              VidBuf_Data <= VidBuf_Data;
           --else
           --   VidBuf_Data <= X"88444488"; -- debug
           end if;
    end if;
  end process VidBuf_Data_GEN;

  -------------------------------------
  -- video_controller
  -------------------------------------

  -- Pixel clock divider  
  Pixel_clk_divider : process (Pixel_Clock_2x, OPB_Rst)
  begin
    if OPB_Rst = '1' then
      Pixel_Clock <= '0';
    elsif Pixel_Clock_2x'event and Pixel_Clock_2x = '1' then
      Pixel_Clock <= not Pixel_Clock;
    end if;
  end process Pixel_clk_divider;
  
  -- Horizontal and vertical counters

  HCounter : process (Pixel_Clock, OPBorMOD_Rst)
  begin    
    if OPBorMOD_Rst = '1' then
      Hcount <= (others => '0');
    elsif Pixel_Clock'event and Pixel_Clock = '1' then
      if EndOfLine = '1' then
        Hcount <= (others => '0');
      else
        Hcount <= Hcount + 1;
      end if;      
    end if;
  end process HCounter;

  EndOfLine <= '1' when Hcount = HTOTAL - 1 else '0';
 
  VCounter: process (Pixel_Clock, OPBorMOD_Rst)
  begin
    if OPBorMOD_Rst = '1' then
      Vcount <= (others => '0');
    elsif Pixel_Clock'event and Pixel_Clock = '1' then
      if EndOfLine = '1' then
        if EndOfField = '1' then
          Vcount <= (others => '0');
        else
          Vcount <= Vcount + 1;
        end if;
      end if;
    end if;
  end process VCounter;

  EndOfField <= '1' when Vcount = VTOTAL - 1 else '0';

  -- State machines to generate HSYNC, VSYNC, HBLANK, and VBLANK

  HSyncGen : process (Pixel_Clock, OPBorMOD_Rst)
  begin    
    if OPBorMOD_Rst = '1' then
      VIDOUT_HSYNC <= '0';
    elsif Pixel_Clock'event and Pixel_Clock = '1' then
      if EndOfLine = '1' then
        VIDOUT_HSYNC <= '1';
      elsif Hcount = HSYNC - 1 then
        VIDOUT_HSYNC <= '0';
      end if;      
    end if;
  end process HSyncGen;

  HBlankGen : process (Pixel_Clock, OPBorMOD_Rst)
  begin    
    if OPBorMOD_Rst = '1' then
      HBLANK_N <= '0';
    elsif Pixel_Clock'event and Pixel_Clock = '1' then
      if Hcount = HSYNC + HBACK_PORCH - 1 then
        HBLANK_N <= '1';
      elsif Hcount = HSYNC + HBACK_PORCH + HACTIVE - 1 then
        HBLANK_N <= '0';
      end if;      
    end if;
  end process HBlankGen;
  
  VSyncGen : process (Pixel_Clock, OPBorMOD_Rst)
  begin    
    if OPBorMOD_Rst = '1' then
      VIDOUT_VSYNC <= '1';
    elsif Pixel_Clock'event and Pixel_Clock = '1' then
      if EndOfLine ='1' then
        if EndOfField = '1' then
          VIDOUT_VSYNC <= '1';
        elsif VCount = VSYNC - 1 then
          VIDOUT_VSYNC <= '0';
        end if;
      end if;      
    end if;
  end process VSyncGen;

  VBlankGen : process (Pixel_Clock, OPBorMOD_Rst)
  begin    
    if OPBorMOD_Rst = '1' then
      VBLANK_N <= '0';
    elsif Pixel_Clock'event and Pixel_Clock = '1' then
      if EndOfLine ='1' then
        if Vcount = VSYNC + VBACK_PORCH - 1 then
          VBLANK_N <= '1';
        elsif VCount = VSYNC + VBACK_PORCH + VACTIVE - 1 then
          VBLANK_N <= '0';
        end if;
      end if;      
    end if;
  end process VBlankGen;
  
  -- video buffer read/write

  HVidBuf_count_X8 <= Hcount - HVidBuf_start;
  HVidBuf_count <= HVidBuf_count_X8(9 downto 3);  -- /8
  VVidBuf_count <= Vcount - VVidBuf_start; -- previous lines excluding current line
  VidBuf_count <= ("000000000" & HVidBuf_count) +
                  (VVidBuf_count(9 downto 0) & "000000") +
                  ("00" & VVidBuf_count(9 downto 0) & "0000");
  --HVidBuf_valid <= '1' when ( (Hcount >= HVidBuf_start) and (Hcount < HVidBuf_stop) ) else
  --                 '0';
  --VVidBuf_valid <= '1' when ( (Vcount >= VVidBuf_start) and (Vcount < VVidBuf_stop) ) else
  --                 '0';
  VidBuf_Load_valid <= '1' when ((HVidBuf_valid = '1') and (VVidBuf_valid = '1')) else
                       '0';  
  --VidBuf_Data_valid <= '1' when ((Hcount >= 143) and (Hcount < 776) and (VVidBuf_valid = '1')) else
  --                     '0';

  HVidBuf_valid_GEN: process (Pixel_Clock, OPBorMOD_Rst)
  begin
    if OPBorMOD_Rst = '1' then
      HVidBuf_valid <= '0';
    elsif Pixel_Clock'event and Pixel_Clock = '1' then
      if (Hcount = 134) then
        HVidBuf_valid <= '1';
      elsif (Hcount = 774) then
        HVidBuf_valid <= '0';
      end if;
    end if;
  end process HVidBuf_valid_GEN;

  VVidBuf_valid_GEN: process (Pixel_Clock, OPBorMOD_Rst)
  begin
    if OPBorMOD_Rst = '1' then
      VVidBuf_valid <= '0';
    elsif Pixel_Clock'event and Pixel_Clock = '1' then
      if (Vcount = 35) then
        VVidBuf_valid <= '1';
      elsif (Vcount = 515) then
        VVidBuf_valid <= '0';
      end if;
    end if;
  end process VVidBuf_valid_GEN;

  VidBuf_Data_valid_GEN: process (Pixel_Clock, OPBorMOD_Rst)
  begin
    if OPBorMOD_Rst = '1' then
      VidBuf_Data_valid <= '0';
    elsif Pixel_Clock'event and Pixel_Clock = '1' then
      if (Hcount = 142 and VVidBuf_valid = '1') then
        VidBuf_Data_valid <= '1';
      elsif (Hcount = 776 and VVidBuf_valid = '1') then
        VidBuf_Data_valid <= '0';
      end if;
    end if;
  end process VidBuf_Data_valid_GEN;

  VidBuf_ABus_GEN: process (Pixel_Clock, OPBorMOD_Rst)
  begin
    if OPBorMOD_Rst = '1' then
      VidBuf_ABus <= X"0000";
    elsif Pixel_Clock'event and Pixel_Clock = '1' then
      if (LoadNShift = '1' and VidBuf_Load_valid = '1') then
        VidBuf_ABus <= VidBuf_count; -- 480*80 words = 38400 words in total
      end if;
    end if;
  end process VidBuf_ABus_GEN;

  LoadNShift <= '1' when Hcount(2 downto 0) = X"7" else '0';
  Vid2Emc_Ena_pixel <= '1' when Hcount(2 downto 0) = X"0" else '0'; 

  -- Shift register

  ShiftRegister: process (Pixel_Clock, OPBorMOD_Rst)
  begin
    if OPBorMOD_Rst = '1' then
      ShiftData <= X"00000000";
    elsif Pixel_Clock'event and Pixel_Clock = '1' then
      if ((LoadNShift = '1') and (VidBuf_Data_valid = '1')) then
        ShiftData <= VidBuf_Data;
      --elsif (LoadNShift = '1' and VidBuf_Data_valid = '0') then
      --  ShiftData <= X"ff0000ff";
      else 
        ShiftData <= ShiftData(27 downto 0) & ShiftData(31 downto 28);
      end if;
    end if;
  end process ShiftRegister;

  VideoData(3 downto 0) <= ShiftData(31 downto 28);

  -- Video signals going to the "video DAC"

  VideoData_GEN: process (Pixel_Clock, OPBorMOD_Rst)
  begin
    if OPBorMOD_Rst = '1' then
      VIDOUT_RED   <= '0';
      VIDOUT_BLUE  <= '0';
      VIDOUT_GREEN <= '0';
    elsif Pixel_Clock'event and Pixel_Clock = '1' then
      if HBLANK_N = '1' and VBLANK_N = '1' then		  
        VIDOUT_RED   <= VideoData(3);
        VIDOUT_GREEN <= VideoData(2);
        VIDOUT_BLUE  <= VideoData(1);
      else
        VIDOUT_RED   <= '0';
        VIDOUT_GREEN <= '0';
        VIDOUT_BLUE  <= '0';
      end if;
    end if;
  end process VideoData_GEN;

  VIDOUT_CLK <= Pixel_Clock;

  -------------------------------------
  -- opb2emc_master_select
  -------------------------------------

  -- Unused OPB control signals
  EMC_errAck <= '0';
  EMC_retry <= '0';
  EMC_toutSup <= '0';

  -- Latch the relevant OPB signals from the OPB, since they arrive late
  --LatchOPB2Emc: process (OPB_Clk, OPB_Rst)
  --begin
    --if OPB_Rst = '1' then
      --OPB2Emc_Abus <= ( others => '0' );
      --OPB2Emc_Dbus <= ( others => '0' );
      --OPB2Emc_RNW <= '1';
      --OPB2Emc_select <= '0';
      --OPB2Emc_BE <= "1111";
      --OPB2Emc_seqAddr <= '0';
    --elsif OPB_Clk'event and OPB_Clk = '1' then
      --OPB2Emc_Abus <= OPB_ABus;
      --OPB2Emc_Dbus <= OPB_DBus;
      --OPB2Emc_RNW <= OPB_RNW;
      --OPB2Emc_select <= OPB_Select;
      --OPB2Emc_BE <= OPB_BE;
      --OPB2Emc_seqAddr <= OPB_seqAddr;
    --end if;
  --end process LatchOPB2Emc;

      -- Don't latch OPB inputs, just use them, 
      -- since they're in the same chip with the same controlled clk skew
      OPB2Emc_Abus <= (others => '0') when OPB_Rst = '1' else 
                      OPB_ABus when OPB_SRAMselect = '1' else
                      (others => '0');
      OPB2Emc_Dbus <= (others => '0') when OPB_Rst = '1' else 
                      OPB_DBus when OPB_SRAMselect = '1' else
                      (others => '0');
      OPB2Emc_RNW <= '0' when OPB_Rst = '1' else 
                     OPB_RNW when OPB_SRAMselect = '1' else
                     '0';
      OPB2Emc_select <= '0' when OPB_Rst = '1' else 
                        OPB_Select when OPB_SRAMselect = '1' else
                        '0';
      OPB2Emc_BE <= (others => '0') when OPB_Rst = '1' else 
                    OPB_BE when OPB_SRAMselect = '1' else
                    (others => '0');
      OPB2Emc_seqAddr <= '0' when OPB_Rst = '1' else 
                         OPB_seqAddr when OPB_SRAMselect = '1' else
                         '0';

  OPB_SRAMselect <= OPB_select when OPB_Abus(31 downto 20) = X"c00" else
                    '0';

  Vid2Emc_SRAMselect <= Vid2Emc_select when OPB_Abus(31 downto 20) = X"c00" else
                    '0';

  -- Latch MasterSelect2Emc in advance to judge MasterSelect2Emc
  -- It's like cache write-through, input to MasterSelect2Emc & external SRAM as well.
  process (OPB_Clk, OPB_Rst)
  begin
    if OPB_Rst='1' then
      MasterSelect2Emc0 <= "001";
      MasterSelect2Emc_INT <= "000";
    elsif OPB_Clk'event and OPB_Clk='1' then
      if OPB_select = '1' and OPB_Abus = X"c00fffff" and OPB_RNW = '0' then
        MasterSelect2Emc0 <= OPB_Dbus(2 downto 0); -- MasterSelect2Emc written
        MasterSelect2Emc_INT <= OPB_Dbus(5 downto 3); -- MasterSelect2Emc written
      end if;      
    end if;
  end process;

  -- reset video controller state whenever mode changes
  MOD_Rst <= '0' when OPB_Rst='1' else
             '1' when OPB_select = '1' and OPB_Abus = X"c00fffff" and OPB_RNW = '0' else
             '0';

  MasterSelect2Emc <= "100" when MasterSelect2Emc_INT = "111" else
                      MasterSelect2Emc0;

  OPBorMOD_Rst <= OPB_Rst or MOD_Rst;

  EMC_Abus_in <= Vid2Emc_ABus when MasterSelect2Emc = "001" and Vid2Emc_SRAMselect = '1' else
                 OPB2Emc_Abus;
  EMC_Dbus_in <= Vid2Emc_DBus when MasterSelect2Emc = "001" and Vid2Emc_SRAMselect = '1' else
                 OPB2Emc_Dbus;
  EMC_RNW_in <= Vid2Emc_RNW when MasterSelect2Emc = "001" and Vid2Emc_SRAMselect = '1' else
                OPB2Emc_RNW;
  EMC_BE_in <= Vid2Emc_BE when MasterSelect2Emc = "001" and Vid2Emc_SRAMselect = '1' else
               OPB2Emc_BE;
  EMC_select_in <= Vid2Emc_select when MasterSelect2Emc = "001" and Vid2Emc_SRAMselect = '1' else
                   OPB2Emc_select;
  EMC_seqAddr_in <= Vid2Emc_seqAddr when MasterSelect2Emc = "001" and Vid2Emc_SRAMselect = '1' else
                    OPB2Emc_seqAddr;

  Emc2OPB_DBus <= EMC_DBus_out when MasterSelect2Emc = "010" or MasterSelect2Emc = "100" else
                  X"00000000";
  Emc2OPB_xferAck <= EMC_xferAck_out when MasterSelect2Emc = "010" or MasterSelect2Emc = "100" else
                     '0';

  -- Just naming convention change
  EMC_DBus <= Emc2OPB_DBus;
  EMC_xferAck <= Emc2OPB_xferAck;

  Emc2Vid_DBus <= EMC_DBus_out when MasterSelect2Emc = "001" else
                  X"00000000";
  Emc2Vid_xferAck <= EMC_xferAck_out when MasterSelect2Emc = "001" else 
                     '0';

  -------------------------------------
  -- emc_controller
  -------------------------------------
  
  -- BE AWARE!
  -- We need to take care of the reverse order problem 
  -- in between OPB address and external SRAM address mismatch,
  -- because FPGA IO pad won't use OPB address (11 to 0).
  
  -- from emc.vhd
  --valid_Memory_T      <= '0' when valid_Memory_Access='1' and Bus2IP_RNW='0'
  --                         else '1';
  --mem_dq_t_int(i) <= valid_Memory_T;
   
  Mem_BEN <= "0000"; -- always read/write a word (4 bytes)

  EMC_DBus_out(31 downto 0) <= Mem_DQ_I(0 to 31) when current_state = SRAM_RW_3 else
                           X"00000000";
  EMC_xferAck_out <= '1' when current_state = SRAM_RW_3 else
                     '0';
                     
  Mem_DQ_O(0 to 31) <= EMC_Dbus_in(31 downto 0) when SRAM_RW_active = '1' else
           X"00000000";                   
  Mem_DQ_T0 <= EMC_RNW_in when SRAM_RW_active = '1' else
               '1';                   
  Mem_DQ_T(0 to 31) <= (others => Mem_DQ_T0);
  Mem_OEN <= not EMC_RNW_in when SRAM_RW_active = '1' else
             '1';
  Mem_CEN <= '0'; -- SRAM always on
  Mem_WEN <= EMC_RNW_in when current_state = SRAM_RW_2 else
             '1';

  SRAM_RW_active <= '1' when current_state = SRAM_RW_1 or 
                             current_state = SRAM_RW_2 or
                             current_state = SRAM_RW_3 else
                    '0';

  Mem_A(31) <= EMC_Abus_in(0) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(30) <= EMC_Abus_in(1) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(29) <= EMC_Abus_in(2) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(28) <= EMC_Abus_in(3) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(27) <= EMC_Abus_in(4) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(26) <= EMC_Abus_in(5) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(25) <= EMC_Abus_in(6) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(24) <= EMC_Abus_in(7) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(23) <= EMC_Abus_in(8) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(22) <= EMC_Abus_in(9) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(21) <= EMC_Abus_in(10) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(20) <= EMC_Abus_in(11) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(19) <= EMC_Abus_in(12) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(18) <= EMC_Abus_in(13) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(17) <= EMC_Abus_in(14) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(16) <= EMC_Abus_in(15) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(15) <= EMC_Abus_in(16) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(14) <= EMC_Abus_in(17) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(13) <= EMC_Abus_in(18) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(12) <= EMC_Abus_in(19) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(11) <= EMC_Abus_in(20) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(10) <= EMC_Abus_in(21) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(9) <= EMC_Abus_in(22) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(8) <= EMC_Abus_in(23) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(7) <= EMC_Abus_in(24) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(6) <= EMC_Abus_in(25) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(5) <= EMC_Abus_in(26) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(4) <= EMC_Abus_in(27) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(3) <= EMC_Abus_in(28) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(2) <= EMC_Abus_in(29) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(1) <= EMC_Abus_in(30) when SRAM_RW_active = '1' else
           '0';                   
  Mem_A(0) <= EMC_Abus_in(31) when SRAM_RW_active = '1' else
           '0';                   

  Ext_SRAM_FSM: process (OPB_Clk, OPB_Rst)
  begin
    if OPB_Rst='1' then
      current_state <= SRAM_RW_0;
    elsif OPB_Clk'event and OPB_Clk='1' then
      if EMC_select_in = '1' then 
        current_state <= next_state;
      else
        current_state <= SRAM_RW_0;
      end if; 
    end if;
  end process Ext_SRAM_FSM;

  Ext_SRAM_FSM_flow: process (OPB_Rst, current_state)
  begin
    if OPB_Rst='1' then
      next_state <= SRAM_RW_0;
    else
      case current_state is
        when SRAM_RW_0 =>
          next_state <= SRAM_RW_1;
        when SRAM_RW_1 =>
          next_state <= SRAM_RW_2;
        when SRAM_RW_2 =>
          next_state <= SRAM_RW_3;
        when SRAM_RW_3 =>
          next_state <= SRAM_RW_0;
        when others =>
          next_state <= SRAM_RW_0;
      end case;
    end if;
  end process Ext_SRAM_FSM_flow;

end Behavioral;




