-------------------------------------------------------------------------------
--
-- I/O Pads and associated circuity for the XSB-300E board
--
-- Cristian Soviani, Dennis Lim, and Stephen A. Edwards
--
-- Pad drivers, a little glue logic, and flip-flops for most bus signals
--
-- All signals, both control and the data and address busses, are registered.
-- FDC and FDP flip-flops are forced into the pads to do this.
--
-- Only the data bus is mildly complex: it latches data in both directions
-- as well as delaying the tristate control signals a cycle.
--
-------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity pad_io is
  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 pad_io;

architecture Behavioral of pad_io is

  -- Flip-flop with asynchronous clear
  
  component FDC
    port (
      C : in std_logic;
      CLR : in std_logic;
      D : in std_logic;
      Q : out std_logic);
  end component;

  -- Flip-flop with asynchronous preset
  
  component FDP
    port (
      C : in std_logic;
      PRE : in std_logic;
      D : in std_logic;
      Q : out std_logic);
  end component;

  -- Setting the iob attribute to "true" ensures that instances of these
  -- components are placed inside the I/O pads and are therefore very fast
  
  attribute iob : string;
  attribute iob of FDC : component is "true";
  attribute iob of FDP : component is "true";

  -- Fast off-chip output buffer, low-voltage TTL levels, 24 mA drive
  -- I is the on-chip signal, O is the pad
  
  component OBUF_F_24
    port (
      O : out STD_ULOGIC;
      I : in STD_ULOGIC);
  end component;

  -- Fast off-chip input/output buffer, low-voltage TTL levels, 24 mA drive
  -- T is the tristate control input, IO is the pad,
  
  component IOBUF_F_24
    port (
      O : out STD_ULOGIC;
      IO : inout STD_ULOGIC;
      I : in STD_ULOGIC;
      T : in STD_ULOGIC);
  end component;

  signal pb_addr_1: std_logic_vector(19 downto 0);
  signal pb_dwrite_1: std_logic_vector(15 downto 0);
  signal pb_tristate: std_logic_vector(15 downto 0);
  signal pb_dread_a: std_logic_vector(15 downto 0);
  signal we_n, pb_we_n1: std_logic;
  signal oe_n, pb_oe_n1: std_logic;
  signal lb_n, pb_lb_n1: std_logic;
  signal ub_n, pb_ub_n1: std_logic;
  signal ramce_n, ram_ce_n1: std_logic;
  signal dataz : std_logic;	

begin

  -- Write enable
  
  we_n <= not pb_wr;

  we_ff : FDP port map (
    C => clk, PRE => rst,
    D => we_n,
    Q => pb_we_n1);
 
  we_pad : OBUF_F_24 port map (
    O => PB_WE_N,
    I => pb_we_n1);

  -- Output Enable

  oe_n <= not pb_rd;

  oe_ff : FDP port map (
    C => clk,
    PRE => rst,
    D => oe_n,
    Q => pb_oe_n1);

  oe_pad : OBUF_F_24 port map (
    O => PB_OE_N,
    I => pb_oe_n1);

  -- RAM Chip Enable

  ramce_n <= not ram_ce;

  ramce_ff : FDP port map (
    C => clk, PRE => rst,
    D => ramce_n,
    Q => ram_ce_n1);

  ramce_pad : OBUF_F_24 port map (
    O => RAM_CE_N,
    I => ram_ce_n1);

  -- Upper byte enable
  
  ub_n <= not pb_ub;

  ub_ff : FDP port map (
    C => clk, PRE => rst,
    D => ub_n,
    Q => pb_ub_n1);

  ub_pad : OBUF_F_24 port map (
    O => PB_UB_N,
    I => pb_ub_n1);

  -- Lower byte enable
  
  lb_n <= not pb_lb;

  lb_ff : FDP port map (
    C => clk,
    PRE => rst,
    D => lb_n,
    Q => pb_lb_n1);

  lb_pad : OBUF_F_24 port map (
    O => PB_LB_N,
    I => pb_lb_n1);

  -- 20-bit address bus

  addressbus : for i in 0 to 19 generate
    address_ff : FDC port map (
      C => clk, CLR => rst,
      D => pb_addr(i),
      Q => pb_addr_1(i));
    
    address_pad : OBUF_F_24 port map (
      O => PB_A(i),
      I => pb_addr_1(i));
  end generate;

  -- 16-bit data bus

  dataz <= (not pb_wr) or pb_rd;

  databus : for i in 0 to 15 generate
    dtff : FDP port map (               -- Trisate enable
      C => clk,
      PRE => rst,
      D => dataz,
      Q => pb_tristate(i));

    drff : FDP port map (
      C => clk,
      PRE => rst,
      D => pb_dread_a(i),
      Q => pb_dread(i));

    dwff : FDP port map (
      C => clk,
      PRE => rst,
      D => pb_dwrite(i),
      Q => pb_dwrite_1(i));

    data_pad : IOBUF_F_24 port map (
      O => pb_dread_a(i),
      IO => PB_D(i),
      I => pb_dwrite_1(i),
      T => pb_tristate(i));
  end generate;

end Behavioral;
