OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [rtl/] [core/] [neorv32_xip.vhd] - Blame information for rev 70

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 70 zero_gravi
-- #################################################################################################
2
-- # << NEORV32 - Execute In Place (XIP) Module >>                                                 #
3
-- # ********************************************************************************************* #
4
-- # This module allows the CPU to execute code (and read constant data) directly from an SPI      #
5
-- # flash memory. Two host ports are implemented: one  for accessing the control and status       #
6
-- # registers (mapped to the processor's IO space) and one for the actual instruction/data fetch. #
7
-- # The actual address space mapping of the "instruction/data interface" is done by programming   #
8
-- # special control register bits.                                                                #
9
-- # ********************************************************************************************* #
10
-- # BSD 3-Clause License                                                                          #
11
-- #                                                                                               #
12
-- # Copyright (c) 2022, Stephan Nolting. All rights reserved.                                     #
13
-- #                                                                                               #
14
-- # Redistribution and use in source and binary forms, with or without modification, are          #
15
-- # permitted provided that the following conditions are met:                                     #
16
-- #                                                                                               #
17
-- # 1. Redistributions of source code must retain the above copyright notice, this list of        #
18
-- #    conditions and the following disclaimer.                                                   #
19
-- #                                                                                               #
20
-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
21
-- #    conditions and the following disclaimer in the documentation and/or other materials        #
22
-- #    provided with the distribution.                                                            #
23
-- #                                                                                               #
24
-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
25
-- #    endorse or promote products derived from this software without specific prior written      #
26
-- #    permission.                                                                                #
27
-- #                                                                                               #
28
-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
29
-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
30
-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
31
-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
32
-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
33
-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
34
-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
35
-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
36
-- # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
37
-- # ********************************************************************************************* #
38
-- # The NEORV32 Processor - https://github.com/stnolting/neorv32              (c) Stephan Nolting #
39
-- #################################################################################################
40
 
41
library ieee;
42
use ieee.std_logic_1164.all;
43
use ieee.numeric_std.all;
44
 
45
library neorv32;
46
use neorv32.neorv32_package.all;
47
 
48
entity neorv32_xip is
49
  port (
50
    -- global control --
51
    clk_i       : in  std_ulogic; -- global clock line
52
    rstn_i      : in  std_ulogic; -- global reset line, low-active
53
    -- host access: control register access port --
54
    ct_addr_i   : in  std_ulogic_vector(31 downto 0); -- address
55
    ct_rden_i   : in  std_ulogic; -- read enable
56
    ct_wren_i   : in  std_ulogic; -- write enable
57
    ct_data_i   : in  std_ulogic_vector(31 downto 0); -- data in
58
    ct_data_o   : out std_ulogic_vector(31 downto 0); -- data out
59
    ct_ack_o    : out std_ulogic; -- transfer acknowledge
60
    -- host access: instruction fetch access port (read-only) --
61
    if_addr_i   : in  std_ulogic_vector(31 downto 0); -- address
62
    if_rden_i   : in  std_ulogic; -- read enable
63
    if_data_o   : out std_ulogic_vector(31 downto 0); -- data out
64
    if_ack_o    : out std_ulogic; -- transfer acknowledge
65
    -- status --
66
    xip_en_o    : out std_ulogic; -- XIP enable
67
    xip_acc_o   : out std_ulogic; -- pending XIP access
68
    xip_page_o  : out std_ulogic_vector(03 downto 0); -- XIP page
69
    -- clock generator --
70
    clkgen_en_o : out std_ulogic; -- enable clock generator
71
    clkgen_i    : in  std_ulogic_vector(07 downto 0);
72
    -- SPI device interface --
73
    spi_csn_o   : out std_ulogic; -- chip-select, low-active
74
    spi_clk_o   : out std_ulogic; -- serial clock
75
    spi_data_i  : in  std_ulogic; -- device data output
76
    spi_data_o  : out std_ulogic  -- controller data output
77
  );
78
end neorv32_xip;
79
 
80
architecture neorv32_xip_rtl of neorv32_xip is
81
 
82
  -- IO space: module base address --
83
  constant hi_abb_c : natural := index_size_f(io_size_c)-1; -- high address boundary bit
84
  constant lo_abb_c : natural := index_size_f(xip_size_c); -- low address boundary bit
85
 
86
  -- CT register access control --
87
  signal ct_acc_en : std_ulogic; -- module access enable
88
  signal ct_addr   : std_ulogic_vector(31 downto 0); -- access address
89
  signal ct_wren   : std_ulogic; -- word write enable
90
  signal ct_rden   : std_ulogic; -- read enable
91
 
92
  -- control register --
93
  constant ctrl_enable_c      : natural :=  0; -- r/w: module enable
94
  constant ctrl_spi_prsc0_c   : natural :=  1; -- r/w: SPI clock prescaler select - bit 0
95
  constant ctrl_spi_prsc1_c   : natural :=  2; -- r/w: SPI clock prescaler select - bit 1
96
  constant ctrl_spi_prsc2_c   : natural :=  3; -- r/w: SPI clock prescaler select - bit 2
97
  constant ctrl_spi_cpol_c    : natural :=  4; -- r/w: SPI (idle) clock polarity
98
  constant ctrl_spi_cpha_c    : natural :=  5; -- r/w: SPI clock phase
99
  constant ctrl_spi_nbytes0_c : natural :=  6; -- r/w: SPI number of bytes in transmission (1..9) - bit 0
100
  constant ctrl_spi_nbytes3_c : natural :=  9; -- r/w: SPI number of bytes in transmission (1..9) - bit 3
101
  constant ctrl_xip_enable_c  : natural := 10; -- r/w: XIP access mode enable
102
  constant ctrl_xip_abytes0_c : natural := 11; -- r/w: XIP number of address bytes (0=1,1=2,2=3,3=4) - bit 0
103
  constant ctrl_xip_abytes1_c : natural := 12; -- r/w: XIP number of address bytes (0=1,1=2,2=3,3=4) - bit 1
104
  constant ctrl_rd_cmd0_c     : natural := 13; -- r/w: SPI flash read command - bit 0
105
  constant ctrl_rd_cmd7_c     : natural := 20; -- r/w: SPI flash read command - bit 7
106
  constant ctrl_page0_c       : natural := 21; -- r/w: XIP memory page - bit 0
107
  constant ctrl_page3_c       : natural := 24; -- r/w: XIP memory page - bit 3
108
  constant ctrl_spi_csen_c    : natural := 25; -- r/w: SPI chip-select enabled
109
  constant ctrl_highspeed_c   : natural := 26; -- r/w: SPI high-speed mode enable (ignoring ctrl_spi_prsc)
110
  --
111
  constant ctrl_phy_busy_c    : natural := 30; -- r/-: SPI PHY is busy when set
112
  constant ctrl_xip_busy_c    : natural := 31; -- r/-: XIP access in progress
113
  --
114
  signal ctrl : std_ulogic_vector(26 downto 0);
115
 
116
  -- Direct SPI access registers --
117
  signal spi_data_lo : std_ulogic_vector(31 downto 0);
118
  signal spi_data_hi : std_ulogic_vector(31 downto 0); -- write-only!
119
  signal spi_trigger : std_ulogic; -- trigger direct SPI operation
120
 
121
  -- XIP access address --
122
  signal xip_addr : std_ulogic_vector(31 downto 0);
123
 
124
  -- SPI access fetch arbiter --
125
  type arbiter_state_t is (S_DIRECT, S_IDLE, S_TRIG, S_BUSY);
126
  type arbiter_t is record
127
    state     : arbiter_state_t;
128
    state_nxt : arbiter_state_t;
129
    addr      : std_ulogic_vector(31 downto 0);
130
    busy      : std_ulogic;
131
  end record;
132
  signal arbiter : arbiter_t;
133
 
134
  -- SPI clock --
135
  signal spi_clk_en : std_ulogic;
136
 
137
  -- Component: SPI PHY --
138
  component neorv32_xip_phy
139
  port (
140
    -- global control --
141
    clk_i        : in  std_ulogic; -- clock
142
    spi_clk_en_i : in  std_ulogic; -- pre-scaled SPI clock-enable
143
    -- operation configuration --
144
    cf_enable_i  : in  std_ulogic; -- module enable (reset if low)
145
    cf_cpha_i    : in  std_ulogic; -- clock phase
146
    cf_cpol_i    : in  std_ulogic; -- clock idle polarity
147
    -- operation control --
148
    op_start_i   : in  std_ulogic; -- trigger new transmission
149
    op_csen_i    : in  std_ulogic; -- actually enabled device for transmission
150
    op_busy_o    : out std_ulogic; -- transmission in progress when set
151
    op_nbytes_i  : in  std_ulogic_vector(03 downto 0); -- actual number of bytes to transmit (1..9)
152
    op_wdata_i   : in  std_ulogic_vector(71 downto 0); -- write data
153
    op_rdata_o   : out std_ulogic_vector(31 downto 0); -- read data
154
    -- SPI interface --
155
    spi_csn_o    : out std_ulogic;
156
    spi_clk_o    : out std_ulogic;
157
    spi_data_i   : in  std_ulogic;
158
    spi_data_o   : out std_ulogic
159
  );
160
  end component;
161
 
162
  -- PHY interface --
163
  type phy_if_t is record
164
    start : std_ulogic; -- trigger new transmission
165
    busy  : std_ulogic; -- transmission in progress when set
166
    wdata : std_ulogic_vector(71 downto 0); -- write data
167
    rdata : std_ulogic_vector(31 downto 0); -- read data
168
  end record;
169
  signal phy_if : phy_if_t;
170
 
171
begin
172
 
173
  -- Access Control (IO/CTRL port) ----------------------------------------------------------
174
  -- -------------------------------------------------------------------------------------------
175
  ct_acc_en <= '1' when (ct_addr_i(hi_abb_c downto lo_abb_c) = xip_base_c(hi_abb_c downto lo_abb_c)) else '0';
176
  ct_addr   <= xip_base_c(31 downto lo_abb_c) & ct_addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
177
  ct_wren   <= ct_acc_en and ct_wren_i;
178
  ct_rden   <= ct_acc_en and ct_rden_i;
179
 
180
 
181
  -- Control Read/Write Access --------------------------------------------------------------
182
  -- -------------------------------------------------------------------------------------------
183
  ctrl_rw_access : process(rstn_i, clk_i)
184
  begin
185
    if (rstn_i = '0') then
186
      ctrl                    <= (others => '-');
187
      ctrl(ctrl_enable_c)     <= '0'; -- required
188
      ctrl(ctrl_xip_enable_c) <= '0'; -- required
189
      spi_data_lo             <= (others => '-');
190
      spi_data_hi             <= (others => '-');
191
      spi_trigger             <= '-';
192
      --
193
      ct_data_o               <= (others => '-');
194
      ct_ack_o                <= '-';
195
    elsif rising_edge(clk_i) then
196
      -- access acknowledge --
197
      ct_ack_o <= ct_wren or ct_rden;
198
 
199
      -- defaults --
200
      spi_trigger <= '0';
201
 
202
      -- write access --
203
      if (ct_wren = '1') then -- only full-word writes!
204
 
205
        -- control register --
206
        if (ct_addr = xip_ctrl_addr_c) then
207
          ctrl(ctrl_enable_c)                                <= ct_data_i(ctrl_enable_c);
208
          ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c)     <= ct_data_i(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c);
209
          ctrl(ctrl_spi_cpol_c)                              <= ct_data_i(ctrl_spi_cpol_c);
210
          ctrl(ctrl_spi_cpha_c)                              <= ct_data_i(ctrl_spi_cpha_c);
211
          ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c) <= ct_data_i(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c);
212
          ctrl(ctrl_xip_enable_c)                            <= ct_data_i(ctrl_xip_enable_c);
213
          ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) <= ct_data_i(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c);
214
          ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c)         <= ct_data_i(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c);
215
          ctrl(ctrl_page3_c downto ctrl_page0_c)             <= ct_data_i(ctrl_page3_c downto ctrl_page0_c);
216
          ctrl(ctrl_spi_csen_c)                              <= ct_data_i(ctrl_spi_csen_c);
217
          ctrl(ctrl_highspeed_c)                             <= ct_data_i(ctrl_highspeed_c);
218
        end if;
219
 
220
        -- SPI direct data access register lo --
221
        if (ct_addr = xip_data_lo_addr_c) then
222
          spi_data_lo <= ct_data_i;
223
        end if;
224
 
225
        -- SPI direct data access register hi --
226
        if (ct_addr = xip_data_hi_addr_c) then
227
          spi_data_hi <= ct_data_i;
228
          spi_trigger <= '1'; -- trigger direct SPI transaction
229
        end if;
230
      end if;
231
 
232
      -- read access --
233
      ct_data_o <= (others => '0');
234
      if (ct_rden = '1') then
235
        case ct_addr(3 downto 2) is
236
          when "00" => -- 'xip_ctrl_addr_c' - control register
237
            ct_data_o(ctrl_enable_c)                                <= ctrl(ctrl_enable_c);
238
            ct_data_o(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c)     <= ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c);
239
            ct_data_o(ctrl_spi_cpol_c)                              <= ctrl(ctrl_spi_cpol_c);
240
            ct_data_o(ctrl_spi_cpha_c)                              <= ctrl(ctrl_spi_cpha_c);
241
            ct_data_o(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c) <= ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c);
242
            ct_data_o(ctrl_xip_enable_c)                            <= ctrl(ctrl_xip_enable_c);
243
            ct_data_o(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) <= ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c);
244
            ct_data_o(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c)         <= ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c);
245
            ct_data_o(ctrl_page3_c downto ctrl_page0_c)             <= ctrl(ctrl_page3_c downto ctrl_page0_c);
246
            ct_data_o(ctrl_spi_csen_c)                              <= ctrl(ctrl_spi_csen_c);
247
            ct_data_o(ctrl_highspeed_c)                             <= ctrl(ctrl_highspeed_c);
248
            --
249
            ct_data_o(ctrl_phy_busy_c) <= phy_if.busy;
250
            ct_data_o(ctrl_xip_busy_c) <= arbiter.busy;
251
          when "10" => -- 'xip_data_lo_addr_c' - SPI direct data access register lo
252
            ct_data_o <= phy_if.rdata;
253
          when others => -- unavailable (not implemented or write-only)
254
            ct_data_o <= (others => '0');
255
        end case;
256
      end if;
257
    end if;
258
  end process ctrl_rw_access;
259
 
260
  -- XIP enabled --
261
  xip_en_o <= ctrl(ctrl_enable_c);
262
 
263
  -- XIP page output --
264
  xip_page_o <= ctrl(ctrl_page3_c downto ctrl_page0_c);
265
 
266
 
267
  -- XIP Address Computation Logic ----------------------------------------------------------
268
  -- -------------------------------------------------------------------------------------------
269
  xip_access_logic: process(arbiter.addr, ctrl)
270
    variable tmp_v : std_ulogic_vector(31 downto 0);
271
  begin
272
    tmp_v(31 downto 28) := "0000";
273
    tmp_v(27 downto 00) := arbiter.addr(27 downto 00);
274
    case ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) is -- shift address bits to be MSB-aligned
275
      when "00"   => xip_addr <= tmp_v(07 downto 0) & x"000000"; -- 1 address byte
276
      when "01"   => xip_addr <= tmp_v(15 downto 0) & x"0000";   -- 2 address bytes
277
      when "10"   => xip_addr <= tmp_v(23 downto 0) & x"00";     -- 3 address bytes
278
      when others => xip_addr <= tmp_v(31 downto 0);             -- 4 address bytes
279
    end case;
280
  end process xip_access_logic;
281
 
282
 
283
  -- SPI Access Arbiter ---------------------------------------------------------------------
284
  -- -------------------------------------------------------------------------------------------
285
  arbiter_sync: process(clk_i)
286
  begin
287
    if rising_edge(clk_i) then
288
      if (ctrl(ctrl_enable_c) = '0') or (ctrl(ctrl_xip_enable_c) = '0') then -- sync reset
289
        arbiter.state <= S_DIRECT;
290
      else
291
        arbiter.state <= arbiter.state_nxt;
292
      end if;
293
      arbiter.addr <= if_addr_i; -- buffer address (reducing fan-out on CPU's address net)
294
    end if;
295
  end process arbiter_sync;
296
 
297
 
298
  -- FSM - combinatorial part --
299
  arbiter_comb: process(arbiter, ctrl, xip_addr, phy_if, if_rden_i, if_addr_i, spi_data_hi, spi_data_lo, spi_trigger)
300
  begin
301
    -- arbiter defaults --
302
    arbiter.state_nxt <= arbiter.state;
303
 
304
    -- bus interface defaults --
305
    if_data_o <= (others => '0');
306
    if_ack_o  <= '0';
307
 
308
    -- SPI PHY interface defaults --
309
    phy_if.start <= '0';
310
    phy_if.wdata <= ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) & xip_addr & x"00000000"; -- MSB-aligned: CMD + address + 32-bit zero data
311
 
312
    -- fsm --
313
    case arbiter.state is
314
 
315
      when S_DIRECT => -- XIP access disabled: allow direct SPI access
316
      -- ------------------------------------------------------------
317
        phy_if.wdata      <= spi_data_hi & spi_data_lo & x"00"; -- MSB-aligned data
318
        phy_if.start      <= spi_trigger;
319
        arbiter.state_nxt <= S_IDLE;
320
 
321
      when S_IDLE => -- XIP: wait for new bus request
322
      -- ------------------------------------------------------------
323
        if (if_rden_i = '1') and (if_addr_i(31 downto 28) = ctrl(ctrl_page3_c downto ctrl_page0_c)) then
324
          arbiter.state_nxt <= S_TRIG;
325
        end if;
326
 
327
      when S_TRIG => -- XIP: trigger flash read
328
      -- ------------------------------------------------------------
329
        phy_if.start      <= '1';
330
        arbiter.state_nxt <= S_BUSY;
331
 
332
      when S_BUSY => -- XIP: wait for PHY to complete operation
333
      -- ------------------------------------------------------------
334
        if (phy_if.busy = '0') then
335
          if_data_o         <= phy_if.rdata;
336
          if_ack_o          <= '1';
337
          arbiter.state_nxt <= S_IDLE;
338
        end if;
339
 
340
      when others => -- undefined
341
      -- ------------------------------------------------------------
342
        arbiter.state_nxt <= S_IDLE;
343
 
344
    end case;
345
  end process arbiter_comb;
346
 
347
  -- arbiter status --
348
  arbiter.busy <= '1' when (arbiter.state = S_TRIG) or (arbiter.state = S_BUSY) else '0'; -- actual XIP access in progress
349
 
350
  -- status output --
351
  xip_acc_o <= arbiter.busy;
352
 
353
 
354
  -- SPI Clock Generator --------------------------------------------------------------------
355
  -- -------------------------------------------------------------------------------------------
356
  -- enable clock generator --
357
  clkgen_en_o <= ctrl(ctrl_enable_c);
358
 
359
  -- clock select --
360
  spi_clk_en <= clkgen_i(to_integer(unsigned(ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c)))) or ctrl(ctrl_highspeed_c);
361
 
362
 
363
  -- SPI Physical Interface -----------------------------------------------------------------
364
  -- -------------------------------------------------------------------------------------------
365
  neorv32_xip_phy_inst: neorv32_xip_phy
366
  port map (
367
    -- global control --
368
    clk_i        => clk_i,
369
    spi_clk_en_i => spi_clk_en,
370
    -- operation configuration --
371
    cf_enable_i  => ctrl(ctrl_enable_c),   -- module enable (reset if low)
372
    cf_cpha_i    => ctrl(ctrl_spi_cpha_c), -- clock phase
373
    cf_cpol_i    => ctrl(ctrl_spi_cpol_c), -- clock idle polarity
374
    -- operation control --
375
    op_start_i   => phy_if.start,          -- trigger new transmission
376
    op_csen_i    => ctrl(ctrl_spi_csen_c), -- actually enabled device for transmission
377
    op_busy_o    => phy_if.busy,           -- transmission in progress when set
378
    op_nbytes_i  => ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c), -- actual number of bytes to transmit
379
    op_wdata_i   => phy_if.wdata,          -- write data
380
    op_rdata_o   => phy_if.rdata,          -- read data
381
    -- SPI interface --
382
    spi_csn_o    => spi_csn_o,
383
    spi_clk_o    => spi_clk_o,
384
    spi_data_i   => spi_data_i,
385
    spi_data_o   => spi_data_o
386
  );
387
 
388
 
389
end neorv32_xip_rtl;
390
 
391
 
392
-- ############################################################################################################################
393
-- ############################################################################################################################
394
 
395
 
396
-- #################################################################################################
397
-- # << NEORV32 - XIP Module - SPI Physical Interface >>                                           #
398
-- # ********************************************************************************************* #
399
-- # BSD 3-Clause License                                                                          #
400
-- #                                                                                               #
401
-- # Copyright (c) 2022, Stephan Nolting. All rights reserved.                                     #
402
-- #                                                                                               #
403
-- # Redistribution and use in source and binary forms, with or without modification, are          #
404
-- # permitted provided that the following conditions are met:                                     #
405
-- #                                                                                               #
406
-- # 1. Redistributions of source code must retain the above copyright notice, this list of        #
407
-- #    conditions and the following disclaimer.                                                   #
408
-- #                                                                                               #
409
-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
410
-- #    conditions and the following disclaimer in the documentation and/or other materials        #
411
-- #    provided with the distribution.                                                            #
412
-- #                                                                                               #
413
-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
414
-- #    endorse or promote products derived from this software without specific prior written      #
415
-- #    permission.                                                                                #
416
-- #                                                                                               #
417
-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
418
-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
419
-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
420
-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
421
-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
422
-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
423
-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
424
-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
425
-- # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
426
-- # ********************************************************************************************* #
427
-- # The NEORV32 Processor - https://github.com/stnolting/neorv32              (c) Stephan Nolting #
428
-- #################################################################################################
429
 
430
library ieee;
431
use ieee.std_logic_1164.all;
432
use ieee.numeric_std.all;
433
 
434
library neorv32;
435
use neorv32.neorv32_package.all;
436
 
437
entity neorv32_xip_phy is
438
  port (
439
    -- global control --
440
    clk_i        : in  std_ulogic; -- clock
441
    spi_clk_en_i : in  std_ulogic; -- pre-scaled SPI clock-enable
442
    -- operation configuration --
443
    cf_enable_i  : in  std_ulogic; -- module enable (reset if low)
444
    cf_cpha_i    : in  std_ulogic; -- clock phase
445
    cf_cpol_i    : in  std_ulogic; -- clock idle polarity
446
    -- operation control --
447
    op_start_i   : in  std_ulogic; -- trigger new transmission
448
    op_csen_i    : in  std_ulogic; -- actually enabled device for transmission
449
    op_busy_o    : out std_ulogic; -- transmission in progress when set
450
    op_nbytes_i  : in  std_ulogic_vector(03 downto 0); -- actual number of bytes to transmit (1..9)
451
    op_wdata_i   : in  std_ulogic_vector(71 downto 0); -- write data
452
    op_rdata_o   : out std_ulogic_vector(31 downto 0); -- read data
453
    -- SPI interface --
454
    spi_csn_o    : out std_ulogic;
455
    spi_clk_o    : out std_ulogic;
456
    spi_data_i   : in  std_ulogic;
457
    spi_data_o   : out std_ulogic
458
  );
459
end neorv32_xip_phy;
460
 
461
architecture neorv32_xip_phy_rtl of neorv32_xip_phy is
462
 
463
  -- controller --
464
  type ctrl_state_t is (S_IDLE, S_START, S_RTX_A, S_RTX_B, S_DONE);
465
  type ctrl_t is record
466
    state   : ctrl_state_t;
467
    sreg    : std_ulogic_vector(71 downto 0); -- only the lowest 32-bit are used as RX data
468
    bitcnt  : std_ulogic_vector(06 downto 0);
469
    di_sync : std_ulogic;
470
    csen    : std_ulogic;
471
  end record;
472
  signal ctrl : ctrl_t;
473
 
474
begin
475
 
476
  -- Serial Interface Control Unit ----------------------------------------------------------
477
  -- -------------------------------------------------------------------------------------------
478
  control_unit: process(clk_i)
479
  begin
480
    if rising_edge(clk_i) then
481
      if (cf_enable_i = '0') then
482
        spi_clk_o    <= '0';
483
        spi_csn_o    <= '1';
484
        --
485
        ctrl.state   <= S_IDLE;
486
        ctrl.csen    <= '-';
487
        ctrl.sreg    <= (others => '-');
488
        ctrl.bitcnt  <= (others => '-');
489
        ctrl.di_sync <= '-';
490
      else
491
        -- defaults --
492
        spi_clk_o    <= cf_cpol_i;
493
        spi_csn_o    <= '1'; -- de-selected by default
494
        ctrl.di_sync <= spi_data_i;
495
 
496
        -- fsm --
497
        case ctrl.state is
498
 
499
          when S_IDLE => -- wait for new transmission trigger
500
          -- ------------------------------------------------------------
501
            ctrl.bitcnt <= op_nbytes_i & "000"; -- number of bytes
502
            ctrl.csen   <= op_csen_i;
503
            if (op_start_i = '1') then
504
              ctrl.sreg  <= op_wdata_i;
505
              ctrl.state <= S_START;
506
            end if;
507
 
508
          when S_START => -- sync start of transmission
509
          -- ------------------------------------------------------------
510
            spi_csn_o <= not ctrl.csen;
511
            if (spi_clk_en_i = '1') then
512
              ctrl.state <= S_RTX_A;
513
            end if;
514
 
515
          when S_RTX_A => -- first half of bit transmission
516
          -- ------------------------------------------------------------
517
            spi_csn_o <= not ctrl.csen;
518
            spi_clk_o <= cf_cpha_i xor cf_cpol_i;
519
            if (spi_clk_en_i = '1') then
520
              ctrl.bitcnt <= std_ulogic_vector(unsigned(ctrl.bitcnt) - 1);
521
              ctrl.state  <= S_RTX_B;
522
            end if;
523
 
524
          when S_RTX_B => -- second half of bit transmission
525
          -- ------------------------------------------------------------
526
            spi_csn_o <= not ctrl.csen;
527
            spi_clk_o <= not (cf_cpha_i xor cf_cpol_i);
528
            if (spi_clk_en_i = '1') then
529
              ctrl.sreg <= ctrl.sreg(ctrl.sreg'left-1 downto 0) & ctrl.di_sync;
530
              if (or_reduce_f(ctrl.bitcnt) = '0') then -- all bits transferred?
531
                ctrl.state <= S_DONE; -- transmission done
532
              else
533
                ctrl.state <= S_RTX_A; -- next bit
534
              end if;
535
            end if;
536
 
537
          when S_DONE => -- transmission done
538
          -- ------------------------------------------------------------
539
            spi_csn_o <= not ctrl.csen;
540
            if (spi_clk_en_i = '1') then
541
              ctrl.state <= S_IDLE;
542
            end if;
543
 
544
          when others => -- undefined
545
          -- ------------------------------------------------------------
546
            ctrl.state <= S_IDLE;
547
 
548
        end case;
549
      end if;
550
    end if;
551
  end process control_unit;
552
 
553
  -- serial unit busy --
554
  op_busy_o <= '0' when (ctrl.state = S_IDLE) else '1';
555
 
556
  -- serial data output --
557
  spi_data_o <= ctrl.sreg(ctrl.sreg'left);
558
 
559
  -- RX data --
560
  op_rdata_o <= ctrl.sreg(31 downto 0);
561
 
562
 
563
end neorv32_xip_phy_rtl;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.