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
);
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
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
+ 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) := (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 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';
end loop;
end process;
+--------------------------------------------------------------------------------
+-- TX MODULE
+--------------------------------------------------------------------------------
tx_control_0 : tx_control port map (
clk => mclk,
fifo_pop => tx_fifo_re
);
- transmitter_0 : transmitter port map (
+ tx_transmitter_0 : transmitter port map (
clk => tx_clk,
reset => puc,
data => tx_data,
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;