~ruther/vhdl-spi-2

d990ecaaf7335612b4f8f2d3ed8e1bb1407a4237 — Rutherther 3 months ago dc0e370
feat: implement masterslave spi switch peripheral
A hdl_spi/src/spi_clkmon.vhd => hdl_spi/src/spi_clkmon.vhd +51 -0
@@ 0,0 1,51 @@
library ieee;
use ieee.std_logic_1164.all;

entity spi_clkmon is

  port (
    clk_i               : in  std_logic;
    rst_in              : in  std_logic;
    sck_i               : in  std_logic;
    csn_i               : in  std_logic;
    clock_polarity_i    : in  std_logic;
    clock_phase_i       : in  std_logic;
    clock_rising_o      : out std_logic;
    sample_data_o : out std_logic;
    change_data_o : out std_logic);

end entity spi_clkmon;

architecture a1 of spi_clkmon is
  signal changing : std_logic;

  signal sample_data : std_logic;
  signal change_data : std_logic;

  signal curr_sck : std_logic;
  signal next_sck : std_logic;

begin  -- architecture a1

  set_curr_sck: process (clk_i) is
  begin  -- process set_curr_sck
    if rising_edge(clk_i) then          -- rising clock edge
      if rst_in = '0' or csn_i = '1' then -- synchronous reset (active low)
        curr_sck <= '0';
      else
        curr_sck <= next_sck;
      end if;
    end if;
  end process set_curr_sck;

  next_sck <= sck_i when clock_polarity_i = '0' else not sck_i;

  changing <= '1' when next_sck /= curr_sck else '0';
  sample_data <= '1' when curr_sck = clock_phase_i and changing = '1' else '0';
  change_data <= '1' when curr_sck /= clock_phase_i and changing = '1' else '0';

  clock_rising_o <= sample_data;
  sample_data_o <= sample_data;
  change_data_o <= change_data;

end architecture a1;

M hdl_spi/src/spi_master.vhd => hdl_spi/src/spi_master.vhd +1 -1
@@ 134,7 134,7 @@ begin  -- architecture a1
      SIZE => MAX_SIZE)
    port map (
      clk_i => clk_i,
      rst_in => rst_in,
      rst_in => rst_n,
      -- Control
      shift_i => latch_sample_data,     -- sampling
      latch_i => latch_new_tx_data,     -- latching tx data

M hdl_spi/src/spi_master_ctrl.vhd => hdl_spi/src/spi_master_ctrl.vhd +16 -2
@@ 169,6 169,10 @@ begin  -- architecture a1
      when others =>
        next_state <= RESET;
    end case;

    if en_i = '0' then
      next_state <= RESET;
    end if;
  end process state;

  tx_state: process(all) is


@@ 210,6 214,11 @@ begin  -- architecture a1
    if curr_state = RESET then
      next_tx_state <= IDLE;
    end if;

    if tx_en_i = '0' then
      next_tx_state <= IDLE;
      tx_got_data <= not rx_block;               -- simulate always receiving new data
    end if;
  end process tx_state;

  rx_state: process(all) is


@@ 248,6 257,11 @@ begin  -- architecture a1
    if curr_state = RESET then
      next_rx_state <= IDLE;
    end if;

    if rx_en_i = '0' then
      next_rx_state <= IDLE;
      rx_block <= '0';                  -- do not block if disabled
    end if;
  end process rx_state;

  error_rx_lost : entity work.rs_latch


@@ 260,8 274,8 @@ begin  -- architecture a1
  shifting_length <= SIZES(to_integer(unsigned(size_sel_i)));
  zero <= '1' when curr_counter = 0 else '0';

  -- Enable IOs
  miso_en_o <= en_i and rx_en_i;
  -- Enable Outputs
  miso_en_o <= '0';
  sck_en_o <= en_i;
  mosi_en_o <= en_i and tx_en_i;
  csn_en_o <= en_i;

A hdl_spi/src/spi_masterslave.vhd => hdl_spi/src/spi_masterslave.vhd +308 -0
@@ 0,0 1,308 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.spi_pkg.all;

entity spi_masterslave is

  generic (
    SIZES            : natural_vector := (8, 16);
    SIZES_2LOG       : natural := 1;
    DIVISORS         : natural_vector := (2, 4, 6, 8, 16, 32, 64, 128, 256);
    DIVISORS_LOG2    : natural := 3;
    CSN_PULSE_CYCLES : natural := 1
  );

  port (
    -- IOs
    sck_io               : inout std_logic;
    miso_io              : inout std_logic;
    mosi_io              : inout std_logic;
    csn_io               : inout std_logic;
    -- Control
    clk_i                : in    std_logic;
    rst_in               : in    std_logic;
    en_i                 : in    std_logic;
    master_i             : in    std_logic;
    clock_polarity_i     : in    std_logic;
    clock_phase_i        : in    std_logic;
    size_sel_i           : in    std_logic_vector(SIZES_2LOG - 1 downto 0);
    div_sel_i            : in    std_logic_vector(DIVISORS_LOG2 - 1 downto 0);
    pulse_csn_i          : in    std_logic;
    rx_block_on_full_i   : in    std_logic;
    -- Data
    -- Rx
    rx_en_i              : in    std_logic;
    rx_data_o            : out   std_logic_vector(get_max_natural(SIZES) - 1 downto 0);
    rx_valid_o           : out   std_logic;
    rx_ready_i           : out   std_logic;
    -- Tx
    tx_en_i              : in    std_logic;
    tx_data_i            : in    std_logic_vector(get_max_natural(SIZES) - 1 downto 0);
    tx_valid_i           : out   std_logic;
    tx_ready_o           : out   std_logic;
    -- State
    busy_o               : out   std_logic;
    err_lost_rx_data_o   : out   std_logic;
    clear_lost_rx_data_i : in    std_logic);

end entity spi_masterslave;

architecture a1 of spi_masterslave is
  constant MAX_SIZE : natural := get_max_natural(SIZES);

  signal rst_n : std_logic;

  signal ctrl_rst_n : std_logic;
  signal master_ctrl_rst_n : std_logic;
  signal slave_ctrl_rst_n : std_logic;

  signal latch_sample_data     : std_logic;
  signal latch_change_data_out : std_logic;
  signal latch_new_tx_data     : std_logic;

  signal tx_input_data : std_logic;
  signal tx_serial_data : std_logic_vector(0 downto 0);
  signal rx_serial_data : std_logic;

  signal start_clock : std_logic;

  signal selected_size : natural;

  signal master_en : std_logic;
  signal slave_en : std_logic;

  signal slave_clock_rising : std_logic;
  signal slave_rx_valid : std_logic;
  signal slave_tx_ready : std_logic;
  signal slave_busy : std_logic;
  signal slave_err_lost_rx_data : std_logic;
  signal slave_ctrl_rst : std_logic;
  signal slave_csn_en : std_logic;
  signal slave_mosi_en : std_logic;
  signal slave_miso_en : std_logic;
  signal slave_sck_mask : std_logic;
  signal slave_sck_en : std_logic;
  signal slave_start_clock : std_logic;
  signal slave_latch_new_tx_data : std_logic;
  signal slave_latch_sample_data : std_logic;
  signal slave_latch_change_data : std_logic;

  signal master_sck : std_logic;
  signal master_clock_rising : std_logic;
  signal master_rx_valid : std_logic;
  signal master_tx_ready : std_logic;
  signal master_busy : std_logic;
  signal master_err_lost_rx_data : std_logic;
  signal master_ctrl_rst : std_logic;
  signal master_csn : std_logic;
  signal master_csn_en : std_logic;
  signal master_mosi_en : std_logic;
  signal master_miso_en : std_logic;
  signal master_sck_mask : std_logic;
  signal master_sck_en : std_logic;
  signal master_start_clock : std_logic;
  signal master_latch_new_tx_data : std_logic;
  signal master_latch_sample_data : std_logic;
  signal master_latch_change_data : std_logic;

begin  -- architecture a1
  master_en <= en_i and master_i;
  slave_en <= en_i and not master_i;

  rst_n <= rst_in and ctrl_rst_n;
  selected_size <= SIZES(to_integer(unsigned(size_sel_i)));

  master_ctrl : entity work.spi_master_ctrl
    generic map (
      SIZES            => SIZES,
      SIZES_2LOG       => SIZES_2LOG,
      CSN_PULSE_CYCLES => CSN_PULSE_CYCLES)
    port map (
      clk_i                => clk_i,
      rst_in               => rst_in,
      en_i                 => master_en,
      size_sel_i           => size_sel_i,
      pulse_csn_i          => pulse_csn_i,
      rx_block_on_full_i   => rx_block_on_full_i,
      rx_en_i              => rx_en_i,
      rx_ready_i           => rx_ready_i,
      tx_en_i              => tx_en_i,
      tx_valid_i           => tx_valid_i,
      clear_lost_rx_data_i => clear_lost_rx_data_i,

      clock_rising_i       => master_clock_rising,
      rx_valid_o           => master_rx_valid,
      tx_ready_o           => master_tx_ready,
      busy_o               => master_busy,
      err_lost_rx_data_o   => master_err_lost_rx_data,
      rst_on               => master_ctrl_rst,
      csn_o                => master_csn,
      csn_en_o             => master_csn_en,
      mosi_en_o            => master_mosi_en,
      miso_en_o            => master_miso_en,
      sck_mask_o           => master_sck_mask,
      sck_en_o             => master_sck_en,
      gen_clk_en_o         => master_start_clock,
      latch_tx_data_o      => master_latch_new_tx_data);

  slave_ctrl : entity work.spi_slave_ctrl
    generic map (
      SIZES            => SIZES,
      SIZES_2LOG       => SIZES_2LOG,
      CSN_PULSE_CYCLES => CSN_PULSE_CYCLES)
    port map (
      clk_i                => clk_i,
      rst_in               => rst_in,
      en_i                 => master_en,
      size_sel_i           => size_sel_i,
      pulse_csn_i          => pulse_csn_i,
      rx_block_on_full_i   => rx_block_on_full_i,
      rx_en_i              => rx_en_i,
      rx_ready_i           => rx_ready_i,
      tx_en_i              => tx_en_i,
      tx_valid_i           => tx_valid_i,
      clear_lost_rx_data_i => clear_lost_rx_data_i,

      clock_rising_i       => slave_clock_rising,
      rx_valid_o           => slave_rx_valid,
      tx_ready_o           => slave_tx_ready,
      busy_o               => slave_busy,
      err_lost_rx_data_o   => slave_err_lost_rx_data,
      rst_on               => slave_ctrl_rst,
      csn_en_o             => slave_csn_en,
      mosi_en_o            => slave_mosi_en,
      miso_en_o            => slave_miso_en,
      sck_mask_o           => slave_sck_mask,
      sck_en_o             => slave_sck_en,
      gen_clk_en_o         => slave_start_clock,
      latch_tx_data_o      => slave_latch_new_tx_data);

  clkgen : entity work.spi_clkgen
    generic map (
      DIVISORS      => DIVISORS,
      DIVISORS_LOG2 => DIVISORS_LOG2)
    port map (
      clk_i            => clk_i,
      rst_in           => master_ctrl_rst_n,
      start_i          => start_clock,
      div_sel_i        => div_sel_i,
      clock_polarity_i => clock_polarity_i,
      clock_phase_i    => clock_phase_i,
      sck_o            => master_sck,
      sck_mask_i       => master_sck_mask,
      clock_rising_o   => master_clock_rising,
      sample_data_o    => master_latch_sample_data,
      change_data_o    => master_latch_change_data);

  clkmon : entity work.spi_clkmon
    port map (
      clk_i            => clk_i,
      rst_in           => slave_ctrl_rst_n,
      clock_polarity_i => clock_polarity_i,
      clock_phase_i    => clock_phase_i,
      sck_i            => sck_io,
      csn_i            => csn_io,
      clock_rising_o   => slave_clock_rising,
      sample_data_o    => slave_latch_sample_data,
      change_data_o    => slave_latch_change_data);

  shift_register: entity work.shift_register
    generic map (
      SIZE => MAX_SIZE)
    port map (
      clk_i => clk_i,
      rst_in => rst_n,
      -- Control
      shift_i => latch_sample_data,     -- sampling
      latch_i => latch_new_tx_data,     -- latching tx data
      -- Parallel
      data_i => tx_data_i,
      data_o => rx_data_o,
      -- Serial
      sd_i => rx_serial_data,
      sd_o => open);

  tx_input_data <= rx_data_o(selected_size - 1);

  mosi_reg : entity work.reg
    generic map (
      SIZE => 1)
    port map (
      -- outputting different bit on mosi
      clk_i   => clk_i,
      rst_in  => rst_n,
      d_i     => (0 => tx_input_data),
      q_o     => tx_serial_data,
      latch_i => latch_change_data_out);

  master_connection : entity work.spi_multiplexor
    port map (
      en_i                => master_en,
      mosi_en_i           => master_mosi_en,
      miso_en_i           => master_miso_en,
      sck_en_i            => master_sck_en,
      csn_en_i            => master_csn_en,
      mosi_i              => tx_serial_data(0),
      miso_i              => '0',
      sck_i               => master_sck,
      csn_i               => master_csn,
      mosi_o              => mosi_io,
      miso_o              => miso_io,
      sck_o               => sck_io,
      csn_o               => csn_io,
      rx_valid_i          => master_rx_valid,
      rx_valid_o          => rx_valid_o,
      tx_ready_i          => master_tx_ready,
      tx_ready_o          => tx_ready_o,
      busy_i              => master_busy,
      busy_o              => busy_o,
      err_lost_rx_data_i  => master_err_lost_rx_data,
      err_lost_rx_data_o  => err_lost_rx_data_o,
      rst_in              => master_ctrl_rst,
      rst_on              => ctrl_rst_n,
      latch_tx_data_i     => master_latch_new_tx_data,
      latch_tx_data_o     => latch_new_tx_data,
      latch_sample_data_i => master_latch_sample_data,
      latch_sample_data_o => latch_sample_data,
      latch_change_data_i => master_latch_change_data,
      latch_change_data_o => latch_change_data_out,
      rx_serial_i         => miso_io,
      rx_serial_o         => rx_serial_data);

  slave_connection : entity work.spi_multiplexor
    port map (
      en_i                => slave_en,
      mosi_en_i           => slave_mosi_en,
      miso_en_i           => slave_miso_en,
      sck_en_i            => slave_sck_en,
      csn_en_i            => slave_csn_en,
      mosi_i              => '0',
      miso_i              => tx_serial_data(0),
      sck_i               => '0',
      csn_i               => '0',
      mosi_o              => mosi_io,
      miso_o              => miso_io,
      sck_o               => sck_io,
      csn_o               => csn_io,
      rx_valid_i          => slave_rx_valid,
      rx_valid_o          => rx_valid_o,
      tx_ready_i          => slave_tx_ready,
      tx_ready_o          => tx_ready_o,
      busy_i              => slave_busy,
      busy_o              => busy_o,
      err_lost_rx_data_i  => slave_err_lost_rx_data,
      err_lost_rx_data_o  => err_lost_rx_data_o,
      rst_in              => slave_ctrl_rst,
      rst_on              => ctrl_rst_n,
      latch_tx_data_i     => slave_latch_new_tx_data,
      latch_tx_data_o     => latch_new_tx_data,
      latch_sample_data_i => slave_latch_sample_data,
      latch_sample_data_o => latch_sample_data,
      latch_change_data_i => slave_latch_change_data,
      latch_change_data_o => latch_change_data_out,
      rx_serial_i         => mosi_io,
      rx_serial_o         => rx_serial_data);

end architecture a1;

A hdl_spi/src/spi_multiplexor.vhd => hdl_spi/src/spi_multiplexor.vhd +63 -0
@@ 0,0 1,63 @@
library ieee;
use ieee.std_logic_1164.all;

entity spi_multiplexor is

  port (
    en_i               : in  std_logic;
    mosi_en_i          : in  std_logic;
    miso_en_i          : in  std_logic;
    sck_en_i           : in  std_logic;
    csn_en_i           : in  std_logic;
    mosi_i             : in  std_logic;
    miso_i             : in  std_logic;
    sck_i              : in  std_logic;
    csn_i              : in  std_logic;
    mosi_o             : out std_logic;
    miso_o             : out std_logic;
    sck_o              : out std_logic;
    csn_o              : out std_logic;
    rx_valid_i         : in  std_logic;
    rx_valid_o         : out std_logic;
    tx_ready_i         : in  std_logic;
    tx_ready_o         : out std_logic;
    busy_i             : in  std_logic;
    busy_o             : out std_logic;
    err_lost_rx_data_i : in  std_logic;
    err_lost_rx_data_o : out std_logic;
    rst_in             : in  std_logic;
    rst_on             : out std_logic;

    latch_tx_data_i : in  std_logic;
    latch_tx_data_o : out std_logic;

    latch_sample_data_i : in  std_logic;
    latch_sample_data_o : out std_logic;

    latch_change_data_i : in  std_logic;
    latch_change_data_o : out std_logic;

    rx_serial_i : in  std_logic;
    rx_serial_o : out std_logic);

end entity spi_multiplexor;

architecture a1 of spi_multiplexor is

begin  -- architecture a1

  mosi_o <= mosi_i when mosi_en_i = '1' and en_i = '1' else 'Z';
  miso_o <= miso_i when miso_en_i = '1' and en_i = '1' else 'Z';
  sck_o <= sck_i when sck_en_i = '1' and en_i = '1' else'Z';
  csn_o <= csn_i when csn_en_i = '1' and en_i = '1' else'Z';
  rx_valid_o <= rx_valid_i when en_i = '1' else'Z';
  tx_ready_o <= tx_ready_i when en_i = '1' else'Z';
  busy_o <= busy_i when en_i = '1' else'Z';
  err_lost_rx_data_o <= err_lost_rx_data_i when en_i = '1' else'Z';
  rst_on <= rst_in when en_i = '1' else'Z';
  latch_tx_data_o <= latch_tx_data_i when en_i = '1' else'Z';
  latch_sample_data_o <= latch_sample_data_i when en_i = '1' else'Z';
  latch_change_data_o <= latch_change_data_i when en_i = '1' else'Z';
  rx_serial_o <= rx_serial_i;

end architecture a1;

A hdl_spi/src/spi_peripheral.vhd => hdl_spi/src/spi_peripheral.vhd +122 -0
@@ 0,0 1,122 @@
library ieee;
use ieee.std_logic_1164.all;
use work.spi_pkg.all;

entity spi_peripheral is

  generic (
    SIZES            : natural_vector := (8, 16);
    SIZES_2LOG       : natural := 1;
    DIVISORS         : natural_vector := (2, 4, 6, 8, 16, 32, 64, 128, 256);
    DIVISORS_LOG2    : natural := 3;
    CSN_PULSE_CYCLES : natural := 1
  );

  port (
    address_i : in std_logic_vector(2 downto 0);
    data_i : in std_logic_vector(31 downto 0);
    data_o : out std_logic_vector(31 downto 0);
    write_i : in std_logic;
    read_i : in std_logic;

    -- IOs
    sck_o                : out std_logic;
    miso_i               : in  std_logic;
    mosi_o               : out std_logic;
    csn_o                : out std_logic;

    -- Control
    clk_i                : in  std_logic;
    rst_in               : in  std_logic;
    rx_data_o            : out std_logic_vector(get_max_natural(SIZES) - 1 downto 0);
    rx_valid_o           : out std_logic;
    tx_ready_o           : out std_logic;
    busy_o               : out std_logic;
    err_lost_rx_data_o   : out std_logic);

end entity spi_peripheral;

architecture a1 of spi_peripheral is
  constant MAX_SIZE : natural := get_max_natural(SIZES);

  constant CTRL_ADDRESS   : std_logic_vector(2 downto 0) := "000";
  constant STATUS_ADDRESS : std_logic_vector(2 downto 0) := "010";
  constant DATA_ADDRESS   : std_logic_vector(2 downto 0) := "011";

  signal rx_buffer : std_logic_vector(MAX_SIZE - 1 downto 0);
  signal rx_buffer_full : std_logic;
  signal tx_buffer : std_logic_vector(MAX_SIZE - 1 downto 0);
  signal tx_buffer_full : std_logic;

  signal rx_ready : std_logic;
  signal rx_valid : std_logic;
  signal tx_valid : std_logic;
  signal tx_ready : std_logic;
  signal tx_data : std_logic_vector(MAX_SIZE - 1 downto 0);
  signal rx_data : std_logic_vector(MAX_SIZE - 1 downto 0);
  signal rx_data_lost : std_logic;
  signal busy : std_logic;

  signal reg_control : std_logic_vector(31 downto 0);
  signal reg_status : std_logic_vector(31 downto 0);

  signal clear_rx_buffer_full : std_logic;
begin  -- architecture a1

  reader: process (clk_i) is
  begin  -- process reader
    if rising_edge(clk_i) then          -- rising clock edge
      if rst_in = '0' then              -- synchronous reset (active low)

      elsif read_i = '1' then
        case address_i is
          when DATA_ADDRESS => clear_rx_buffer_full <= '1';
          when others => null;
        end case;
      else
        clear_rx_buffer_full <= '0';
      end if;
    end if;
  end process reader;

  output_register: process (all) is
  begin  -- process output_register
    case address_i is
      when CTRL_ADDRESS => data_o(reg_control'range) <= reg_control(reg_control'range);
      when STATUS_ADDRESS => data_o <= reg_status;
      when DATA_ADDRESS => data_o <= rx_buffer;
      when others => null;
    end case;
  end process output_register;

  rx_buffer_reader: process (clk_i) is
  begin  -- process rx_buffer_full
    if rising_edge(clk_i) then          -- rising clock edge
      if rst_in = '0' then              -- synchronous reset (active low)
        rx_buffer_full <= '0';
      else
        if clear_rx_buffer_full = '1' then
          rx_buffer_full <= '0';
        end if;

        if rx_valid = '1' then
          rx_buffer_full <= '1';
          rx_buffer <= rx_data;
        end if;
      end if;
    end if;
  end process rx_buffer_reader;

  reg_status <= "000000000000000000000000000" &
                rx_data_lost &
                busy &
                "0" &
                tx_buffer_full &
                rx_buffer_full;

  tx_data <= tx_buffer;

  rx_ready <= not rx_buffer_full;
  tx_valid <= tx_buffer_full;

end architecture a1;

A hdl_spi/src/spi_slave_ctrl.vhd => hdl_spi/src/spi_slave_ctrl.vhd +48 -0
@@ 0,0 1,48 @@
library ieee;
use ieee.std_logic_1164.all;
use work.spi_pkg.all;

entity spi_slave_ctrl is

  generic (
    SIZES            : natural_vector := (8, 16);
    SIZES_2LOG       : natural := 1;
    CSN_PULSE_CYCLES : natural := 1
  );

  port (
    clk_i                : in  std_logic;
    rst_in               : in  std_logic;
    en_i                 : in  std_logic;
    size_sel_i           : in  std_logic_vector(SIZES_2LOG - 1 downto 0);
    pulse_csn_i          : in  std_logic;
    clock_rising_i       : in  std_logic;
    rx_block_on_full_i   : in  std_logic;
    rx_en_i              : in  std_logic;
    rx_valid_o           : out std_logic;
    rx_ready_i           : in  std_logic;
    tx_en_i              : in  std_logic;
    tx_valid_i           : in  std_logic;
    tx_ready_o           : out std_logic;
    busy_o               : out std_logic;
    err_lost_rx_data_o   : out std_logic;
    clear_lost_rx_data_i : in  std_logic;
    rst_on               : out std_logic;
    csn_o                : out std_logic;
    csn_en_o             : out std_logic;
    mosi_en_o            : out std_logic;
    miso_en_o            : out std_logic;
    sck_mask_o           : out std_logic;
    sck_en_o             : out std_logic;
    gen_clk_en_o         : out std_logic;
    latch_tx_data_o      : out std_logic);

end entity spi_slave_ctrl;

architecture a1 of spi_slave_ctrl is

begin  -- architecture a1



end architecture a1;

Do not follow this link