component uart is
generic (
- output_fifo_width : integer
+ output_fifo_width : integer := 2;
+ input_fifo_width : integer := 2
);
port (
mclk : in std_logic;
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;
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);
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';
end loop;
end process;
-
+
+ -- Reset generation
process
begin
reset <= '0';
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";
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';
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;
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
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';
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;