~ruther/vhdl-i2c

78ec71947645e90e3aadadb07ca773ec466b5d02 — Rutherther 1 year, 3 months ago 6d023a1
tests: add message handler for i2c bus model
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 (

Do not follow this link