-- -- LVDS transmitter -- library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.std_logic_unsigned.all; library UNISIM; use UNISIM.VCOMPONENTS.all; -- our private library --library dsat_lib; --use dsat_lib.dsat.all; entity lvdstx 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 (two devices) 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; -- debug output signal g_trig : in std_logic; -- global trigger from SCL bp_start : in std_logic; fc : in std_logic; -- first crossing from SCL -- LVDS transmitter signals txck : out std_logic; -- transmit clocks tx_data : out std_logic_vector(27 downto 0)); -- DDR data for channels 0/1 end lvdstx; architecture lvdstx_a of lvdstx is 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 constant CSR_rep : integer := 5; -- CSR auto repeat 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 ssrb : std_logic; -- ram port B preset signal ena_s : std_logic; -- ram port A ram enables signal tx_ena_s : std_logic; -- transmitter enabled signal tx_ena_d : std_logic; -- transmitter enable delayed signal tx_trig, tx_trig_d : std_logic; -- transmit trigger (delayed) signal tx_addr : std_logic_vector(8 downto 0); signal tx_wcount : std_logic_vector(8 downto 0); signal tx_data_s : std_logic_vector(31 downto 0); signal bogus_a : std_logic_vector(0 downto 0); signal bogus_b : std_logic_vector(3 downto 0); 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); begin -- lvdstx_a ------------------------------------------------------------------------------- -- Synchronous logic (global RF clock) ------------------------------------------------------------------------------- process (gclk, grst) begin -- process if grst = '0' then -- asynchronous reset (active low) tx_addr <= (others => '0'); tx_ena_s <= '0'; elsif gclk'event and gclk = '1' then -- rising clock edge -- leading edge of tx_trig, zero address and enable transmitter if tx_trig = '1' and bp_start = '1' then tx_ena_s <= '1'; elsif tx_addr = tx_wcount - 1 then -- disable when word count reached tx_ena_s <= csr(CSR_rep); end if; if tx_ena_s = '0' or tx_addr = tx_wcount - 1 then tx_addr <= (others => '0'); else tx_addr <= tx_addr + 1; end if; end if; end process; process (gclk) begin -- process if gclk'event and gclk = '1' then -- rising clock edge tx_ena_d <= tx_ena_s; -- pipelined enable for ram delay -- global trigger if (csr(CSR_ena) and csr(CSR_glo) and g_trig) = '1' then -- tx_trig <= not tx_ena_s; tx_trig <= '1'; end if; -- first crossing trigger if (csr(CSR_ena) and csr(CSR_fc) and fc) = '1' then tx_trig <= not tx_ena_s; end if; -- transmit control -- tx_trig_d <= tx_trig; -- delayed tx_trig if tx_trig = '1' and bp_start = '1' then tx_trig <= '0'; 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 if (csr(CSR_ena) and lb_data_in(CSR_trig)) = '1' then -- write trigger bit? tx_trig <= '1'; end if; csr <= lb_data_in; -- other bits write to CSR end if; if lb_addr = "11" then -- write to word count case lb_byte is when "00" => tx_wcount(7 downto 0) <= lb_data_in; when "01" => tx_wcount(8) <= lb_data_in(0); when others => null; end case; end if; end if; -- auto-increment ram address on R/W when crossing a word boundary if ena_s = '1' then if lb_byte = "11" then local_addr_l <= local_addr_l + 1; end if; end if; -- continous eof bit, signal inverted to fix PCB LVDS polarity problem tx_data(0) <= not bp_start; end if; end process; ------------------------------------------------------------------------------- -- Asynchronous logic ------------------------------------------------------------------------------- txck <= not gclk; -- transmitter clock. invert for -- better t(su) and t(h) -- form local RAM address from lb address and lb byte 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. Bit 1 is busy with lb_byte select lb_mux(2) <= csr(7 downto 2) & tx_ena_d & csr(0) when "00", "00000000" when others; debug <= tx_ena_d; -- word count read with lb_byte select lb_mux(3) <= tx_wcount(7 downto 0) when "00", "0000000" & tx_wcount(8) when "01", "00000000" when others; ena_s <= '1' when (lb_ena = '1') and (lb_addr = "01") else '0'; -- RAM port A enable tx_data(27 downto 1) <= not tx_data_s(27 downto 1); ssrb <= not tx_ena_s; -- dual-port RAM entity r1 : RAMB16_S9_S36 port map ( ADDRA => local_addr_s, ADDRB => tx_addr, DIA => lb_data_in, DIB => (others => '0'), DIPA => (others => '0'), DIPB => (others => '0'), WEA => lb_write, WEB => '0', CLKA => gclk, CLKB => gclk, SSRA => '0', SSRB => ssrb, ENA => ena_s, ENB => '1', DOA => lb_mux(1), DOB => tx_data_s, DOPA => bogus_a, DOPB => bogus_b); end lvdstx_a;