diff --git a/examples/vhdl/uart/run.py b/examples/vhdl/uart/run.py index 1f73b5f5a..45f240a19 100644 --- a/examples/vhdl/uart/run.py +++ b/examples/vhdl/uart/run.py @@ -27,4 +27,14 @@ VU.add_library("uart_lib").add_source_files(SRC_PATH / "*.vhd") VU.add_library("tb_uart_lib").add_source_files(SRC_PATH / "test" / "*.vhd") +for tb in VU.library("tb_uart_lib").get_test_benches(): + for parity in [0, 1, 2]: + generics = dict( + parity=parity + ) + tb.add_config( + name=",".join("{}={}".format(k, v) for (k, v) in generics.items()), + generics=generics, + ) + VU.main() diff --git a/examples/vhdl/uart/src/test/tb_uart_rx.vhd b/examples/vhdl/uart/src/test/tb_uart_rx.vhd index e9e136280..a55c3e92e 100644 --- a/examples/vhdl/uart/src/test/tb_uart_rx.vhd +++ b/examples/vhdl/uart/src/test/tb_uart_rx.vhd @@ -16,7 +16,8 @@ library uart_lib; entity tb_uart_rx is generic ( - runner_cfg : string); + runner_cfg : string; + parity : natural); end entity; architecture tb of tb_uart_rx is @@ -33,7 +34,9 @@ architecture tb of tb_uart_rx is signal num_overflows : integer := 0; - constant uart_bfm : uart_master_t := new_uart_master(initial_baud_rate => baud_rate); + constant uart_bfm : uart_master_t := new_uart_master(initial_baud_rate => baud_rate, + initial_parity => int_to_parity(parity)); + constant uart_stream : stream_master_t := as_stream(uart_bfm); constant axi_stream_bfm : axi_stream_slave_t := new_axi_stream_slave(data_length => tdata'length); @@ -87,7 +90,8 @@ begin dut : entity uart_lib.uart_rx generic map ( - cycles_per_bit => cycles_per_bit) + cycles_per_bit => cycles_per_bit, + parity => parity) port map ( clk => clk, rx => rx, diff --git a/examples/vhdl/uart/src/test/tb_uart_tx.vhd b/examples/vhdl/uart/src/test/tb_uart_tx.vhd index 62cd6ade3..157f7df38 100644 --- a/examples/vhdl/uart/src/test/tb_uart_tx.vhd +++ b/examples/vhdl/uart/src/test/tb_uart_tx.vhd @@ -19,7 +19,8 @@ library uart_lib; entity tb_uart_tx is generic ( - runner_cfg : string); + runner_cfg : string; + parity : natural); end entity; architecture tb of tb_uart_tx is @@ -35,6 +36,7 @@ architecture tb of tb_uart_tx is shared variable rnd_stimuli, rnd_expected : RandomPType; constant uart_bfm : uart_slave_t := new_uart_slave(initial_baud_rate => baud_rate, + initial_parity => int_to_parity(parity), data_length => tdata'length); constant uart_stream : stream_slave_t := as_stream(uart_bfm); @@ -79,7 +81,8 @@ begin dut : entity uart_lib.uart_tx generic map ( - cycles_per_bit => cycles_per_bit) + cycles_per_bit => cycles_per_bit, + parity => parity) port map ( clk => clk, tx => tx, diff --git a/examples/vhdl/uart/src/uart_rx.vhd b/examples/vhdl/uart/src/uart_rx.vhd index acd196dcb..2ae7079b4 100644 --- a/examples/vhdl/uart/src/uart_rx.vhd +++ b/examples/vhdl/uart/src/uart_rx.vhd @@ -15,7 +15,8 @@ use vunit_lib.logger_pkg.all; entity uart_rx is generic ( - cycles_per_bit : natural := 434); + cycles_per_bit : natural := 434; + parity : natural := 0); port ( clk : in std_logic; @@ -29,6 +30,7 @@ entity uart_rx is tvalid : out std_Logic := '0'; tdata : out std_logic_vector(7 downto 0)); begin + -- pragma translate_off check_stable(clk, check_enabled, tvalid, tready, tdata, "tdata must be stable until tready is active"); check_stable(clk, check_enabled, tvalid, tready, tvalid, "tvalid must be active until tready is active"); @@ -46,12 +48,30 @@ end entity; architecture a of uart_rx is signal tvalid_int : std_logic := '0'; + + function data_size( + constant parity: natural + ) return natural is + begin + if parity = 0 then + -- uart data (8 bits) + return 8; + elsif parity = 1 or parity = 2 then + -- uart data (8 bits)+ parity + return 9; + else + -- invalid mode + return 0; + end if; + end function data_size; + begin main : process (clk) type state_t is (idle, receiving, done); variable state : state_t := idle; + variable datawidth : natural := data_size(parity); variable cycles : natural range 0 to cycles_per_bit-1 := 0; - variable data : std_logic_vector(7 downto 0); + variable data : std_logic_vector(datawidth-1 downto 0); variable index : natural range 0 to data'length-1 := 0; begin if rising_edge(clk) then @@ -89,7 +109,7 @@ begin -- New output overwrites old output overflow <= tvalid_int and not tready; tvalid_int <= '1'; - tdata <= data; + tdata <= data(7 downto 0); state := idle; end case; diff --git a/examples/vhdl/uart/src/uart_tx.vhd b/examples/vhdl/uart/src/uart_tx.vhd index 23993adaa..45b476abd 100644 --- a/examples/vhdl/uart/src/uart_tx.vhd +++ b/examples/vhdl/uart/src/uart_tx.vhd @@ -15,7 +15,8 @@ use vunit_lib.logger_pkg.all; entity uart_tx is generic ( - cycles_per_bit : natural := 434); + cycles_per_bit : natural := 434; + parity : natural := 0); port ( clk : in std_logic; @@ -44,12 +45,42 @@ end entity; architecture a of uart_tx is signal tready_int : std_logic := '0'; + + function data_size( + constant parity: natural + ) return natural is + begin + if parity = 0 then + -- uart data (8 bits) + return 8; + elsif parity = 1 or parity = 2 then + -- uart data (8 bits)+ parity + return 9; + else + -- invalid mode + return 0; + end if; + end function data_size; + + function even_parity (data : std_logic_vector) return std_logic is + begin + return xor data; + + end function even_parity; + + function odd_parity (data : std_logic_vector) return std_logic is + begin + + return xnor data; + end function odd_parity; + begin main : process (clk) type state_t is (idle, sending); variable state : state_t := idle; + variable datawidth : natural := data_size(parity) + 2; variable cycles : natural range 0 to cycles_per_bit-1 := 0; - variable data : std_logic_vector(9 downto 0); + variable data : std_logic_vector(datawidth-1 downto 0); variable index : natural range 0 to data'length-1 := 0; begin if rising_edge(clk) then @@ -60,7 +91,14 @@ begin state := sending; cycles := 0; index := 0; - data := '1' & tdata & '0'; + + if parity = 0 then + data := '1' & tdata & '0'; + elsif parity = 1 then + data := '1' & odd_parity(tdata) & tdata & '0'; + elsif parity = 2 then + data := '1' & even_parity(tdata) & tdata & '0'; + end if; end if; when sending => tx <= data(0); diff --git a/vunit/vhdl/com/src/com_types.vhd b/vunit/vhdl/com/src/com_types.vhd index 3d10519b2..ccfacf72e 100644 --- a/vunit/vhdl/com/src/com_types.vhd +++ b/vunit/vhdl/com/src/com_types.vhd @@ -48,6 +48,11 @@ package com_types_pkg is duplicate_actor_name_error, new_actor_from_root_id_error); + type parity_t is ( + PARITY_NONE, + PARITY_ODD, + PARITY_EVEN); + subtype com_error_t is com_status_t range timeout to new_actor_from_root_id_error; -- All fields of the actor type are private @@ -406,6 +411,9 @@ package com_types_pkg is -- Private impure function is_valid(code : integer) return boolean; + + function int_to_parity(value : integer) return parity_t; + end package; package body com_types_pkg is @@ -889,4 +897,18 @@ package body com_types_pkg is return (p_id_number => value); end; + function int_to_parity(value: integer) return parity_t is + begin + case value is + when 0 => + return PARITY_NONE; + when 1 => + return PARITY_ODD; + when 2 => + return PARITY_EVEN; + when others => + return PARITY_NONE; + end case; + end function int_to_parity; + end package body com_types_pkg; diff --git a/vunit/vhdl/verification_components/src/uart_master.vhd b/vunit/vhdl/verification_components/src/uart_master.vhd index 0b2b49384..5fb77234e 100644 --- a/vunit/vhdl/verification_components/src/uart_master.vhd +++ b/vunit/vhdl/verification_components/src/uart_master.vhd @@ -17,10 +17,12 @@ use work.uart_pkg.all; entity uart_master is generic ( - uart : uart_master_t); + uart : uart_master_t + ); port ( - tx : out std_logic := uart.p_idle_state); -end entity; + tx : out std_logic := uart.p_idle_state + ); +end entity uart_master; architecture a of uart_master is begin @@ -28,7 +30,9 @@ begin main : process procedure uart_send(data : std_logic_vector; signal tx : out std_logic; - baud_rate : integer) is + baud_rate : integer; + parity : parity_t + ) is constant time_per_bit : time := (10**9 / baud_rate) * 1 ns; procedure send_bit(value : std_logic) is @@ -43,11 +47,19 @@ begin for i in 0 to data'length-1 loop send_bit(data(i)); end loop; + + if parity = PARITY_ODD then + send_bit(odd_parity(data)); + elsif parity = PARITY_EVEN then + send_bit(even_parity(data)); + end if; + send_bit(uart.p_idle_state); end procedure; variable msg : msg_t; variable baud_rate : natural := uart.p_baud_rate; + variable parity : parity_t := uart.p_parity; variable msg_type : msg_type_t; begin receive(net, uart.p_actor, msg); @@ -56,9 +68,11 @@ begin handle_sync_message(net, msg_type, msg); if msg_type = stream_push_msg then - uart_send(pop_std_ulogic_vector(msg), tx, baud_rate); + uart_send(pop_std_ulogic_vector(msg), tx, baud_rate, parity); elsif msg_type = uart_set_baud_rate_msg then baud_rate := pop(msg); + elsif msg_type = uart_set_parity_msg then + parity := int_to_parity(pop(msg)); else unexpected_msg_type(msg_type); end if; diff --git a/vunit/vhdl/verification_components/src/uart_pkg.vhd b/vunit/vhdl/verification_components/src/uart_pkg.vhd index 690003b4f..b558324c5 100644 --- a/vunit/vhdl/verification_components/src/uart_pkg.vhd +++ b/vunit/vhdl/verification_components/src/uart_pkg.vhd @@ -18,12 +18,14 @@ package uart_pkg is type uart_master_t is record p_actor : actor_t; p_baud_rate : natural; + p_parity : parity_t; p_idle_state : std_logic; - end record; + end record uart_master_t; type uart_slave_t is record p_actor : actor_t; p_baud_rate : natural; + p_parity : parity_t; p_idle_state : std_logic; p_data_length : positive; end record; @@ -37,14 +39,27 @@ package uart_pkg is uart_slave : uart_slave_t; baud_rate : natural); + -- 0 = no parity, 1 = odd parity, 2 = even parity + procedure set_parity(signal net : inout network_t; + uart_master : uart_master_t; + parity : parity_t); + + procedure set_parity(signal net : inout network_t; + uart_slave : uart_slave_t; + parity : parity_t); + constant default_baud_rate : natural := 115200; constant default_idle_state : std_logic := '1'; constant default_data_length : positive := 8; + constant default_parity : parity_t := PARITY_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; + initial_parity : parity_t := default_parity) 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; + initial_parity : parity_t := default_parity) 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; @@ -52,24 +67,38 @@ package uart_pkg is impure function as_sync(uart_slave : uart_slave_t) return sync_handle_t; constant uart_set_baud_rate_msg : msg_type_t := new_msg_type("uart set baud rate"); + + constant uart_set_parity_msg : msg_type_t := new_msg_type("uart set parity"); + + function even_parity(data : std_logic_vector) return std_logic; + function odd_parity (data : std_logic_vector) return std_logic; + 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; + initial_parity : parity_t := default_parity + ) return uart_master_t is begin return (p_actor => new_actor, p_baud_rate => initial_baud_rate, + p_parity => initial_parity, p_idle_state => idle_state); end; - impure function new_uart_slave(initial_baud_rate : natural := default_baud_rate; + 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; + initial_parity : parity_t := default_parity + ) return uart_slave_t is + begin return (p_actor => new_actor, p_baud_rate => initial_baud_rate, + p_parity => initial_parity, p_idle_state => idle_state, p_data_length => data_length); end; @@ -116,4 +145,40 @@ package body uart_pkg is begin set_baud_rate(net, uart_slave.p_actor, baud_rate); end; + + procedure set_parity(signal net : inout network_t; + actor : actor_t; + parity : parity_t) is + variable msg : msg_t := new_msg(uart_set_parity_msg); + begin + + push(msg, parity_t'pos(parity)); + send(net, actor, msg); + end; + + procedure set_parity(signal net : inout network_t; + uart_master : uart_master_t; + parity : parity_t) is + begin + set_parity(net, uart_master.p_actor, parity); + end; + + procedure set_parity(signal net : inout network_t; + uart_slave : uart_slave_t; + parity : parity_t) is + begin + set_parity(net, uart_slave.p_actor, parity); + end; + + function even_parity (data : std_logic_vector) return std_logic is + begin + return xor data; + + end function even_parity; + + function odd_parity (data : std_logic_vector) return std_logic is + begin + + return xnor data; + end function odd_parity; end package body; diff --git a/vunit/vhdl/verification_components/src/uart_slave.vhd b/vunit/vhdl/verification_components/src/uart_slave.vhd index 480f4558e..29dfb0007 100644 --- a/vunit/vhdl/verification_components/src/uart_slave.vhd +++ b/vunit/vhdl/verification_components/src/uart_slave.vhd @@ -24,6 +24,7 @@ end entity; architecture a of uart_slave is signal baud_rate : natural := uart.p_baud_rate; + signal parity : parity_t := uart.p_parity; signal local_event : std_logic := '0'; constant data_queue : queue_t := new_queue; begin @@ -37,7 +38,8 @@ begin if msg_type = uart_set_baud_rate_msg then baud_rate <= pop(msg); - + elsif msg_type = uart_set_parity_msg then + parity <= int_to_parity(pop(msg)); elsif msg_type = stream_pop_msg then reply_msg := new_msg; if not (length(data_queue) > 0) then @@ -56,9 +58,12 @@ begin recv : process procedure uart_recv(variable data : out std_logic_vector; signal rx : in std_logic; - baud_rate : integer) is + baud_rate : integer; + parity : parity_t) 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; + variable parity_bit : std_logic; + variable parity_calc : std_logic; begin wait for time_per_half_bit; -- middle of start bit assert rx = not uart.p_idle_state; @@ -69,13 +74,37 @@ begin wait for time_per_bit; end loop; + if parity = PARITY_ODD then + parity_bit := rx; + parity_calc := odd_parity(data); + wait for 0 ns; + + if parity_bit /= parity_calc then + report "odd parity mismatch" + severity WARNING; + end if; + + wait for time_per_bit; + elsif parity = PARITY_EVEN then + parity_bit := rx; + parity_calc := even_parity(data); + wait for 0 ns; + + if parity_bit /= parity_calc then + report "even parity mismatch" + severity WARNING; + end if; + + wait for time_per_bit; + end if; + assert rx = uart.p_idle_state; end procedure; variable data : std_logic_vector(uart.p_data_length-1 downto 0); begin wait on rx until rx = not uart.p_idle_state; - uart_recv(data, rx, baud_rate); + uart_recv(data, rx, baud_rate, parity); push_std_ulogic_vector(data_queue, data); local_event <= '1'; wait for 0 ns; diff --git a/vunit/vhdl/verification_components/test/tb_uart.vhd b/vunit/vhdl/verification_components/test/tb_uart.vhd index a7e6e5037..cfb769e98 100644 --- a/vunit/vhdl/verification_components/test/tb_uart.vhd +++ b/vunit/vhdl/verification_components/test/tb_uart.vhd @@ -27,6 +27,12 @@ architecture a of tb_uart is constant slave_uart : uart_slave_t := new_uart_slave(data_length => 8); constant slave_stream : stream_slave_t := as_stream(slave_uart); + -- parity related VCs + constant master_uart_p : uart_master_t := new_uart_master; + constant master_stream_p : stream_master_t := as_stream(master_uart); + + constant slave_uart_p : uart_slave_t := new_uart_slave(data_length => 8); + constant slave_stream_p : stream_slave_t := as_stream(slave_uart); signal chan : std_logic; begin @@ -83,6 +89,28 @@ begin test_baud_rate(2000); test_baud_rate(7000); test_baud_rate(200000); + elsif run("test_parity_odd") then + set_parity(net, master_uart_p, PARITY_ODD); + set_parity(net, slave_uart_p, PARITY_ODD); + + for i in 0 to 7 loop + push_stream(net, master_stream_p, + std_logic_vector(to_unsigned(i+1, data'length))); + pop_stream(net, slave_stream_p, data); + check_equal(data, std_logic_vector(to_unsigned(i+1, data'length)), "pop stream data"); + end loop; + + elsif run("test_parity_even") then + set_parity(net, master_uart_p, PARITY_EVEN); + set_parity(net, slave_uart_p, PARITY_EVEN); + + for i in 0 to 7 loop + push_stream(net, master_stream_p, + std_logic_vector(to_unsigned(i+1, data'length))); + pop_stream(net, slave_stream_p, data); + check_equal(data, std_logic_vector(to_unsigned(i+1, data'length)), "pop stream data"); + end loop; + end if; test_runner_cleanup(runner);