library IEEE; use IEEE.STD_LOGIC_1164.all; library UNISIM; use UNISIM.vcomponents.all; -- OutClockMultiplier : integer := 1; -- 40MHz clock multiplied by to achieve output clock -- OutClockDivisor : integer := 10; -- 40MHz clock divided by to achieve output clock -- Oserdes_factor : integer := 4); -- OSERDES factor, fixed because of -- OSERDES input mapping -- entity tsserdes is generic ( OutClockMultiplier : integer := 1; OutClockDivisor : integer := 10; Oserdes_factor : integer := 4; -- faktor betweenn output frequency and input frequency, number of parallel inputs of oserdes parw : integer := 640; -- number of input lines serw : integer := 8); -- number of output lines (1..8) port ( reset_n : in std_logic; clk : in std_logic; psen : in std_logic; psincdec : in std_logic; psdone : out std_logic; locked : out std_logic; dclk : out std_logic; -- dataclock (high speed at output) dclkdiv : out std_logic; -- dataclock slow pardata : in std_logic_vector(parw-1 downto 0); serdata : out std_logic_vector(serw-1 downto 0); spoilcrc : in std_logic; -- send wrong crc start : in std_logic; -- start command to send one block active : out std_logic; -- high during sending (may need wait registers?) done : out std_logic); -- finished sending packet end tsserdes; architecture behv of tsserdes is component tsdcm generic ( OutClockMultiplier : integer; OutClockDivisor : integer; Oserdes_factor : integer); port ( clk40 : in std_logic; rst : in std_logic; psen : in std_logic; psincdec : in std_logic; psdone : out std_logic; locked : out std_logic; dclk : out std_logic; dclkdiv : out std_logic); end component; component ucrc_par generic ( POLYNOMIAL : std_logic_vector; INIT_VALUE : std_logic_vector; DATA_WIDTH : integer range 2 to 256; SYNC_RESET : integer range 0 to 1); port ( clk_i : in std_logic; rst_i : in std_logic; clken_i : in std_logic; data_i : in std_logic_vector(DATA_WIDTH - 1 downto 0); match_o : out std_logic; crc_o : out std_logic_vector(POLYNOMIAL'length - 1 downto 0)); end component; constant oserdesblock_input_width : integer := Oserdes_factor * serw; -- number of bits used in parallel to shift out constant number_of_blocks : integer := parw/oserdesblock_input_width; -- number of counts to shift out parallel input constant active_delay : integer := 2; -- number of slow cycles to delay the active signal signal muxcounter : integer range 0 to number_of_blocks; -- not -1, last count is CRC signal running : std_logic; -- muxcounter state signal cntclk : std_logic; signal dclk_i : std_logic; signal dclkdiv_i : std_logic; signal reset_serdes : std_logic; signal reset_crc : std_logic; signal active_sfr : std_logic_vector(active_delay-1 downto 0); -- Array to map inputs for mux, one more (no -1) for crcout subtype muxout_t is std_logic_vector(oserdesblock_input_width-1 downto 0); type muxin_t is array(0 to number_of_blocks) of muxout_t; signal muxin : muxin_t; signal muxout : std_logic_vector(oserdesblock_input_width-1 downto 0); -- Checksum signal crcout : std_logic_vector(oserdesblock_input_width-1 downto 0); signal rst_i : std_logic; begin -- behv assert ((parw mod oserdesblock_input_width) = 0) report "parw must be multiple of (serw*Oserdes_Factor)" severity error; -- map pardata to muxer input, MSBlock first muxmap : for i in 0 to number_of_blocks-1 generate muxin(number_of_blocks-1-i) <= pardata((i+1)*oserdesblock_input_width-1 downto i*oserdesblock_input_width); end generate muxmap; -- map CRC -- crcout <= x"deadaffe"; muxin(number_of_blocks) <= crcout when spoilcrc = '0' else not(crcout); -- Multiplexer muxout_p : process (muxcounter, muxin) begin -- process muxcounter muxout <= muxin(muxcounter); end process muxout_p; done <= '1' when muxcounter = number_of_blocks else '0'; -- delay active by n slow cycles active_sfr_p : process (dclkdiv_i, reset_n) begin -- process active_sfr_p if reset_n = '0' then -- asynchronous reset (active low) active_sfr <= (others => '0'); elsif dclkdiv_i'event and dclkdiv_i = '1' then -- rising clock edge if muxcounter /= 0 then active_sfr(active_delay-1) <= '1'; else active_sfr(active_delay-1) <= '0'; end if; active_sfr(active_delay-2 downto 0) <= active_sfr(active_delay-1 downto 1); end if; end process active_sfr_p; active <= active_sfr(0); -- muxcounter muxcnt_p : process (cntclk, reset_n) begin -- process muxcnt_p if reset_n = '0' then -- asynchronous reset (active low) muxcounter <= 0; running <= '0'; elsif cntclk'event and cntclk = '1' then -- rising clock edge if start = '1' then running <= '1'; muxcounter <= 0; elsif running = '1' then if muxcounter = number_of_blocks then running <= '0'; muxcounter <= 0; else running <= '1'; muxcounter <= muxcounter + 1; end if; end if; end if; end process muxcnt_p; reset_crc <= '1' when muxcounter = 0 else '0'; ucrc_par_1 : ucrc_par generic map ( POLYNOMIAL => x"04C11DB7", INIT_VALUE => x"00000000", DATA_WIDTH => oserdesblock_input_width, SYNC_RESET => 1) port map ( clk_i => dclkdiv_i, rst_i => reset_crc, clken_i => '1', data_i => muxout, match_o => open, crc_o => crcout); reset_serdes <= not reset_n; assert Oserdes_factor = 4 report "Works only for Oserdes_factor=4, sorry" severity error; oserdes_block : for i in 0 to serw-1 generate U_OSERDES : OSERDES generic map ( DATA_RATE_OQ => "SDR", DATA_RATE_TQ => "SDR", DATA_WIDTH => Oserdes_factor, INIT_OQ => '0', INIT_TQ => '0', SERDES_MODE => "MASTER", SRVAL_OQ => '0', SRVAL_TQ => '0', TRISTATE_WIDTH => 1) port map ( OQ => serdata(i), SHIFTOUT1 => open, SHIFTOUT2 => open, TQ => open, CLK => dclk_i, CLKDIV => dclkdiv_i, D1 => muxout(Oserdes_factor*i+3), D2 => muxout(Oserdes_factor*i+2), D3 => muxout(Oserdes_factor*i+1), D4 => muxout(Oserdes_factor*i+0), D5 => '0', D6 => '0', OCE => '1', REV => '0', SHIFTIN1 => '0', SHIFTIN2 => '0', SR => reset_serdes, T1 => '0', T2 => '0', T3 => '0', T4 => '0', TCE => '0'); end generate oserdes_block; rst_i <= not reset_n; tsdcm_1 : tsdcm generic map ( OutClockMultiplier => OutClockMultiplier, OutClockDivisor => OutClockDivisor, Oserdes_factor => Oserdes_factor) port map ( clk40 => clk, rst => rst_i, psen => psen, psincdec => psincdec, psdone => psdone, locked => locked, dclk => dclk_i, dclkdiv => dclkdiv_i); cntclk <= dclkdiv_i; dclkdiv <= dclkdiv_i; dclk <= dclk_i; end behv;