---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2006
--
-- Filename: PISO6x32.vhd
-- Language: VHDL '93
-- Project:  RapiDaq Card Peripheral FPGA
--
-- Design Description:
-- PISO with 6 x 32 bit inputs using Dual Port Block Ram ( Spartan-II / IIE )
-- Use the different bus width option to do some of the muxing
---------------------------------------------------------------------------

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;

library UNISIM;
use UNISIM.vcomponents.all;

entity PISO6x32 is
  port (pnReset      : in  std_ulogic;
        pClock       : in  std_ulogic;
        pStart       : in  std_ulogic;
        pDataIn0     : in  std_logic_vector(31 downto 0);
        pDataIn1     : in  std_logic_vector(31 downto 0);
        pDataIn2     : in  std_logic_vector(31 downto 0);
        pDataIn3     : in  std_logic_vector(31 downto 0);
        pDataIn4     : in  std_logic_vector(31 downto 0);
        pDataIn5     : in  std_logic_vector(31 downto 0);
        pSerialOut   : out std_ulogic;
        pSerialOutEn : out std_ulogic);
end PISO6x32;

architecture Rtl of PISO6x32 is

  signal Reset : std_ulogic;

  signal DataInMux : std_logic_vector(31 downto 0);
  signal DataInMux4: std_logic_vector(31 downto 0);
  signal InMuxSel  : std_logic_vector(5 downto 0);
  signal WriteCount: std_logic_vector(2 downto 0);
  signal WriteAddr : std_logic_vector(7 downto 0);
  signal WriteEn   : std_ulogic;

  signal BeginShift   : std_ulogic;
  signal ShiftCount   : std_logic_vector(7 downto 0);
  signal ShiftResults : std_ulogic;
  
  signal DataOutMux : std_logic_vector(1 downto 0);
  signal OutMuxSel  : std_ulogic;
  signal ReadAddr   : std_logic_vector(11 downto 0);
  signal ReadValid  : std_ulogic;
  constant cLo : std_logic_vector(1 downto 0) := "00";

begin

  Reset <= not pnReset;

  GenStrobes: process(pnReset, pClock)
  begin
    if pnReset = '0' then
      InMuxSel <= (others => '0');
      WriteCount <= (others => '0');
      WriteEn <= '0';
      BeginShift <= '0';
    elsif rising_edge(pClock) then
      BeginShift <= '0';
      if pStart = '1' then
        InMuxSel <= "000001";
        WriteCount <= (others => '0');
        WriteEn <= '1';
      else
        InMuxSel <= InMuxSel(4 downto 0) & '0';
        WriteCount <= unsigned(WriteCount) + 1;
        if InMuxSel(5) = '1' then
          WriteEn <= '0';
          BeginShift <= '1';
        end if;
      end if;
    end if;
  end process GenStrobes;

  WriteAddr <= "00000" & WriteCount;

  -- tristate mux for input data
--  DataInMux <= pDataIn0 when InMuxSel(0) = '1' else (others => 'Z');
--  DataInMux <= pDataIn1 when InMuxSel(1) = '1' else (others => 'Z');
--  DataInMux <= pDataIn2 when InMuxSel(2) = '1' else (others => 'Z');
--  DataInMux <= pDataIn3 when InMuxSel(3) = '1' else (others => 'Z');
  DataInMux <= pDataIn4 when InMuxSel(4) = '1' else (others => 'Z');
  DataInMux <= pDataIn5 when InMuxSel(5) = '1' else (others => 'Z');
  DataInMux <= DataInMux4 when WriteAddr(2) = '0' else (others => 'Z'); 

  DataInMux4 <= pDataIn0 when WriteAddr(1 downto 0) = "00" else
                pDataIn1 when WriteAddr(1 downto 0) = "01" else
                pDataIn2 when WriteAddr(1 downto 0) = "10" else
                pDataIn3;

  RAMB4_S1_S16_High : RAMB4_S1_S16
    port map (
      DOA   => DataOutMux(1 downto 1),  -- Port A 1-bit data output
      DOB   => open,                    -- Port B 16-bit data output
      ADDRA => ReadAddr,                -- Port A 12-bit address input
      ADDRB => WriteAddr,               -- Port B 8-bit address input
      CLKA  => pClock,                  -- Port A clock input
      CLKB  => pClock,                  -- Port B clock input
      DIA   => cLo(1 downto 1),         -- Port A 1-bit data input
      DIB   => DataInMux(31 downto 16), -- Port B 16-bit data input
      ENA   => '1',                     -- Port A RAM enable input
      ENB   => '1',                     -- Port B RAM enable input
      RSTA  => Reset,                   -- Port A Synchronous reset input
      RSTB  => Reset,                   -- Port B Synchronous reset input
      WEA   => '0',                     -- Port A RAM write enable input
      WEB   => WriteEn);                -- Port B RAM write enable input

  RAMB4_S1_S16_Low : RAMB4_S1_S16
    port map (
      DOA   => DataOutMux(0 downto 0),  -- Port A 1-bit data output
      DOB   => open,                    -- Port B 16-bit data output
      ADDRA => ReadAddr,                -- Port A 12-bit address input
      ADDRB => WriteAddr,               -- Port B 8-bit address input
      CLKA  => pClock,                  -- Port A clock input
      CLKB  => pClock,                  -- Port B clock input
      DIA   => cLo(0 downto 0),         -- Port A 1-bit data input
      DIB   => DataInMux(15 downto 0),  -- Port B 16-bit data input
      ENA   => '1',                     -- Port A RAM enable input
      ENB   => '1',                     -- Port B RAM enable input
      RSTA  => Reset,                   -- Port A Synchronous reset input
      RSTB  => Reset,                   -- Port B Synchronous reset input
      WEA   => '0',                     -- Port A RAM write enable input
      WEB   => WriteEn);                -- Port B RAM write enable input


  GenShiftCount: process(pnReset, pClock)
  begin
    if pnReset = '0' then
      ShiftCount   <= X"00";
      ShiftResults <= '0';
    elsif rising_edge(pClock) then
      if BeginShift = '1' then
        ShiftCount   <= X"BF";
        ShiftResults <= '1';
      else
        if ShiftCount /= X"00" then
          ShiftCount <= unsigned(ShiftCount) - 1;
        else
          ShiftResults <= '0';
        end if;
      end if;
    end if;
  end process GenShiftCount;

  ReadAddr <= "00000" & ShiftCount(7 downto 5) & ShiftCount(3 downto 0);

  GenSerialDataOut: process(pnReset, pClock)
  begin
    if pnReset = '0' then
      pSerialOut   <= '0';
      pSerialOutEn <= '0';
      OutMuxSel <= '0';
      ReadValid <= '0';
    elsif rising_edge(pClock) then
      OutMuxSel <= ShiftCount(4);
      if OutMuxSel = '0' then
        pSerialOut <= DataOutMux(0);
      else
        pSerialOut <= DataOutMux(1);
      end if;

      ReadValid <= ShiftResults;
      pSerialOutEn <= ReadValid;
    end if;
  end process GenSerialDataOut;

end architecture Rtl;

