-------------------------------------------------------------------------------
--
-- OPB bus bridge for the XESS XSB-300E board
--
-- Includes a memory controller, a VGA framebuffer, and glue for the SRAM
--
--
-- Cristian Soviani, Dennis Lim, and Stephen A. Edwards
--
-------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity opb_xsb300 is
  generic (
    C_OPB_AWIDTH    : integer := 32;
    C_OPB_DWIDTH    : integer := 32;
    C_BASEADDR      : std_logic_vector := X"2000_0000";
    C_HIGHADDR      : std_logic_vector := X"2000_00FF");

  port (
    OPB_Clk : in std_logic;
    OPB_Rst : in std_logic;
    OPB_ABus : in std_logic_vector (31 downto 0);
    OPB_BE : in std_logic_vector (3 downto 0);
    OPB_DBus : in std_logic_vector (31 downto 0);
    OPB_RNW : in std_logic;
    OPB_select : in std_logic;
    OPB_seqAddr : in std_logic;
    pixel_clock : in std_logic;
    UIO_DBus : out std_logic_vector (31 downto 0);
    UIO_errAck : out std_logic;
    UIO_retry : out std_logic;
    UIO_toutSup : out std_logic;
    UIO_xferAck : out std_logic;
    PB_A : out std_logic_vector (19 downto 0);
    PB_UB_N : out std_logic; 
    PB_LB_N : out std_logic;
    PB_WE_N : out std_logic;
    PB_OE_N : out std_logic;
    RAM_CE_N : out std_logic;
    VIDOUT_CLK : out std_logic;
    VIDOUT_RCR : out std_logic_vector (9 downto 0);
    VIDOUT_GY : out std_logic_vector (9 downto 0);
    VIDOUT_BCB : out std_logic_vector (9 downto 0);
    VIDOUT_BLANK_N : out std_logic;
    VIDOUT_HSYNC_N : out std_logic;
    VIDOUT_VSYNC_N : out std_logic;
    PB_D : inout std_logic_vector (15 downto 0));
end opb_xsb300;

architecture Behavioral of opb_xsb300 is

  constant C_MASK : integer := 0; -- huge address window as we are a bridge

  signal addr_mux : std_logic_vector(19 downto 0);
  signal video_addr : std_logic_vector (19 downto 0);
  signal video_data : std_logic_vector (15 downto 0);
  signal video_req : std_logic;
  signal video_ce : std_logic;
  signal i : integer;
  signal cs : std_logic;

  signal onecycle : std_logic ;
  signal videocycle, amuxsel, hihalf : std_logic;
  signal rce0, rce1, rreset : std_logic;
  signal xfer : std_logic;
  signal pb_wr, pb_rd : std_logic;

  signal sram_ce : std_logic;

  signal rnw : std_logic;

  signal addr : std_logic_vector (23 downto 0); 	

  signal be : std_logic_vector (3 downto 0);
  signal pb_bytesel : std_logic_vector (1 downto 0);

  signal wdata : std_logic_vector (31 downto 0);
  signal wdata_mux : std_logic_vector (15 downto 0);

  signal rdata : std_logic_vector (15 downto 0); -- register data read - FDRE

  component vga
    port (
      clk : in std_logic;
      pix_clk : in std_logic;
      rst : in std_logic;
      video_data : in std_logic_vector(15 downto 0);
      video_addr : out std_logic_vector(19 downto 0);
      video_req : out std_logic;
      vidout_clk : out std_logic;
      vidout_RCR : out std_logic_vector(9 downto 0);
      vidout_GY : out std_logic_vector(9 downto 0);
      vidout_BCB : out std_logic_vector(9 downto 0);
      vidout_BLANK_N : out std_logic;
      vidout_HSYNC_N : out std_logic;
      vidout_VSYNC_N : out std_logic);
  end component;

  component memoryctrl 
    port (
      rst : in std_logic;
      clk : in std_logic;
      cs : in std_logic;
      select0 : in std_logic;
      rnw : in std_logic;
      vreq : in std_logic;
      onecycle : in std_logic;
      videocycle : out std_logic;
      hihalf : out std_logic;
      pb_wr : out std_logic;
      pb_rd : out std_logic;
      xfer : out std_logic;
      ce0 : out std_logic;
      ce1 : out std_logic;
      rres : out std_logic;
      video_ce : out std_logic);
  end component;

  component pad_io 
    port (
      clk : in std_logic;
      rst : in std_logic;
      PB_A : out std_logic_vector(19 downto 0);
      PB_UB_N : out std_logic;
      PB_LB_N : out std_logic;
      PB_WE_N : out std_logic;
      PB_OE_N : out std_logic;
      RAM_CE_N : out std_logic;
      PB_D : inout std_logic_vector(15 downto 0);
      pb_addr : in std_logic_vector(19 downto 0);
      pb_ub : in std_logic;
      pb_lb : in std_logic;
      pb_wr : in std_logic;
      pb_rd : in std_logic;
      ram_ce : in std_logic;
      pb_dread : out std_logic_vector(15 downto 0);
      pb_dwrite : in std_logic_vector(15 downto 0));
  end component;

begin

  -- Framebuffer

  vga1 : vga
    port map (
      clk => OPB_Clk,
      pix_clk => pixel_clock,
      rst => OPB_Rst,
      video_addr => video_addr,
      video_data => video_data,
      video_req => video_req,
      VIDOUT_CLK => VIDOUT_CLK,
      VIDOUT_RCR => VIDOUT_RCR, 
      VIDOUT_GY => VIDOUT_GY, 
      VIDOUT_BCB => VIDOUT_BCB,
      VIDOUT_BLANK_N => VIDOUT_BLANK_N,
      VIDOUT_HSYNC_N => VIDOUT_HSYNC_N, 
      VIDOUT_VSYNC_N => VIDOUT_VSYNC_N);

-- Memory control/arbitration state machine
  
  memoryctrl1 : memoryctrl port map (
    rst => OPB_Rst,
    clk => OPB_Clk,
    cs => cs, 
    select0 => OPB_select, 
    rnw => rnw, 
    vreq => video_req, 
    onecycle => onecycle,
    videocycle => videocycle, 
    hihalf => hihalf, 
    pb_wr => pb_wr, 
    pb_rd => pb_rd, 
    xfer => xfer,
    ce0 => rce0, 
    ce1 => rce1, 
    rres => rreset, 
    video_ce => video_ce);

-- I/O pads

  pad_io1 : pad_io port map (
    clk => OPB_Clk,
    rst => OPB_Rst,
    PB_A => PB_A,
    PB_UB_N => PB_UB_N,	
    PB_LB_N => PB_LB_N,
    PB_WE_N => PB_WE_N,
    PB_OE_N => PB_OE_N, 
    RAM_CE_N => RAM_CE_N,
    PB_D => PB_D,
    pb_addr => addr_mux,
    pb_rd => pb_rd,
    pb_wr => pb_wr,
    pb_ub => pb_bytesel(1),
    pb_lb => pb_bytesel(0),
    ram_ce => sram_ce,
    pb_dread  => rdata,
    pb_dwrite => wdata_mux);

  sram_ce <= pb_rd or pb_wr;

  amuxsel <= videocycle;

  addr_mux <= video_addr when (amuxsel = '1')
              else (addr(20 downto 2) & (addr(1) or hihalf));

  onecycle <= (not be(3)) or (not be(2)) or (not be(1)) or (not be(0));

  wdata_mux <= wdata(15 downto 0) when ((addr(1) or hihalf) = '1')
               else wdata(31 downto 16);

  process(videocycle, be, addr(1), hihalf, pb_rd, pb_wr)
  begin
    if videocycle = '1' then
      pb_bytesel <= "11";
    elsif pb_rd='1' or pb_wr='1' then
      if addr(1)='1' or hihalf='1' then
        pb_bytesel <= be(1 downto 0);
      else
        pb_bytesel <= be(3 downto 2);
      end if;
    else
      pb_bytesel <= "00";
    end if;
  end process;

  cs <= OPB_select when OPB_ABus(31 downto 20) = X"008" else '0';

  process (OPB_Clk)
  begin
    if OPB_Clk'event and OPB_Clk = '1' then      
      if OPB_Rst = '1' then
        rnw <= '0'; 
      else 
        rnw <= OPB_RNW;
      end if;
    end if;
  end process;

  process (OPB_Clk)
  begin
    if OPB_Clk'event and OPB_Clk = '1' then
      if OPB_RST = '1' then
        addr <= X"000000";
      else
        addr <= OPB_ABus(23 downto 0);
      end if;
    end if;
  end process;

  process (OPB_Clk)
  begin
    if OPB_Clk'event and OPB_Clk = '1' then
      if OPB_Rst = '1' then
        be <= "0000";
      else
        be <= OPB_BE;
      end if;
    end if;
  end process;
  
  process (OPB_Clk)
  begin
    if OPB_Clk'event and OPB_Clk = '1' then
      if OPB_Rst = '1' then
        wdata <= X"00000000";
      else
        wdata <= OPB_DBus;
      end if;
    end if;
  end process;
  
  process (OPB_Clk)
  begin
    if OPB_Clk'event and OPB_Clk = '1' then
      if video_ce = '1' then 
        video_data <= rdata;
      end if;
    end if;
  end process;

  -- Write the low two bytes if rce0 or rce1 is enabled

  process (OPB_Clk, OPB_Rst)
  begin
    if OPB_Rst = '1' then
      UIO_DBus(15 downto 0) <= X"0000";
    elsif OPB_Clk'event and OPB_Clk = '1' then 
      if rreset = '1' then
        UIO_DBus(15 downto 0) <= X"0000";
      elsif (rce1 or rce0) = '1' then
        UIO_DBus(15 downto 0) <= rdata(15 downto 0);
      end if;
    end if;
  end process;

  -- Write the high two bytes if rce0 is enabled

  process (OPB_Clk, OPB_Rst)
  begin
    if OPB_Rst = '1' then
      UIO_DBus(31 downto 16) <= X"0000";
    elsif OPB_Clk'event and OPB_Clk = '1' then 
      if rreset = '1' then
        UIO_DBus(31 downto 16) <= X"0000";
      elsif rce0 = '1' then
        UIO_DBus(31 downto 16) <= rdata(15 downto 0);
      end if;
    end if;
  end process;

  -- unused outputs
  
  UIO_errAck <= '0';
  UIO_retry <= '0';
  UIO_toutSup <= '0';
    
  UIO_xferAck <= xfer;

end Behavioral;
