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

use work.sercon_types.all;


entity sx2_ui is

  port(
    rstin: in std_logic;
    clkin: in std_logic;
    --
    sysclk: out std_logic;
    logic_reset: out std_logic;
    
    -- usb interface:
    sx2_ifclk: out std_logic;
    sx2_int: in std_logic;
    sx2_ready: in std_logic;
    sx2_reset: out std_logic;
    sx2_sloe: out std_logic;
    sx2_slrd: out std_logic;
    sx2_slwr: out std_logic;
    sx2_pkt_end: out std_logic;
    sx2_fifo_address:out std_logic_vector(2 downto 0);
    sx2_flag_a: in std_logic;
    sx2_flag_b: in std_logic;
    sx2_flag_c: in std_logic;
    sx2_wakeup: out std_logic;
    sx2_n_cs  : out std_logic;
    sx2_fifo_data: inout std_logic_vector(15 downto 0);
    usb_nc: in std_logic;
    --
    flush_sx2_buffers: in std_logic:='0';
    -- user configuration interface:
    config_control: out sercon_ctrl;
    config_src: out sercon_bus;
    config_dest: in sercon_bus;
    -- data pipe for block transfers into the design (from the pc):
    wren: out std_logic;
    full: in std_logic;
    data_from_pc: out std_logic_vector(15 downto 0);
    -- data pipe for block transfers out of the design (to the pc):
    rden: out std_logic;
    empty: in std_logic;
    data_to_pc: in std_logic_vector(15 downto 0)
    );
  

end entity sx2_ui;



architecture v0 of sx2_ui is

  constant int_low: std_logic:='0';
  constant int_high: std_logic:='1';
  
  component clk_buf
    port(
      rst: in std_logic;
      clkin : in std_logic;
      --
      logic_reset: out std_logic;
      clk0: out std_logic;
      clk90: out std_logic
      );
  end component clk_buf;


  component sx2_interface
    generic(
      dwidth:natural
      );
    port(
      clk:in std_logic;
      async_reset:in std_logic;
      buffer_flush:in std_logic;
      allow_full_speed:in std_logic;
      enum_vid:in std_logic_vector(15 downto 0) := x"0bd7";
      enum_pid:in std_logic_vector(15 downto 0) := x"1003";
      enum_did:in std_logic_vector(15 downto 0) := x"0000";
      enumok:out std_logic;
      sx2_interrupt:in std_logic;
      sx2_ready:in std_logic;
      sx2_reset:out std_logic;
      sx2_sloe:out std_logic;
      sx2_slrd:out std_logic;
      sx2_slwr:out std_logic;
      sx2_pkt_end:out std_logic;
      sx2_fifo_address:out std_logic_vector(2 downto 0);
      sx2_flag_a:in std_logic;
      sx2_flag_b:in std_logic;
      sx2_flag_c:in std_logic;
      sx2_wakeup:out std_logic;
      sx2_n_cs:out std_logic;
      ep2_write_en:out std_logic;
      ep4_write_en:out std_logic;
      ep6_read_en:out std_logic;
      ep8_read_en:out std_logic;

      ep2_full:in std_logic;
      ep4_full:in std_logic;
      ep6_empty:in std_logic;
      ep8_empty:in std_logic;
      sx2_fifo_data:inout std_logic_vector(dwidth-1 downto 0);
      ep2_fifo_data:out std_logic_vector(dwidth-1 downto 0) := (others => '0');
      ep4_fifo_data:out std_logic_vector(dwidth-1 downto 0) := (others => '0');
      ep6_fifo_data:in std_logic_vector(dwidth-1 downto 0);
      ep8_fifo_data:in std_logic_vector(dwidth-1 downto 0)
      );
  end component sx2_interface;

  constant dwidth:natural:=16;

  signal int_ep2_full : std_logic;
  signal int_ep4_full : std_logic;
  signal int_ep6_empty : std_logic;
  signal int_ep8_empty : std_logic;

  signal int_ep2_wren: std_logic;
  signal int_ep4_wren: std_logic;

  signal int_ep6_rden: std_logic;
  signal int_ep8_rden: std_logic;

  signal int_ep2_fifo_data : std_logic_vector(dwidth-1 downto 0);
  signal int_ep4_fifo_data : std_logic_vector(dwidth-1 downto 0);
  signal int_ep6_fifo_data : std_logic_vector(dwidth-1 downto 0);
  signal int_ep8_fifo_data : std_logic_vector(dwidth-1 downto 0);

  signal int_config_in_rden: std_logic;
  signal int_config_in_empty: std_logic;
  signal int_config_in_data: std_logic_vector(31 downto 0);
  signal int_config_in_data_le: std_logic_vector(31 downto 0);

  signal int_config_out_full: std_logic;
  signal int_config_out_wren: std_logic;
  signal int_config_out_data: std_logic_vector(31 downto 0);
  signal int_config_out_data_be: std_logic_vector(31 downto 0);
    

  
  component sercon_master
    generic(
      bit_width: natural
      );
    port(
      rst: in std_logic;
      clk: in std_logic;
      --
      busy: out std_logic;
      --
      -- fifo interface:
      empty: in std_logic;
      rd_en: out std_logic;
      pdin: in std_logic_vector(bit_width-1 downto 0);
      --
      full: in std_logic;
      wr_en: out std_logic;
      pdout: out std_logic_vector(bit_width-1 downto 0);
      --
      -- serial interface:
      ctrl_bus: out sercon_ctrl;
      --
      src:out sercon_bus;
      ret: in sercon_bus);
  end component sercon_master;

  

  component config_fifo_in
    port (
      din: in std_logic_vector(15 downto 0);
      rd_clk: in std_logic;
      rd_en: in std_logic;
      rst: in std_logic;
      wr_clk: in std_logic;
      wr_en: in std_logic;
      dout: out std_logic_vector(31 downto 0);
      empty: out std_logic;
      full: out std_logic);
  end component config_fifo_in;

  component config_fifo_out 
    port (
      din: in std_logic_vector(31 downto 0);
      rd_clk: in std_logic;
      rd_en: in std_logic;
      rst: in std_logic;
      wr_clk: in std_logic;
      wr_en: in std_logic;
      dout: out std_logic_vector(15 downto 0);
      empty: out std_logic;
      full: out std_logic);     
  end component config_fifo_out;

  
  
  signal int_rst:std_logic;
  signal int_logic_reset: std_logic;

  signal int_clk0: std_logic;
  signal int_clk90: std_logic;


  signal int_vid: std_logic_vector(15 downto 0);
  signal int_pid: std_logic_vector(15 downto 0);
  signal int_did: std_logic_vector(15 downto 0);

  signal int_sx2_interface_reset:std_logic;
  
begin

  int_rst<=not(rstin);
  int_sx2_interface_reset<=int_logic_reset or not(usb_nc);
  
  u_clk_buf:clk_buf
    port map(
      rst => int_rst,
      clkin => clkin,
      --
      logic_reset => int_logic_reset,
      clk0 => int_clk0,
      clk90 => int_clk90
      );

  -- map these user-side signals:
  sysclk<=int_clk0;
  logic_reset<=int_logic_reset;

  -- this mapping offsets the correct
  -- phase between the data/control
  -- signal transitions and the rising edge of the
  -- interface clock for the sx2.
  --  (note the UCF constraints
  --   must be in place.)
  sx2_ifclk<=not(int_clk90);

  int_vid<=x"feed";
  int_pid<=x"beef";
  int_did<=x"0000";
  
  u_sx2:sx2_interface
    generic map(
      dwidth=>dwidth
      )
    port map(
      clk => int_clk0,
      async_reset => int_sx2_interface_reset,
      buffer_flush =>flush_sx2_buffers,
      allow_full_speed => int_low,

      enum_vid => int_vid,
      enum_pid => int_pid,
      enum_did => int_did,

      enumok => open,--int_enumok,
      -- sx2 control signals
      sx2_interrupt => sx2_int,
      sx2_ready => sx2_ready,
      --
      sx2_reset => sx2_reset,
      -- sx2 strobes
      sx2_sloe => sx2_sloe,
      sx2_slrd => sx2_slrd,
      sx2_slwr => sx2_slwr,
      sx2_pkt_end => sx2_pkt_end,

      -- fifo address control
      sx2_fifo_address => sx2_fifo_address,

      sx2_flag_a => sx2_flag_a,
      sx2_flag_b => sx2_flag_b,
      sx2_flag_c => sx2_flag_c,
      sx2_wakeup => sx2_wakeup,
      sx2_n_cs  => sx2_n_cs,

      ep2_write_en => int_ep2_wren,
      ep4_write_en => int_ep4_wren,
      ep6_read_en  => int_ep6_rden,
      ep8_read_en  => int_ep8_rden,

      ep2_full =>int_ep2_full,
      ep4_full =>int_ep4_full,
      ep6_empty =>int_ep6_empty,
      ep8_empty =>int_ep8_empty,

      -- data ports
      sx2_fifo_data => sx2_fifo_data,

      ep2_fifo_data => int_ep2_fifo_data,
      ep4_fifo_data => int_ep4_fifo_data,
      ep6_fifo_data => int_ep6_fifo_data,
      ep8_fifo_data => int_ep8_fifo_data
      );

  -- expose the block transfer interface
  -- to the user side:
  -- from PC:
  wren<=int_ep4_wren;
  int_ep4_full<=full;
  data_from_pc<=int_ep4_fifo_data;

  -- to PC:
  rden<=int_ep8_rden;
  int_ep8_empty<=empty;
  int_ep8_fifo_data<=data_to_pc;
  
  
  -- instance the input (PC->) configuration space fifo:
  u_conf_in: config_fifo_in
    port map(
      rst=>int_logic_reset,
      rd_clk=>int_clk0,
      wr_clk=>int_clk0,
      -- sx2 side:
      wr_en=>int_ep2_wren,
      full=>int_ep2_full,
      din=>int_ep2_fifo_data,
      -- sercon_master side:
      rd_en=>int_config_in_rden,
      empty=>int_config_in_empty,
      dout=>int_config_in_data_le
      );
  
  -- instance the output (->PC) configuration space fifo:
  u_conf_out: config_fifo_out
    port map(
      rst=>int_logic_reset,
      rd_clk=>int_clk0,
      wr_clk=>int_clk0,
      -- sercon_master side:
      full=>int_config_out_full,
      wr_en=>int_config_out_wren,
      din=>int_config_out_data,
      -- sx2 side:
      rd_en=>int_ep6_rden,
      empty=>int_ep6_empty,
      dout=>int_ep6_fifo_data
      );
  
  -- deal with word swap:
  int_config_in_data<=
    int_config_in_data_le(15 downto 0)&
    int_config_in_data_le(31 downto 16);
  
  int_config_out_data<=
    int_config_out_data_be(15 downto 0)&
    int_config_out_data_be(31 downto 16);
  
  
  -- instance the sercon_master:
  u_sercon_master:sercon_master
    generic map(bit_width=>32)
    port map(
      rst=>int_logic_reset,
      clk=>int_clk0,
      --
      busy=>open,
      --
      -- input interface:
      empty=>int_config_in_empty,
      rd_en=>int_config_in_rden,
      pdin=>int_config_in_data,
      -- output interface:
      full=>int_config_out_full,
      wr_en=>int_config_out_wren,
      pdout=>int_config_out_data_be,
      --
      -- serial interface:
      ctrl_bus=>config_control,
      --
      src=>config_src,
      ret=>config_dest
      ); 
    
  
  
  

end architecture v0;
