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

Subversion Repositories yifive

[/] [yifive/] [trunk/] [caravel_yifive/] [verilog/] [rtl/] [spi_master/] [src/] [spim_regs.sv] - Blame information for rev 21

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 18 dinesha
//////////////////////////////////////////////////////////////////////
2
////                                                              ////
3
////  SPI WishBone Register I/F Module                            ////
4
////                                                              ////
5
////  This file is part of the YIFive cores project               ////
6
////  http://www.opencores.org/cores/yifive/                      ////
7
////                                                              ////
8
////  Description                                                 ////
9
////     SPI WishBone I/F module                                  ////
10
////     This block support following functionality               ////
11
////        1. Direct SPI Read memory support for address rang    ////
12
////             0x0000 to 0x0FFF_FFFF - Use full for Instruction ////
13
////             Data Memory fetch                                ////
14
////        2. SPI Local Register Access                          ////
15
////        3. Indirect register way to access SPI Memory         ////
16
////                                                              ////
17
////  To Do:                                                      ////
18
////    nothing                                                   ////
19
////                                                              ////
20
////  Author(s):                                                  ////
21
////      - Dinesh Annayya, dinesha@opencores.org                 ////
22
////                                                              ////
23
////  Revision :                                                  ////
24
////     V.0  -  June 8, 2021                                     ////
25
////                                                              ////
26
//////////////////////////////////////////////////////////////////////
27
////                                                              ////
28
//// Copyright (C) 2000 Authors and OPENCORES.ORG                 ////
29
////                                                              ////
30
//// This source file may be used and distributed without         ////
31
//// restriction provided that this copyright statement is not    ////
32
//// removed from the file and that any derivative work contains  ////
33
//// the original copyright notice and the associated disclaimer. ////
34
////                                                              ////
35
//// This source file is free software; you can redistribute it   ////
36
//// and/or modify it under the terms of the GNU Lesser General   ////
37
//// Public License as published by the Free Software Foundation; ////
38
//// either version 2.1 of the License, or (at your option) any   ////
39
//// later version.                                               ////
40
////                                                              ////
41
//// This source is distributed in the hope that it will be       ////
42
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
43
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
44
//// PURPOSE.  See the GNU Lesser General Public License for more ////
45
//// details.                                                     ////
46
////                                                              ////
47
//// You should have received a copy of the GNU Lesser General    ////
48
//// Public License along with this source; if not, download it   ////
49
//// from http://www.opencores.org/lgpl.shtml                     ////
50
////                                                              ////
51
//////////////////////////////////////////////////////////////////////
52
 
53
 
54
module spim_regs #( parameter WB_WIDTH = 32) (
55
    input  logic                         mclk,
56
    input  logic                         rst_n,
57
 
58
    input  logic                         wbd_stb_i, // strobe/request
59
    input  logic   [WB_WIDTH-1:0]        wbd_adr_i, // address
60
    input  logic                         wbd_we_i,  // write
61
    input  logic   [WB_WIDTH-1:0]        wbd_dat_i, // data output
62
    input  logic   [3:0]                 wbd_sel_i, // byte enable
63
    output logic   [WB_WIDTH-1:0]        wbd_dat_o, // data input
64
    output logic                         wbd_ack_o, // acknowlegement
65
    output logic                         wbd_err_o,  // error
66
 
67
    output logic                   [7:0] spi_clk_div,
68
    output logic                         spi_clk_div_valid,
69 21 dinesha
    input logic                    [8:0] spi_status,
70 18 dinesha
 
71
    // Towards SPI TX/RX FSM
72
 
73
 
74
    output logic                          spi_req,
75
    output logic                   [31:0] spi_addr,
76
    output logic                    [5:0] spi_addr_len,
77
    output logic                   [7:0]  spi_cmd,
78
    output logic                    [5:0] spi_cmd_len,
79
    output logic                   [7:0]  spi_mode_cmd,
80
    output logic                          spi_mode_cmd_enb,
81
    output logic                    [3:0] spi_csreg,
82
    output logic                   [15:0] spi_data_len,
83
    output logic                   [15:0] spi_dummy_rd_len,
84
    output logic                   [15:0] spi_dummy_wr_len,
85
    output logic                          spi_swrst,
86
    output logic                          spi_rd,
87
    output logic                          spi_wr,
88
    output logic                          spi_qrd,
89
    output logic                          spi_qwr,
90
    output logic                   [31:0] spi_wdata,
91
    input logic                   [31:0]  spi_rdata,
92
    input logic                           spi_ack
93
 
94
    );
95
 
96
//----------------------------
97
// Register Decoding
98
// ---------------------------
99
parameter REG_CTRL     = 4'b0000;
100
parameter REG_CLKDIV   = 4'b0001;
101
parameter REG_SPICMD   = 4'b0010;
102
parameter REG_SPIADR   = 4'b0011;
103
parameter REG_SPILEN   = 4'b0100;
104
parameter REG_SPIDUM   = 4'b0101;
105
parameter REG_SPIWDATA = 4'b0110;
106
parameter REG_SPIRDATA = 4'b0111;
107
parameter REG_STATUS   = 4'b1000;
108
 
109
// Init FSM
110 21 dinesha
parameter SPI_INIT_IDLE      = 3'b000;
111
parameter SPI_INIT_CMD_WAIT  = 3'b001;
112
parameter SPI_INIT_WREN_CMD  = 3'b010;
113
parameter SPI_INIT_WREN_WAIT = 3'b011;
114
parameter SPI_INIT_WRR_CMD   = 3'b100;
115
parameter SPI_INIT_WRR_WAIT  = 3'b101;
116 18 dinesha
 
117
//---------------------------------------------------------
118
// Variable declartion
119
// -------------------------------------------------------
120
logic                 spi_init_done  ;
121
logic   [2:0]         spi_init_state ;
122
logic                spim_mem_req   ;
123
logic                spim_reg_req   ;
124
 
125
 
126
logic                 spim_wb_req    ;
127
logic                 spim_wb_req_l  ;
128
logic [WB_WIDTH-1:0]  spim_wb_wdata  ;
129
logic [WB_WIDTH-1:0]  spim_wb_addr   ;
130
logic                 spim_wb_ack    ;
131
logic                 spim_wb_we     ;
132
logic [3:0]           spim_wb_be     ;
133
logic [WB_WIDTH-1:0]  spim_reg_rdata ;
134
logic [WB_WIDTH-1:0]  spim_wb_rdata  ;
135
logic  [WB_WIDTH-1:0] reg_rdata      ;
136
 
137
// Control Signal Generated from Reg to SPI Access
138
logic                 reg2spi_req;
139
logic         [31:0]  reg2spi_addr;
140
logic          [5:0]  reg2spi_addr_len;
141
logic         [31:0]  reg2spi_cmd;
142
logic          [5:0]  reg2spi_cmd_len;
143
logic          [3:0]  reg2spi_csreg;
144
logic         [15:0]  reg2spi_data_len;
145
logic                 reg2spi_mode_enb; // mode enable
146
logic         [7:0]   reg2spi_mode;     // mode
147
logic         [15:0]  reg2spi_dummy_rd_len;
148
logic         [15:0]  reg2spi_dummy_wr_len;
149
logic                 reg2spi_swrst;
150
logic                 reg2spi_rd;
151
logic                 reg2spi_wr;
152
logic                 reg2spi_qrd;
153
logic                 reg2spi_qwr;
154
logic         [31:0]  reg2spi_wdata;
155
//------------------------------------------------------------------
156
// Priority given to mem2spi request over Reg2Spi
157
 
158
    assign  spi_req           =  (spim_mem_req && !spim_wb_we) ? 1'b1                           : reg2spi_req;
159
    assign  spi_addr          =  (spim_mem_req && !spim_wb_we) ? {spim_wb_addr[23:0],8'h0}      : reg2spi_addr;
160
    assign  spi_addr_len      =  (spim_mem_req && !spim_wb_we) ? 24                             : reg2spi_addr_len;
161
    assign  spi_cmd           =  (spim_mem_req && !spim_wb_we) ? 8'hEB                          : reg2spi_cmd;
162
    assign  spi_cmd_len       =  (spim_mem_req && !spim_wb_we) ? 8                              : reg2spi_cmd_len;
163
    assign  spi_mode_cmd      =  (spim_mem_req && !spim_wb_we) ? 8'h00                          : reg2spi_mode;
164
    assign  spi_mode_cmd_enb  =  (spim_mem_req && !spim_wb_we) ? 1                              : reg2spi_mode_enb;
165
    assign  spi_csreg         =  (spim_mem_req && !spim_wb_we) ? '1                             : reg2spi_csreg;
166 21 dinesha
    assign  spi_data_len      =  (spim_mem_req && !spim_wb_we) ? 'h20                           : reg2spi_data_len;
167
    assign  spi_dummy_rd_len  =  (spim_mem_req && !spim_wb_we) ? 'h20                           : reg2spi_dummy_rd_len;
168 18 dinesha
    assign  spi_dummy_wr_len  =  (spim_mem_req && !spim_wb_we) ? 0                              : reg2spi_dummy_wr_len;
169
    assign  spi_swrst         =  (spim_mem_req && !spim_wb_we) ? 0                              : reg2spi_swrst;
170
    assign  spi_rd            =  (spim_mem_req && !spim_wb_we) ? 0                              : reg2spi_rd;
171
    assign  spi_wr            =  (spim_mem_req && !spim_wb_we) ? 0                              : reg2spi_wr;
172
    assign  spi_qrd           =  (spim_mem_req && !spim_wb_we) ? 1                              : reg2spi_qrd;
173
    assign  spi_qwr           =  (spim_mem_req && !spim_wb_we) ? 0                              : reg2spi_qwr;
174
    assign  spi_wdata         =  (spim_mem_req && !spim_wb_we) ? 0                              : reg2spi_wdata;
175
 
176
 
177
 
178
 
179
  //---------------------------------------------------------------
180
  // Address Decoding
181
  // 0x0000_0000 - 0x0FFF_FFFF  - SPI FLASH MEMORY ACCESS - 256MB
182
  // 0x1000_0000 -              - SPI Register Access
183
  // --------------------------------------------------------------
184
 
185
  assign spim_mem_req = ((spim_wb_req) && spim_wb_addr[31:28] == 4'b0000);
186
  assign spim_reg_req = ((spim_wb_req) && spim_wb_addr[31:28] == 4'b0001);
187
 
188
 
189
  assign wbd_dat_o  =  spim_wb_rdata;
190
  assign wbd_ack_o  =  spim_wb_ack;
191
  assign wbd_err_o  =  1'b0;
192
 
193
  // To reduce the load/Timing Wishbone I/F, all the variable are registered
194
always_ff @(negedge rst_n or posedge mclk) begin
195
    if ( rst_n == 1'b0 ) begin
196
        spim_wb_req   <= '0;
197
        spim_wb_req_l <= '0;
198
        spim_wb_wdata <= '0;
199
        spim_wb_rdata <= '0;
200
        spim_wb_addr  <= '0;
201
        spim_wb_be    <= '0;
202
        spim_wb_we    <= '0;
203
        spim_wb_ack   <= '0;
204
   end else begin
205 21 dinesha
        if(spi_init_done) begin // Wait for internal SPI Init Done
206
            spim_wb_req   <= wbd_stb_i && (spi_ack == 0) && (spim_wb_ack==0);
207
            spim_wb_req_l <= spim_wb_req;
208
            spim_wb_wdata <= wbd_dat_i;
209
            spim_wb_addr  <= wbd_adr_i;
210
            spim_wb_be    <= wbd_sel_i;
211
            spim_wb_we    <= wbd_we_i;
212
 
213
 
214
        // If there is Reg2Spi read Access, Register the Read Data
215
        if(reg2spi_req && (reg2spi_rd || reg2spi_qrd ) && spi_ack)
216
                 spim_reg_rdata <= spi_rdata;
217
 
218
        if(!spim_wb_we && spim_wb_req && spi_ack)
219
               spim_wb_rdata <= spi_rdata;
220
            else if (spim_reg_req)
221
               spim_wb_rdata <= reg_rdata;
222
 
223 18 dinesha
        // For safer design, we have generated ack after 2 cycle latter to
224 21 dinesha
        // cross-check current request is towards SPI or not
225
            spim_wb_ack   <= (spi_req && spim_wb_req) ? spi_ack :
226
                         ((spim_wb_ack==0) && spim_wb_req && spim_wb_req_l) ;
227
       end
228 18 dinesha
   end
229
end
230
 
231
  integer byte_index;
232
  always_ff @(negedge rst_n or posedge mclk) begin
233
    if ( rst_n == 1'b0 ) begin
234
      reg2spi_swrst         <= 1'b0;
235
      reg2spi_rd            <= 1'b0;
236
      reg2spi_wr            <= 1'b0;
237
      reg2spi_qrd           <= 1'b0;
238
      reg2spi_qwr           <= 1'b0;
239
      reg2spi_cmd           <=  'h0;
240
      reg2spi_addr          <=  'h0;
241
      reg2spi_cmd_len       <=  'h0;
242
      reg2spi_addr_len      <=  'h0;
243
      reg2spi_data_len      <=  'h0;
244
      reg2spi_wdata         <=  'h0;
245
      reg2spi_mode_enb      <=  'h0;
246
      reg2spi_mode          <=  'h0;
247
      reg2spi_dummy_rd_len  <=  'h0;
248
      reg2spi_dummy_wr_len  <=  'h0;
249
      reg2spi_csreg         <=  'h0;
250
      reg2spi_req           <=  'h0;
251
      spi_clk_div_valid     <= 1'b0;
252
      spi_clk_div           <=  'h2;
253
      spi_init_done         <=  'h0;
254
      spi_init_state        <=  SPI_INIT_IDLE;
255
    end
256
    else if (spi_init_done == 0) begin
257
       case(spi_init_state)
258
           SPI_INIT_IDLE:
259
           begin
260
              reg2spi_rd        <= 'h0;
261
              reg2spi_wr        <= 'h1; // SPI Write Req
262
              reg2spi_qrd       <= 'h0;
263
              reg2spi_qwr       <= 'h0;
264
              reg2spi_swrst     <= 'h0;
265
              reg2spi_csreg     <= 'h1;
266 21 dinesha
              reg2spi_cmd[7:0]  <= 'hAB; // POWER UP command
267 18 dinesha
              reg2spi_mode[7:0] <= 'h0;
268
              reg2spi_cmd_len   <= 'h8;
269
              reg2spi_addr_len  <= 'h0;
270
              reg2spi_data_len  <= 'h0;
271
              reg2spi_wdata     <= 'h0;
272
              reg2spi_req       <= 'h1;
273
              spi_init_state    <=  SPI_INIT_CMD_WAIT;
274
           end
275
           SPI_INIT_CMD_WAIT:
276
           begin
277
              if(spi_ack)   begin
278
                 reg2spi_req      <= 1'b0;
279 21 dinesha
                 spi_init_state    <=  SPI_INIT_WREN_CMD;
280
              end
281
           end
282
           SPI_INIT_WREN_CMD:
283
           begin
284
              reg2spi_rd        <= 'h0;
285
              reg2spi_wr        <= 'h1; // SPI Write Req
286
              reg2spi_qrd       <= 'h0;
287
              reg2spi_qwr       <= 'h0;
288
              reg2spi_swrst     <= 'h0;
289
              reg2spi_csreg     <= 'h1;
290
              reg2spi_cmd[7:0]  <= 'h6; // WREN command
291
              reg2spi_mode[7:0] <= 'h0;
292
              reg2spi_cmd_len   <= 'h8;
293
              reg2spi_addr_len  <= 'h0;
294
              reg2spi_data_len  <= 'h0;
295
              reg2spi_wdata     <= 'h0;
296
              reg2spi_req       <= 'h1;
297
              spi_init_state    <=  SPI_INIT_WREN_WAIT;
298
           end
299
           SPI_INIT_WREN_WAIT:
300
           begin
301
              if(spi_ack)   begin
302
                 reg2spi_req      <= 1'b0;
303 18 dinesha
                 spi_init_state    <=  SPI_INIT_WRR_CMD;
304
              end
305
           end
306
           SPI_INIT_WRR_CMD:
307
           begin
308
              reg2spi_rd        <= 'h0;
309
              reg2spi_wr        <= 'h1; // SPI Write Req
310
              reg2spi_qrd       <= 'h0;
311
              reg2spi_qwr       <= 'h0;
312
              reg2spi_swrst     <= 'h0;
313
              reg2spi_csreg     <= 'h1;
314
              reg2spi_cmd[7:0]  <= 'h1; // WRR command
315
              reg2spi_mode[7:0] <= 'h0;
316
              reg2spi_cmd_len   <= 'h8;
317
              reg2spi_addr_len  <= 'h0;
318
              reg2spi_data_len  <= 'h10;
319
              reg2spi_wdata     <= {8'h0,8'h2,16'h0}; // <<16'h0> cr1[1] = 1 indicate quad mode
320
              reg2spi_req       <= 'h1;
321
              spi_init_state    <=  SPI_INIT_WRR_WAIT;
322
           end
323
           SPI_INIT_WRR_WAIT:
324
           begin
325
              if(spi_ack)   begin
326
                 reg2spi_req      <= 1'b0;
327
                 spi_init_done    <=  'h1;
328
              end
329
           end
330
       endcase
331
    end else if (spim_reg_req & spim_wb_we )
332
    begin
333
      case(spim_wb_addr[7:4])
334
        REG_CTRL:
335
        begin
336
          if ( spim_wb_be[0] == 1 )
337
          begin
338
            reg2spi_rd    <= spim_wb_wdata[0];
339
            reg2spi_wr    <= spim_wb_wdata[1];
340
            reg2spi_qrd   <= spim_wb_wdata[2];
341
            reg2spi_qwr   <= spim_wb_wdata[3];
342
            reg2spi_swrst <= spim_wb_wdata[4];
343
            reg2spi_req   <= 1'b1;
344
          end
345
          if ( spim_wb_be[1] == 1 )
346
          begin
347
            reg2spi_csreg <= spim_wb_wdata[11:8];
348
          end
349
        end
350
        REG_CLKDIV:
351
          if ( spim_wb_be[0] == 1 )
352
          begin
353
            spi_clk_div <= spim_wb_wdata[7:0];
354
            spi_clk_div_valid <= 1'b1;
355
          end
356
        REG_SPICMD: begin
357
          if ( spim_wb_be[0] == 1 )
358
              reg2spi_cmd[7:0] <= spim_wb_wdata[7:0];
359
          if ( spim_wb_be[1] == 1 )
360
              reg2spi_mode[7:0] <= spim_wb_wdata[15:8];
361
          end
362
        REG_SPIADR:
363
          for (byte_index = 0; byte_index < 4; byte_index = byte_index+1 )
364
            if ( spim_wb_be[byte_index] == 1 )
365
              reg2spi_addr[byte_index*8 +: 8] <= spim_wb_wdata[(byte_index*8) +: 8];
366
        REG_SPILEN:
367
        begin
368
          if ( spim_wb_be[0] == 1 ) begin
369
               reg2spi_mode_enb <= spim_wb_wdata[6];
370
               reg2spi_cmd_len  <= spim_wb_wdata[5:0];
371
          end
372
          if ( spim_wb_be[1] == 1 )
373
            reg2spi_addr_len <= spim_wb_wdata[13:8];
374
          if ( spim_wb_be[2] == 1 )
375
            reg2spi_data_len[7:0] <= spim_wb_wdata[23:16];
376
          if ( spim_wb_be[3] == 1 )
377
            reg2spi_data_len[15:8] <= spim_wb_wdata[31:24];
378
        end
379
        REG_SPIDUM:
380
        begin
381
          if ( spim_wb_be[0] == 1 )
382
            reg2spi_dummy_rd_len[7:0]  <= spim_wb_wdata[7:0];
383
          if ( spim_wb_be[1] == 1 )
384
            reg2spi_dummy_rd_len[15:8] <= spim_wb_wdata[15:8];
385
          if ( spim_wb_be[2] == 1 )
386
            reg2spi_dummy_wr_len[7:0]  <= spim_wb_wdata[23:16];
387
          if ( spim_wb_be[3] == 1 )
388
            reg2spi_dummy_wr_len[15:8] <= spim_wb_wdata[31:24];
389
        end
390
        REG_SPIWDATA: begin
391
           reg2spi_wdata     <= spim_wb_wdata;
392
        end
393
      endcase
394
    end
395
    else
396
    begin
397
      if(spi_ack && spim_reg_req)
398
         reg2spi_req <= 1'b0;
399
    end
400
  end
401
 
402
 
403 21 dinesha
 
404
  wire [3:0] reg_addr = spim_wb_addr[7:4];
405
 
406 18 dinesha
  // implement slave model register read mux
407
  always_comb
408
    begin
409
      reg_rdata = '0;
410 21 dinesha
      if(spim_reg_req) begin
411
          case(reg_addr)
412
            REG_CTRL:
413
                    reg_rdata[31:0] =  { 20'h0,
414
                                     reg2spi_csreg,
415
                                     3'b0,
416
                                     reg2spi_swrst,
417
                                     reg2spi_qwr,
418
                                     reg2spi_qrd,
419
                                     reg2spi_wr,
420
                                     reg2spi_rd};
421 18 dinesha
 
422 21 dinesha
            REG_CLKDIV:
423
                    reg_rdata[31:0] = {24'h0,spi_clk_div};
424
            REG_SPICMD:
425
                    reg_rdata[31:0] = {16'h0,reg2spi_mode,reg2spi_cmd};
426
            REG_SPIADR:
427
                    reg_rdata[31:0] = reg2spi_addr;
428
            REG_SPILEN:
429
                    reg_rdata[31:0] = {reg2spi_data_len,2'b00,reg2spi_addr_len,1'b0,reg2spi_mode_enb,reg2spi_cmd_len};
430
            REG_SPIDUM:
431
                    reg_rdata[31:0] = {reg2spi_dummy_wr_len,reg2spi_dummy_rd_len};
432
            REG_SPIWDATA:
433
                    reg_rdata[31:0] = reg2spi_wdata;
434
            REG_SPIRDATA:
435
                    reg_rdata[31:0] = spim_reg_rdata;
436
            REG_STATUS:
437
                    reg_rdata[31:0] = {23'h0,spi_status};
438
          endcase
439
       end
440 18 dinesha
    end
441
 
442
 
443
endmodule

powered by: WebSVN 2.1.0

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