library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity async_8n1_rx is port ( clk : in std_logic; rst : in std_logic; en : in std_logic; read : in std_logic; data_in : in std_logic; data_available : out std_logic; frame_error : out std_logic; overflow_error : out std_logic; data_out : out unsigned (7 downto 0) ); end entity; architecture beh of async_8n1_rx is -- RX shift register related signal i_reg_rx_data : unsigned(8 downto 0) := (others => '1'); signal i_sig_data : unsigned(7 downto 0); signal i_sig_finished : std_logic; signal i_sig_clear_rx_data : std_logic; signal i_sig_frame_error : std_logic; -- Received data related signal i_reg_stored_data : unsigned(7 downto 0) := (others => '0'); signal i_reg_available : std_logic := '0'; signal i_reg_overflow : std_logic := '0'; signal i_reg_frame_error : std_logic := '0'; signal i_sig_storage_full : std_logic; signal i_sig_load_data : std_logic; signal i_sig_overflow_next : std_logic; signal i_sig_available_next : std_logic; begin -- Outputs data_available <= i_reg_available; frame_error <= i_reg_frame_error; overflow_error <= i_reg_overflow; data_out <= i_reg_stored_data; -- Concurrent statements -- RX shift register concurrent statements -- This is the data when a complete frame is received i_sig_data <= i_reg_rx_data(8 downto 1); -- When the start bit has propagated to bit 0 in shift register, frame is finished i_sig_finished <= not i_reg_rx_data(0); -- When frame is finished, reset shift register to only '1's i_sig_clear_rx_data <= i_sig_finished; -- If incoming stop bit is '0', we have a framing error i_sig_frame_error <= i_sig_finished and not data_in; -- Storage register concurrent statements -- The storage is considered full (next cycle) when data is available and no read is performed i_sig_storage_full <= i_reg_available and not read; -- Only load received byte if storage is not full i_sig_load_data <= i_sig_finished and not i_sig_storage_full; -- If there is a received byte, and the storage is full, and no read is performed, next cycle will -- cause an overflow and the latest received byte is discarded i_sig_overflow_next <= not read and (i_reg_overflow or (i_reg_available and i_sig_finished)); -- If a byte just has been received, or the storage is full, then there will be data available next cycle i_sig_available_next <= i_sig_finished or i_sig_storage_full; -- Register process(clk) is begin if rising_edge(clk) then if en = '1' then -- i_reg_rx_data if i_sig_clear_rx_data = '0' then -- Take a step i_reg_rx_data <= data_in & i_sig_data; else -- Synchronously set to '1' i_reg_rx_data <= (others => '1'); end if; -- i_reg_stored_data and i_reg_frame_error -- Update data store with received byte and frame status if i_sig_load_data = '1' then i_reg_stored_data <= i_sig_data; i_reg_frame_error <= i_sig_frame_error; else i_reg_stored_data <= i_reg_stored_data; i_reg_frame_error <= i_reg_frame_error; end if; -- i_reg_available -- Assume next evaluated value i_reg_available <= i_sig_available_next; -- i_reg_overflow -- Assume next evaluated value i_reg_overflow <= i_sig_overflow_next; else -- don't load registers (explicitly) i_reg_rx_data <= i_reg_rx_data; i_reg_stored_data <= i_reg_stored_data; i_reg_frame_error <= i_reg_frame_error; i_reg_available <= i_reg_available; i_reg_overflow <= i_reg_overflow; end if; end if; if rst = '1' then -- Async reset -- Only registers whose initial value matters i_reg_rx_data <= (others => '1'); i_reg_available <= '0'; i_reg_overflow <= '0'; end if; end process; end architecture;