M tb/i2c/model/i2c_bus_mod.vhd => tb/i2c/model/i2c_bus_mod.vhd +626 -40
@@ 11,12 11,14 @@ 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);
+ sda_io : inout std_logic;
+ scl_io : inout std_logic;
+ clk_i : in std_logic;
+ scl_rising_o : out std_logic;
+ scl_falling_o : out std_logic);
end entity i2c_bus_mod;
@@ 24,80 26,653 @@ 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");
+ function get_period (
+ constant frequency : in real) return time is
+ begin -- procedure get_period
+ return (1_000_000_000.0 / frequency) * 1 ns;
+ end function get_period;
- 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_free_sda_req : event_t := new_event(inst_name & "free sda");
+ signal s_free_scl_req : event_t := new_event(inst_name & "free scl");
- signal s_data_req : event_t := new_event("gen data");
- signal s_clk_req : event_t := new_event("gen data");
+ signal s_start_cond_req : event_t := new_event(inst_name & "start cond gen");
+ signal s_start_cond_done : event_t := new_event(inst_name & "start cond done");
- signal s_scl_stretch_timeout : time := default_stretch_timeout;
- signal s_scl_frequency : real := default_scl_freq;
+ signal s_stop_cond_req : event_t := new_event(inst_name & "stop cond gen");
+ signal s_stop_cond_done : event_t := new_event(inst_name & "stop cond done");
+
+ signal s_check_data_req : event_t := new_event(inst_name & "check data req");
+ signal s_check_data_done : event_t := new_event(inst_name & "check data done");
+
+ signal s_data_req : event_t := new_event(inst_name & "gen data");
+ signal s_data_done : event_t := new_event(inst_name & "data done");
- signal s_request_clks_count : natural;
- signal s_request_data : std_logic_vector(1023 downto 0);
+ signal s_clk_req : event_t := new_event(inst_name & "gen clk");
+ signal s_clk_done : event_t := new_event(inst_name & "clk done");
+
+ signal s_scl_frequency : real := default_scl_freq;
+ signal s_scl_period : time := get_period(default_scl_freq);
- signal s_auto_ack_req : event_t := new_event("auto ack");
+ signal s_auto_ack_req : event_t := new_event(inst_name & "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;
+ signal s_data_count : natural;
+ signal s_data : std_logic_vector(1023 downto 0);
+
+ signal s_clk_count : natural;
+ signal s_clk_start : std_logic;
+
+ signal s_timeout : time;
+
+ signal s_byte_sent : event_t := new_event(inst_name & "byte sent");
+ signal s_start_cond : event_t := new_event(inst_name & "start cond");
+ signal s_bus_busy : std_logic;
+ signal s_read_byte : std_logic_vector(7 downto 0);
+ signal s_bits_since_start_cond : natural := 0;
+
procedure wait_for_start (
signal sda : inout std_logic;
signal scl : inout std_logic;
- constant timeout : in time);
+ variable timeout : inout time) is
+ constant v_now : time := now;
+ begin
+ wait until scl = 'H' and falling_edge(sda) for timeout;
+
+ if scl /= 'H' or not falling_edge(sda) then
+ failure(logger, "Timed out when waiting for start condition!");
+ else
+ timeout := timeout - (now - v_now);
+ end if;
+ end procedure wait_for_start;
procedure wait_for_stop (
signal sda : inout std_logic;
signal scl : inout std_logic;
- constant timeout : in time);
+ variable timeout : inout time) is
+ constant v_now : time := now;
+ begin
+ wait until scl = 'H' and rising_edge(sda) for timeout;
+
+ if scl /= 'H' or not rising_edge(sda) then
+ error(logger, "Timed out when waiting for stop condition!");
+ else
+ timeout := timeout - (now - v_now);
+ end if;
+ end procedure wait_for_stop;
procedure wait_for_clock (
signal sda : inout std_logic;
signal scl : inout std_logic;
- constant timeout : in time);
+ variable timeout : inout time) is
+ variable v_now : time := now;
+ begin
+ -- TODO: start or stop condition?
+ wait until rising_edge(scl) for timeout;
+
+ if not rising_edge(scl) then
+ error(logger, "Timed out when waiting for clock!");
+ else
+ timeout := timeout - (now - v_now);
+ end if;
+ end procedure wait_for_clock;
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);
+ variable timeout : inout time;
+ variable continue : inout boolean) is
+ variable v_now : time := now;
+ begin
+ if scl = 'H' then
+ wait until (sda'event and scl = 'H') or falling_edge(scl) for timeout;
+ end if;
+
+ if sda'event and scl = 'H' then
+ wait for 0 ns;
+ error(logger, "Got start or stop condition when trying to write a bit!");
+ continue := false;
+ return;
+ elsif falling_edge(scl) then
+ -- nop
+ wait for s_scl_period / 4;
+ timeout := timeout - (now - v_now);
+ elsif scl = '0' then
+ else
+ error(logger, "Timed out when waiting for falling edge of scl to write a bit!");
+ continue := false;
+ -- timeout
+ return;
+ end if;
- function read_bit (
+ if data = '1' then
+ sda <= 'Z';
+ else
+ sda <= data;
+ end if;
+
+ -- wait for next clock
+ wait until (sda'event and scl = 'H') or falling_edge(scl) for timeout;
+
+ if sda'event and scl = 'H' then
+ wait for 0 ns;
+ error(logger, "Got start or stop condition when trying to write a bit!");
+ continue := false;
+ sda <= 'Z';
+ elsif falling_edge(scl) then
+ wait for s_scl_period / 4;
+ sda <= 'Z';
+ else
+ continue := false;
+ error(logger, "Could not get rising edge of scl to write data.");
+ end if;
+
+ end procedure write_bit;
+
+ procedure 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;
+ variable data : out std_logic;
+ variable timeout : inout time;
+ variable continue : inout boolean) is
+ variable v_now : time := now;
+ begin
+ if not continue then
+ data := 'X';
+ return;
+ end if;
+
+ wait until (sda'event and scl = 'H') or rising_edge(scl) for timeout;
+
+ if sda'event and scl = 'H' then
+ -- start / stop condition. Cannot read further.
+ error(logger, "Got start or stop condition when trying to read a bit!");
+ continue := false;
+ data := 'X';
+ return;
+ elsif rising_edge(scl) then
+ if sda = 'H' then
+ data := '1';
+ return;
+ end if;
- function read_data (
+ timeout := timeout - (now - v_now);
+ data := sda;
+ return;
+ else
+ -- timeout
+ error(logger, "Timed out when waiting for rising edge to read a bit!");
+ continue := false;
+ end if;
+
+ end procedure read_bit;
+
+ procedure read_data (
signal sda : inout std_logic;
signal scl : inout std_logic;
- constant timeout : in time;
- variable continue : inout boolean) return std_logic_vector;
+ constant count : in natural;
+ variable data : out std_logic_vector;
+ variable timeout : inout time;
+ variable continue : inout boolean) is
+ begin
+ for i in (count - 1) downto 0 loop
+ read_bit(sda, scl, data(i), timeout, continue);
+
+ if not continue then
+ return;
+ end if;
+ end loop; -- i
+ end procedure read_data;
+
+ procedure process_disconnect_req (
+ signal evnt : inout event_t;
+ signal sda : inout std_logic;
+ signal scl : inout std_logic) is
+
+ variable scl_freed : boolean := false;
+ variable sda_freed : boolean := false;
+ begin
+ while not scl_freed or not sda_freed loop
+ if is_active(s_free_sda_req) then
+ sda_freed := true;
+ sda <= 'Z';
+ end if;
+
+ if is_active(s_free_scl_req) then
+ scl_freed := true;
+ scl <= 'Z';
+ end if;
+
+ if is_active(evnt) then
+ exit;
+ end if;
+
+ if not scl_freed or not sda_freed then
+ wait until is_active(s_free_scl_req) or is_active(s_free_sda_req) or is_active(evnt);
+ end if;
+ end loop;
+ end procedure process_disconnect_req;
+
+ procedure req_disconnect(
+ signal free_sda_req: inout event_t;
+ signal free_scl_req: inout event_t) is
+ begin
+ notify(free_sda_req);
+ notify(free_scl_req);
+ end procedure req_disconnect;
+
+ procedure dc(
+ signal sda : inout std_logic;
+ signal scl : inout std_logic) is
+ begin -- procedure disconnect
+ sda <= 'Z';
+ scl <= 'Z';
+ end procedure dc;
begin -- architecture behav
+ scl_io <= 'H';
+ sda_io <= 'H';
+
+ start_cond_gen: process is
+ begin -- process start_cond_gen
+ dc(sda_io, scl_io);
+ if not is_active(s_start_cond_req) then
+ wait until is_active(s_start_cond_req);
+ end if;
+
+ info(logger, "Initiating communication on the bus by generating a start condition.");
+
+ check(checker, sda_io = 'H', "SDA cannot be low to generate a start condition!", level => failure);
+ check(checker, scl_io = 'H', "SCL cannot be low to generate a start condition!", level => failure);
+
+ req_disconnect(s_free_sda_req, s_free_scl_req);
+
+ sda_io <= '0';
+ wait until scl_io'event for s_scl_period / 4;
+ scl_io <= '0';
+ wait for s_scl_period / 4;
+
+ info(logger, "Start condition generated.");
+
+ notify(s_start_cond_done);
+ process_disconnect_req(s_start_cond_req, sda_io, scl_io);
+ end process start_cond_gen;
+
+ stop_cond_gen: process is
+ variable v_timeout : time;
+ begin -- process stop_cond_gen
+ dc(sda_io, scl_io);
+ if not is_active(s_stop_cond_req) then
+ wait until is_active(s_stop_cond_req);
+ end if;
+
+ v_timeout := s_timeout;
+
+ check(checker, scl_io = '0', "SCL cannot be high to generate a stop condition!", level => failure);
+
+ scl_io <= '0';
+ sda_io <= '0';
+ req_disconnect(s_free_sda_req, s_free_scl_req);
+
+ info(logger, "Stopping communication on the bus by generating a stop condition.");
+
+ wait for s_scl_period / 4;
+ scl_io <= 'Z';
+
+ wait until scl_io = 'H' for v_timeout;
+
+ if scl_io /= 'H' then
+ error(logger, "Timed out when waiting for scl rising edge to generate a stop condition!");
+ end if;
+
+ wait for s_scl_period / 4;
+ sda_io <= 'Z';
+
+ wait until sda_io = 'H' for v_timeout;
+
+ if sda_io /= 'H' then
+ error(logger, "Timed out when waiting for sda rising edge to generate a stop condition!");
+ end if;
+
+ wait for s_scl_period / 4;
+
+ info(logger, "Stop condition generated.");
+
+ notify(s_stop_cond_done);
+
+ -- already freed...
+ -- process_disconnect_req(sda_io, scl_io);
+ end process stop_cond_gen;
+
+ data_gen: process is
+ variable v_timeout : time;
+ variable v_position : natural;
+ variable v_continue : boolean;
+
+ variable v_data : std_logic_vector(1023 downto 0);
+ variable v_count : natural;
+ begin -- process data_gen
+ dc(sda_io, scl_io);
+ if not is_active(s_data_req) then
+ wait until is_active(s_data_req);
+ end if;
+
+ v_timeout := s_timeout;
+ v_continue := true;
+ v_data := s_data;
+ v_count := s_data_count;
+
+ notify(s_free_sda_req);
+
+ v_position := 0;
+ while v_continue and v_position < v_count loop
+ write_bit(sda_io, scl_io, v_data(v_count - 1 - v_position), v_timeout, v_continue);
+ v_position := v_position + 1;
+ end loop;
+
+ if v_continue and v_count = 8 then
+ info(logger, "Sent I2C frame of data.");
+ elsif v_count = 8 then
+ warning(logger, "Could not send requested data to the bus.");
+ end if;
+
+ if s_bits_since_start_cond <= 8 and v_count = 8 then
+ -- send address and rw
+ info(logger, "Sent I2C Frame: " & to_string(v_data(v_count - 1 downto 0)));
+ info(logger, " Slave Address: " & to_string(v_data(7 downto 1)));
+ info(logger, " RW: " & to_string(v_data(0)));
+ elsif v_count = 8 then
+ -- sent just data
+ info(logger, "I2C Frame: " & to_string(v_data(v_count - 1 downto 0)));
+ end if;
+
+ if v_count = 1 and s_bits_since_start_cond mod 9 = 8 then
+ if v_continue then
+ info(logger, "Sent ACK.");
+ else
+ warning(logger, "Could not send ACK!");
+ end if;
+ end if;
+
+ notify(s_data_done);
+ wait until is_active(s_free_sda_req) or is_active(s_data_req);
+ sda_io <= 'Z';
+ end process data_gen;
+
+ clk_gen: process is
+ variable v_start : std_logic;
+
+ variable v_continue : boolean;
+
+ variable v_count : natural;
+ variable v_position : natural;
+ variable v_timeout : time;
+ variable v_now : time;
+ begin -- process clk_gen
+ dc(sda_io, scl_io);
+ if not is_active(s_clk_req) then
+ wait until is_active(s_clk_req);
+ end if;
+
+ v_count := s_clk_count;
+ v_timeout := s_timeout;
+ v_start := s_clk_start;
+ v_now := now;
+
+ scl_io <= v_start;
+ notify(s_free_scl_req);
+
+ if v_start = 'H' then
+ if scl_io /= 'H' then
+ wait until scl_io = 'H' for v_timeout;
+ end if;
+
+ if scl_io /= 'H' then
+ error(logger, "Timed out when waiting for scl rising edge to generate clock.");
+ end if;
+
+ wait until scl_io /= 'H' for s_scl_period / 2;
+
+ if scl_io /= 'H' then
+ error(logger, "Got instability at scl when generating clock!");
+ end if;
+
+ scl_io <= '0';
+ wait for s_scl_period / 4;
+ end if;
+
+ v_position := 0;
+ v_continue := true;
+ while v_continue and v_position < v_count loop
+ wait for s_scl_period / 4;
+
+ scl_io <= 'Z';
+
+ if scl_io /= 'H' then
+ wait until scl_io = 'H' for v_timeout;
+ end if;
+
+ if scl_io /= 'H' then
+ error(logger, "Timed out when waiting for scl rising edge to generate clock.");
+ end if;
+
+ wait until scl_io /= 'H' for s_scl_period / 2;
+
+ if scl_io /= 'H' then
+ error(logger, "Got instability at scl when generating clock!");
+ end if;
+
+ scl_io <= '0';
+ wait for s_scl_period / 4;
+
+ v_position := v_position + 1;
+ end loop;
+
+ notify(s_clk_done);
+ wait until is_active(s_free_scl_req) or is_active(s_clk_req);
+ end process clk_gen;
+
+ data_checker: process is
+ variable v_timeout : time;
+ variable v_position : natural;
+ variable v_continue : boolean;
+
+ variable v_exp_data : std_logic_vector(1023 downto 0);
+ variable v_read_data : std_logic_vector(1023 downto 0);
+ variable v_count : natural;
+ begin -- process data_checker
+ dc(sda_io, scl_io);
+ if not is_active(s_check_data_req) then
+ wait until is_active(s_check_data_req);
+ end if;
+
+ v_timeout := s_timeout;
+ v_exp_data := s_data;
+ v_count := s_data_count;
+
+ v_position := 0;
+ v_continue := true;
+ while v_continue and v_position < v_count loop
+ read_bit(sda_io, scl_io, v_read_data(v_count - 1 - v_position), v_timeout, v_continue);
+ v_position := v_position + 1;
+ end loop;
+
+ if v_continue and v_count = 8 then
+ info(logger, "Received I2C frame of data.");
+ elsif v_count = 8 then
+ warning(logger, "Could not receive requested data on the bus.");
+ end if;
+
+ if v_exp_data(v_count - 1 downto 0) = v_read_data(v_count - 1 downto 0) then
+ info(logger, "Got expected data.");
+ else
+ error(logger, "Received data do not match expected data.");
+ end if;
+
+ if s_bits_since_start_cond <= 8 and v_count = 8 then
+ -- send address and rw
+ info(logger, "Expected I2C Frame: " & to_string(v_exp_data(v_count - 1 downto 0)));
+ info(logger, " Slave Address: " & to_string(v_exp_data(7 downto 1)));
+ info(logger, " RW: " & to_string(v_exp_data(0)));
+ info(logger, "Received I2C Frame: " & to_string(v_read_data(v_count - 1 downto 0)));
+ info(logger, " Slave Address: " & to_string(v_read_data(7 downto 1)));
+ info(logger, " RW: " & to_string(v_read_data(0)));
+ elsif v_count = 8 then
+ -- sent just data
+ info(logger, "Received I2C Frame: " & to_string(v_read_data(v_count - 1 downto 0)));
+ info(logger, "Expected I2C Frame: " & to_string(v_exp_data(v_count - 1 downto 0)));
+ end if;
+
+ if v_count = 1 and s_bits_since_start_cond mod 9 = 8 then
+ if v_continue then
+ if v_exp_data(0) = '0' then
+ if v_read_data(0) = '0' then
+ info(logger, "Received ACK.");
+ else
+ error(logger, "Received NACK instead of ACK.");
+ end if;
+ else
+ if v_read_data(0) = '0' then
+ error(logger, "Received unexpected ACK.");
+ else
+ info(logger, "Received expected NACK.");
+ end if;
+ end if;
+ else
+ warning(logger, "Could not receive ACK!");
+ end if;
+ end if;
+
+ notify(s_check_data_done);
+
+ end process data_checker;
+
+ gen_rising_pulse: process is
+ begin -- process gen_rising_pulse
+ dc(sda_io, scl_io);
+ scl_rising_o <= '0';
+ wait until rising_edge(scl_io);
+ scl_rising_o <= '1';
+
+ wait until rising_edge(clk_i);
+ wait until falling_edge(clk_i);
+ end process gen_rising_pulse;
+
+ gen_falling_pulse: process is
+ begin -- process gen_rising_pulse
+ dc(sda_io, scl_io);
+ scl_falling_o <= '0';
+ wait until falling_edge(scl_io);
+ scl_falling_o <= '1';
+
+ wait until rising_edge(clk_i);
+ wait until falling_edge(clk_i);
+ end process gen_falling_pulse;
+
+ auto_ack_gen: process is
+ variable v_address : std_logic_vector(6 downto 0);
+ variable v_rw : std_logic;
+
+ variable v_continue : boolean;
+ variable v_timeout : time;
+ begin -- process auto_ack_gen
+ dc(sda_io, scl_io);
+ if not s_auto_ack_active then
+ wait until is_active(s_auto_ack_req);
+ end if;
+
+ wait until is_active(s_byte_sent) or is_active(s_auto_ack_req);
+
+ if is_active(s_byte_sent) and s_auto_ack_active then
+ if s_bits_since_start_cond = 8 then
+ v_address := s_read_byte(7 downto 1);
+ v_rw := s_read_byte(0);
+ end if;
+
+ v_timeout := time'high;
+ v_continue := true;
+ if v_address = s_auto_ack_address and v_rw = '0' then
+ write_bit(sda_io, scl_io, '0', v_timeout, v_continue);
+ info(logger, "Sent automatic ACK as " & to_string(v_address));
+ write_bit(sda_io, scl_io, '1', v_timeout, v_continue);
+ elsif v_address = "0000000" and v_rw = '1' and s_bits_since_start_cond > 8 then
+ write_bit(sda_io, scl_io, '0', v_timeout, v_continue);
+ info(logger, "Sent automatic ACK as master.");
+ write_bit(sda_io, scl_io, '1', v_timeout, v_continue);
+ end if;
+ end if;
+ end process auto_ack_gen;
+
+ bit_counter: process is
+ variable v_started : boolean;
+ variable v_read : std_logic;
+ variable v_timeout : time;
+ begin -- process bit_counter
+ dc(sda_io, scl_io);
+ if not v_started then
+ v_timeout := time'high;
+ wait_for_start(sda_io, scl_io, v_timeout);
+ v_started := true;
+
+ notify(s_start_cond);
+ s_bus_busy <= '1';
+ s_bits_since_start_cond <= 0;
+ end if;
+
+ wait until (sda_io'event and scl_io = 'H') or rising_edge(scl_io);
+
+ if rising_edge(scl_io) then
+ if sda_io = 'H' then
+ v_read := '1';
+ else
+ v_read := sda_io;
+ end if;
+
+ s_read_byte <= s_read_byte(6 downto 0) & v_read;
+ s_bits_since_start_cond <= s_bits_since_start_cond + 1;
+
+ wait for 0 ns;
+ if s_bits_since_start_cond mod 8 = 0 then
+ notify(s_byte_sent);
+ end if;
+ else
+ s_bits_since_start_cond <= 0;
+
+ wait for 0 ns;
+ if sda_io = 'H' then
+ v_started := false;
+ s_bus_busy <= '0';
+ else
+ notify(s_start_cond);
+ end if;
+ end if;
+ end process bit_counter;
message_handler: process is
constant self : actor_t := new_actor(inst_name);
variable msg : msg_t;
variable msg_type : msg_type_t;
+
+ variable v_frequency : real;
+ variable v_count : natural;
+ variable v_timeout : time;
begin -- process message_handler
+ dc(sda_io, scl_io);
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);
+ wait for s_scl_period / 4;
+ req_disconnect(s_free_sda_req, s_free_scl_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
+ s_timeout <= pop(msg);
notify(s_start_cond_req);
wait until is_active(s_start_cond_done);
elsif msg_type = gen_stop_cond_msg then
@@ 105,54 680,65 @@ begin -- architecture behav
notify(s_stop_cond_req);
wait until is_active(s_stop_cond_done);
elsif msg_type = gen_clocks_msg then
+ s_clk_start <= scl_io;
s_clk_count <= pop(msg);
s_timeout <= pop(msg);
- notify(s_gen_clk_req);
- wait until is_active(s_gen_clk_done);
+ notify(s_clk_req);
+ wait until is_active(s_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);
+ wait until is_active(s_data_done);
elsif msg_type = send_data_clocks_msg then
+ s_clk_start <= scl_io;
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);
+ notify(s_clk_req, s_data_req);
+ wait until is_active(s_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));
+ req_disconnect(s_free_sda_req, s_free_scl_req);
+ v_timeout := pop(msg);
+ wait_for_start(sda_io, scl_io, v_timeout);
elsif msg_type = wait_stop_cond_msg then
- wait_for_stop(sda_io, scl_io, pop(msg));
+ req_disconnect(s_free_sda_req, s_free_scl_req);
+ v_timeout := pop(msg);
+ wait_for_stop(sda_io, scl_io, v_timeout);
elsif msg_type = wait_clocks_msg then
+ req_disconnect(s_free_sda_req, s_free_scl_req);
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
+ req_disconnect(s_free_sda_req, s_free_scl_req);
s_data_count <= pop(msg);
- s_data_exp <= pop(msg);
+ s_data <= 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
+ s_clk_start <= scl_io;
+ notify(s_free_sda_req);
v_count := pop(msg);
s_data_count <= v_count;
s_clk_count <= v_count;
- s_data_exp <= pop(msg);
+ s_data <= 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
+ notify(s_clk_req);
+ notify(s_check_data_req);
+ wait until is_active(s_clk_done);
+ elsif msg_type = wait_until_idle_msg then
acknowledge(net, msg, true);
end if;
M tb/i2c/model/i2c_bus_pkg.vhd => tb/i2c/model/i2c_bus_pkg.vhd +58 -5
@@ 29,87 29,110 @@ package i2c_bus_pkg is
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");
+ constant wait_until_idle_msg : msg_type_t := new_msg_type("wait until idle");
impure function get_actor (
constant inst_name : string)
return actor_t;
procedure free_bus (
+ signal net : inout network_t;
constant actor : in actor_t);
procedure set_scl_frequency (
+ signal net : inout network_t;
constant frequency : in real;
constant actor : in actor_t);
procedure gen_start_cond (
+ signal net : inout network_t;
constant timeout : in time;
constant actor : in actor_t);
procedure gen_stop_cond (
+ signal net : inout network_t;
constant timeout : in time;
constant actor : in actor_t);
procedure gen_clocks (
+ signal net : inout network_t;
constant times : in natural;
constant timeout : in time;
constant actor : in actor_t);
procedure send_data (
+ signal net : inout network_t;
constant data : in std_logic_vector;
constant timeout : in time;
constant actor : in actor_t);
procedure send_ack (
+ signal net : inout network_t;
constant timeout : in time;
constant actor : in actor_t);
procedure send_ack_and_clock (
+ signal net : inout network_t;
constant timeout : in time;
constant actor : in actor_t);
procedure send_data_and_clock (
+ signal net : inout network_t;
constant data : in std_logic_vector;
constant timeout : in time;
constant actor : in actor_t);
procedure wait_for_start_cond (
+ signal net : inout network_t;
constant timeout : in time;
constant actor : in actor_t);
procedure wait_for_stop_cond (
+ signal net : inout network_t;
constant timeout : in time;
constant actor : in actor_t);
procedure wait_for_clocks (
+ signal net : inout network_t;
constant times : in natural;
constant timeout : in time;
constant actor : in actor_t);
procedure check_data (
+ signal net : inout network_t;
constant exp_data : in std_logic_vector;
constant timeout : in time;
constant actor : in actor_t);
procedure check_data_gen_clock (
+ signal net : inout network_t;
constant exp_data : in std_logic_vector;
constant timeout : in time;
constant actor : in actor_t);
procedure check_ack_gen_clock (
+ signal net : inout network_t;
+ constant ack : in std_logic := '1';
constant timeout : in time;
constant actor : in actor_t);
procedure check_ack (
+ signal net : inout network_t;
+ constant ack : in std_logic := '1';
constant timeout : in time;
constant actor : in actor_t);
procedure set_auto_ack (
+ signal net : inout network_t;
constant auto_ack : in boolean;
constant address : in std_logic_vector(6 downto 0);
constant bytes_count : in natural;
constant actor : in actor_t);
+ procedure wait_until_idle (
+ signal net : inout network_t;
+ constant actor : in actor_t);
+
end package i2c_bus_pkg;
package body i2c_bus_pkg is
@@ 122,6 145,7 @@ package body i2c_bus_pkg is
end function get_actor;
procedure free_bus (
+ signal net : inout network_t;
constant actor : in actor_t) is
variable msg : msg_t := new_msg(free_bus_msg);
begin
@@ 129,6 153,7 @@ package body i2c_bus_pkg is
end procedure free_bus;
procedure set_scl_frequency (
+ signal net : inout network_t;
constant frequency : in real;
constant actor : in actor_t) is
variable msg : msg_t := new_msg(set_scl_freq_msg);
@@ 138,6 163,7 @@ package body i2c_bus_pkg is
end procedure set_scl_frequency;
procedure gen_start_cond (
+ signal net : inout network_t;
constant timeout : in time;
constant actor : in actor_t) is
variable msg : msg_t := new_msg(gen_start_cond_msg);
@@ 147,6 173,7 @@ package body i2c_bus_pkg is
end procedure gen_start_cond;
procedure gen_stop_cond (
+ signal net : inout network_t;
constant timeout : in time;
constant actor : in actor_t) is
variable msg : msg_t := new_msg(gen_stop_cond_msg);
@@ 156,6 183,7 @@ package body i2c_bus_pkg is
end procedure gen_stop_cond;
procedure gen_clocks (
+ signal net : inout network_t;
constant times : in natural;
constant timeout : in time;
constant actor : in actor_t) is
@@ 167,6 195,7 @@ package body i2c_bus_pkg is
end procedure gen_clocks;
procedure send_data (
+ signal net : inout network_t;
constant data : in std_logic_vector;
constant timeout : in time;
constant actor : in actor_t) is
@@ 181,20 210,23 @@ package body i2c_bus_pkg is
end procedure send_data;
procedure send_ack (
+ signal net : inout network_t;
constant timeout : in time;
constant actor : in actor_t) is
begin
- send_data("0", timeout, actor);
+ send_data(net, "0", timeout, actor);
end procedure send_ack;
procedure send_ack_and_clock (
+ signal net : inout network_t;
constant timeout : in time;
constant actor : in actor_t) is
begin
- send_data_and_clock("0", timeout, actor);
+ send_data_and_clock(net, "0", timeout, actor);
end procedure send_ack_and_clock;
procedure send_data_and_clock (
+ signal net : inout network_t;
constant data : in std_logic_vector;
constant timeout : in time;
constant actor : in actor_t) is
@@ 209,6 241,7 @@ package body i2c_bus_pkg is
end procedure send_data_and_clock;
procedure wait_for_start_cond (
+ signal net : inout network_t;
constant timeout : in time;
constant actor : in actor_t) is
variable msg : msg_t := new_msg(wait_start_cond_msg);
@@ 218,6 251,7 @@ package body i2c_bus_pkg is
end procedure wait_for_start_cond;
procedure wait_for_stop_cond (
+ signal net : inout network_t;
constant timeout : in time;
constant actor : in actor_t) is
variable msg : msg_t := new_msg(wait_stop_cond_msg);
@@ 227,6 261,7 @@ package body i2c_bus_pkg is
end procedure wait_for_stop_cond;
procedure wait_for_clocks (
+ signal net : inout network_t;
constant times : in natural;
constant timeout : in time;
constant actor : in actor_t) is
@@ 238,6 273,7 @@ package body i2c_bus_pkg is
end procedure wait_for_clocks;
procedure check_data (
+ signal net : inout network_t;
constant exp_data : in std_logic_vector;
constant timeout : in time;
constant actor : in actor_t) is
@@ 252,6 288,7 @@ package body i2c_bus_pkg is
end procedure check_data;
procedure check_data_gen_clock (
+ signal net : inout network_t;
constant exp_data : in std_logic_vector;
constant timeout : in time;
constant actor : in actor_t) is
@@ 266,20 303,27 @@ package body i2c_bus_pkg is
end procedure check_data_gen_clock;
procedure check_ack_gen_clock (
+ signal net : inout network_t;
+ constant ack : in std_logic := '1';
constant timeout : in time;
constant actor : in actor_t) is
+ variable v_vector : std_logic_vector(0 downto 0) := (0 => not ack);
begin
- check_data_gen_clock("0", timeout, actor);
+ check_data_gen_clock(net, v_vector, timeout, actor);
end procedure check_ack_gen_clock;
procedure check_ack (
+ signal net : inout network_t;
+ constant ack : in std_logic := '1';
constant timeout : in time;
constant actor : in actor_t) is
+ variable v_vector : std_logic_vector(0 downto 0) := (0 => not ack);
begin
- check_data("0", timeout, actor);
+ check_data(net, v_vector, timeout, actor);
end procedure check_ack;
procedure set_auto_ack (
+ signal net : inout network_t;
constant auto_ack : in boolean;
constant address : in std_logic_vector(6 downto 0);
constant bytes_count : in natural;
@@ 292,4 336,13 @@ package body i2c_bus_pkg is
send(net, actor, msg);
end procedure set_auto_ack;
+ procedure wait_until_idle (
+ signal net : inout network_t;
+ constant actor : in actor_t) is
+ variable msg : msg_t := new_msg(wait_until_idle_msg);
+ variable ack : boolean;
+ begin
+ request(net, actor, msg, ack);
+ end procedure wait_until_idle;
+
end package body i2c_bus_pkg;
M tb/i2c/model/i2c_master_pkg.vhd => tb/i2c/model/i2c_master_pkg.vhd +25 -20
@@ 14,19 14,21 @@ use work.i2c_bus_pkg;
package i2c_master_pkg is
procedure write (
+ signal net : inout network_t;
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 (
+ signal net : inout network_t;
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 (
+ signal net : inout network_t;
constant address : in std_logic_vector(6 downto 0);
constant data : in std_logic_vector;
constant exp_data : in std_logic_vector;
@@ 38,6 40,7 @@ end package i2c_master_pkg;
package body i2c_master_pkg is
procedure write (
+ signal net : inout network_t;
constant address : in std_logic_vector(6 downto 0);
constant data : in std_logic_vector;
constant timeout : in time;
@@ 47,18 50,19 @@ package body i2c_master_pkg is
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);
+ i2c_bus_pkg.gen_start_cond(net, timeout, actor);
+ i2c_bus_pkg.send_data_and_clock(net, 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);
+ i2c_bus_pkg.send_data_and_clock(net, data(data'left - i*8 downto data'left - 7 - i*8), timeout, actor);
+ i2c_bus_pkg.check_ack_gen_clock(net, '1', timeout, actor);
end loop; -- i
- i2c_bus_pkg.gen_stop_cond(actor);
+ i2c_bus_pkg.gen_stop_cond(net, timeout, actor);
end procedure write;
procedure read (
+ signal net : inout network_t;
constant address : in std_logic_vector(6 downto 0);
constant exp_data : in std_logic_vector;
constant timeout : in time;
@@ 68,18 72,19 @@ package body i2c_master_pkg is
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);
+ i2c_bus_pkg.gen_start_cond(net, timeout, actor);
+ i2c_bus_pkg.send_data_and_clock(net, 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);
+ i2c_bus_pkg.check_data_gen_clock(net, exp_data(exp_data'left - i*8 downto exp_data'left - 7 - i*8), timeout, actor);
+ i2c_bus_pkg.send_ack_and_clock(net, timeout, actor);
end loop; -- i
- i2c_bus_pkg.gen_stop_cond(actor);
+ i2c_bus_pkg.gen_stop_cond(net, timeout, actor);
end procedure read;
procedure write_read (
+ signal net : inout network_t;
constant address : in std_logic_vector(6 downto 0);
constant data : in std_logic_vector;
constant exp_data : in std_logic_vector;
@@ 94,23 99,23 @@ package body i2c_master_pkg is
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);
+ i2c_bus_pkg.gen_start_cond(net, timeout, actor);
+ i2c_bus_pkg.send_data_and_clock(net, 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);
+ i2c_bus_pkg.send_data_and_clock(net, data(data'left - i*8 downto data'left - 7 - i*8), timeout, actor);
+ i2c_bus_pkg.check_ack_gen_clock(net, '1', timeout, actor);
end loop; -- i
- i2c_bus_pkg.gen_start_cond(actor);
- i2c_bus_pkg.send_data_and_clock(address & '1', timeout, actor);
+ i2c_bus_pkg.gen_start_cond(net, timeout, actor);
+ i2c_bus_pkg.send_data_and_clock(net, 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);
+ i2c_bus_pkg.check_data_gen_clock(net, exp_data(exp_data'left - i*8 downto exp_data'left - 7 - i*8), timeout, actor);
+ i2c_bus_pkg.send_ack_and_clock(net, timeout, actor);
end loop; -- i
- i2c_bus_pkg.gen_stop_cond(actor);
+ i2c_bus_pkg.gen_stop_cond(net, timeout, actor);
end procedure write_read;
end package body i2c_master_pkg;
M tb/i2c/model/i2c_slave_pkg.vhd => tb/i2c/model/i2c_slave_pkg.vhd +26 -20
@@ 14,18 14,21 @@ use work.i2c_bus_pkg;
package i2c_slave_pkg is
procedure write (
+ signal net : inout network_t;
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 (
+ signal net : inout network_t;
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 (
+ signal net : inout network_t;
constant address : in std_logic_vector(6 downto 0);
constant exp_data : in std_logic_vector;
constant data : in std_logic_vector;
@@ 37,6 40,7 @@ end package i2c_slave_pkg;
package body i2c_slave_pkg is
procedure write (
+ signal net : inout network_t;
constant address : in std_logic_vector(6 downto 0);
constant exp_data : in std_logic_vector;
constant timeout : in time;
@@ 46,18 50,19 @@ package body i2c_slave_pkg is
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);
+ i2c_bus_pkg.wait_for_start_cond(net, timeout, actor);
+ i2c_bus_pkg.check_data(net, 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);
+ i2c_bus_pkg.check_data(net, exp_data(exp_data'left - i*8 downto exp_data'left - 7 - i*8), timeout, actor);
+ i2c_bus_pkg.send_ack(net, timeout, actor);
end loop; -- i
- i2c_bus_pkg.wait_for_stop_cond(timeout, actor);
+ i2c_bus_pkg.wait_for_stop_cond(net, timeout, actor);
end procedure write;
procedure read (
+ signal net : inout network_t;
constant address : in std_logic_vector(6 downto 0);
constant data : in std_logic_vector;
constant timeout : in time;
@@ 67,21 72,22 @@ package body i2c_slave_pkg is
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);
+ i2c_bus_pkg.wait_for_start_cond(net, timeout, actor);
+ i2c_bus_pkg.check_data(net, 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);
+ i2c_bus_pkg.send_data(net, data(data'left - i*8 downto data'left - 7 - i*8), timeout, actor);
+ i2c_bus_pkg.check_ack(net, '1', timeout, actor);
end loop; -- i
- i2c_bus_pkg.wait_for_stop_cond(timeout, actor);
+ i2c_bus_pkg.wait_for_stop_cond(net, timeout, actor);
end procedure read;
procedure write_read (
+ signal net : inout network_t;
constant address : in std_logic_vector(6 downto 0);
- constant data : in std_logic_vector;
constant exp_data : in std_logic_vector;
+ constant data : in std_logic_vector;
constant timeout : in time;
constant actor : in actor_t) is
begin
@@ 92,23 98,23 @@ package body i2c_slave_pkg is
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);
+ i2c_bus_pkg.wait_for_start_cond(net, timeout, actor);
+ i2c_bus_pkg.send_data_and_clock(net, 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);
+ i2c_bus_pkg.check_data(net, exp_data(exp_data'left - i*8 downto exp_data'left - 7 - i*8), timeout, actor);
+ i2c_bus_pkg.send_ack(net, 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);
+ i2c_bus_pkg.wait_for_start_cond(net, timeout, actor);
+ i2c_bus_pkg.send_data_and_clock(net, 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);
+ i2c_bus_pkg.send_data(net, data(data'left - i*8 downto data'left - 7 - i*8), timeout, actor);
+ i2c_bus_pkg.check_ack(net, '1', timeout, actor);
end loop; -- i
- i2c_bus_pkg.wait_for_stop_cond(timeout, actor);
+ i2c_bus_pkg.wait_for_stop_cond(net, timeout, actor);
end procedure write_read;