LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; USE IEEE.STD_LOGIC_UNSIGNED.ALL; entity UART_VHDL is port ( clock: in std_logic; reset_N: in std_logic; address: in std_logic; writeData: in std_logic_vector(7 downto 0); write: in std_logic; readData: out std_logic_vector(7 downto 0); read: in std_logic; serialIn: in std_logic; serialOut: out std_logic ); end UART_VHDL; ARCHITECTURE RTL OF UART_VHDL IS type t_retime is record once: std_logic; twice: std_logic; end record; type t_TxState is ( IDLE, START, SEND, STOP ); type t_RxState is ( IDLE, START, RECEIVE, STOP, FULL, ERROR ); constant c_TX: std_logic := '0'; constant c_RX: std_logic := '0'; constant c_STATUS: std_logic := '1'; constant RxReady: integer := 0; constant RxError: integer := 1; constant TxReady: integer := 2; signal s_serialOut: std_logic; signal s_readData: std_logic_vector(7 downto 0); begin --+++++++++++++++++++++++++++ -- + -- Main clocked logic. + -- + --+++++++++++++++++++++++++++ clockedLogic: process (clock, reset_N) variable RxState: t_RxState; variable TxState: t_TxState; variable serialInRetimed: t_retime; variable Tx, Rx: std_logic_vector(7 downto 0); variable RxSampleCount, RxBitCount, TxSampleCount, TxBitCount: integer range 0 to 8; variable v_serialOut: std_logic; variable v_readData: std_logic_vector(7 downto 0); begin if reset_N = '0' then RxState := IDLE; TxState := IDLE; Tx := (others=>'0'); Rx := (others=>'0'); serialInRetimed := ('1','1'); s_serialOut <= '1'; RxSampleCount := 0; RxBitCount := 0; TxSampleCount := 0; TxBitCount := 0; elsif clock'event and clock='1' then --++++++++++++++++++++++++++++++++++++++++++++++++ -- + -- Assign all temporary variables in order to + -- avoid generating unwanted flip-flops. + -- + --++++++++++++++++++++++++++++++++++++++++++++++++ v_serialOut := s_serialOut; v_readData := (others=>'0'); --+++++++++++++++++++++++++++++ -- + -- Read/Write Registers. + -- + --+++++++++++++++++++++++++++++ if write = '1' then case address is when c_TX => Tx := writeData; TxState := START; when others => end case; end if; if read = '1' then case address is when c_RX => v_readData := Rx; RxState := IDLE; when c_STATUS => if RxState=FULL then v_readData(RxReady) := '1'; end if; if RxState=ERROR then v_readData(RxError) := '1'; RxState := IDLE; end if; if TxState=IDLE then v_readData(TxReady) := '1'; end if; when others => end case; end if; --+++++++++++++++++++++++++++++++ -- + -- Transmit State Machine. + -- + --+++++++++++++++++++++++++++++++ case TxState is when IDLE => when START => v_SerialOut := '0'; -- Start Bit. TxSampleCount := 0; TxBitCount := 0; TxState := SEND; when SEND => TxSampleCount := TxSampleCount+1; -- Eight Data Bits. if TxSampleCount = 8 then TxSampleCount := 0; v_SerialOut := Tx(TxBitCount); TxBitCount := TxBitCount+1; if TxBitCount=8 then TxState := STOP; end if; end if; when STOP => TxSampleCount := TxSampleCount+1; if TxSampleCount = 8 then v_SerialOut := '1'; -- Stop Bit. TxState := IDLE; end if; end case; --++++++++++++++++++++++++++++++ -- + -- Receive State Machine. + -- + --++++++++++++++++++++++++++++++ case RxState is when IDLE => if SerialInRetimed.TWICE = '0' then -- Falling Edge of Start Bit. RxSampleCount := 0; RxBitCount := 0; RxState := RECEIVE; end if; when START => RxSampleCount := RxSampleCount+1; if RxSampleCount = 4 then -- Centre of Start Bit RxState := RECEIVE; end if; when RECEIVE => RxSampleCount := RxSampleCount+1; -- Eight Data Bits. if RxSampleCount = 8 then RxSampleCount := 0; Rx(RxBitCount) := serialInRetimed.TWICE; RxBitCount := RxBitCount+1; if RxBitCount=8 then RxState := STOP; end if; end if; when STOP => RxSampleCount := RxSampleCount+1; if RxSampleCount = 8 then if serialInRetimed.TWICE = '1' then -- Check Stop Bit RxState := FULL; else RxState := ERROR; end if; end if; when FULL => when ERROR => end case; --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -- + -- Re-time any asynchronous signals before use in order + -- to avoid race hazards or problems of metastability + -- + --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ serialInRetimed.TWICE := serialInRetimed.ONCE; serialInRetimed.ONCE := serialIn; --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -- + -- Assign the temporary variables to their `real' counterparts. + -- + --+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ s_serialOut <= v_serialOut; s_readData <= v_readData; end if; end process clockedLogic; --++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -- + -- Assign the outputs from their associated internal signals. + -- + --++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ serialOut <= s_serialOut; readData <= s_readData; end RTL;