'I tried writing UART VHDL code for loopback testing. Can anyone help me how to write a testbench for it
UART loopback testing code for an FPGA:
--
-- Inputs/Outputs:
--
-- SYS:
-- I_clk - system clock - at least 16x baud rate for recieve
-- but can be less if only using TX.
-- I_clk_baud_count - the number of cycles of I_clk between baud ticks
-- used to set a known transmit/recieve baud rate.
-- I_reset - reset line. ideally, reset whilst changing baud.
--
-- TX:
-- I_txData - data to transmit.
-- I_txSig - signal to transmit (deassert when txReady low) or
-- change I_txData to stream out.
-- O_txRdy - '1' when idle, '0' when transmitting.
-- O_tx - actual serial output.
--
-- RX:
-- I_rx - actual serial input.
-- I_rxCont - receive enable/continue.
-- O_rxData - data received.
-- O_rxSig - data available signal - does not deassert until new
-- frame starts being received.
entity UART is
Port (I_clk : in STD_LOGIC;
I_reset: in STD_LOGIC;
O_tx : out STD_LOGIC;
I_rx : in STD_LOGIC;
O_txRdy : out STD_LOGIC);
end UART;
architecture Behavioral of UART is
constant I_clk_baud_count :integer:=10416; -- for 100MHz @ 9600 baud rate
signal I_txSig : STD_LOGIC;
signal tx_data : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');
signal tx_state: integer := 0;
signal tx_rdy : STD_LOGIC := '1';
signal tx: STD_LOGIC := '1';
signal rx_sample_count : integer := 0;
signal rx_sample_offset : integer := 3;
signal rx_state: integer := 0;
signal rx_data : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');
signal rx_sig : STD_LOGIC := '0';
signal rx_clk_counter : integer := 0;
signal rx_clk_reset : STD_LOGIC := '0';
signal rx_clk_baud_tick: STD_LOGIC := '0';
signal tx_clk_counter : integer := 0;
signal tx_clk : STD_LOGIC := '0';
constant OFFSET_START_BIT: integer := 7; -- for start bit
constant OFFSET_DATA_BITS: integer := 15; -- for data bit
constant OFFSET_STOP_BIT: integer := 7; -- for stop bit
begin
-- clock process
clk_gen: process (I_clk)
begin
if rising_edge(I_clk) then
-- RX baud 'ticks' generated for sampling, with reset
if (rx_clk_counter = 0) then
-- x16 sampled - so chop off 4 LSB
rx_clk_counter <= I_clk_baud_count;
rx_clk_baud_tick <= '1';
else
if (rx_clk_reset = '1') then
rx_clk_counter <= I_clk_baud_count;
else
rx_clk_counter <= rx_clk_counter - 1;
end if;
rx_clk_baud_tick <= '0';
end if;
-- TX standard baud clock, no reset
if (tx_clk_counter = 0) then
-- chop off LSB to get a clock
tx_clk_counter <= I_clk_baud_count;
tx_clk <= not tx_clk;
else
tx_clk_counter <= tx_clk_counter - 1;
end if;
end if;
end process;
-- transmission process
tx_proc: process (tx_clk, I_reset, I_txSig, tx_state)
begin
-- TX runs off the TX baud clock
if rising_edge(tx_clk) then
if I_reset = '1' then
tx_state <= 0;
tx_data <= X"00";
tx_rdy <= '1';
tx <= '1';
else
if (tx_state = 0 and I_txsig = '1') then
tx_state <= 1;
tx_rdy <= '0';
tx <= '0'; -- start bit
elsif (tx_state < 9 and tx_rdy = '0') then
tx <= tx_data(0);
tx_data <= '0' & tx_data (7 downto 1);
tx_state <= tx_state + 1;
elsif (tx_state = 9 and tx_rdy = '0') then
tx <= '1'; -- stop bit
tx_rdy <= '1';
tx_state <= 0;
end if;
end if;
end if;
end process;
-- receiving process
rx_proc: process (I_clk, I_reset, I_rx)
begin
-- RX runs off the system clock, and operates on baud 'ticks'
if rising_edge(I_clk) then
if (rx_clk_reset = '1') then
rx_clk_reset <= '0';
end if;
if (I_reset = '1') then
rx_state <= 0;
rx_sig <= '0';
rx_sample_count <= 0;
rx_sample_offset <= OFFSET_START_BIT;
rx_data <= X"00";
elsif (I_rx = '0' and rx_state = 0) then
-- first encounter of falling edge start
rx_state <= 1; -- start bit sample stage
rx_sample_offset <= OFFSET_START_BIT;
rx_sample_count <= 0;
-- need to reset the baud tick clock to line up with the start
-- bit leading edge.
rx_clk_reset <= '1';
elsif (rx_clk_baud_tick = '1' and I_rx = '0' and rx_state = 1) then
-- inc sample count
rx_sample_count <= rx_sample_count + 1;
if (rx_sample_count = rx_sample_offset) then
-- start bit sampled, time to enable data
rx_sig <= '0';
rx_state <= 2;
rx_data <= X"00";
rx_sample_offset <= OFFSET_DATA_BITS;
rx_sample_count <= 0;
end if;
elsif (rx_clk_baud_tick = '1' and rx_state >= 2 and rx_state < 10) then
-- sampling data
if (rx_sample_count = rx_sample_offset) then
rx_data(6 downto 0) <= rx_data(7 downto 1);
rx_data(7) <= I_rx;
rx_sample_count <= 0;
rx_state <= rx_state + 1;
else
rx_sample_count <= rx_sample_count + 1;
end if;
elsif (rx_clk_baud_tick = '1' and rx_state = 10) then
if (rx_sample_count = OFFSET_STOP_BIT) then
rx_state <= 0;
rx_sig <= '1';
tx_data <= rx_data;
else
rx_sample_count <= rx_sample_count + 1;
end if;
end if;
end if;
end process;
O_tx <= tx;
O_txRdy <= tx_rdy;
I_txSig <= rx_sig;
end Behavioral;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|