From: Vladimir Burian Date: Fri, 4 Feb 2011 13:06:14 +0000 (+0100) Subject: Receiving capability added to the top component. X-Git-Url: http://rtime.felk.cvut.cz/gitweb/fpga/uart.git/commitdiff_plain/81d30909cb24a0f382a045c90f11444dd35cc1cf Receiving capability added to the top component. Now receiving and transmitting works and is usable. In the USTAT register there are flags of TX and RX FIFOs states. In the UIE register coresponding interrupts can be enabled. --- diff --git a/tb/tb_uart.vhd b/tb/tb_uart.vhd index b4d1f22..f35be5e 100644 --- a/tb/tb_uart.vhd +++ b/tb/tb_uart.vhd @@ -11,7 +11,8 @@ architecture testbench of tb_uart is component uart is generic ( - output_fifo_width : integer + output_fifo_width : integer := 2; + input_fifo_width : integer := 2 ); port ( mclk : in std_logic; @@ -20,10 +21,11 @@ architecture testbench of tb_uart is per_en : in std_logic; per_wen : in std_logic_vector (1 downto 0); puc : in std_logic; - --per_irq_acc : in std_logic; - --per_irq : out std_logic; + per_irq_acc : in std_logic; + per_irq : out std_logic; per_dout : out std_logic_vector (15 downto 0); + rxd : in std_logic; txd : out std_logic ); end component; @@ -31,8 +33,8 @@ architecture testbench of tb_uart is signal clk : std_logic; signal reset : std_logic; - constant period : time := 1 us; - constant offset : time := 2 us; + constant period : time := 200 ns; + constant offset : time := 2 * period; signal per_addr : std_logic_vector (7 downto 0); @@ -40,40 +42,54 @@ architecture testbench of tb_uart is signal per_en : std_logic; signal per_wen : std_logic_vector (1 downto 0); signal per_dout : std_logic_vector (15 downto 0); + signal per_irq : std_logic; + signal rxd : std_logic; signal txd : std_logic; - type test_record is record - we : std_logic; + type per_test_record is record + we : std_logic; word : std_logic; data : std_logic_vector (15 downto 0); addr : std_logic_vector (15 downto 0); end record; - type test_array is array (positive range <>) of test_record; + type per_test_array is array (positive range <>) of per_test_record; + type rxd_test_array is array (positive range <>) of std_logic_vector (7 downto 0); - constant test_vectors : test_array := ( - ('1','1',X"0002",X"0100"), - ('1','0',X"0065",X"0102") + constant addr_offset : std_logic_vector (15 downto 0) := X"0100"; + + constant per_test_vectors : per_test_array := ( + ('1','1',X"0002",X"0000"), + ('1','0',X"0065",X"0002") + ); + + constant rxd_test_vectors : rxd_test_array := ( + "01000011", + "01000100" ); -------------------------------------------------------------------------------- begin UUT : uart port map ( - mclk => clk, - per_addr => per_addr, - per_din => per_din, - per_en => per_en, - per_wen => per_wen, - puc => reset, - per_dout => per_dout, - - txd => txd + mclk => clk, + per_addr => per_addr, + per_din => per_din, + per_en => per_en, + per_wen => per_wen, + puc => reset, + per_irq_acc => '0', + per_irq => per_irq, + per_dout => per_dout, + + rxd => rxd, + txd => txd ); - + + -- Clock generation process begin clk <= '0'; @@ -87,7 +103,8 @@ begin end loop; end process; - + + -- Reset generation process begin reset <= '0'; @@ -98,9 +115,10 @@ begin wait; end process; - + + -- Bus communication with UART peripherial (per_test_vector) process - variable vector : test_record; + variable vector : per_test_record; begin per_addr <= X"00"; per_din <= X"0000"; @@ -110,9 +128,10 @@ begin wait for 3.1 * period; - for i in test_vectors'range loop - vector := test_vectors(i); - + for i in per_test_vectors'range loop + vector := per_test_vectors(i); + vector.addr := vector.addr + addr_offset; + per_addr <= vector.addr (8 downto 1); per_en <= '1'; @@ -140,6 +159,36 @@ begin wait; end process; + + + -- UART RXD signal generation (rxd_test_vector) + process + constant baud_period : time := 6 * period; + constant extra_wait : time := 2 * baud_period; -- waiting between frames + variable vector : std_logic_vector (7 downto 0); + begin + rxd <= '1'; + + wait for 4.1 * period; + + for i in rxd_test_vectors'range loop + vector := rxd_test_vectors (i); + + rxd <= '0'; + wait for baud_period; + + for j in 7 downto 0 loop + rxd <= vector (j); + wait for baud_period; + end loop; + + rxd <= '1'; + wait for baud_period; + wait for extra_wait; + end loop; + + wait; + end process; end testbench; diff --git a/uart.vhd b/uart.vhd index cddd6c8..11eb9b2 100644 --- a/uart.vhd +++ b/uart.vhd @@ -5,41 +5,25 @@ use ieee.std_logic_unsigned.all; entity uart is generic ( - output_fifo_width : integer := 2 + output_fifo_width : integer := 2; + input_fifo_width : integer := 2 ); port ( mclk : in std_logic; - per_addr : in std_logic_vector (7 downto 0); - per_din : in std_logic_vector (15 downto 0); -- unused + per_addr : in std_logic_vector (7 downto 0); + per_din : in std_logic_vector (15 downto 0); per_en : in std_logic; - per_wen : in std_logic_vector (1 downto 0); -- unused - puc : in std_logic; -- unused - --per_irq_acc : in std_logic; -- unused - --per_irq : out std_logic; + per_wen : in std_logic_vector (1 downto 0); + puc : in std_logic; + per_irq_acc : in std_logic; + per_irq : out std_logic; per_dout : out std_logic_vector (15 downto 0); + rxd : in std_logic; txd : out std_logic ); end uart; --- Registers: --- - Prescaler .16b --- - Modulator .8b --- - TX data .8b --- - TX enable --- - TX buffer full .1b --- - TX buffer empty .1b --- - TX buffer empty IE 1.b --- - RX data .8b --- - RX enable --- - RX buffer empty .1b --- - RX buffer half full .1b --- - RX buffer full .1b --- - RX buffer half full IE .1b --- - RX buffer full IE .1b --- - RX framing error .1b --- - RX buffer overflow .1b - -------------------------------------------------------------------------------- architecture dataflow of uart is @@ -66,6 +50,34 @@ architecture dataflow of uart is ); end component; + component rx_control is + port ( + clk : in std_logic; + reset : in std_logic; + rx : in std_logic; + bad_start_bit : in std_logic; + bad_stop_bit : in std_logic; + rx_ready : in std_logic; + rx_reset : out std_logic; + rx_en : out std_logic; + fifo_we : out std_logic; + clk_en : out std_logic + ); + end component rx_control; + + component receiver is + port ( + clk : in std_logic; + reset : in std_logic; + en : in std_logic; + rx : in std_logic; + ready : out std_logic; + bad_start_bit : out std_logic; + bad_stop_bit : out std_logic; + data : out std_logic_vector (7 downto 0) + ); + end component receiver; + component fifo is generic ( width : integer := 2 @@ -90,46 +102,80 @@ architecture dataflow of uart is clk : in std_logic; ce : in std_logic; reset : in std_logic; - scale : in std_logic_vector (15 downto 0); - clk_baud : out std_logic + scale : in std_logic_vector (15 downto 0); + clk_baud : out std_logic ); end component; -------------------------------------------------------------------------------- + alias per_din_low : std_logic_vector (7 downto 0) is per_din (7 downto 0); + alias per_din_high : std_logic_vector (7 downto 0) is per_din (15 downto 8); + type boolean_vector is array (natural range <>) of boolean; -------------------------------------------------------------------------------- constant base_addr : integer := 16#0100#; - constant UBAUD : integer := base_addr + 00; - constant UTX : integer := base_addr + 02; + constant UBAUD : integer := base_addr + 00; -- 2B - Baud rate generator + constant UTX : integer := base_addr + 02; -- 1B - Transmit data + constant URX : integer := base_addr + 04; -- 1B - Read data + constant USTAT : integer := base_addr + 06; -- 1B - Rx & Tx status + constant UIE : integer := base_addr + 07; -- 1B - Interrupt enable - signal reg_we : std_logic_vector (511 downto 0); - signal reg_re : boolean_vector (511 downto 0); + signal reg_we : std_logic_vector (511 downto 0); + signal reg_re : std_logic_vector (511 downto 0); + signal reg_re_b : boolean_vector (512 downto 0); - signal tx_clk : std_logic; - signal tx_data : std_logic_vector (7 downto 0); - signal tx_we : std_logic; - signal tx_ready : std_logic; + + signal reg_baud : std_logic_vector (15 downto 0) := "0000000000000010"; + signal reg_stat : std_logic_vector (7 downto 0); + signal reg_ie : std_logic_vector (7 downto 0); + + signal tx_clk : std_logic; + signal tx_data : std_logic_vector (7 downto 0); + signal tx_we : std_logic; + signal tx_ready : std_logic; + signal tx_fifo_full : std_logic; + signal tx_fifo_hfull : std_logic; signal tx_fifo_empty : std_logic; - signal tx_fifo_re : std_logic; - signal tx_fifo_we : std_logic; + signal tx_fifo_re : std_logic; + signal rx_clk : std_logic; + signal rx_clk_en : std_logic; + signal rx_en : std_logic; + signal rx_ready : std_logic; + signal rx_reset : std_logic; + signal rx_data : std_logic_vector (7 downto 0); + signal rx_bad_start_bit : std_logic; + signal rx_bad_stop_bit : std_logic; + signal rx_fifo_we : std_logic; + signal rx_fifo_out : std_logic_vector (7 downto 0); + signal rx_fifo_full : std_logic; + signal rx_fifo_hfull : std_logic; + signal rx_fifo_empty : std_logic; + signal rx_fifo_ow : std_logic; + signal rx_fifo_ow_clear : std_logic; + -------------------------------------------------------------------------------- begin + -- Address decoder process (per_addr, per_wen, per_en) begin for i in reg_re'range loop - reg_re (i) <= false; - reg_we (i) <= '0'; + reg_re_b (i) <= false; + reg_re (i) <= '0'; + reg_we (i) <= '0'; if (per_en = '1' and per_addr = i/2) then - reg_re (i) <= true; + -- Register of the corresponding address is always read, so + -- read-modify-write operation in one cycle is possible. + reg_re_b (i) <= true; + reg_re (i) <= '1'; if (per_wen (i mod 2) = '1') then reg_we (i) <= '1'; @@ -138,6 +184,9 @@ begin end loop; end process; +-------------------------------------------------------------------------------- +-- TX MODULE +-------------------------------------------------------------------------------- tx_control_0 : tx_control port map ( clk => mclk, @@ -148,7 +197,7 @@ begin fifo_pop => tx_fifo_re ); - transmitter_0 : transmitter port map ( + tx_transmitter_0 : transmitter port map ( clk => tx_clk, reset => puc, data => tx_data, @@ -157,32 +206,125 @@ begin tx => txd ); - tx_fifo : fifo port map ( + tx_fifo_0 : fifo port map ( clk => mclk, reset => puc, - we => tx_fifo_we, + we => reg_we (UTX), re => tx_fifo_re, clear_ow => '0', d_in => per_din (7 downto 0), d_out => tx_data, - full => open, - hfull => open, + full => tx_fifo_full, + hfull => tx_fifo_hfull, empty => tx_fifo_empty, overflow => open - ); + ); - baud_gen_0 : baud_gen port map ( + tx_baud_gen_0 : baud_gen port map ( clk => mclk, ce => '1', reset => puc, - scale => "0000000000000000", + scale => reg_baud, clk_baud => tx_clk - ); + ); + +-------------------------------------------------------------------------------- +-- RX MODULE +-------------------------------------------------------------------------------- + rx_control_0 : rx_control + port map ( + clk => mclk, + reset => puc, + rx => rxd, + bad_start_bit => rx_bad_start_bit, + bad_stop_bit => rx_bad_stop_bit, + rx_ready => rx_ready, + rx_reset => rx_reset, + rx_en => rx_en, + fifo_we => rx_fifo_we, + clk_en => rx_clk_en); + rx_receiver_0 : receiver + port map ( + clk => rx_clk, + reset => puc, + en => rx_en, + rx => rxd, + ready => rx_ready, + bad_start_bit => rx_bad_start_bit, + bad_stop_bit => rx_bad_stop_bit, + data => rx_data); + + rx_fifo_0 : fifo + port map ( + clk => mclk, + reset => puc, + we => rx_fifo_we, + re => reg_re (URX), + clear_ow => rx_fifo_ow_clear, + d_in => rx_data, + d_out => rx_fifo_out, + full => rx_fifo_full, + hfull => rx_fifo_hfull, + empty => rx_fifo_empty, + overflow => rx_fifo_ow); + + rx_baud_gen_0 : baud_gen + port map ( + clk => mclk, + ce => rx_clk_en, + reset => puc, + scale => reg_baud, + clk_baud => rx_clk); + -------------------------------------------------------------------------------- +-- OTHER LOGIC +-------------------------------------------------------------------------------- + + process (mclk, puc) is + begin + if puc = '1' then + reg_baud <= (others => '0'); + reg_ie <= (others => '0'); + + elsif mclk'event and mclk = '1' then + if reg_we (UBAUD) = '1' then + reg_baud (7 downto 0) <= per_din_low; + end if; + + if reg_we (UBAUD+1) = '1' then + reg_baud (15 downto 8) <= per_din_high; + end if; - tx_fifo_we <= reg_we (UTX); + if reg_we (USTAT) = '1' then + reg_ie <= per_din_low; + end if; + end if; + end process; + + + reg_stat <= tx_fifo_empty & + tx_fifo_hfull & + tx_fifo_full & + not rx_fifo_empty & + rx_fifo_hfull & + rx_fifo_full & + rx_fifo_ow & + '0'; + + + per_irq <= '1' when (reg_stat and reg_ie and "10011100") /= "00000000" else '0' ; + + per_dout <= reg_baud when reg_re_b (UBAUD) else + "00000000" & tx_data when reg_re_b (UTX) else + "00000000" & rx_fifo_out when reg_re_b (URX) else + reg_ie & reg_stat when reg_re_b (USTAT) else + (others => '0'); + +-------------------------------------------------------------------------------- + + rx_fifo_ow_clear <= per_din (1) and reg_we (USTAT); end dataflow;