~ruther/vhdl-spi-2

88802885bee07d584c0d74a579f3118d7dd59b02 — Rutherther 3 months ago fcd7233
feat: implement spi memory mapped peripheral
1 files changed, 181 insertions(+), 39 deletions(-)

M hdl_spi/src/spi_peripheral.vhd
M hdl_spi/src/spi_peripheral.vhd => hdl_spi/src/spi_peripheral.vhd +181 -39
@@ 13,63 13,186 @@ entity spi_peripheral is
  );

  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;

    waddress_i         : in    std_logic_vector(2 downto 0);
    wdata_i            : in    std_logic_vector(31 downto 0);
    raddress_i         : in    std_logic_vector(2 downto 0);
    rdata_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;

    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;
    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);
    clk_i              : in    std_logic;
    rst_in             : in    std_logic;
    interrupt_o        : out   std_logic
    -- 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";
  constant CTRL_ADDRESS    : std_logic_vector(2 downto 0) := "000";
  constant INTMASK_ADDRESS : std_logic_vector(2 downto 0) := "001";
  constant STATUS_ADDRESS  : std_logic_vector(2 downto 0) := "010";
  constant DATA_ADDRESS    : std_logic_vector(2 downto 0) := "011";

  constant CTRL_EN_BIT             : natural := 0;
  constant CTRL_MASTER_BIT         : natural := 1;
  constant CTRL_TX_EN_BIT          : natural := 2;
  constant CTRL_RX_EN_BIT          : natural := 3;
  constant CTRL_CLOCK_POLARITY_BIT : natural := 4;
  constant CTRL_CLOCK_PHASE_BIT    : natural := 5;
  constant CTRL_PULSE_CSN_BIT      : natural := 6;
  constant CTRL_LSBFIRST_BIT       : natural := 7;
  -- constant CTRL_RX_BLOCK_ON_FULL_BIT : natural := 8;
  constant CTRL_SIZE_SEL_BIT       : natural := 10;
  constant CTRL_DIV_SEL_BIT        : natural := 20;

  signal rx_buffer : std_logic_vector(MAX_SIZE - 1 downto 0);
  constant INTMASK_RX_BUFFER_FULL : natural := 0;
  constant INTMASK_TX_BUFFER_EMPTY : natural := 1;
  constant INTMASK_LOST_RX_DATA : natural := 4;

  constant CTRL_DEFAULT : std_logic_vector(31 downto 0)
  := (CTRL_TX_EN_BIT => '1',
      CTRL_RX_EN_BIT => '1',
      others         => '0');
  constant INTMASK_DEFAULT : std_logic_vector(31 downto 0) := (others => '0');

  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      : 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 fill_tx_buffer : std_logic;

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

  signal clear_rx_buffer_full : std_logic;

  signal en                 : std_logic;
  signal master             : std_logic;
  signal clock_polarity     : std_logic;
  signal clock_phase        : std_logic;
  signal size_sel           : std_logic_vector(SIZES_2LOG - 1 downto 0);
  signal div_sel            : std_logic_vector(DIVISORS_LOG2 - 1 downto 0);
  signal pulse_csn          : std_logic;
  signal rx_block_on_full   : std_logic;
  signal lsbfirst           : std_logic;
  -- Rx
  signal rx_en              : std_logic;
  signal rx_data            : std_logic_vector(MAX_SIZE - 1 downto 0);
  signal rx_valid           : std_logic;
  signal rx_ready           : std_logic;
  -- Tx
  signal tx_en              : std_logic;
  signal tx_data            : std_logic_vector(MAX_SIZE - 1 downto 0);
  signal tx_valid           : std_logic;
  signal tx_ready           : std_logic;
  -- State
  signal busy               : std_logic;
  signal err_lost_rx_data   : std_logic;
  signal clear_lost_rx_data : std_logic;
begin  -- architecture a1

  interrupt_o <= (rx_buffer_full and reg_intmask(INTMASK_RX_BUFFER_FULL)) or
                 (not tx_buffer_full and reg_intmask(INTMASK_TX_BUFFER_EMPTY)) or
                 (err_lost_rx_data and reg_intmask(INTMASK_LOST_RX_DATA));

  en             <= reg_control(CTRL_EN_BIT);
  master         <= reg_control(CTRL_MASTER_BIT);
  clock_polarity <= reg_control(CTRL_CLOCK_POLARITY_BIT);
  clock_phase    <= reg_control(CTRL_CLOCK_PHASE_BIT);
  pulse_csn      <= reg_control(CTRL_PULSE_CSN_BIT);
  size_sel       <= reg_control(CTRL_SIZE_SEL_BIT + SIZES_2LOG - 1 downto CTRL_SIZE_SEL_BIT);
  div_sel        <= reg_control(CTRL_DIV_SEL_BIT + DIVISORS_LOG2 - 1 downto CTRL_DIV_SEL_BIT);
  lsbfirst       <= reg_control(CTRL_LSBFIRST_BIT);

  tx_en          <= reg_control(CTRL_TX_EN_BIT);
  rx_en          <= reg_control(CTRL_RX_EN_BIT);

  rx_block_on_full <= '0';

  masterslave : entity work.spi_masterslave
    generic map (
      DIVISORS         => DIVISORS,
      DIVISORS_LOG2    => DIVISORS_LOG2,
      SIZES            => SIZES,
      SIZES_2LOG       => SIZES_2LOG,
      CSN_PULSE_CYCLES => CSN_PULSE_CYCLES)
    port map (
      -- IOs
      sck_io               => sck_io,
      miso_io              => miso_io,
      mosi_io              => mosi_io,
      csn_io               => csn_io,
      -- Control
      clk_i                => clk_i,
      rst_in               => rst_in,
      en_i                 => en,
      master_i             => master,
      clock_polarity_i     => clock_polarity,
      clock_phase_i        => clock_phase,
      size_sel_i           => size_sel,
      div_sel_i            => div_sel,
      pulse_csn_i          => pulse_csn,
      rx_block_on_full_i   => rx_block_on_full,
      lsbfirst_i           => lsbfirst,
      -- Data
      -- Rx
      rx_en_i              => rx_en,
      rx_data_o            => rx_data,
      rx_valid_o           => rx_valid,
      rx_ready_i           => rx_ready,
      -- Tx
      tx_en_i              => tx_en,
      tx_data_i            => tx_data,
      tx_valid_i           => tx_valid,
      tx_ready_o           => tx_ready,
      -- State
      busy_o               => busy,
      err_lost_rx_data_o   => err_lost_rx_data,
      clear_lost_rx_data_i => clear_lost_rx_data);

  writer: process (clk_i) is
  begin  -- process writer
    if rising_edge(clk_i) then          -- rising clock edge
      if rst_in = '0' then              -- synchronous reset (active low)
        reg_control <= CTRL_DEFAULT;
        reg_intmask <= INTMASK_DEFAULT;
        fill_tx_buffer <= '0';
      elsif write_i = '1' then
        case waddress_i is
          when CTRL_ADDRESS => reg_control <= wdata_i;
          when INTMASK_ADDRESS => reg_intmask <= wdata_i;
          when DATA_ADDRESS => fill_tx_buffer <= '1';
          when STATUS_ADDRESS =>
            clear_lost_rx_data <= wdata_i(4);
          when others => null;
        end case;
      else
        fill_tx_buffer <= '0';
        clear_lost_rx_data <= '0';
      end if;
    end if;
  end process writer;

  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)

        clear_rx_buffer_full <= '0';
      elsif read_i = '1' then
        case address_i is
        case raddress_i is
          when DATA_ADDRESS => clear_rx_buffer_full <= '1';
          when others => null;
        end case;


@@ 81,14 204,33 @@ begin  -- architecture a1

  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;
    case raddress_i is
      when CTRL_ADDRESS => rdata_o <= reg_control;
      when STATUS_ADDRESS => rdata_o <= reg_status;
      when DATA_ADDRESS => rdata_o <= (rx_buffer'range => rx_buffer, others => '0');
      when INTMASK_ADDRESS => rdata_o <= reg_intmask;
      when others => null;
    end case;
  end process output_register;

  tx_buffer_writer: process (clk_i) is
  begin  -- process tx_buffer_writer
    if rising_edge(clk_i) then          -- rising clock edge
      if rst_in = '0' then              -- synchronous reset (active low)
        tx_buffer <= (others => '0');
        tx_buffer_full <= '0';
      else
        if fill_tx_buffer = '1' and tx_buffer_full =  '0' then
          tx_buffer_full <= '1';
          tx_buffer <= wdata_i(tx_buffer'range);
          tx_buffer_full <= '1';
        elsif tx_ready = '1' and tx_buffer_full = '1' then
          tx_buffer_full <= '0';
        end if;
      end if;
    end if;
  end process tx_buffer_writer;

  rx_buffer_reader: process (clk_i) is
  begin  -- process rx_buffer_full
    if rising_edge(clk_i) then          -- rising clock edge


@@ 108,7 250,7 @@ begin  -- architecture a1
  end process rx_buffer_reader;

  reg_status <= "000000000000000000000000000" &
                rx_data_lost &
                err_lost_rx_data &
                busy &
                "0" &
                tx_buffer_full &

Do not follow this link