diff --git a/vunit/vhdl/verification_components/run.py b/vunit/vhdl/verification_components/run.py index 4033e484f..c36ce267f 100644 --- a/vunit/vhdl/verification_components/run.py +++ b/vunit/vhdl/verification_components/run.py @@ -170,4 +170,11 @@ def gen_avalon_master_tests(obj, *args): name="stall_slave", generics=dict(g_stall_percentage_slave=40) ) +tb_uart_parity_test = LIB.test_bench("tb_uart").get_tests("test parity")[0] +parity_modes = {"even", "odd", "space", "mark"} +for master_parity_mode, slave_parity_mode in product(parity_modes, parity_modes): + tb_cfg = dict(master_parity_mode=master_parity_mode, slave_parity_mode=slave_parity_mode) + config_as_str = encode(tb_cfg) + tb_uart_parity_test.add_config(name=config_as_str, generics=dict(encoded_tb_cfg=config_as_str)) + UI.main() diff --git a/vunit/vhdl/verification_components/src/uart_master.vhd b/vunit/vhdl/verification_components/src/uart_master.vhd index 5b0aa97f1..8d2330cae 100644 --- a/vunit/vhdl/verification_components/src/uart_master.vhd +++ b/vunit/vhdl/verification_components/src/uart_master.vhd @@ -26,10 +26,11 @@ architecture a of uart_master is begin main : process - procedure uart_send(data : std_logic_vector; + procedure uart_send(data : std_logic_vector; signal tx : out std_logic; - baud_rate : integer) is + baud_rate : integer) is constant time_per_bit : time := (10**9 / baud_rate) * 1 ns; + constant parity_mode : parity_mode_t := uart.p_parity_mode; procedure send_bit(value : std_logic) is begin @@ -43,12 +44,22 @@ begin for i in 0 to data'length-1 loop send_bit(data(i)); end loop; + + -- Send parity bit (if parity_mode /= none) + case parity_mode is + when even => send_bit(xor data); + when odd => send_bit(not (xor data)); + when space => send_bit('0'); + when mark => send_bit('1'); + when others => null; + end case; + send_bit(uart.p_idle_state); end procedure; - variable msg : msg_t; + variable msg : msg_t; variable baud_rate : natural := uart.p_baud_rate; - variable msg_type : msg_type_t; + variable msg_type : msg_type_t; begin receive(net, uart.p_actor, msg); msg_type := message_type(msg); diff --git a/vunit/vhdl/verification_components/src/uart_pkg.vhd b/vunit/vhdl/verification_components/src/uart_pkg.vhd index d04965693..05d0717f3 100644 --- a/vunit/vhdl/verification_components/src/uart_pkg.vhd +++ b/vunit/vhdl/verification_components/src/uart_pkg.vhd @@ -15,10 +15,13 @@ use work.integer_vector_ptr_pkg.all; use work.queue_pkg.all; package uart_pkg is + type parity_mode_t is (none, even, odd, space, mark); + type uart_master_t is record p_actor : actor_t; p_baud_rate : natural; p_idle_state : std_logic; + p_parity_mode : parity_mode_t; end record; type uart_slave_t is record @@ -26,6 +29,7 @@ package uart_pkg is p_baud_rate : natural; p_idle_state : std_logic; p_data_length : positive; + p_parity_mode : parity_mode_t; end record; -- Set the baud rate [bits/s] @@ -40,11 +44,14 @@ package uart_pkg is constant default_baud_rate : natural := 115200; constant default_idle_state : std_logic := '1'; constant default_data_length : positive := 8; + constant default_parity_mode : parity_mode_t := none; impure function new_uart_master(initial_baud_rate : natural := default_baud_rate; - idle_state : std_logic := default_idle_state) return uart_master_t; + idle_state : std_logic := default_idle_state; + parity_mode : parity_mode_t := default_parity_mode) return uart_master_t; impure function new_uart_slave(initial_baud_rate : natural := default_baud_rate; idle_state : std_logic := default_idle_state; - data_length : positive := default_data_length) return uart_slave_t; + data_length : positive := default_data_length; + parity_mode : parity_mode_t := default_parity_mode) return uart_slave_t; impure function as_stream(uart_master : uart_master_t) return stream_master_t; impure function as_stream(uart_slave : uart_slave_t) return stream_slave_t; @@ -57,21 +64,25 @@ end package; package body uart_pkg is impure function new_uart_master(initial_baud_rate : natural := default_baud_rate; - idle_state : std_logic := default_idle_state) return uart_master_t is + idle_state : std_logic := default_idle_state; + parity_mode : parity_mode_t := default_parity_mode) return uart_master_t is begin return (p_actor => new_actor, p_baud_rate => initial_baud_rate, - p_idle_state => idle_state); + p_idle_state => idle_state, + p_parity_mode => parity_mode); end; impure function new_uart_slave(initial_baud_rate : natural := default_baud_rate; idle_state : std_logic := default_idle_state; - data_length : positive := default_data_length) return uart_slave_t is + data_length : positive := default_data_length; + parity_mode : parity_mode_t := default_parity_mode) return uart_slave_t is begin return (p_actor => new_actor, p_baud_rate => initial_baud_rate, p_idle_state => idle_state, - p_data_length => data_length); + p_data_length => data_length, + p_parity_mode => parity_mode); end; impure function as_stream(uart_master : uart_master_t) return stream_master_t is diff --git a/vunit/vhdl/verification_components/src/uart_slave.vhd b/vunit/vhdl/verification_components/src/uart_slave.vhd index 3084659b2..ef2544256 100644 --- a/vunit/vhdl/verification_components/src/uart_slave.vhd +++ b/vunit/vhdl/verification_components/src/uart_slave.vhd @@ -22,14 +22,15 @@ entity uart_slave is end entity; architecture a of uart_slave is - signal baud_rate : natural := uart.p_baud_rate; - signal local_event : std_logic := '0'; - constant data_queue : queue_t := new_queue; + signal baud_rate : natural := uart.p_baud_rate; + signal local_event : std_logic := '0'; + constant data_queue : queue_t := new_queue; + begin main : process variable reply_msg, msg : msg_t; - variable msg_type : msg_type_t; + variable msg_type : msg_type_t; begin receive(net, uart.p_actor, msg); msg_type := message_type(msg); @@ -53,21 +54,49 @@ begin end process; recv : process + constant parity_mode : parity_mode_t := uart.p_parity_mode; + procedure uart_recv(variable data : out std_logic_vector; - signal rx : in std_logic; - baud_rate : integer) is - constant time_per_bit : time := (10**9 / baud_rate) * 1 ns; + signal rx : in std_logic; + baud_rate : integer) is + constant time_per_bit : time := (10**9 / baud_rate) * 1 ns; constant time_per_half_bit : time := (10**9 / (2*baud_rate)) * 1 ns; + + procedure check_parity( + data : in std_logic_vector; + parity_bit : in std_logic) is + constant checker : checker_t := new_checker("uart"); + begin + case parity_mode is + when even => + check_equal(checker, parity_bit, xor data, result(". Data 0x" & to_hstring(data) &". Incorrect parity bit for parity even")); + when odd => + check_equal(checker, parity_bit, not (xor data), result(". Data 0x" & to_hstring(data) & ". Incorrect parity bit for parity odd")); + when space => + check_equal(checker, parity_bit, '0', result(". Data 0x" & to_hstring(data) & ". Incorrect parity bit for parity space")); + when mark => + check_equal(checker, parity_bit, '1', result(". Data 0x" & to_hstring(data) & ". Incorrect parity bit for parity mark")); + when others => null; + end case; + end procedure check_parity; + begin - wait for time_per_half_bit; -- middle of start bit + wait for time_per_half_bit; -- middle of start bit assert rx = not uart.p_idle_state; - wait for time_per_bit; -- skip start bit + wait for time_per_bit; -- skip start bit for i in 0 to data'length-1 loop data(i) := rx; wait for time_per_bit; end loop; + if parity_mode /= none then + check_parity( + data => data, + parity_bit => rx); + wait for time_per_bit; + end if; + assert rx = uart.p_idle_state; end procedure; diff --git a/vunit/vhdl/verification_components/test/tb_uart.vhd b/vunit/vhdl/verification_components/test/tb_uart.vhd index 13ea70bd5..58ee84741 100644 --- a/vunit/vhdl/verification_components/test/tb_uart.vhd +++ b/vunit/vhdl/verification_components/test/tb_uart.vhd @@ -17,26 +17,38 @@ use work.stream_master_pkg.all; use work.stream_slave_pkg.all; entity tb_uart is - generic (runner_cfg : string); + generic ( + runner_cfg : string; + encoded_tb_cfg : string := ""); end entity; architecture a of tb_uart is - constant master_uart : uart_master_t := new_uart_master; + + -- Allow different parity modes for slave and master to check for errors. + constant master_parity_mode : parity_mode_t := parity_mode_t'value(get(encoded_tb_cfg, "master_parity_mode", parity_mode_t'image(default_parity_mode))); + constant slave_parity_mode : parity_mode_t := parity_mode_t'value(get(encoded_tb_cfg, "slave_parity_mode", parity_mode_t'image(default_parity_mode))); + + constant master_uart : uart_master_t := new_uart_master( + parity_mode => master_parity_mode); constant master_stream : stream_master_t := as_stream(master_uart); - constant slave_uart : uart_slave_t := new_uart_slave(data_length => 8); + constant slave_uart : uart_slave_t := new_uart_slave( + data_length => 8, + parity_mode => slave_parity_mode); constant slave_stream : stream_slave_t := as_stream(slave_uart); signal chan : std_logic; begin main : process - variable data : std_logic_vector(7 downto 0); - variable reference_queue : queue_t := new_queue; - variable reference : stream_reference_t; + constant uart_logger : logger_t := get_logger("uart"); + variable data : std_logic_vector(7 downto 0); + variable reference_queue : queue_t := new_queue; + variable reference : stream_reference_t; procedure test_baud_rate(baud_rate : natural) is - variable start : time; + constant parity_mode : parity_mode_t := master_uart.p_parity_mode; + variable start : time; variable got, expected : time; begin set_baud_rate(net, master_uart, baud_rate); @@ -49,7 +61,11 @@ begin wait_until_idle(net, as_sync(master_uart)); got := now - start; - expected := (10 * (1 sec)) / (baud_rate); + if parity_mode = none then + expected := (10 * (1 sec)) / (baud_rate); + else + expected := (11 * (1 sec)) / (baud_rate); + end if; check(abs (got - expected) <= 10 ns, "Unexpected baud rate got " & to_string(got) & " expected " & to_string(expected)); @@ -83,19 +99,99 @@ begin test_baud_rate(2000); test_baud_rate(7000); test_baud_rate(200000); + + elsif run("test parity") then + mock(uart_logger, error); + + debug("master_parity_mode = " & parity_mode_t'image(master_parity_mode) & lf & + "slave_parity_mode = " & parity_mode_t'image(slave_parity_mode)); + push_stream(net, master_stream, x"77"); + pop_stream(net, slave_stream, data); + + push_stream(net, master_stream, x"76"); + pop_stream(net, slave_stream, data); + + if (master_parity_mode = space and + slave_parity_mode = mark) then + -- Fails on any data. + check_log(uart_logger, "Equality check failed. Data 0x77. Incorrect parity bit for parity mark - Got 0. Expected 1.", error); + check_log(uart_logger, "Equality check failed. Data 0x76. Incorrect parity bit for parity mark - Got 0. Expected 1.", error); + + elsif (master_parity_mode = mark and + slave_parity_mode = space) then + -- Fails on any data. + check_log(uart_logger, "Equality check failed. Data 0x77. Incorrect parity bit for parity space - Got 1. Expected 0.", error); + check_log(uart_logger, "Equality check failed. Data 0x76. Incorrect parity bit for parity space - Got 1. Expected 0.", error); + + elsif (master_parity_mode = odd and + slave_parity_mode = even) then + -- Fails on even data. + check_log(uart_logger, "Equality check failed. Data 0x77. Incorrect parity bit for parity even - Got 1. Expected 0.", error); + check_log(uart_logger, "Equality check failed. Data 0x76. Incorrect parity bit for parity even - Got 0. Expected 1.", error); + + elsif (master_parity_mode = even and + slave_parity_mode = odd) then + -- Fails on any data. + check_log(uart_logger, "Equality check failed. Data 0x77. Incorrect parity bit for parity odd - Got 0. Expected 1.", error); + check_log(uart_logger, "Equality check failed. Data 0x76. Incorrect parity bit for parity odd - Got 1. Expected 0.", error); + + elsif (master_parity_mode = space and + slave_parity_mode = even) then + -- Fails on odd data. + check_log(uart_logger, "Equality check failed. Data 0x76. Incorrect parity bit for parity even - Got 0. Expected 1.", error); + + elsif (master_parity_mode = space and + slave_parity_mode = odd) then + -- Fails on even data. + check_log(uart_logger, "Equality check failed. Data 0x77. Incorrect parity bit for parity odd - Got 0. Expected 1.", error); + + elsif (master_parity_mode = mark and + slave_parity_mode = even) then + -- Fails on even data. + check_log(uart_logger, "Equality check failed. Data 0x77. Incorrect parity bit for parity even - Got 1. Expected 0.", error); + + elsif (master_parity_mode = mark and + slave_parity_mode = odd) then + -- Fails on odd data. + check_log(uart_logger, "Equality check failed. Data 0x76. Incorrect parity bit for parity odd - Got 1. Expected 0.", error); + + elsif (master_parity_mode = even and + slave_parity_mode = space) then + -- Fails on odd data. + check_log(uart_logger, "Equality check failed. Data 0x76. Incorrect parity bit for parity space - Got 1. Expected 0.", error); + + elsif (master_parity_mode = even and + slave_parity_mode = mark) then + -- Fails on even data. + check_log(uart_logger, "Equality check failed. Data 0x77. Incorrect parity bit for parity mark - Got 0. Expected 1.", error); + + elsif (master_parity_mode = odd and + slave_parity_mode = mark) then + -- Fails on odd data. + check_log(uart_logger, "Equality check failed. Data 0x76. Incorrect parity bit for parity mark - Got 0. Expected 1.", error); + + elsif (master_parity_mode = odd and + slave_parity_mode = space) then + -- Fails on even data. + check_log(uart_logger, "Equality check failed. Data 0x77. Incorrect parity bit for parity space - Got 1. Expected 0.", error); + + end if; + + unmock(uart_logger); end if; test_runner_cleanup(runner); + wait; end process; test_runner_watchdog(runner, 20 ms); - uart_master_inst: entity work.uart_master + uart_master_inst : entity work.uart_master generic map ( uart => master_uart) port map ( tx => chan); - uart_slave_inst: entity work.uart_slave + uart_slave_inst : entity work.uart_slave generic map ( uart => slave_uart) port map (