From 78ec71947645e90e3aadadb07ca773ec466b5d02 Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sat, 17 Feb 2024 18:25:00 +0100 Subject: [PATCH] tests: add message handler for i2c bus model --- tb/i2c/model/i2c_bus_mod.vhd | 161 ++++++++++++++++++++++++++++++++ tb/i2c/model/i2c_bus_pkg.vhd | 12 +++ tb/i2c/model/i2c_master_pkg.vhd | 4 + tb/i2c/model/i2c_slave_pkg.vhd | 28 +----- 4 files changed, 181 insertions(+), 24 deletions(-) create mode 100644 tb/i2c/model/i2c_bus_mod.vhd diff --git a/tb/i2c/model/i2c_bus_mod.vhd b/tb/i2c/model/i2c_bus_mod.vhd new file mode 100644 index 0000000..153589b --- /dev/null +++ b/tb/i2c/model/i2c_bus_mod.vhd @@ -0,0 +1,161 @@ +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.all; + +entity i2c_bus_mod is + + generic ( + inst_name : string; + default_stretch_timeout: time; + default_scl_freq: real); + + port ( + sda_io : inout std_logic; + scl_io : inout std_logic); + +end entity i2c_bus_mod; + +architecture behav of i2c_bus_mod is + constant logger : logger_t := get_logger("i2c_bus_mod::" & inst_name); + constant checker : checker_t := new_checker(logger); + + signal s_free_sda_req : event_t := new_event("free sda"); + signal s_free_scl_req : event_t := new_event("free scl"); + + signal s_start_cond_req : event_t := new_event("start cond gen"); + signal s_stop_cond_req : event_t := new_event("stop cond gen"); + + signal s_data_req : event_t := new_event("gen data"); + signal s_clk_req : event_t := new_event("gen data"); + + signal s_scl_stretch_timeout : time := default_stretch_timeout; + signal s_scl_frequency : real := default_scl_freq; + + signal s_request_clks_count : natural; + signal s_request_data : std_logic_vector(1023 downto 0); + + signal s_auto_ack_req : event_t := new_event("auto ack"); + signal s_auto_ack_address : std_logic_vector(6 downto 0); + signal s_auto_ack_active : boolean; + signal s_auto_ack_count : natural; + + procedure wait_for_start ( + signal sda : inout std_logic; + signal scl : inout std_logic; + constant timeout : in time); + + procedure wait_for_stop ( + signal sda : inout std_logic; + signal scl : inout std_logic; + constant timeout : in time); + + procedure wait_for_clock ( + signal sda : inout std_logic; + signal scl : inout std_logic; + constant timeout : in time); + + procedure write_bit ( + signal sda : inout std_logic; + signal scl : inout std_logic; + constant data : in std_logic; + constant timeout : in time; + variable continue : inout boolean); + + function read_bit ( + signal sda : inout std_logic; + signal scl : inout std_logic; + constant data : in std_logic; + constant timeout : in time; + variable continue : inout boolean) return std_logic; + + function read_data ( + signal sda : inout std_logic; + signal scl : inout std_logic; + constant timeout : in time; + variable continue : inout boolean) return std_logic_vector; + +begin -- architecture behav + + message_handler: process is + constant self : actor_t := new_actor(inst_name); + + variable msg : msg_t; + variable msg_type : msg_type_t; + begin -- process message_handler + receive(net, self, msg); + msg_type := message_type(msg); + + if msg_type = free_bus_msg then + notify(s_free_scl_req); + notify(s_free_sda_req); + elsif msg_type = set_scl_freq_msg then + v_frequency := pop(msg); + s_scl_frequency <= v_frequency; + s_scl_period <= get_period(v_frequency); + elsif msg_type = gen_start_cond_msg then + notify(s_start_cond_req); + wait until is_active(s_start_cond_done); + elsif msg_type = gen_stop_cond_msg then + s_timeout <= pop(msg); + notify(s_stop_cond_req); + wait until is_active(s_stop_cond_done); + elsif msg_type = gen_clocks_msg then + s_clk_count <= pop(msg); + s_timeout <= pop(msg); + notify(s_gen_clk_req); + wait until is_active(s_gen_clk_done); + elsif msg_type = send_data_msg then + s_data_count <= pop(msg); + s_data <= pop(msg); + s_timeout <= pop(msg); + notify(s_data_req); + wait until is_active(s_data_req); + elsif msg_type = send_data_clocks_msg then + v_count := pop(msg); + s_data_count <= v_count; + s_clk_count <= v_count; + s_data <= pop(msg); + s_timeout <= pop(msg); + notify(s_gen_clk_req, s_data_clk_req); + wait until is_active(s_gen_clk_done); + elsif msg_type = auto_ack_msg then + s_auto_ack_active <= pop(msg); + s_auto_ack_address <= pop(msg); + s_auto_ack_count <= pop(msg); + notify(s_auto_ack_req); + elsif msg_type = wait_start_cond_msg then + wait_for_start(sda_io, scl_io, pop(msg)); + elsif msg_type = wait_stop_cond_msg then + wait_for_stop(sda_io, scl_io, pop(msg)); + elsif msg_type = wait_clocks_msg then + v_count := pop(msg); + v_timeout := pop(msg); + for i in 1 to v_count loop + wait_for_clock(sda_io, scl_io, v_timeout); + end loop; -- i + elsif msg_type = check_data_msg then + s_data_count <= pop(msg); + s_data_exp <= pop(msg); + s_timeout <= pop(msg); + notify(s_check_data_req); + wait until is_active(s_check_data_done); + elsif msg_type = check_data_clocks_msg then + v_count := pop(msg); + s_data_count <= v_count; + s_clk_count <= v_count; + s_data_exp <= pop(msg); + s_timeout <= pop(msg); + notify(s_gen_clk_req, s_check_data_req); + wait until is_active(s_gen_clk_done); + elsif msg_type = wait_until_idle then + acknowledge(net, msg, true); + end if; + + end process message_handler; + +end architecture behav; diff --git a/tb/i2c/model/i2c_bus_pkg.vhd b/tb/i2c/model/i2c_bus_pkg.vhd index 4a9d47c..69e2144 100644 --- a/tb/i2c/model/i2c_bus_pkg.vhd +++ b/tb/i2c/model/i2c_bus_pkg.vhd @@ -5,6 +5,12 @@ library vunit_lib; context vunit_lib.vunit_context; context vunit_lib.com_context; +-- except for wait_until_idle, +-- the procedures take 0 simulation time. +-- wait_until_idle will take time until all +-- operations requested on the i2c were +-- performed. + 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"); @@ -37,9 +43,11 @@ package i2c_bus_pkg is constant actor : in actor_t); procedure gen_start_cond ( + constant timeout : in time; constant actor : in actor_t); procedure gen_stop_cond ( + constant timeout : in time; constant actor : in actor_t); procedure gen_clocks ( @@ -130,16 +138,20 @@ package body i2c_bus_pkg is end procedure set_scl_frequency; procedure gen_start_cond ( + constant timeout : in time; constant actor : in actor_t) is variable msg : msg_t := new_msg(gen_start_cond_msg); begin + push(msg, timeout); send(net, actor, msg); end procedure gen_start_cond; procedure gen_stop_cond ( + constant timeout : in time; constant actor : in actor_t) is variable msg : msg_t := new_msg(gen_stop_cond_msg); begin + push(msg, timeout); send(net, actor, msg); end procedure gen_stop_cond; diff --git a/tb/i2c/model/i2c_master_pkg.vhd b/tb/i2c/model/i2c_master_pkg.vhd index 6481e06..e6ed452 100644 --- a/tb/i2c/model/i2c_master_pkg.vhd +++ b/tb/i2c/model/i2c_master_pkg.vhd @@ -7,6 +7,10 @@ context vunit_lib.com_context; use work.i2c_bus_pkg; +-- all procedures here take 0 simulation time +-- call i2c_bus_pkg.wait_until_idle to wait +-- until the operation is performed. + package i2c_master_pkg is procedure write ( diff --git a/tb/i2c/model/i2c_slave_pkg.vhd b/tb/i2c/model/i2c_slave_pkg.vhd index 37f43d3..88037c3 100644 --- a/tb/i2c/model/i2c_slave_pkg.vhd +++ b/tb/i2c/model/i2c_slave_pkg.vhd @@ -1,27 +1,3 @@ ---- 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; @@ -31,6 +7,10 @@ context vunit_lib.com_context; use work.i2c_bus_pkg; +-- all procedures here take 0 simulation time +-- call i2c_bus_pkg.wait_until_idle to wait +-- until the operation is performed. + package i2c_slave_pkg is procedure write ( -- 2.49.0