-- -- LVDS receiver -- library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.std_logic_unsigned.all; library UNISIM; use UNISIM.VCOMPONENTS.all; library dsat_lib; use dsat_lib.dsat.all; entity lvdsrx is port ( gclk, grst : in std_logic; -- Local bus signals lb_data_in : in std_logic_vector(7 downto 0); -- data in lb_data_out : out std_logic_vector(7 downto 0); -- data out lb_addr : in std_logic_vector(1 downto 0); -- latched address (low bits) lb_ena : in std_logic; -- address match lb_byte : in std_logic_vector(1 downto 0); -- byte counter for word access lb_read : in std_logic; -- local bus read enable lb_write : in std_logic; -- local bus write enable debug : out std_logic_vector(3 downto 0); g_trig : in std_logic; -- global trigger from SCL bp_start : in std_logic; fc : in std_logic; -- first crossing from SCL -- LVDS input signals iso_out : in std_logic; rx_clk : in std_logic; -- LVDS receiver 0 clock rxd : in std_logic_vector(27 downto 0)); end lvdsrx; architecture lvdsrx_a of lvdsrx is -- bit pattern for idle on LVDS inputs -- constant LVDS_idle_bits : std_logic_vector(27 downto 0) := (others => '0'); constant CSR_ena : integer := 0; -- CSR enable bit constant CSR_busy : integer := 1; -- CSR busy bit (read only) constant CSR_trig : integer := 2; -- CSR trigger bit (write only) constant CSR_glo : integer := 3; -- CSR global trigger enable bit constant CSR_fc : integer := 4; -- CSR FC trigger enable bit type lb_mux_t is array (3 downto 0) of std_logic_vector(7 downto 0); signal lb_mux : lb_mux_t; signal ram_ena : std_logic; -- DPRAM port B enable (receiver) signal port_a_ena : std_logic; -- DPRAM port A enable (lb access) signal pre_trig : std_logic; -- external trigger (fc or global) -- starts delay for receiver active signal en_delay_ctr : std_logic; signal ram_trig : std_logic; -- receiver trigger (CSR_trig, or pre_ -- trig plus delay) signal local_addr_l : std_logic_vector(8 downto 0); -- latch for adx(10:2) signal local_addr_s : std_logic_vector(10 downto 0); -- RAM port A adx signal csr : std_logic_vector(7 downto 0); signal rx_delay : std_logic_vector(6 downto 0); -- receiver delay register (R/W) signal delay_ctr : std_logic_vector(6 downto 0); -- receiver delay countdown signal ram_addr : std_logic_vector(8 downto 0); signal ram_data : std_logic_vector(31 downto 0); signal rx_frame : std_logic_vector(2 downto 0); signal en_rx : std_logic; signal bp_start_dl : std_logic; signal iso_out_q : std_logic; signal iso_out_dl : std_logic; signal iso_rxclk : std_logic; begin -- lvdsrx_a ------------------------------------------------------------------------------- -- Synchronous logic (receiver clock) ------------------------------------------------------------------------------- process (rx_clk) begin if rx_clk'event and rx_clk = '1' then if((ram_data(27 downto 25) = "111" and ram_data(7 downto 6) = "00") or rx_frame = "110")then rx_frame <= "000"; else rx_frame <= rx_frame + 1; end if; end if; end process; process (rx_clk, grst) begin if grst = '0' then ram_addr <= (others => '0'); ram_ena <= '0'; elsif rx_clk'event and rx_clk = '1' then if en_rx = '1' and rx_frame = "101" then ram_ena <= '1'; ram_addr <= (others => '0'); end if; -- receive data if (enabled) and (not full) if ram_ena = '1' then ram_addr <= ram_addr + 1; if ram_addr = "111111111" then ram_ena <= '0'; -- disable when full end if; end if; end if; end process; ------------------------------------------------------------------------------- -- Synchronous logic (global RF clock) ------------------------------------------------------------------------------- process (gclk, grst) begin -- process if grst = '0' then -- asynchronous reset (active low) en_rx <= '0'; ram_trig <= '0'; local_addr_l <= (others => '0'); pre_trig <= '0'; delay_ctr <= (others => '0'); elsif gclk'event and gclk = '1' then -- rising clock edge if ((lb_ena = '1' and lb_write = '1' and lb_addr = "10" and lb_byte = "00" and lb_data_in( CSR_trig) = '1') or (csr(CSR_glo) = '1' and g_trig = '1') or (csr(CSR_fc) = '1' and fc = '1')) then -- if enabled, trigger bit sets ram_trig pre_trig <= csr( CSR_ena); csr(CSR_fc) <= csr(CSR_fc) and not (fc and csr(CSR_ena)); elsif bp_start = '1' then pre_trig <= '0'; end if; if bp_start = '1' then if pre_trig = '1' then delay_ctr <= rx_delay; en_delay_ctr <= '1'; elsif en_delay_ctr = '1' then if delay_ctr = 0 then en_delay_ctr <= '0'; else delay_ctr <= delay_ctr -1; end if; end if; if delay_ctr = 0 and en_delay_ctr = '1' then ram_trig <= '1'; else ram_trig <= '0'; end if; end if; en_rx <= ram_trig; -- local bus write if lb_ena = '1' and lb_write = '1' then if lb_addr = "00" then -- write to address register case lb_byte is when "00" => local_addr_l(7 downto 0) <= lb_data_in; when "01" => local_addr_l(8) <= lb_data_in(0); when others => null; end case; end if; end if; -- local bus write if lb_ena = '1' and lb_write = '1' then if lb_addr = "00" then -- write to address register case lb_byte is when "00" => local_addr_l(7 downto 0) <= lb_data_in; when "01" => local_addr_l(8) <= lb_data_in(0); when others => null; end case; end if; if lb_addr = "10" and lb_byte = "00" then -- write to CSR lsb csr <= lb_data_in; end if; if lb_addr = "11" then -- write to delay case lb_byte is when "00" => rx_delay <= lb_data_in(6 downto 0); when others => null; end case; end if; end if; -- auto-increment ram address on R/W if port_a_ena = '1' then if lb_byte = "11" then local_addr_l <= local_addr_l + 1; end if; end if; end if; end process; ------------------------------------------------------------------------------- -- Asynchronous logic ------------------------------------------------------------------------------- debug(0) <= ram_trig; debug(1) <= en_rx; debug(2) <= ram_ena; local_addr_s <= local_addr_l & lb_byte; lb_data_out <= lb_mux( conv_integer( lb_addr)); -- address register read with lb_byte select lb_mux(0) <= local_addr_l(7 downto 0) when "00", ("0000000" & local_addr_l(8)) when "01", "00000000" when others; -- CSR read with receiver spy in upper bits with lb_byte select lb_mux(2) <= csr when "00", rxd(7 downto 0) when "10", rxd(15 downto 8) when "11", "00000000" when others; -- delay and word count read with lb_byte select lb_mux(3) <= '0' & rx_delay when "00", ram_addr(7 downto 0) when "10", "0000000" & ram_addr(8 downto 8) when "11", "00000000" when others; port_a_ena <= '1' when (lb_ena = '1') and (lb_addr = "01") else '0'; -- RAM port A enable -- dual-port RAM entity -- debug option: save address and low 22 data bits -- ram_data <= '1' & ram_addr & rxd(21 downto 0); i_bp_start_dl: srlc16e port map( d => bp_start, clk => gclk, ce => '1', a0 => '0', a1 => '1', a2 => '0', a3 => '0', q => bp_start_dl); i_iso_out_dl: srlc16e port map( d => iso_out_q, clk => gclk, ce => bp_start_dl, a0 => '1', a1 => '0', a2 => '0', a3 => '0', q => iso_out_dl); process(gclk) begin if(gclk'event and gclk = '1')then if(bp_start_dl = '1')then iso_out_q <= iso_out; end if; end if; end process; process(rx_clk) begin if(rx_clk'event and rx_clk = '1')then if(rx_frame = "000")then iso_rxclk <= iso_out_dl; else iso_rxclk <= '0'; end if; end if; end process; -- set MSB of the last L1 word i_iso_rxclk: srlc16e port map( d => iso_rxclk, clk => rx_clk, ce => '1', a0 => '1', a1 => '1', a2 => '0', a3 => '0', q => ram_data(31)); ram_data(30 downto 0) <= '0' & iso_out_dl & en_rx & rxd; -- save data with MSB set r1 : RAMB16_S9_S36 port map ( ADDRA => local_addr_s, ADDRB => ram_addr, DIA => lb_data_in, DIB => ram_data, DIPA => (others => '0'), DIPB => (others => '0'), WEA => lb_write, WEB => '1', CLKA => gclk, CLKB => rx_clk, SSRA => '0', SSRB => '0', ENA => port_a_ena, ENB => ram_ena, DOA => lb_mux(1), DOB => open, DOPA => open, DOPB => open); end lvdsrx_a;