Przeglądaj źródła

Add uart receiver. Update Makefile and testbench to test this.

Jonatan Gezelius 2 lat temu
rodzic
commit
17da3ad6fc

+ 1 - 1
uart_module/Makefile

@@ -7,7 +7,7 @@ VIEWERTCL = simulation/gtkwave.tcl
 #TOP_DESIGN = top.vhd # Not used when not synthesizing..
 
 # Add design files to this row
-DESIGN_FILES = generic_counter.vhd ha.vhd generic_prescaler.vhd async_8n1_tx_v2.vhd async_8n1_tx.vhd
+DESIGN_FILES = generic_counter.vhd ha.vhd generic_prescaler.vhd async_8n1_tx_v2.vhd async_8n1_tx.vhd async_8n1_rx.vhd
 
 DESIGN_FILES_DIR = hdl_design
 DESIGN_FILES_FULL_PATH = $(addprefix $(DESIGN_FILES_DIR)/,$(DESIGN_FILES))

+ 118 - 0
uart_module/hdl_design/async_8n1_rx.vhd

@@ -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;

+ 71 - 7
uart_module/testbench/async_8n1_tx_tb.vhd

@@ -46,13 +46,28 @@ architecture beh of async_8n1_tx_tb is
 			data_out : out std_logic
 		);
 	end component;
+
+	component 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 component;
 	
 	constant freq : integer := 50; -- MHz
 	constant period : time := 1000 / freq * 1 ns;
 	constant half_period : time := period / 2;
 	signal num_rising_edges : integer := 0;
 	
-	constant simulation_periods : integer := 5155*21;
+	constant simulation_periods : integer := 5155*121;
 
 	signal clock : std_logic := '0';
 	signal enable : std_logic;
@@ -70,10 +85,16 @@ architecture beh of async_8n1_tx_tb is
 	
 	signal tx2 : std_logic;
 	signal rdy2 : std_logic;
-	
+
+	signal rx_available : std_logic;
+	signal rx_read : std_logic := '0';
 	
 	signal wr : std_logic;
 	signal tx_char : unsigned (7 downto 0);
+	signal rx_char : unsigned (7 downto 0);
+
+	type hex_arr is array (0 to 3) of unsigned(7 downto 0);
+	signal tx_char_buffer : hex_arr := (x"aa", x"55", x"00", x"ff");
 	
 begin
 	running <= true,
@@ -91,11 +112,11 @@ begin
 		  '1' after 11 * period;
 	
 	--tx_char <= to_unsigned(character'pos('a'), 8);
-	tx_char <= x"aa",
-			   x"55" after 50 * period,
-			   x"00" after 100 * period,
-			   x"ff" after 150 * period,
-			   x"aa" after 200 * period;
+	--tx_char <= x"aa",
+	--		   x"55" after 50 * prescaler_value * period,
+	--		   x"00" after 100 * prescaler_value * period,
+	--		   x"ff" after 150 * prescaler_value * period,
+	--		   x"aa" after 200 * prescaler_value * period;
 
 	i_prescaler : generic_prescaler
 		generic map(
@@ -131,6 +152,20 @@ begin
 			rdy => rdy2,
 			data_out => tx2
 		);
+	
+	DUT3 : async_8n1_rx
+		port map(
+			clk => clock,
+			rst => reset,
+			en => prescaled_clk_en,
+			read => rx_read,
+			data_in => tx2,
+			data_available => rx_available,
+			frame_error => open,
+			overflow_error => open,
+			data_out => rx_char
+		);
+
 	-- clock process
 	process is
 	begin
@@ -142,6 +177,35 @@ begin
 			wait;
 		end if;
 	end process;
+
+	process(tx_char) is
+	begin
+		--wait for half_period;
+		--report time'image(period);
+		report "Tx-char: " & integer'image(to_integer(tx_char));
+		--wait;
+	end process;
+	
+	-- simulate a read operation after every received byte
+	process is
+	begin
+		wait until rx_available = '1';
+		wait for prescaler_value * period;
+		rx_read <= '1';
+		wait until rx_available = '0';
+		wait for prescaler_value * period;
+		rx_read <= '0';
+	end process;
+
+	-- Loop through the tx char buffer everythime a transceiver is ready
+	process is
+	begin
+		for i in tx_char_buffer'range loop
+			wait until rdy1 = '1';
+			tx_char <= tx_char_buffer(i);
+			wait until rdy1 = '0';
+		end loop;
+	end process;
 	
 	-- Rising edge counter
 	process(clock) is