Skip to content

Commit 6cf842a

Browse files
committed
[FEATURE]: Add better simulation
1 parent b80a104 commit 6cf842a

File tree

3 files changed

+221
-106
lines changed

3 files changed

+221
-106
lines changed

rtl/uart.vhd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ use IEEE.MATH_REAL.ALL;
3131
-- Fixed fake received transaction after FPGA boot without reset.
3232
-- Added more precisely clock dividers, dividing with rounding.
3333
-- UART loopback example is for CYC1000 board now.
34+
-- Version 1.3 -
35+
-- Added better simulation with automatic checking of transactions.
3436

3537
entity UART is
3638
Generic (

sim/sim.tcl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ vcom -93 ./uart_tb.vhd
2222
vsim work.uart_tb
2323

2424
# Setup and start simulation
25-
#add wave *
2625
add wave sim:/uart_tb/utt/*
27-
run 200 us
26+
#add wave sim:/uart_tb/utt/uart_rx_i/*
27+
#add wave sim:/uart_tb/utt/uart_tx_i/*
28+
#add wave sim:/uart_tb/*
29+
run -All

sim/uart_tb.vhd

Lines changed: 215 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
--------------------------------------------------------------------------------
22
-- PROJECT: SIMPLE UART FOR FPGA
33
--------------------------------------------------------------------------------
4-
-- MODULE: TESTBANCH OF UART TOP MODULE
54
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
65
-- LICENSE: The MIT License (MIT), please read LICENSE file
76
-- WEBSITE: https://github.com/jakubcabal/uart-for-fpga
@@ -10,126 +9,238 @@
109
library IEEE;
1110
use IEEE.STD_LOGIC_1164.ALL;
1211
use IEEE.NUMERIC_STD.ALL;
12+
use IEEE.MATH_REAL.ALL;
1313

1414
entity UART_TB is
1515
end UART_TB;
1616

1717
architecture FULL of UART_TB is
1818

19-
signal CLK : std_logic;
20-
signal RST : std_logic;
21-
signal tx_uart : std_logic;
22-
signal rx_uart : std_logic;
23-
signal din : std_logic_vector(7 downto 0);
24-
signal din_vld : std_logic;
25-
signal din_rdy : std_logic;
26-
signal dout : std_logic_vector(7 downto 0);
27-
signal dout_vld : std_logic;
28-
signal frame_error : std_logic;
29-
30-
constant clk_period : time := 20 ns;
31-
constant uart_period : time := 8680.56 ns;
32-
constant data_value : std_logic_vector(7 downto 0) := "10100111";
33-
constant data_value2 : std_logic_vector(7 downto 0) := "00110110";
19+
signal CLK : std_logic;
20+
signal RST : std_logic;
21+
22+
signal driver_rxd_din : std_logic_vector(7 downto 0);
23+
signal driver_rxd : std_logic := '1';
24+
signal driver_rxd_done : std_logic := '0';
25+
26+
signal monitor_dout_expected : std_logic_vector(7 downto 0);
27+
signal monitor_dout : std_logic_vector(7 downto 0);
28+
signal monitor_dout_vld : std_logic;
29+
signal monitor_dout_done : std_logic := '0';
30+
31+
signal driver_din : std_logic_vector(7 downto 0);
32+
signal driver_din_vld : std_logic := '0';
33+
signal driver_din_rdy : std_logic;
34+
signal driver_din_done : std_logic := '0';
35+
36+
signal monitor_txd_dout_expected : std_logic_vector(7 downto 0);
37+
signal monitor_txd_dout : std_logic_vector(7 downto 0);
38+
signal monitor_txd : std_logic := '1';
39+
signal monitor_txd_done : std_logic := '0';
40+
signal monitor_txd_start_bit : std_logic := '0';
41+
signal monitor_txd_stop_bit : std_logic := '0';
42+
43+
signal frame_error : std_logic;
44+
signal rand_int : integer := 0;
45+
46+
constant CLK_FREQ : natural := 50e6;
47+
constant BAUD_RATE : natural := 115200;
48+
constant TRANS_COUNT : natural := 2**8;
49+
constant CLK_PERIOD : time := 1 ns * integer(real(1e9)/real(CLK_FREQ));
50+
constant UART_PERIOD_I : natural := integer(real(1e9)/real(BAUD_RATE));
51+
constant UART_PERIOD : time := 1 ns * UART_PERIOD_I;
52+
53+
procedure UART_DRIVER (
54+
constant UART_PER : time;
55+
signal UART_DIN : in std_logic_vector(7 downto 0);
56+
signal UART_TXD : out std_logic
57+
) is
58+
variable rnd_delay : natural;
59+
begin
60+
-- start bit
61+
UART_TXD <= '0';
62+
wait for UART_PER;
63+
-- data bits
64+
for i in 0 to (UART_DIN'LENGTH-1) loop
65+
UART_TXD <= UART_DIN(i);
66+
wait for UART_PER;
67+
end loop;
68+
-- stop bit
69+
UART_TXD <= '1';
70+
wait for UART_PER;
71+
end procedure;
72+
73+
procedure UART_MONITOR (
74+
constant UART_PER : time;
75+
signal UART_RXD : in std_logic;
76+
signal UART_DOUT : out std_logic_vector(7 downto 0);
77+
signal UART_START_BIT : out std_logic;
78+
signal UART_STOP_BIT : out std_logic
79+
) is begin
80+
if (UART_RXD = '1') then
81+
wait until UART_RXD = '0';
82+
end if;
83+
UART_START_BIT <= '1';
84+
-- start bit
85+
wait for UART_PER;
86+
UART_START_BIT <= '0';
87+
-- data bits
88+
wait for UART_PER/2; -- move to middle data bit
89+
for i in 0 to (UART_DOUT'LENGTH-2) loop
90+
UART_DOUT(i) <= UART_RXD;
91+
wait for UART_PER;
92+
end loop;
93+
-- last data bit
94+
UART_DOUT(UART_DOUT'LENGTH-1) <= UART_RXD;
95+
wait for UART_PER/2;
96+
-- stop bit
97+
UART_STOP_BIT <= '1';
98+
-- move to middle of stop bit
99+
wait for UART_PER/2;
100+
if (UART_RXD = '0') then
101+
report "Invalid stop bit in UART_MONITOR!" severity failure;
102+
end if;
103+
UART_STOP_BIT <= '0';
104+
-- in middle of stop bit move to resync (wait for start bit)
105+
end procedure;
34106

35107
begin
36108

37-
utt: entity work.UART
109+
rand_int_p : process
110+
variable seed1, seed2: positive;
111+
variable rand : real;
112+
begin
113+
uniform(seed1, seed2, rand);
114+
rand_int <= integer(rand*real(20));
115+
--report "Random number X: " & integer'image(rand_int);
116+
wait for CLK_PERIOD;
117+
end process;
118+
119+
120+
utt : entity work.UART
38121
generic map (
39-
CLK_FREQ => 50e6,
40-
BAUD_RATE => 115200,
41-
PARITY_BIT => "none"
122+
CLK_FREQ => CLK_FREQ,
123+
BAUD_RATE => BAUD_RATE,
124+
PARITY_BIT => "none" -- parity bit is not supported in this simulation
42125
)
43126
port map (
44127
CLK => CLK,
45128
RST => RST,
46129
-- UART INTERFACE
47-
UART_TXD => tx_uart,
48-
UART_RXD => rx_uart,
130+
UART_TXD => monitor_txd,
131+
UART_RXD => driver_rxd,
49132
-- USER DATA INPUT INTERFACE
50-
DIN => din,
51-
DIN_VLD => din_vld,
52-
DIN_RDY => din_rdy,
133+
DIN => driver_din,
134+
DIN_VLD => driver_din_vld,
135+
DIN_RDY => driver_din_rdy,
53136
-- USER DATA OUTPUT INTERFACE
54-
DOUT => dout,
55-
DOUT_VLD => dout_vld,
137+
DOUT => monitor_dout,
138+
DOUT_VLD => monitor_dout_vld,
56139
FRAME_ERROR => frame_error
57140
);
58141

59-
clk_process : process
60-
begin
61-
CLK <= '0';
62-
wait for clk_period/2;
63-
CLK <= '1';
64-
wait for clk_period/2;
65-
end process;
66-
67-
rst_gen_p : process
68-
begin
69-
RST <= '1';
70-
wait for clk_period*3;
71-
RST <= '0';
72-
wait;
73-
end process;
74-
75-
test_rx_uart : process
76-
begin
77-
rx_uart <= '1';
78-
79-
wait until RST = '0';
80-
wait until rising_edge(CLK);
81-
82-
rx_uart <= '0'; -- start bit
83-
wait for uart_period;
84-
85-
for i in 0 to (data_value'LENGTH-1) loop
86-
rx_uart <= data_value(i); -- data bits
87-
wait for uart_period;
88-
end loop;
89-
90-
rx_uart <= '1'; -- stop bit
91-
wait for uart_period;
92-
93-
rx_uart <= '0'; -- start bit
94-
wait for uart_period;
95-
96-
for i in 0 to (data_value2'LENGTH-1) loop
97-
rx_uart <= data_value2(i); -- data bits
98-
wait for uart_period;
99-
end loop;
100-
101-
rx_uart <= '1'; -- stop bit
102-
wait for uart_period;
103-
104-
wait;
105-
106-
end process;
107-
108-
test_tx_uart : process
109-
begin
110-
din <= data_value;
111-
din_vld <= '0';
112-
113-
wait until RST = '0';
114-
wait until rising_edge(CLK);
115-
din_vld <= '1';
116-
117-
wait until rising_edge(CLK);
118-
din_vld <= '0';
119-
120-
wait until rising_edge(CLK);
121-
wait for 80 us;
122-
123-
wait until rising_edge(CLK);
124-
din_vld <= '1';
125-
din <= data_value2;
126-
127-
wait until rising_edge(CLK);
128-
din_vld <= '0';
129-
130-
wait until rising_edge(CLK);
131-
wait;
132-
133-
end process;
134-
135-
end FULL;
142+
clk_gen_p : process
143+
begin
144+
CLK <= '0';
145+
wait for CLK_PERIOD/2;
146+
CLK <= '1';
147+
wait for CLK_PERIOD/2;
148+
end process;
149+
150+
rst_gen_p : process
151+
begin
152+
RST <= '1';
153+
wait for CLK_PERIOD*3;
154+
RST <= '0';
155+
wait;
156+
end process;
157+
158+
-- -------------------------------------------------------------------------
159+
-- UART MODULE RECEIVING TEST
160+
-- -------------------------------------------------------------------------
161+
162+
driver_rxd_p : process
163+
begin
164+
driver_rxd <= '1';
165+
wait until RST = '0';
166+
wait for 33 ns;
167+
for i in 0 to TRANS_COUNT-1 loop
168+
driver_rxd_din <= std_logic_vector(to_unsigned(i,driver_rxd_din'LENGTH));
169+
UART_DRIVER(UART_PERIOD, driver_rxd_din, driver_rxd);
170+
wait for (rand_int/2) * UART_PERIOD;
171+
end loop;
172+
driver_rxd_done <= '1';
173+
wait;
174+
end process;
175+
176+
monitor_dout_p : process
177+
begin
178+
for i in 0 to TRANS_COUNT-1 loop
179+
monitor_dout_expected <= std_logic_vector(to_unsigned(i,monitor_dout_expected'LENGTH));
180+
wait until monitor_dout_vld = '1';
181+
if (monitor_dout = monitor_dout_expected) then
182+
--report "Transaction on DOUT port is OK." severity note;
183+
else
184+
report "Unexpected transaction on DOUT port!" severity failure;
185+
end if;
186+
wait for CLK_PERIOD;
187+
end loop;
188+
monitor_dout_done <= '1';
189+
wait;
190+
end process;
191+
192+
-- -------------------------------------------------------------------------
193+
-- UART MODULE TRANSMISSION TEST
194+
-- -------------------------------------------------------------------------
195+
196+
driver_din_p : process
197+
begin
198+
wait until RST = '0';
199+
wait until rising_edge(CLK);
200+
wait for CLK_PERIOD/2;
201+
for i in 0 to TRANS_COUNT-1 loop
202+
driver_din <= std_logic_vector(to_unsigned(i,driver_din'LENGTH));
203+
driver_din_vld <= '1';
204+
if (driver_din_rdy = '0') then
205+
wait until driver_din_rdy = '1';
206+
wait for CLK_PERIOD/2;
207+
end if;
208+
wait for CLK_PERIOD;
209+
driver_din_vld <= '0';
210+
wait for rand_int*(UART_PERIOD_I/16)*CLK_PERIOD;
211+
end loop;
212+
driver_din_done <= '1';
213+
wait;
214+
end process;
215+
216+
monitor_txd_p : process
217+
begin
218+
for i in 0 to TRANS_COUNT-1 loop
219+
monitor_txd_dout_expected <= std_logic_vector(to_unsigned(i,monitor_txd_dout_expected'LENGTH));
220+
UART_MONITOR(UART_PERIOD, monitor_txd, monitor_txd_dout, monitor_txd_start_bit, monitor_txd_stop_bit);
221+
if (monitor_txd_dout = monitor_txd_dout_expected) then
222+
--report "Transaction on UART_TXD port is OK." severity note;
223+
else
224+
report "Unexpected transaction on UART_TXD port!" severity failure;
225+
end if;
226+
end loop;
227+
monitor_txd_done <= '1';
228+
wait;
229+
end process;
230+
231+
-- -------------------------------------------------------------------------
232+
-- TEST DONE CHECK
233+
-- -------------------------------------------------------------------------
234+
235+
test_done_p : process
236+
variable v_test_done : std_logic;
237+
begin
238+
v_test_done := driver_rxd_done and monitor_dout_done and driver_din_done and monitor_txd_done;
239+
if (v_test_done = '1') then
240+
wait for 100*CLK_PERIOD;
241+
report "Simulation successfully completed." severity failure;
242+
end if;
243+
wait for CLK_PERIOD;
244+
end process;
245+
246+
end architecture;

0 commit comments

Comments
 (0)