A tb/i2c/model/i2c_bus_mod.vhd => tb/i2c/model/i2c_bus_mod.vhd +161 -0
@@ 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;
M tb/i2c/model/i2c_bus_pkg.vhd => tb/i2c/model/i2c_bus_pkg.vhd +12 -0
@@ 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;
M tb/i2c/model/i2c_master_pkg.vhd => tb/i2c/model/i2c_master_pkg.vhd +4 -0
@@ 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 (
M tb/i2c/model/i2c_slave_pkg.vhd => tb/i2c/model/i2c_slave_pkg.vhd +4 -24
@@ 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 (