LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; ENTITY e_io_uart IS PORT ( rst: IN std_logic; clk: IN std_logic; i_addr: IN std_logic_vector( 1 DOWNTO 0); o_rd_data: OUT std_logic_vector(31 DOWNTO 0); i_rd_en: IN std_logic_vector( 3 DOWNTO 0); i_wr_data: IN std_logic_vector(31 DOWNTO 0); i_wr_en: IN std_logic_vector( 3 DOWNTO 0); pin_i_rx: IN std_logic; pin_o_tx: OUT std_logic ); END ENTITY e_io_uart; ARCHITECTURE a_io_uart OF e_io_uart IS TYPE t_state IS (inactive, start, data, stop); SIGNAL n_cfg_scale: std_logic_vector(15 DOWNTO 0); SIGNAL r_cfg_scale: std_logic_vector(15 DOWNTO 0) := X"0001"; SIGNAL n_cfg_bits: std_logic_vector( 3 DOWNTO 0); SIGNAL r_cfg_bits: std_logic_vector( 3 DOWNTO 0) := X"1"; SIGNAL n_cfg_stop: std_logic_vector( 1 DOWNTO 0); SIGNAL r_cfg_stop: std_logic_vector( 1 DOWNTO 0) := "01"; SIGNAL s_rx_wr_rdy: std_logic; SIGNAL s_rx_wr_data: std_logic_vector(15 DOWNTO 0); SIGNAL s_rx_wr_en: std_logic; SIGNAL s_rx_rd_rdy: std_logic; SIGNAL s_rx_rd_data: std_logic_vector(15 DOWNTO 0); SIGNAL s_rx_rd_en: std_logic; SIGNAL n_rx_scale: natural RANGE 2**16 - 1 DOWNTO 0; SIGNAL r_rx_scale: natural RANGE 2**16 - 1 DOWNTO 0 := 1; SIGNAL n_rx_bits: natural RANGE 15 DOWNTO 0; SIGNAL r_rx_bits: natural RANGE 15 DOWNTO 0 := 1; SIGNAL n_rx_stop: natural RANGE 3 DOWNTO 0; SIGNAL r_rx_stop: natural RANGE 3 DOWNTO 0 := 1; SIGNAL n_rx_state: t_state; SIGNAL r_rx_state: t_state := inactive; SIGNAL n_rx_cnt: natural RANGE 2**16 - 1 DOWNTO 0; SIGNAL r_rx_cnt: natural RANGE 2**16 - 1 DOWNTO 0 := 0; SIGNAL n_rx_sample: natural RANGE 6 DOWNTO 0; SIGNAL r_rx_sample: natural RANGE 6 DOWNTO 0 := 0; SIGNAL n_rx_bit: natural RANGE 15 DOWNTO 0; SIGNAL r_rx_bit: natural RANGE 15 DOWNTO 0 := 0; SIGNAL n_rx_samples: std_logic_vector( 1 DOWNTO 0); SIGNAL r_rx_samples: std_logic_vector( 1 DOWNTO 0) := "00"; SIGNAL n_rx_data: std_logic_vector(15 DOWNTO 0); SIGNAL r_rx_data: std_logic_vector(15 DOWNTO 0) := X"0000"; SIGNAL s_tx_wr_rdy: std_logic; SIGNAL s_tx_wr_en: std_logic; SIGNAL s_tx_rd_rdy: std_logic; SIGNAL s_tx_rd_data: std_logic_vector(15 DOWNTO 0); SIGNAL s_tx_rd_en: std_logic; SIGNAL n_tx_scale: natural RANGE 2**16 - 1 DOWNTO 0; SIGNAL r_tx_scale: natural RANGE 2**16 - 1 DOWNTO 0 := 1; SIGNAL n_tx_bits: natural RANGE 15 DOWNTO 0; SIGNAL r_tx_bits: natural RANGE 15 DOWNTO 0 := 1; SIGNAL n_tx_stop: natural RANGE 3 DOWNTO 0; SIGNAL r_tx_stop: natural RANGE 3 DOWNTO 0 := 1; SIGNAL n_tx_state: t_state; SIGNAL r_tx_state: t_state := inactive; SIGNAL n_tx_cnt: natural RANGE 2**16 - 1 DOWNTO 0; SIGNAL r_tx_cnt: natural RANGE 2**16 - 1 DOWNTO 0 := 0; SIGNAL n_tx_sample: natural RANGE 6 DOWNTO 0; SIGNAL r_tx_sample: natural RANGE 6 DOWNTO 0 := 0; SIGNAL n_tx_bit: natural RANGE 15 DOWNTO 0; SIGNAL r_tx_bit: natural RANGE 15 DOWNTO 0 := 0; SIGNAL n_tx_data: std_logic_vector(15 DOWNTO 0); SIGNAL r_tx_data: std_logic_vector(15 DOWNTO 0) := X"0000"; COMPONENT e_block_fifo IS GENERIC ( addr_width: natural; data_width: natural ); PORT ( rst: IN std_logic; clk: IN std_logic; o_wr_rdy: OUT std_logic; i_wr_data: IN std_logic_vector(data_width - 1 DOWNTO 0); i_wr_en: IN std_logic; o_rd_rdy: OUT std_logic; o_rd_data: OUT std_logic_vector(data_width - 1 DOWNTO 0); i_rd_en: IN std_logic ); END COMPONENT e_block_fifo; BEGIN p_cfg_next: PROCESS(r_cfg_scale, r_cfg_bits, r_cfg_stop, i_addr, i_wr_data, i_wr_en) BEGIN n_cfg_scale <= r_cfg_scale; n_cfg_bits <= r_cfg_bits; n_cfg_stop <= r_cfg_stop; IF i_addr = "00" THEN IF i_wr_en(1 DOWNTO 0) = "11" AND i_wr_data(15 DOWNTO 0) /= X"0000" THEN n_cfg_scale <= i_wr_data(15 DOWNTO 0); END IF; IF i_wr_en(2) = '1' AND i_wr_data(23 DOWNTO 20) = X"0" AND i_wr_data(19 DOWNTO 16) /= X"0" THEN n_cfg_bits <= i_wr_data(19 DOWNTO 16); END IF; IF i_wr_en(3) = '1' AND i_wr_data(31 DOWNTO 26) = "000000" AND i_wr_data(25 DOWNTO 24) /= "00" THEN n_cfg_stop <= i_wr_data(25 DOWNTO 24); END IF; END IF; END PROCESS p_cfg_next; p_cfg_sync: PROCESS(rst, clk) BEGIN IF rst = '1' THEN r_cfg_scale <= X"0001"; r_cfg_bits <= X"1"; r_cfg_stop <= "01"; ELSIF rising_edge(clk) THEN r_cfg_scale <= n_cfg_scale; r_cfg_bits <= n_cfg_bits; r_cfg_stop <= n_cfg_stop; END IF; END PROCESS p_cfg_sync; s_rx_rd_en <= '1' WHEN i_addr = "11" AND i_rd_en(1 DOWNTO 0) = "11" ELSE '0'; rx_fifo: e_block_fifo GENERIC MAP ( addr_width => 4, data_width => 16 ) PORT MAP ( rst => rst, clk => clk, o_wr_rdy => s_rx_wr_rdy, i_wr_data => s_rx_wr_data, i_wr_en => s_rx_wr_en, o_rd_rdy => s_rx_rd_rdy, o_rd_data => s_rx_rd_data, i_rd_en => s_rx_rd_en ); p_rx_next: PROCESS(r_cfg_scale, r_cfg_bits, r_cfg_stop, r_rx_scale, r_rx_bits, r_rx_stop, r_rx_state, r_rx_cnt, r_rx_sample, r_rx_bit, r_rx_samples, r_rx_data, pin_i_rx, s_rx_wr_rdy) VARIABLE v_next_cnt: boolean; VARIABLE v_next_sample: boolean; VARIABLE v_next_bit: boolean; VARIABLE v_next_state: boolean; VARIABLE v_complete: boolean; VARIABLE v_bits: natural RANGE 15 DOWNTO 0; VARIABLE v_samples: std_logic_vector( 2 DOWNTO 0); VARIABLE v_bit_val: std_logic; VARIABLE v_data: std_logic_vector(15 DOWNTO 0); BEGIN s_rx_wr_data <= (OTHERS => '0'); s_rx_wr_en <= '0'; n_rx_scale <= r_rx_scale; n_rx_bits <= r_rx_bits; n_rx_stop <= r_rx_stop; n_rx_state <= r_rx_state; n_rx_cnt <= r_rx_cnt; n_rx_sample <= r_rx_sample; n_rx_bit <= r_rx_bit; n_rx_samples <= r_rx_samples; v_next_cnt := false; v_next_sample := false; v_next_bit := false; v_next_state := false; v_complete := false; v_bits := 0; v_samples := "000"; v_bit_val := '0'; v_data := r_rx_data; IF r_rx_state = inactive THEN IF pin_i_rx = '0' THEN n_rx_scale <= to_integer(unsigned(r_cfg_scale)); n_rx_bits <= to_integer(unsigned(r_cfg_bits)); n_rx_stop <= to_integer(unsigned(r_cfg_stop)); n_rx_state <= start; n_rx_cnt <= 0; n_rx_sample <= 3; -- sample in middle of received bits n_rx_bit <= 0; -- n_rx_samples: no initialization needed -- n_rx_data/v_data: keep error bit (bit 15), no initialization needed for other bits END IF; ELSE v_next_cnt := true; END IF; IF v_next_cnt THEN IF r_rx_cnt + 1 /= r_rx_scale THEN n_rx_cnt <= r_rx_cnt + 1; ELSE n_rx_cnt <= 0; v_next_sample := true; END IF; END IF; IF v_next_sample THEN IF r_rx_sample = 4 THEN n_rx_samples(0) <= pin_i_rx; ELSIF r_rx_sample = 5 THEN n_rx_samples(1) <= pin_i_rx; ELSIF r_rx_sample = 6 THEN v_samples := pin_i_rx & r_rx_samples; CASE v_samples IS WHEN "000" | "001" | "010" | "100" => v_bit_val := '0'; WHEN "011" | "101" | "110" | "111" => v_bit_val := '1'; WHEN OTHERS => NULL; END CASE; CASE r_rx_state IS WHEN start => IF v_bit_val /= '0' THEN v_data(15) := '1'; -- set error bit END IF; WHEN data => v_data(r_rx_bit) := v_bit_val; WHEN stop => IF v_bit_val /= '1' THEN v_data(15) := '1'; -- set error bit END IF; WHEN OTHERS => NULL; END CASE; END IF; IF r_rx_sample /= 6 THEN n_rx_sample <= r_rx_sample + 1; ELSE n_rx_sample <= 0; v_next_bit := true; END IF; END IF; IF v_next_bit THEN CASE r_rx_state IS WHEN start => v_bits := 1; WHEN data => v_bits := r_rx_bits; WHEN stop => v_bits := r_rx_stop; WHEN OTHERS => NULL; END CASE; IF r_rx_bit + 1 /= v_bits THEN n_rx_bit <= r_rx_bit + 1; ELSE n_rx_bit <= 0; v_next_state := true; END IF; END IF; IF v_next_state THEN CASE r_rx_state IS WHEN start => n_rx_state <= data; WHEN data => n_rx_state <= stop; WHEN stop => n_rx_state <= inactive; v_complete := true; WHEN OTHERS => NULL; END CASE; END IF; IF v_complete THEN IF s_rx_wr_rdy = '1' THEN s_rx_wr_data <= v_data; s_rx_wr_en <= '1'; v_data(15) := '0'; -- clear error bit ELSE v_data(15) := '1'; -- set error bit (RX FIFO overflow) END IF; END IF; n_rx_data <= v_data; END PROCESS p_rx_next; p_rx_sync: PROCESS(rst, clk) BEGIN IF rst = '1' THEN r_rx_scale <= 1; r_rx_bits <= 1; r_rx_stop <= 1; r_rx_state <= inactive; r_rx_cnt <= 0; r_rx_sample <= 0; r_rx_bit <= 0; r_rx_samples <= "00"; r_rx_data <= X"0000"; ELSIF rising_edge(clk) THEN r_rx_scale <= n_rx_scale; r_rx_bits <= n_rx_bits; r_rx_stop <= n_rx_stop; r_rx_state <= n_rx_state; r_rx_cnt <= n_rx_cnt; r_rx_sample <= n_rx_sample; r_rx_bit <= n_rx_bit; r_rx_samples <= n_rx_samples; r_rx_data <= n_rx_data; END IF; END PROCESS p_rx_sync; s_tx_wr_en <= '1' WHEN i_addr = "10" AND i_wr_en(1 DOWNTO 0) = "11" ELSE '0'; tx_fifo: e_block_fifo GENERIC MAP ( addr_width => 4, data_width => 16 ) PORT MAP ( rst => rst, clk => clk, o_wr_rdy => s_tx_wr_rdy, i_wr_data => i_wr_data(15 DOWNTO 0), i_wr_en => s_tx_wr_en, o_rd_rdy => s_tx_rd_rdy, o_rd_data => s_tx_rd_data, i_rd_en => s_tx_rd_en ); p_tx_next: PROCESS(r_cfg_scale, r_cfg_bits, r_cfg_stop, r_tx_scale, r_tx_bits, r_tx_stop, r_tx_state, r_tx_cnt, r_tx_sample, r_tx_bit, r_tx_data, s_tx_rd_rdy, s_tx_rd_data) VARIABLE v_next_cnt: boolean; VARIABLE v_next_sample: boolean; VARIABLE v_next_bit: boolean; VARIABLE v_next_state: boolean; VARIABLE v_bits: natural RANGE 15 DOWNTO 0; BEGIN s_tx_rd_en <= '0'; n_tx_scale <= r_tx_scale; n_tx_bits <= r_tx_bits; n_tx_stop <= r_tx_stop; n_tx_state <= r_tx_state; n_tx_cnt <= r_tx_cnt; n_tx_sample <= r_tx_sample; n_tx_bit <= r_tx_bit; n_tx_data <= r_tx_data; v_next_cnt := false; v_next_sample := false; v_next_bit := false; v_next_state := false; v_bits := 0; IF r_tx_state = inactive THEN IF s_tx_rd_rdy = '1' THEN s_tx_rd_en <= '1'; n_tx_scale <= to_integer(unsigned(r_cfg_scale)); n_tx_bits <= to_integer(unsigned(r_cfg_bits)); n_tx_stop <= to_integer(unsigned(r_cfg_stop)); n_tx_state <= start; n_tx_cnt <= 0; n_tx_sample <= 0; n_tx_bit <= 0; n_tx_data <= s_tx_rd_data; END IF; ELSE v_next_cnt := true; END IF; IF v_next_cnt THEN IF r_tx_cnt + 1 /= r_tx_scale THEN n_tx_cnt <= r_tx_cnt + 1; ELSE n_tx_cnt <= 0; v_next_sample := true; END IF; END IF; IF v_next_sample THEN IF r_tx_sample /= 6 THEN n_tx_sample <= r_tx_sample + 1; ELSE n_tx_sample <= 0; v_next_bit := true; END IF; END IF; IF v_next_bit THEN CASE r_tx_state IS WHEN start => v_bits := 1; WHEN data => v_bits := r_tx_bits; WHEN stop => v_bits := r_tx_stop; WHEN OTHERS => NULL; END CASE; IF r_tx_bit + 1 /= v_bits THEN n_tx_bit <= r_tx_bit + 1; ELSE n_tx_bit <= 0; v_next_state := true; END IF; END IF; IF v_next_state THEN CASE r_tx_state IS WHEN start => n_tx_state <= data; WHEN data => n_tx_state <= stop; WHEN stop => n_tx_state <= inactive; WHEN OTHERS => NULL; END CASE; END IF; END PROCESS p_tx_next; p_tx_sync: PROCESS(rst, clk) BEGIN IF rst = '1' THEN r_tx_scale <= 1; r_tx_bits <= 1; r_tx_stop <= 1; r_tx_state <= inactive; r_tx_cnt <= 0; r_tx_sample <= 0; r_tx_bit <= 0; r_tx_data <= X"0000"; ELSIF rising_edge(clk) THEN r_tx_scale <= n_tx_scale; r_tx_bits <= n_tx_bits; r_tx_stop <= n_tx_stop; r_tx_state <= n_tx_state; r_tx_cnt <= n_tx_cnt; r_tx_sample <= n_tx_sample; r_tx_bit <= n_tx_bit; r_tx_data <= n_tx_data; END IF; END PROCESS p_tx_sync; p_tx_out: PROCESS(r_tx_bit, r_tx_state, r_tx_data) BEGIN pin_o_tx <= '1'; CASE r_tx_state IS WHEN start => pin_o_tx <= '0'; WHEN data => pin_o_tx <= r_tx_data(r_tx_bit); WHEN stop => pin_o_tx <= '1'; WHEN OTHERS => NULL; END CASE; END PROCESS p_tx_out; p_read: PROCESS(rst, clk) BEGIN IF rst = '1' THEN o_rd_data <= (OTHERS => '0'); ELSIF rising_edge(clk) THEN o_rd_data <= (OTHERS => '0'); CASE i_addr IS WHEN "00" => IF i_rd_en(1 DOWNTO 0) = "11" THEN o_rd_data(15 DOWNTO 0) <= r_cfg_scale; END IF; IF i_rd_en(2) = '1' THEN o_rd_data(19 DOWNTO 16) <= r_cfg_bits; END IF; IF i_rd_en(3) = '1' THEN o_rd_data(25 DOWNTO 24) <= r_cfg_stop; END IF; WHEN "01" => IF i_rd_en(0) = '1' THEN o_rd_data(0) <= s_tx_wr_rdy; END IF; IF i_rd_en(1) = '1' THEN o_rd_data(8) <= s_rx_rd_rdy; END IF; WHEN "11" => IF i_rd_en(1 DOWNTO 0) = "11" THEN o_rd_data(15 DOWNTO 0) <= s_rx_rd_data; END IF; WHEN OTHERS => NULL; END CASE; END IF; END PROCESS p_read; END ARCHITECTURE a_io_uart;