~ruther/vhdl-i2c

15eb81c6daee1b663491ca1f7f4ecc1d464f2b0c — Rutherther 1 year, 3 months ago c06b683
feat: add counter and register testing slave top levels
2 files changed, 237 insertions(+), 0 deletions(-)

A src/mcu_slave/counter.vhd
A src/mcu_slave/regs.vhd
A src/mcu_slave/counter.vhd => src/mcu_slave/counter.vhd +101 -0
@@ 0,0 1,101 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library utils;
library i2c;

entity counter is

  generic (
    MAX : integer := 100);

  port (
    clk_i  : in std_logic;
    rst_i : in std_logic;
    err_noack_o : out std_logic;
    bus_busy_o : out std_logic;
    dev_busy_o : out std_logic;
    sda_io : inout std_logic;
    scl_io : inout std_logic);

end entity counter;

architecture a1 of counter is
  constant ADDRESS : std_logic_vector(6 downto 0) := "1110100";
  signal curr_count : unsigned(7 downto 0);
  signal next_count : unsigned(7 downto 0);

  signal go_next : std_logic;

  signal rst_n : std_logic;

  signal sda, scl : std_logic;
  signal sda_enable, scl_enable : std_logic;

  signal tx_valid, tx_ready : std_logic;
  signal tx_data : std_logic_vector(7 downto 0);
begin
  rst_n <= not rst_i;

  next_count <= (curr_count + 1) mod MAX when go_next = '1' else
                curr_count;

  go_next <= tx_ready;

  tx_valid <= tx_ready;
  tx_data <= std_logic_vector(curr_count);

  uut: entity i2c.slave
    generic map (
      SCL_FALLING_DELAY => 1)
    port map (
      clk_i          => clk_i,
      rst_in         => rst_n,
      address_i      => ADDRESS,
      generate_ack_i => '1',
      expect_ack_i   => '1',

      rx_valid_o     => open,
      rx_data_o      => open,
      rx_confirm_i   => '1',
      rx_stretch_i   => '0',

      tx_ready_o     => tx_ready,
      tx_valid_i     => tx_valid,
      tx_data_i      => tx_data,
      tx_stretch_i   => '0',
      tx_clear_buffer_i => '0',

      err_noack_o    => err_noack_o,
      rw_o           => open,
      dev_busy_o     => dev_busy_o,
      bus_busy_o     => bus_busy_o,
      sda_i          => sda,
      scl_i          => scl,
      sda_enable_o   => sda_enable,
      scl_enable_o   => scl_enable);

  sda_open_buffer: entity utils.open_drain_buffer
    port map (
      pad_io   => sda_io,
      enable_i => sda_enable,
      state_o  => sda);
  scl_open_buffer: entity utils.open_drain_buffer
    port map (
      pad_io   => scl_io,
      enable_i => scl_enable,
      state_o  => scl);

  set_regs: process (clk_i) is
  begin  -- process set_regs
    if rising_edge(clk_i) then          -- rising clock edge
      if rst_n = '0' then              -- synchronous reset (active low)
        curr_count <= "00000000";
      else
        curr_count <= next_count;
      end if;
    end if;
  end process set_regs;

end architecture a1;

A src/mcu_slave/regs.vhd => src/mcu_slave/regs.vhd +136 -0
@@ 0,0 1,136 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library utils;
library i2c;

entity regs is

  generic (
    MAX : integer := 100);

  port (
    clk_i  : in std_logic;
    rst_i : in std_logic;
    err_noack_o : out std_logic;
    bus_busy_o : out std_logic;
    dev_busy_o : out std_logic;
    sda_io : inout std_logic;
    scl_io : inout std_logic);

end entity regs;

architecture a1 of regs is
  constant ADDRESS : std_logic_vector(6 downto 0) := "1110101";

  constant REGS_COUNT : integer := 20;
  type regs_t is array (0 to REGS_COUNT - 1) of std_logic_vector(7 downto 0);
  signal curr_regs : regs_t;
  signal next_regs : regs_t;

  signal rst_n : std_logic;

  signal sda, scl : std_logic;
  signal sda_enable, scl_enable : std_logic;

  signal tx_valid, tx_ready, tx_clear_buffer : std_logic;
  signal tx_data : std_logic_vector(7 downto 0);

  signal rx_valid, rx_confirm : std_logic;
  signal rx_data : std_logic_vector(7 downto 0);

  signal curr_reg_address_filled : std_logic;
  signal next_reg_address_filled : std_logic;

  signal curr_reg_address : unsigned(7 downto 0);
  signal next_reg_address : unsigned(7 downto 0);

  signal dev_busy : std_logic;

  signal curr_dev_busy : std_logic;
  signal next_dev_busy : std_logic;

  signal rw : std_logic;
begin
  rst_n <= not rst_i;
  dev_busy_o <= dev_busy;

  next_dev_busy <= dev_busy;

  next_reg_address_filled <= '0' when curr_dev_busy = '0' and dev_busy = '1' and rw = '0' else
                             '1' when curr_reg_address_filled = '0' and rx_valid = '1' else
                             curr_reg_address_filled;

  rx_confirm <= rx_valid;

  next_reg_address <= unsigned(rx_data) when rx_valid = '1' and curr_reg_address_filled = '0' else
                      (curr_reg_address + 1) mod REGS_COUNT when rx_valid = '1' else
                      (curr_reg_address + 1) mod REGS_COUNT when tx_valid = '1' and dev_busy = '1' and rw = '1' else
                      curr_reg_address;

  tx_clear_buffer <= not curr_reg_address_filled;
  tx_data <= curr_regs(to_integer(curr_reg_address));
  tx_valid <= '1' when tx_ready = '1' and dev_busy = '1' and rw = '1' else
              '0';

  set_next_regs: process (all) is
  begin  -- process set_next_regs
    next_regs <= curr_regs;

    if rx_valid = '1' and curr_reg_address_filled = '1' then
      next_regs(to_integer(curr_reg_address)) <= rx_data;
    end if;
  end process set_next_regs;

  uut: entity i2c.slave
    generic map (
      SCL_FALLING_DELAY => 1)
    port map (
      clk_i          => clk_i,
      rst_in         => rst_n,
      address_i      => ADDRESS,
      generate_ack_i => '1',
      expect_ack_i   => '1',

      rx_valid_o     => rx_valid,
      rx_data_o      => rx_data,
      rx_confirm_i   => rx_confirm,
      rx_stretch_i   => '0',

      tx_ready_o     => tx_ready,
      tx_valid_i     => tx_valid,
      tx_data_i      => tx_data,
      tx_stretch_i   => '0',
      tx_clear_buffer_i => tx_clear_buffer,

      err_noack_o    => err_noack_o,
      rw_o           => rw,
      dev_busy_o     => dev_busy,
      bus_busy_o     => bus_busy_o,
      sda_i          => sda,
      scl_i          => scl,
      sda_enable_o   => sda_enable,
      scl_enable_o   => scl_enable);

  sda_open_buffer: entity utils.open_drain_buffer
    port map (
      pad_io   => sda_io,
      enable_i => sda_enable,
      state_o  => sda);
  scl_open_buffer: entity utils.open_drain_buffer
    port map (
      pad_io   => scl_io,
      enable_i => scl_enable,
      state_o  => scl);

  set_regs: process (clk_i) is
  begin  -- process set_regs
    if rising_edge(clk_i) then          -- rising clock edge
      if rst_n = '0' then              -- synchronous reset (active low)
      else
      end if;
    end if;
  end process set_regs;

end architecture a1;

Do not follow this link