|
@@ -0,0 +1,118 @@
|
|
|
|
|
+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;
|