-- ----------------------------------------------------------------------- -- -- Syntiac's generic VHDL support files. -- -- ----------------------------------------------------------------------- -- Copyright 2005-2010 by Peter Wendrich (pwsoft@syntiac.com) -- http://www.syntiac.com/?.html -- ----------------------------------------------------------------------- -- -- gen_usart.vhd -- -- ----------------------------------------------------------------------- -- -- USART - Synchronous serial receiver/transmitter -- -- ----------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.ALL; -- ----------------------------------------------------------------------- entity gen_usart is generic ( bits : integer := 8 ); port ( clk : in std_logic; d : in unsigned(bits-1 downto 0) := (others => '0'); d_trigger : in std_logic := '0'; d_empty : out std_logic; q : out unsigned(bits-1 downto 0); q_trigger : out std_logic; serial_clk : in std_logic; serial_rxd : in std_logic := '1'; serial_txd : out std_logic; serial_cts_n : in std_logic := '0' ); end entity; -- ----------------------------------------------------------------------- architecture rtl of gen_usart is type state_t is ( STATE_IDLE, STATE_BITS, STATE_STOP); signal serial_clk_reg : std_logic := '0'; signal serial_clk_dly : std_logic := '0'; signal receive_state : state_t := STATE_IDLE; signal receive_shift : unsigned(bits-1 downto 0) := (others => '0'); signal receive_cnt : integer range 0 to bits-1 := 0; signal transmit_state : state_t := STATE_IDLE; signal transmit_empty : std_logic := '1'; signal transmit_buffer : unsigned(bits-1 downto 0) := (others => '0'); signal transmit_shift : unsigned(bits-1 downto 0) := (others => '0'); signal transmit_cnt : integer range 0 to bits-1 := 0; begin d_empty <= transmit_empty and (not d_trigger); process(clk) begin if rising_edge(clk) then serial_clk_reg <= serial_clk; serial_clk_dly <= serial_clk_reg; end if; end process; receive_process: process(clk) begin if rising_edge(clk) then q_trigger <= '0'; -- Detect rising edge if (serial_clk_reg = '1') and (serial_clk_dly = '0') then case receive_state is when STATE_IDLE => receive_cnt <= 0; if serial_rxd = '0' then receive_state <= STATE_BITS; end if; when STATE_BITS => receive_shift <= serial_rxd & receive_shift(receive_shift'high downto 1); if receive_cnt = bits-1 then receive_state <= STATE_STOP; else receive_cnt <= receive_cnt + 1; end if; when STATE_STOP => receive_state <= STATE_IDLE; if serial_rxd = '1' then q <= receive_shift; q_trigger <= '1'; end if; end case; end if; end if; end process; transmit_process: process(clk) begin if rising_edge(clk) then -- Detect falling edge if (serial_clk_reg = '0') and (serial_clk_dly = '1') then case transmit_state is when STATE_IDLE => transmit_cnt <= 0; if (transmit_empty = '0') and (serial_cts_n = '0') then transmit_shift <= transmit_buffer; transmit_empty <= '1'; transmit_state <= STATE_BITS; serial_txd <= '0'; else serial_txd <= '1'; end if; when STATE_BITS => serial_txd <= transmit_shift(transmit_cnt); if transmit_cnt = bits-1 then transmit_state <= STATE_STOP; else transmit_cnt <= transmit_cnt + 1; end if; when STATE_STOP => serial_txd <= '1'; transmit_state <= STATE_IDLE; end case; end if; if d_trigger = '1' then transmit_buffer <= d; transmit_empty <= '0'; end if; end if; end process; end architecture;