~ruther/vhdl-spi-2

ref: 85e40acbb9c47cff0d091bcd607da8299c6928ea vhdl-spi-2/hdl_spi/src/spi_peripheral.vhd -rw-r--r-- 9.8 KiB
85e40acb — Rutherther feat(stm): Echo received number back 3 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
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 (
    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_i                : in  std_logic;
    miso_i               : in  std_logic;
    mosi_i               : in  std_logic;
    csn_i                : in  std_logic;
    sck_o                : out std_logic;
    miso_o               : out std_logic;
    mosi_o               : out std_logic;
    csn_o                : out std_logic;
    sck_t                : out std_logic;
    miso_t               : out std_logic;
    mosi_t               : out std_logic;
    csn_t                : out std_logic;
    -- Control
    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 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;

  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_full : 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_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_o               => sck_o,
      miso_o              => miso_o,
      mosi_o              => mosi_o,
      csn_o               => csn_o,
      sck_i               => sck_i,
      miso_i              => miso_i,
      mosi_i              => mosi_i,
      csn_i               => csn_i,
      sck_t               => sck_t,
      miso_t              => miso_t,
      mosi_t              => mosi_t,
      csn_t               => csn_t,
      -- 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 raddress_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 raddress_i is
      when CTRL_ADDRESS => rdata_o <= reg_control;
      when STATUS_ADDRESS => rdata_o <= reg_status;
      when DATA_ADDRESS => rdata_o <= (15 downto 0 => rx_buffer, others => '0');
      when INTMASK_ADDRESS => rdata_o <= reg_intmask;
      when others => rdata_o <= (others => '0');
    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
      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" &
                err_lost_rx_data &
                busy &
                "0" &
                (not tx_buffer_full) &
                rx_buffer_full;

  tx_data <= tx_buffer;

  rx_ready <= not rx_buffer_full;
  tx_valid <= tx_buffer_full;

end architecture a1;
Do not follow this link