Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parity bit in the uart VCs #906

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions vunit/vhdl/verification_components/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
19 changes: 15 additions & 4 deletions vunit/vhdl/verification_components/src/uart_master.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down
23 changes: 17 additions & 6 deletions vunit/vhdl/verification_components/src/uart_pkg.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,21 @@ 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
p_actor : actor_t;
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]
Expand All @@ -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;
Expand All @@ -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
Expand Down
47 changes: 38 additions & 9 deletions vunit/vhdl/verification_components/src/uart_slave.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;

Expand Down
116 changes: 106 additions & 10 deletions vunit/vhdl/verification_components/test/tb_uart.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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));
Expand Down Expand Up @@ -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 (
Expand Down