From 6d023a1fedb92085f8d8d06c5be1825bad586d1d Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sat, 17 Feb 2024 16:04:45 +0100 Subject: [PATCH] tests: add packages for communication with i2c bus model --- tb/i2c/model/i2c_bus_pkg.vhd | 283 ++++++++++++++++++++++++++++++++ tb/i2c/model/i2c_master_pkg.vhd | 112 +++++++++++++ tb/i2c/model/i2c_slave_pkg.vhd | 135 +++++++++++++++ 3 files changed, 530 insertions(+) create mode 100644 tb/i2c/model/i2c_bus_pkg.vhd create mode 100644 tb/i2c/model/i2c_master_pkg.vhd create mode 100644 tb/i2c/model/i2c_slave_pkg.vhd diff --git a/tb/i2c/model/i2c_bus_pkg.vhd b/tb/i2c/model/i2c_bus_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..4a9d47cf52b70cd1597a2835d196a83c6fe967b6 --- /dev/null +++ b/tb/i2c/model/i2c_bus_pkg.vhd @@ -0,0 +1,283 @@ +library ieee; +use ieee.std_logic_1164.all; + +library vunit_lib; +context vunit_lib.vunit_context; +context vunit_lib.com_context; + +package i2c_bus_pkg is + constant free_bus_msg : msg_type_t := new_msg_type("free bus"); + constant set_scl_freq_msg : msg_type_t := new_msg_type("scl freq"); + constant gen_start_cond_msg : msg_type_t := new_msg_type("gen start cond"); + constant gen_stop_cond_msg : msg_type_t := new_msg_type("gen stop cond"); + constant gen_clocks_msg : msg_type_t := new_msg_type("gen clocks"); + constant send_data_msg : msg_type_t := new_msg_type("send data"); + constant send_data_clocks_msg : msg_type_t := new_msg_type("send data and clocks"); + + constant auto_ack_msg : msg_type_t := new_msg_type("auto acknowledge"); + + constant wait_start_cond_msg : msg_type_t := new_msg_type("wait start cond"); + constant wait_stop_cond_msg : msg_type_t := new_msg_type("wait stop cond"); + constant wait_clocks_msg : msg_type_t := new_msg_type("wait clocks"); + + constant check_data_msg : msg_type_t := new_msg_type("check data"); + constant check_data_clocks_msg : msg_type_t := new_msg_type("check data and gen clocks"); + + constant wait_until_idle : msg_type_t := new_msg_type("wait until idle"); + + impure function get_actor ( + constant inst_name : string) + return actor_t; + + procedure free_bus ( + constant actor : in actor_t); + + procedure set_scl_frequency ( + constant frequency : in real; + constant actor : in actor_t); + + procedure gen_start_cond ( + constant actor : in actor_t); + + procedure gen_stop_cond ( + constant actor : in actor_t); + + procedure gen_clocks ( + constant times : in natural; + constant timeout : in time; + constant actor : in actor_t); + + procedure send_data ( + constant data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t); + + procedure send_ack ( + constant timeout : in time; + constant actor : in actor_t); + + procedure send_ack_and_clock ( + constant timeout : in time; + constant actor : in actor_t); + + procedure send_data_and_clock ( + constant data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t); + + procedure wait_for_start_cond ( + constant timeout : in time; + constant actor : in actor_t); + + procedure wait_for_stop_cond ( + constant timeout : in time; + constant actor : in actor_t); + + procedure wait_for_clocks ( + constant times : in natural; + constant timeout : in time; + constant actor : in actor_t); + + procedure check_data ( + constant exp_data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t); + + procedure check_data_gen_clock ( + constant exp_data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t); + + procedure check_ack_gen_clock ( + constant timeout : in time; + constant actor : in actor_t); + + procedure check_ack ( + constant timeout : in time; + constant actor : in actor_t); + + procedure set_auto_ack ( + constant auto_ack : in boolean; + constant address : in std_logic_vector(6 downto 0); + constant bytes_count : in natural; + constant actor : in actor_t); + +end package i2c_bus_pkg; + +package body i2c_bus_pkg is + + impure function get_actor ( + constant inst_name : string) + return actor_t is + begin + return find(inst_name); + end function get_actor; + + procedure free_bus ( + constant actor : in actor_t) is + variable msg : msg_t := new_msg(free_bus_msg); + begin + send(net, actor, msg); + end procedure free_bus; + + procedure set_scl_frequency ( + constant frequency : in real; + constant actor : in actor_t) is + variable msg : msg_t := new_msg(set_scl_freq_msg); + begin + push(msg, frequency); + send(net, actor, msg); + end procedure set_scl_frequency; + + procedure gen_start_cond ( + constant actor : in actor_t) is + variable msg : msg_t := new_msg(gen_start_cond_msg); + begin + send(net, actor, msg); + end procedure gen_start_cond; + + procedure gen_stop_cond ( + constant actor : in actor_t) is + variable msg : msg_t := new_msg(gen_stop_cond_msg); + begin + send(net, actor, msg); + end procedure gen_stop_cond; + + procedure gen_clocks ( + constant times : in natural; + constant timeout : in time; + constant actor : in actor_t) is + variable msg : msg_t := new_msg(gen_clocks_msg); + begin + push(msg, times); + push(msg, timeout); + send(net, actor, msg); + end procedure gen_clocks; + + procedure send_data ( + constant data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t) is + variable msg : msg_t := new_msg(send_data_msg); + variable msg_data : std_logic_vector(1023 downto 0); + begin + msg_data(data'length - 1 downto 0) := data(data'range); + push(msg, data'length); + push(msg, msg_data); + push(msg, timeout); + send(net, actor, msg); + end procedure send_data; + + procedure send_ack ( + constant timeout : in time; + constant actor : in actor_t) is + begin + send_data("0", timeout, actor); + end procedure send_ack; + + procedure send_ack_and_clock ( + constant timeout : in time; + constant actor : in actor_t) is + begin + send_data_and_clock("0", timeout, actor); + end procedure send_ack_and_clock; + + procedure send_data_and_clock ( + constant data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t) is + variable msg : msg_t := new_msg(send_data_clocks_msg); + variable msg_data : std_logic_vector(1023 downto 0); + begin + msg_data(data'length - 1 downto 0) := data(data'range); + push(msg, data'length); + push(msg, msg_data); + push(msg, timeout); + send(net, actor, msg); + end procedure send_data_and_clock; + + procedure wait_for_start_cond ( + constant timeout : in time; + constant actor : in actor_t) is + variable msg : msg_t := new_msg(wait_start_cond_msg); + begin + push(msg, timeout); + send(net, actor, msg); + end procedure wait_for_start_cond; + + procedure wait_for_stop_cond ( + constant timeout : in time; + constant actor : in actor_t) is + variable msg : msg_t := new_msg(wait_stop_cond_msg); + begin + push(msg, timeout); + send(net, actor, msg); + end procedure wait_for_stop_cond; + + procedure wait_for_clocks ( + constant times : in natural; + constant timeout : in time; + constant actor : in actor_t) is + variable msg : msg_t := new_msg(wait_clocks_msg); + begin + push(msg, times); + push(msg, timeout); + send(net, actor, msg); + end procedure wait_for_clocks; + + procedure check_data ( + constant exp_data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t) is + variable msg_data : std_logic_vector(1023 downto 0); + variable msg : msg_t := new_msg(check_data_msg); + begin + msg_data(exp_data'length - 1 downto 0) := exp_data(exp_data'range); + push(msg, exp_data'length); + push(msg, msg_data); + push(msg, timeout); + send(net, actor, msg); + end procedure check_data; + + procedure check_data_gen_clock ( + constant exp_data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t) is + variable msg_data : std_logic_vector(1023 downto 0); + variable msg : msg_t := new_msg(check_data_clocks_msg); + begin + msg_data(exp_data'length - 1 downto 0) := exp_data(exp_data'range); + push(msg, exp_data'length); + push(msg, msg_data); + push(msg, timeout); + send(net, actor, msg); + end procedure check_data_gen_clock; + + procedure check_ack_gen_clock ( + constant timeout : in time; + constant actor : in actor_t) is + begin + check_data_gen_clock("0", timeout, actor); + end procedure check_ack_gen_clock; + + procedure check_ack ( + constant timeout : in time; + constant actor : in actor_t) is + begin + check_data("0", timeout, actor); + end procedure check_ack; + + procedure set_auto_ack ( + constant auto_ack : in boolean; + constant address : in std_logic_vector(6 downto 0); + constant bytes_count : in natural; + constant actor : in actor_t) is + variable msg : msg_t := new_msg(auto_ack_msg); + begin + push(msg, auto_ack); + push(msg, address); + push(msg, bytes_count); + send(net, actor, msg); + end procedure set_auto_ack; + +end package body i2c_bus_pkg; diff --git a/tb/i2c/model/i2c_master_pkg.vhd b/tb/i2c/model/i2c_master_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..6481e06b0a8805f2fef7818961a3e43fd185aac4 --- /dev/null +++ b/tb/i2c/model/i2c_master_pkg.vhd @@ -0,0 +1,112 @@ +library ieee; +use ieee.std_logic_1164.all; + +library vunit_lib; +context vunit_lib.vunit_context; +context vunit_lib.com_context; + +use work.i2c_bus_pkg; + +package i2c_master_pkg is + + procedure write ( + constant address : in std_logic_vector(6 downto 0); + constant data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t); + + procedure read ( + constant address : in std_logic_vector(6 downto 0); + constant data : in std_logic_vector; + constant exp_data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t); + + procedure write_read ( + constant address : in std_logic_vector(6 downto 0); + constant data : in std_logic_vector; + constant exp_data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t); + +end package i2c_master_pkg; + +package body i2c_master_pkg is + + procedure write ( + constant address : in std_logic_vector(6 downto 0); + constant data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t) is + begin + if data'length mod 8 /= 0 then + failure("The number of bits to write to the slave have to be divisible by 8."); + end if; + + i2c_bus_pkg.gen_start_cond(actor); + i2c_bus_pkg.send_data_and_clock(address & '0', timeout, actor); + + for i in 0 to data'length/8 - 1 loop + i2c_bus_pkg.send_data_and_clock(data(data'left - i*8 downto data'left - 7 - i*8), timeout, actor); + i2c_bus_pkg.check_ack_gen_clock(timeout, actor); + end loop; -- i + + i2c_bus_pkg.gen_stop_cond(actor); + end procedure write; + + procedure read ( + constant address : in std_logic_vector(6 downto 0); + constant exp_data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t) is + begin + if exp_data'length mod 8 /= 0 then + failure("The number of bits to read from the slave have to be divisible by 8."); + end if; + + i2c_bus_pkg.gen_start_cond(actor); + i2c_bus_pkg.send_data_and_clock(address & '1', timeout, actor); + + for i in 0 to exp_data'length/8 - 1 loop + i2c_bus_pkg.check_data_gen_clock(exp_data(exp_data'left - i*8 downto exp_data'left - 7 - i*8), timeout, actor); + i2c_bus_pkg.send_ack_and_clock(timeout, actor); + end loop; -- i + + i2c_bus_pkg.gen_stop_cond(actor); + end procedure read; + + procedure write_read ( + constant address : in std_logic_vector(6 downto 0); + constant data : in std_logic_vector; + constant exp_data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t) is + begin + if data'length mod 8 /= 0 then + failure("The number of bits to write to the slave have to be divisible by 8."); + end if; + + if exp_data'length mod 8 /= 0 then + failure("The number of bits to read from the slave have to be divisible by 8."); + end if; + + i2c_bus_pkg.gen_start_cond(actor); + i2c_bus_pkg.send_data_and_clock(address & '0', timeout, actor); + + for i in 0 to data'length/8 - 1 loop + i2c_bus_pkg.send_data_and_clock(data(data'left - i*8 downto data'left - 7 - i*8), timeout, actor); + i2c_bus_pkg.check_ack_gen_clock(timeout, actor); + end loop; -- i + + i2c_bus_pkg.gen_start_cond(actor); + i2c_bus_pkg.send_data_and_clock(address & '1', timeout, actor); + + for i in 0 to exp_data'length/8 - 1 loop + i2c_bus_pkg.check_data_gen_clock(exp_data(exp_data'left - i*8 downto exp_data'left - 7 - i*8), timeout, actor); + i2c_bus_pkg.send_ack_and_clock(timeout, actor); + end loop; -- i + + i2c_bus_pkg.gen_stop_cond(actor); + end procedure write_read; + +end package body i2c_master_pkg; diff --git a/tb/i2c/model/i2c_slave_pkg.vhd b/tb/i2c/model/i2c_slave_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..37f43d3e672b11c6ca44f3eae9e9c5b15da272e6 --- /dev/null +++ b/tb/i2c/model/i2c_slave_pkg.vhd @@ -0,0 +1,135 @@ +--- read(address, exp_data, timeout) +--- wait start +--- wait address +--- ack (if matching) +--- read data, check it +--- check ack on every byte +--- wait stop? +--- write(address, data, timeout) +--- wait start +--- wait address +--- ack (if matching) +--- write data, check ack +--- wait stop? +--- read_write(address, exp_data, data, timeout) +--- wait start +--- wait address +--- ack (if matcihng) +--- start matching bytes +--- ack every byte +--- wait start +--- wait address +--- ack (if matching) +--- write data, check ack + +library ieee; +use ieee.std_logic_1164.all; + +library vunit_lib; +context vunit_lib.vunit_context; +context vunit_lib.com_context; + +use work.i2c_bus_pkg; + +package i2c_slave_pkg is + + procedure write ( + constant address : in std_logic_vector(6 downto 0); + constant exp_data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t); + + procedure read ( + constant address : in std_logic_vector(6 downto 0); + constant data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t); + + procedure write_read ( + constant address : in std_logic_vector(6 downto 0); + constant exp_data : in std_logic_vector; + constant data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t); + +end package i2c_slave_pkg; + +package body i2c_slave_pkg is + + procedure write ( + constant address : in std_logic_vector(6 downto 0); + constant exp_data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t) is + begin + if exp_data'length mod 8 /= 0 then + failure("The number of bits to be written to the slave have to be divisible by 8."); + end if; + + i2c_bus_pkg.wait_for_start_cond(timeout, actor); + i2c_bus_pkg.check_data(address & '0', timeout, actor); + + for i in 0 to exp_data'length/8 - 1 loop + i2c_bus_pkg.check_data(exp_data(exp_data'left - i*8 downto exp_data'left - 7 - i*8), timeout, actor); + i2c_bus_pkg.send_ack(timeout, actor); + end loop; -- i + + i2c_bus_pkg.wait_for_stop_cond(timeout, actor); + end procedure write; + + procedure read ( + constant address : in std_logic_vector(6 downto 0); + constant data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t) is + begin + if data'length mod 8 /= 0 then + failure("The number of bits to be read from the slave have to be divisible by 8."); + end if; + + i2c_bus_pkg.wait_for_start_cond(timeout, actor); + i2c_bus_pkg.check_data(address & '1', timeout, actor); + + for i in 0 to data'length/8 - 1 loop + i2c_bus_pkg.send_data(data(data'left - i*8 downto data'left - 7 - i*8), timeout, actor); + i2c_bus_pkg.check_ack(timeout, actor); + end loop; -- i + + i2c_bus_pkg.wait_for_stop_cond(timeout, actor); + end procedure read; + + procedure write_read ( + constant address : in std_logic_vector(6 downto 0); + constant data : in std_logic_vector; + constant exp_data : in std_logic_vector; + constant timeout : in time; + constant actor : in actor_t) is + begin + if exp_data'length mod 8 /= 0 then + failure("The number of bits to be written to the slave have to be divisible by 8."); + end if; + if data'length mod 8 /= 0 then + failure("The number of bits to be read from the slave have to be divisible by 8."); + end if; + + i2c_bus_pkg.wait_for_start_cond(timeout, actor); + i2c_bus_pkg.send_data_and_clock(address & '0', timeout, actor); + + for i in 0 to exp_data'length/8 - 1 loop + i2c_bus_pkg.check_data(exp_data(exp_data'left - i*8 downto exp_data'left - 7 - i*8), timeout, actor); + i2c_bus_pkg.send_ack(timeout, actor); + end loop; -- i + + i2c_bus_pkg.wait_for_start_cond(timeout, actor); + i2c_bus_pkg.send_data_and_clock(address & '1', timeout, actor); + + for i in 0 to data'length/8 - 1 loop + i2c_bus_pkg.send_data(data(data'left - i*8 downto data'left - 7 - i*8), timeout, actor); + i2c_bus_pkg.check_ack(timeout, actor); + end loop; -- i + + i2c_bus_pkg.wait_for_stop_cond(timeout, actor); + end procedure write_read; + + +end package body i2c_slave_pkg;