B.5. SummaryThis example has demonstrated how two Impulse C software processes (the producer and consumer processes in Figure B-4) can be connected via a standard, readily available serial interface device for creating an FPGA-based grid computing system. When you combine this kind of high-speed serial communication with embedded software processors and related embedded operating systems (as demonstrated in earlier chapters) you can create extremely powerful, FPGA-based grid computing platforms for relatively little cost. Figure B-5. Transceiver VHDL source code.--transceiver.vhdl --This VHDL code describes the implementation of an eight-bit ImpulseC --compatible stream for use over the DS92LV16 serializer/deserializer. -- --Scott Bekker --6/24/04 library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity transceiver is generic(data_width : natural := 8); -- Max data width: 13 due to -- 16 bit serdes bus width - 3 flag bits used port ( clk : in std_logic; -- hardware transceiver ports rclk : in std_logic; din : out std_logic_vector(15 downto 0); rout : in std_logic_vector(15 downto 0); sync_out : out std_logic; local_lock_active_low : in std_logic; --producer ports producer_os_rdy : out std_logic; producer_wr_en : in std_logic; producer_eos : in std_logic; producer_data_in : in std_ulogic_vector(data_width - 1 downto 0); --consumer ports consumer_os_rdy : out std_logic; consumer_rd_en : in std_logic; consumer_eos : out std_logic; consumer_data_out : out std_ulogic_vector(data_width - 1 downto 0)); end transceiver; architecture Behavioral of transceiver is component async_fifo IS port ( din: IN std_logic_VECTOR(15 downto 0); wr_en: IN std_logic; wr_clk: IN std_logic; rd_en: IN std_logic; rd_clk: IN std_logic; ainit: IN std_logic; dout: OUT std_logic_VECTOR(15 downto 0); full: OUT std_logic; empty: OUT std_logic; rd_count: OUT std_logic_VECTOR(6 downto 0)); END component; TYPE state_type is (send_sync, send_sync_240, send_flags_240, send_ack1, send_ack2, connected); signal present_state : state_type := send_sync; signal counter : std_logic_vector(23 downto 0); signal din_sig : std_logic_vector(15 downto 0); signal data_to_transceiver : std_logic_vector(15 downto 0); signal link_established : std_ulogic; signal rout_sig : std_logic_vector(15 downto 0); signal flag_cnt : std_logic_vector(7 downto 0); signal fifo_out_sig : std_logic_vector(15 downto 0); signal wr_en_sig : std_logic; signal rd_en_sig : std_logic; signal empty_sig : std_logic; signal rd_count_sig : std_logic_vector(6 downto 0); signal remote_fifo_too_full : std_logic; signal local_fifo_too_full : std_logic; signal producer_data_in_sig : std_logic_vector(data_width - 1 downto 0); signal consumer_data_out_sig : std_ulogic_vector(data_width - 1 downto 0); begin async_fifo0: async_fifo port map( din => rout_sig, wr_en => wr_en_sig, wr_clk => rclk, rd_en => rd_en_sig, rd_clk => clk, ainit => '0',--reset_sig, dout => fifo_out_sig, full => open, empty => empty_sig, rd_count => rd_count_sig); --state machine process to perform handshaking and establish a serial connection process(clk) begin if rising_edge(clk) then --allow producer to write if remote fifo is not too --full and link is established producer_os_rdy <= (not remote_fifo_too_full) and link_established; --rdy signal must be synchronous to clk case present_state is when send_sync => --send sync pattern until local transceiver --has been locked for a period of time sync_out <= '1'; link_established <= '0'; flag_cnt <= X"00"; if local_lock_active_low = '0' then counter <= counter + 1; if counter > X"200000" then --26 ms at 80 MHz (delay for switch bounce) counter <= X"000000"; present_state <= send_sync_240; else present_state <= send_sync; end if; else present_state <= send_sync; counter <= X"000000"; end if; when send_sync_240 => --send sync pattern until a valid flag --pattern is received or until timeout occurs sync_out <= '1'; link_established <= '0'; if local_lock_active_low = '0' then if counter > X"000FFF" then counter <= X"000000"; present_state <= send_flags_240; else counter <= counter + 1; if (rout = X"00BB") or (rout = X"00CC") or (rout = X"00DD") then --remote transceiver is in send_xxxx_160 or send_ackx flag_cnt <= flag_cnt + 1; if flag_cnt > X"F0" then counter <= X"000000"; flag_cnt <= X"00"; present_state <= send_ack1; end if; else flag_cnt <= X"00"; present_state <= send_sync_240; end if; end if; else present_state <= send_sync; end if; when send_flags_240 => --send flag pattern until a valid flag pattern --is received or until timeout occurs sync_out <= '0'; din_sig <= X"00BB"; link_established <= '0'; if local_lock_active_low = '0' then if counter > X"000FFF" then counter <= X"000000"; present_state <= send_sync_240; else counter <= counter + 1; if (rout = X"00BB") or (rout = X"00CC") or (rout = X"00DD") then --remote transceiver is in --send_xxxx_240 or send_ackx flag_cnt <= flag_cnt + 1; if flag_cnt > X"F0" then counter <= X"000000"; flag_cnt <= X"00"; present_state <= send_ack1; end if; else flag_cnt <= X"00"; present_state <= send_flags_240; end if; end if; else present_state <= send_sync; end if; when send_ack1 => --wait here for remote transceiver to reach this state --or the next state sync_out <= '0'; link_established <= '0'; din_sig <= X"00CC"; if local_lock_active_low = '0' then if (rout_sig = X"00CC") or (rout_sig = X"00DD") then --remote transceiver is in send_ack1 or send_ack2 flag_cnt <= flag_cnt + 1; if flag_cnt > X"F0" then counter <= X"000000"; present_state <= send_ack2; end if; else flag_cnt <= X"00"; present_state <= send_ack1; end if; else present_state <= send_sync; end if; when send_ack2 => --when this state is reached both transceivers are --locked, send flags for a period then go to connected state sync_out <= '0'; link_established <= '0'; din_sig <= X"00DD"; counter <= counter + 1; if local_lock_active_low = '0' then if counter > X"0000FFF" then present_state <= connected; else if rout_sig = X"00DD" then flag_cnt <= flag_cnt + 1; if flag_cnt > X"F0" or counter > X"0000FFF" then present_state <= connected; end if; else flag_cnt <= X"00"; present_state <= send_ack2; end if; end if; else present_state <= send_sync; end if; when connected => --both transceivers are connected, assert --link_established signal and allow data transmission sync_out <= '0'; din_sig <= data_to_transceiver; link_established <= '1'; if local_lock_active_low = '0' then present_state <= connected; else counter <= X"000000"; present_state <= send_sync; end if; when others => present_state <= send_sync; end case; end if; end process; --retrieve remote fifo too full signal off of transceiver output when link is established with link_established select remote_fifo_too_full <= rout_sig(15) when '1', '1' when others; --retrieve end of stream signal off of transceiver output when link is established, --consumer enables read, and data is valid with std_logic_vector'(link_established, consumer_rd_en, fifo_out_sig(14)) select consumer_eos <= fifo_out_sig(13) when "111", '0' when others; --retrieve data from fifo and output to the consumer consumer_data_out <= consumer_data_out_sig; with std_logic_vector'(link_established, consumer_rd_en, fifo_out_sig(14)) select consumer_data_out_sig <= std_ulogic_vector(fifo_out_sig(data_width - 1 downto 0)) when "111", consumer_data_out_sig when others; --if there is data in the fifo, allow consumer to read it consumer_os_rdy <= not empty_sig; --send flags and data to the transceiver for sending data_to_transceiver(15 downto 13) <= local_fifo_too_full & producer_wr_en & producer_eos; data_to_transceiver(data_width - 1 downto 0) <= producer_data_in_sig; --latch data from producer when producer write enable is asserted with producer_wr_en select producer_data_in_sig <= std_logic_vector(producer_data_in) when '1', producer_data_in_sig when others; --assert fifo write enable when link is established and write flag is set with std_logic_vector'(link_established, rout_sig(14)) select wr_en_sig <= '1' when "11", '0' when others; --assert fifo read enable when consumer asserts read enable or when fifo data --is not valid rd_en_sig <= consumer_rd_en or not fifo_out_sig(14); --latch data from DS92LV16 on rising edge of rclk when locked onto serial data stream process(rclk) begin if rising_edge(rclk) then if local_lock_active_low = '0' then rout_sig <= rout; end if; end if; end process; --update transceiver input data on falling edge of the clock -- hardware transceiver reads input on rising clock edge so data must be -- stable during rising edge process(clk) begin if falling_edge(clk) then din <= din_sig; end if; end process; --set local_fifo_too_full_sig based on rd_count_sig flag is -- set if fifo contains more than 64 items and cleared if fifo -- contains fewer than 31 items process(clk) begin if rising_edge(clk) then if rd_count_sig > "1000000" and rd_count_sig < "1111111" then --fifo occasionally --reports a count of --127 when it is empty local_fifo_too_full <= '1'; elsif rd_count_sig < "0011111" then local_fifo_too_full <= '0'; else local_fifo_too_full <= local_fifo_too_full; end if; end if; end process; end Behavioral; |