Jonatan Gezelius пре 4 година
родитељ
комит
2462a7191b
3 измењених фајлова са 264 додато и 3 уклоњено
  1. 3 3
      uart_module/Makefile
  2. 131 0
      uart_module/hdl_design/async_8n1_tx.vhd
  3. 130 0
      uart_module/testbench/async_8n1_tx_tb.vhd

+ 3 - 3
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
+DESIGN_FILES = generic_counter.vhd ha.vhd generic_prescaler.vhd async_8n1_tx.vhd
 
 DESIGN_FILES_DIR = hdl_design
 DESIGN_FILES_FULL_PATH = $(addprefix $(DESIGN_FILES_DIR)/,$(DESIGN_FILES))
@@ -17,10 +17,10 @@ WORK_LIBRARY = work
 GHDL_OPTIONS = --work=$(WORK_LIBRARY) --workdir=$(WORK_DIR)
 
 # Name of the testbench entity to simulate
-TOP_TESTBENCH = generic_prescaler_tb
+TOP_TESTBENCH = async_8n1_tx_tb
 
 # Add all testbench-related files on this row
-TEST_BENCHES = generic_prescaler_tb.vhd generic_counter_tb.vhd
+TEST_BENCHES = generic_prescaler_tb.vhd generic_counter_tb.vhd async_8n1_tx_tb.vhd
 
 TEST_BENCHES_DIR = testbench
 TEST_BENCHES_FULL_PATH = $(addprefix $(TEST_BENCHES_DIR)/,$(TEST_BENCHES))

+ 131 - 0
uart_module/hdl_design/async_8n1_tx.vhd

@@ -0,0 +1,131 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity async_8n1_tx is
+	port
+	(
+		clk : in std_logic;
+		rst : in std_logic;
+		en  : in std_logic;
+		wr  : in std_logic;
+		data_in : in unsigned (7 downto 0);
+		data_out : out std_logic
+	);
+end entity;
+
+architecture beh of async_8n1_tx is
+	component generic_counter is
+		generic (
+			counter_bits : integer := 4
+		);
+		port(
+			clk : in std_logic;
+			rst : in std_logic;
+			en  : in std_logic;
+			cnt : out unsigned (counter_bits -1 downto 0)
+		);
+	end component;
+
+	type t_output_state is (mark, space, data);
+	type t_tx_state is (idle, send_start, send_data, send_stop);
+
+	signal i_data_out : std_logic;
+	signal i_data_reg : unsigned(7 downto 0);
+	signal i_next_data : std_logic;
+	signal i_output_mux : t_output_state;
+	signal i_current_state : t_tx_state;
+	signal i_next_state : t_tx_state;
+	signal i_cnt : unsigned(3 downto 0);
+	signal i_clear_counter : std_logic;
+	
+	signal tmp_current_state : integer;
+	signal tmp_next_state : integer;
+	signal tmp_output_mux : integer;
+begin
+
+	tmp_current_state <= t_tx_state'pos(i_current_state);
+	tmp_next_state <= t_tx_state'pos(i_next_state);
+	tmp_output_mux <= t_output_state'pos(i_output_mux);
+	
+	data_out <= i_data_out;
+
+	with i_output_mux select
+		i_data_out <= '1' when mark,
+					  '0' when space,
+					  i_next_data when data;
+
+	i_next_data <= i_data_reg(0);
+
+	i_clear_counter <= '1' when i_current_state = idle or rst = '1'
+						else '0';
+	
+	i_counter : generic_counter
+		port map(
+			clk => clk,
+			rst => i_clear_counter,
+			en => en,
+			cnt => i_cnt);
+	
+	with i_current_state select
+		i_output_mux <= mark  when idle,
+						space when send_start,
+						data  when send_data,
+						mark  when send_stop;
+	
+	-- Concurrent process
+	process(i_current_state, wr, i_cnt) is
+	begin
+		if i_current_state = idle then
+			if wr = '1' then
+				i_next_state <= send_start;
+			else
+				i_next_state <= i_current_state;
+			end if;
+			
+		elsif i_current_state = send_start then
+			i_next_state <= send_data;
+			
+		elsif i_current_state = send_data then
+			if i_cnt = to_unsigned(7, 4) then
+				i_next_state <= send_stop;
+			else
+				i_next_state <= i_current_state;
+			end if;
+			
+		elsif i_current_state = send_stop then
+			i_next_state <= idle;
+		else
+			i_next_state <= i_current_state;
+		end if;
+	end process;
+
+	-- Shift register
+	process(clk) is
+	begin
+		if rising_edge(clk) then
+			if rst = '1' then
+				i_data_reg <= (others => '0');
+			elsif en = '1' and i_current_state = send_data then
+				i_data_reg <= '1' & i_data_reg(7 downto 1);
+			elsif en = '1' and i_current_state = idle and wr = '1' then
+				i_data_reg <= data_in;
+			else
+				i_data_reg <= i_data_reg;
+			end if;
+		end if;
+	end process;
+
+	-- State machine
+	process(clk) is
+	begin
+		if rising_edge(clk) then
+			if rst = '1' then
+				i_current_state <= idle;
+			elsif en = '1' then
+				i_current_state <= i_next_state;
+			end if;
+		end if;
+	end process;
+
+end architecture;

+ 130 - 0
uart_module/testbench/async_8n1_tx_tb.vhd

@@ -0,0 +1,130 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use IEEE.math_real.all;
+
+entity async_8n1_tx_tb is
+end entity;
+
+architecture beh of async_8n1_tx_tb is
+	component generic_prescaler is
+		generic (
+			prescaler_bits : integer := 8
+		);
+		port(
+			clk : in std_logic;
+			rst : in std_logic;
+			en  : in std_logic;
+			load : in std_logic;
+			prescaler_value : in unsigned (prescaler_bits - 1 downto 0);
+			en_out : out std_logic
+		);
+	end component;
+	
+	component async_8n1_tx is
+		port
+		(
+			clk : in std_logic;
+			rst : in std_logic;
+			en  : in std_logic;
+			wr  : in std_logic;
+			data_in : in unsigned (7 downto 0);
+			data_out : out std_logic
+		);
+	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;
+
+	signal clock : std_logic := '0';
+	signal enable : std_logic;
+	signal reset : std_logic;
+
+	signal prescaled_clk_en : std_logic;
+	
+	constant prescaler_value : integer := 10;
+	constant prescaler_num_bits : integer := integer(ceil(log2(real(prescaler_value))));
+
+	signal running : boolean := true;
+	
+	signal tx : std_logic;
+	signal wr : std_logic;
+	signal tx_char : unsigned (7 downto 0);
+	
+begin
+	running <= true,
+			   false after 50 * period;
+	
+	reset <= '0',
+			 '1' after 2 * period,
+			 '0' after 3 * period;
+	
+	enable <= '0',
+			  '1' after 5 * period;
+
+	wr <= '0',
+		  '1' after 10 * period,
+		  '0' after 11 * period;
+	
+	tx_char <= to_unsigned(character'pos('a'), 8);
+
+	i_prescaler : generic_prescaler
+		generic map(
+			prescaler_bits => prescaler_num_bits
+		)
+		port map(
+			clk => clock,
+			rst => reset,
+			en => enable,
+			load => '1',
+			prescaler_value => to_unsigned(prescaler_value, prescaler_num_bits),
+			en_out => prescaled_clk_en
+		);
+	
+	DUT : async_8n1_tx
+		port map(
+			clk => clock,
+			rst => reset,
+			en => enable,
+			wr => wr,
+			data_in => tx_char,
+			data_out => tx
+		);
+	-- clock process
+	process is
+	begin
+		if running then
+			wait for half_period;
+			clock <= not clock;
+		else
+			report "End of simulation!";
+			wait;
+		end if;
+	end process;
+	
+	-- Rising edge counter
+	process(clock) is
+	begin
+		if rising_edge(clock) then
+			if reset = '1' then
+				num_rising_edges <= 0;
+			elsif enable = '1' then
+				num_rising_edges <= num_rising_edges+1;
+			else
+				-- Explicit no change
+				num_rising_edges <= num_rising_edges;
+			end if;
+		end if;
+	end process;
+
+	-- Automated checks
+	process(clock) is
+	begin
+		if rising_edge(clock) 
+			and num_rising_edges > 1 then
+			assert not (num_rising_edges mod prescaler_value = 0 and prescaled_clk_en /= '1') report "Prescaler not working!" severity error;
+		end if;
+	end process;
+end architecture;