---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 16:04:58 09/23/2009 -- Design Name: -- Module Name: UARTUnit - beh -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity UARTUnit is Generic( -- BAUDGEN_REG_SIZE is the size of the register that holds the counter in bits. -- BAUDGEN_CLOCK_TO_BAUD_MOD represents the modulo value, i.e., if 10, counter counts to 9 and wraps -- FOR SIMULATION ONLY!!!!! OTHERWISE, USE ONE OF THE FOLLOWING. For simulation, also set N to 2 in -- DEBOUNCE.vhd, i.e., Change FROM 'constant N: integer:= 22;' to 'constant N: integer:= 2;' -- BAUDGEN_CLOCK_TO_BAUD_MOD: integer := 2; -- 9600 with a 100MHz clock requires 50,000,000/(16*9600) = 50,000,000/153,600 = 326 BAUDGEN_CLOCK_TO_BAUD_MOD: integer := 326; BAUDGEN_REG_SIZE: integer := 10; DATA_BITS: integer := 8; -- # TICKS for stop bits (16, 24, 32 for 1, 1.5 and 2) STOP_BITS_TICKS: integer := 16; -- Number of addr bits for FIFO sets it's size as FIFO = 2^FIFO_NUM_ADDR_BITS FIFO_NUM_ADDR_BITS: integer := 4); -- clk and reset needed for UART state machine. rd_uart causes RX FIFO to move pointer -- to next byte in FIFO and therefore rx_loc_sys_data will change following the rising -- edge of clock (after the propagation delay). So rd_uart is really REMOVE current -- data on rx_loc_sys_data and go to next element. -- tx_wire is output wire to UART connector. rx_wire is input wire from UART Port ( clk, reset : in std_logic; rd_uart, wr_uart : in std_logic; rx_wire : in std_logic; tx_loc_sys_data : in std_logic_vector(DATA_BITS-1 downto 0); tx_full, rx_empty: out std_logic; rx_loc_sys_data : out std_logic_vector(DATA_BITS-1 downto 0); tx_wire : out std_logic ); end UARTUnit; architecture beh of UARTUnit is signal baud_clk: std_logic; signal rx_move_to_fifo: std_logic; signal fifo_to_TX_data: std_logic_vector(DATA_BITS-1 downto 0); signal RX_data_to_fifo: std_logic_vector(DATA_BITS-1 downto 0); signal tx_empty, tx_fifo_not_empty: std_logic; signal tx_done_tick: std_logic; begin BaudGenInst: entity work.BaudGen(beh) generic map(N=>BAUDGEN_REG_SIZE, M=>BAUDGEN_CLOCK_TO_BAUD_MOD) port map(clk=>clk, reset=>reset, baud_tick=>baud_clk, count_out=>open); -- Receiver -- asychronously reads bits sent to it by remote system through rx_wire. When -- byte received to loc_sys, move data (RX_data_to_fifo) to fifo automatically (rx_move_to_fifo) -- Note that this is safe because rx_done_tick is asserted for ONE clock cycle AFTER the -- stop bit is completely received -- therefore the dout (byte just read) is stable and -- ready to be written to the FIFO. RX_Inst: entity work.UART_RX(beh) generic map (DBIT=>DATA_BITS, STOP_BITS_TICKS=>STOP_BITS_TICKS) port map (clk=>clk, reset=>reset, rx=>rx_wire, baud_in=>baud_clk, rx_done_tick=>rx_move_to_fifo, dout=>RX_data_to_fifo); -- When loc_sys requests read (rd_uart), we actually move the read pointer to the next -- element in the FIFO so r_data changes after the register propagation delay following -- the rising edge of clock. FIFO_RX_Inst: entity work.FIFO(beh) generic map (NUM_DATA_BITS=>DATA_BITS, NUM_ADDR_BITS=>FIFO_NUM_ADDR_BITS) port map (clk=>clk, reset=>reset, rd=>rd_uart, wr=>rx_move_to_fifo, w_data=>RX_data_to_fifo, empty=>rx_empty, full=>open, r_data=>rx_loc_sys_data); -- When wr_uart is asserted, current byte on tx_loc_sys_data is written into the FIFO at the -- current value of the w_ptr_data pointer and THEN the pointer is advanced to the next empty -- element in the FIFO. The data on the output of the RX unit (rx_loc_sys_data) is latched on -- the rising edge (good thing, because it is about to change). The write does NOT occur if -- tx_full is asserted. -- Also, fifo_to_TX_data does NOT change until after the clock edge. The tx_empty signal goes to 0 -- after the byte is written to the FIFO. This value is inverted and then used to tell the transmitter -- to send a value. If more than one data value exists in FIFO, after TX transmits a byte, -- it pulses tx_done_tick which causes the FIFO to put the next value on fifo_to_TX_data -- and the process starts again. FIFO_TX_Inst: entity work.FIFO(beh) generic map (NUM_DATA_BITS=>DATA_BITS, NUM_ADDR_BITS=>FIFO_NUM_ADDR_BITS) port map (clk=>clk, reset=>reset, rd=>tx_done_tick, wr=>wr_uart, w_data=>tx_loc_sys_data, empty=>tx_empty, full=>tx_full, r_data=>fifo_to_TX_data); tx_fifo_not_empty <= not tx_empty; -- Transmitter -- synchronously send bits to remote system through tx_wire. tx_done_tick is pulsed -- when the transmission is complete. TX_Inst: entity work.UART_TX(beh) generic map(DBIT=>DATA_BITS, STOP_BITS_TICKS=>STOP_BITS_TICKS) port map(clk=>clk, reset=>reset, tx_start=>tx_fifo_not_empty, baud_in=>baud_clk, din=>fifo_to_TX_data, tx_done_tick=>tx_done_tick, tx=>tx_wire); end beh;