library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity uart is generic ( 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); 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_dout : out std_logic_vector (15 downto 0); rxd : in std_logic; txd : out std_logic ); end uart; -------------------------------------------------------------------------------- architecture dataflow of uart is component tx_control is port ( clk : in std_logic; reset : in std_logic; tx_ready : in std_logic; fifo_empty : in std_logic; tx_we : out std_logic; fifo_pop : out std_logic ); end component; component transmitter is port ( clk : in std_logic; reset : in std_logic; data : in std_logic_vector (7 downto 0); we : in std_logic; ready : out std_logic; tx : out std_logic ); 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 ); port ( clk : in std_logic; reset : in std_logic; we : in std_logic; re : in std_logic; clear_ow : in std_logic; d_in : in std_logic_vector (7 downto 0); d_out : out std_logic_vector (7 downto 0); full : out std_logic; hfull : out std_logic; empty : out std_logic; overflow : out std_logic ); end component; component baud_gen is port ( 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 ); 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; -- 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 : std_logic_vector (511 downto 0); signal reg_re_b : boolean_vector (512 downto 0); signal reg_baud : std_logic_vector (15 downto 0) := (others => '0'); signal reg_stat : std_logic_vector (7 downto 0); signal reg_ie : std_logic_vector (7 downto 0) := (others => '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 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_b (i) <= false; reg_re (i) <= '0'; reg_we (i) <= '0'; if (per_en = '1' and per_addr = i/2) then -- 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'; end if; end if; end loop; end process; -------------------------------------------------------------------------------- -- TX MODULE -------------------------------------------------------------------------------- tx_control_0 : tx_control port map ( clk => mclk, reset => puc, tx_ready => tx_ready, fifo_empty => tx_fifo_empty, tx_we => tx_we, fifo_pop => tx_fifo_re ); tx_transmitter_0 : transmitter port map ( clk => tx_clk, reset => puc, data => tx_data, we => tx_we, ready => tx_ready, tx => txd ); tx_fifo_0 : fifo port map ( clk => mclk, reset => puc, we => reg_we (UTX), re => tx_fifo_re, clear_ow => '0', d_in => per_din (7 downto 0), d_out => tx_data, full => tx_fifo_full, hfull => tx_fifo_hfull, empty => tx_fifo_empty, overflow => open ); tx_baud_gen_0 : baud_gen port map ( clk => mclk, ce => '1', reset => puc, 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 mclk'event and mclk = '1' then if puc = '1' then reg_baud <= (others => '0'); reg_ie <= (others => '0'); else 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; if reg_we (USTAT) = '1' then reg_ie <= per_din_low; end if; 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;