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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [rtl/] [verilog/] [simple_spi/] [simple_spi.v] - Blame information for rev 361

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 361 julius
/////////////////////////////////////////////////////////////////////
2
////                                                             ////
3
////  OpenCores                    MC68HC11E based SPI interface ////
4
////                                                             ////
5
////  Author: Richard Herveille                                  ////
6
////          richard@asics.ws                                   ////
7
////          www.asics.ws                                       ////
8
////                                                             ////
9
/////////////////////////////////////////////////////////////////////
10
////                                                             ////
11
//// Copyright (C) 2002 Richard Herveille                        ////
12
////                    richard@asics.ws                         ////
13
////                                                             ////
14
//// This source file may be used and distributed without        ////
15
//// restriction provided that this copyright statement is not   ////
16
//// removed from the file and that any derivative work contains ////
17
//// the original copyright notice and the associated disclaimer.////
18
////                                                             ////
19
////     THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     ////
20
//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   ////
21
//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   ////
22
//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      ////
23
//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         ////
24
//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    ////
25
//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   ////
26
//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        ////
27
//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  ////
28
//// LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  ////
29
//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  ////
30
//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         ////
31
//// POSSIBILITY OF SUCH DAMAGE.                                 ////
32
////                                                             ////
33
/////////////////////////////////////////////////////////////////////
34
 
35
//  CVS Log
36
//
37
//  $Id: simple_spi_top.v,v 1.5 2004-02-28 15:59:50 rherveille Exp $
38
//
39
//  $Date: 2004-02-28 15:59:50 $
40
//  $Revision: 1.5 $
41
//  $Author: rherveille $
42
//  $Locker:  $
43
//  $State: Exp $
44
//
45
// Change History:
46
//               $Log: not supported by cvs2svn $
47
//               Revision 1.4  2003/08/01 11:41:54  rherveille
48
//               Fixed some timing bugs.
49
//
50
//               Revision 1.3  2003/01/09 16:47:59  rherveille
51
//               Updated clkcnt size and decoding due to new SPR bit assignments.
52
//
53
//               Revision 1.2  2003/01/07 13:29:52  rherveille
54
//               Changed SPR bits coding.
55
//
56
//               Revision 1.1.1.1  2002/12/22 16:07:15  rherveille
57
//               Initial release
58
//
59
//
60
 
61
 
62
 
63
//
64
// Motorola MC68HC11E based SPI interface
65
//
66
// Currently only MASTER mode is supported
67
//
68
 
69
// synopsys translate_off
70
`include "timescale.v"
71
// synopsys translate_on
72
 
73
`define SIMPLE_SPI_RST_SENS rst_i
74
 
75
//module simple_spi_top(
76
module simple_spi ( // renamed by Julius
77
                    // 8bit WISHBONE bus slave interface
78
                    clk_i,         // clock
79
                    rst_i,         // reset (asynchronous active low)
80
                    cyc_i,         // cycle
81
                    stb_i,         // strobe
82
                    adr_i,         // address
83
                    we_i,          // write enable
84
                    dat_i,         // data input
85
                    dat_o,         // data output
86
                    ack_o,         // normal bus termination
87
                    inta_o,        // interrupt output
88
 
89
 
90
                    sck_o,         // serial clock output
91
                    ss_o, //slave select
92
                    mosi_o,        // MasterOut SlaveIN
93
                    miso_i         // MasterIn SlaveOut             
94
                    );
95
 
96
   parameter slave_select_width = 1;
97
 
98
   input  wire      clk_i;         // clock
99
   input  wire      rst_i;         // reset (asynchronous active low)
100
   input  wire      cyc_i;         // cycle
101
   input  wire      stb_i;         // strobe
102
   input  wire [2:0] adr_i;         // address
103
   input  wire       we_i;          // write enable
104
   input  wire [7:0] dat_i;         // data input
105
   output reg [7:0]  dat_o;         // data output
106
   output reg        ack_o;         // normal bus termination
107
   output reg        inta_o;        // interrupt output
108
 
109
   // SPI port
110
   output reg        sck_o;         // serial clock output
111
   output [slave_select_width-1:0] ss_o;
112
   output wire                         mosi_o;        // MasterOut SlaveIN
113
   input  wire                         miso_i;         // MasterIn SlaveOut     
114
 
115
 
116
   reg [slave_select_width-1:0]        ss_r;
117
 
118
  //
119
  // Module body
120
  //
121
  reg  [7:0] spcr;       // Serial Peripheral Control Register ('HC11 naming)
122
  wire [7:0] spsr;       // Serial Peripheral Status register ('HC11 naming)
123
  reg  [7:0] sper;       // Serial Peripheral Extension register
124
  reg  [7:0] treg; // Transmit/Receive register
125
 
126
  // fifo signals
127
  wire [7:0] rfdout;
128
  reg        wfre, rfwe;
129
  wire       rfre, rffull, rfempty;
130
  wire [7:0] wfdout;
131
  wire       wfwe, wffull, wfempty;
132
 
133
  // misc signals
134
  wire      tirq;     // transfer interrupt (selected number of transfers done)
135
  wire      wfov;     // write fifo overrun (writing while fifo full)
136
  reg [1:0] state;    // statemachine state
137
  reg [2:0] bcnt;
138
 
139
 
140
   // Little startup init FSM and logic
141
   // Does 4 accesses and waits to read out the data so the module is 
142
   // properly reset:
143
   // Write 1: 0x3
144
   // Write 2: 0x0
145
   // Write 3: 0x0
146
   // Write 4: 0x0
147
   //
148
   // This means anysoftware that wants to read can simply start pushing stuff
149
   // into the fifo to kick it off
150
   //
151
   reg [3:0]                            startup_state = 0;
152
   reg [3:0]                            startup_state_r = 0;
153
   parameter startup_state_reset = 0; // Set to 0x10 to init to read on startup
154
   parameter startup_spcr = 0;
155
   parameter startup_slave_select = 0;
156
 
157
   wire                                startup_rfre;
158
   wire                                startup_busy;
159
   assign startup_busy = |startup_state_r;
160
 
161
 
162
   always @(posedge clk_i)
163
     if (rst_i)
164
       startup_state <= startup_state_reset;
165
     else if ((startup_state == startup_state_r))// Whenever state is back to 0
166
       startup_state <= {1'b0,startup_state[3:1]};
167
 
168
   always @(posedge clk_i)
169
     if (rst_i)
170
       startup_state_r <= startup_state_reset;
171
     else if (startup_rfre)
172
       startup_state_r <= {1'b0,startup_state_r[3:1]};
173
 
174
   wire [1:0]                           startup_state_wdf;
175
   // This sets the 0x3 command, to read
176
   assign startup_state_wdf = {startup_state[3], startup_state[3]};
177
 
178
   wire                                startup_wfwe;
179
   assign startup_wfwe = startup_busy & (startup_state == startup_state_r & !rst_i);
180
 
181
 
182
   assign startup_rfre = (startup_busy) & !rfempty &
183
                         (startup_state != startup_state_r);
184
 
185
 
186
  //
187
  // Wishbone interface
188
  wire wb_acc = cyc_i & stb_i & !startup_busy;       // WISHBONE access
189
  wire wb_wr  = wb_acc & we_i;       // WISHBONE write access
190
 
191
  // dat_i
192
  always @(posedge clk_i)
193
    if (`SIMPLE_SPI_RST_SENS)
194
      begin
195
         spcr <=  8'h10 | startup_spcr;  // set master bit
196
         sper <=  8'h00;
197
         ss_r <=  0;
198
      end
199
    else if (wb_wr)
200
      begin
201
        if (adr_i == 3'b000)
202
          spcr <=  dat_i | 8'h10; // always set master bit
203
 
204
        if (adr_i == 3'b011)
205
          sper <=  dat_i;
206
 
207
         if (adr_i == 3'b100)
208
           ss_r <=  dat_i[slave_select_width-1:0];
209
      end // if (wb_wr)
210
    else if (startup_busy)
211
      ss_r <= startup_slave_select;
212
 
213
   // Slave select output
214
   // SPI slave select is active low   
215
   assign ss_o = ~ss_r;
216
 
217
  // write fifo
218
  assign wfwe = wb_acc & (adr_i == 3'b010) & ack_o &  we_i;
219
  assign wfov = wfwe & wffull;
220
 
221
  // dat_o
222
  always @(posedge clk_i)
223
    case(adr_i) // synopsys full_case parallel_case
224
      3'b000: dat_o <=  spcr;
225
      3'b001: dat_o <=  spsr;
226
      3'b010: dat_o <=  rfdout;
227
      3'b011: dat_o <=  sper;
228
      3'b100: dat_o <=  {{(8-slave_select_width){1'b0}},ss_r};
229
      default:
230
        dat_o <= 0;
231
    endcase
232
 
233
  // read fifo
234
  assign rfre = wb_acc & (adr_i == 3'b010) & ack_o & ~we_i;
235
 
236
  // ack_o
237
  always @(posedge clk_i)
238
    if (`SIMPLE_SPI_RST_SENS)
239
      ack_o <=  1'b0;
240
    else
241
      ack_o <=  wb_acc & !ack_o;
242
 
243
  // decode Serial Peripheral Control Register
244
  wire       spie = spcr[7];   // Interrupt enable bit
245
  wire       spe  = spcr[6];   // System Enable bit
246
  wire       dwom = spcr[5];   // Port D Wired-OR Mode Bit
247
  wire       mstr = spcr[4];   // Master Mode Select Bit
248
  wire       cpol = spcr[3];   // Clock Polarity Bit
249
  wire       cpha = spcr[2];   // Clock Phase Bit
250
  wire [1:0] spr  = spcr[1:0]; // Clock Rate Select Bits
251
 
252
  // decode Serial Peripheral Extension Register
253
  wire [1:0] icnt = sper[7:6]; // interrupt on transfer count
254
  wire [1:0] spre = sper[1:0]; // extended clock rate select
255
 
256
  wire [3:0] espr = {spre, spr};
257
 
258
  // generate status register
259
  wire wr_spsr = wb_wr & (adr_i == 3'b001);
260
 
261
  reg spif;
262
  always @(posedge clk_i)
263
    if (~spe | rst_i)
264
      spif <=  1'b0;
265
    else
266
      spif <=  (tirq | spif) & ~(wr_spsr & dat_i[7]);
267
 
268
  reg wcol;
269
  always @(posedge clk_i)
270
    if (~spe | rst_i)
271
      wcol <=  1'b0;
272
    else
273
      wcol <=  (wfov | wcol) & ~(wr_spsr & dat_i[6]);
274
 
275
  assign spsr[7]   = spif;
276
  assign spsr[6]   = wcol;
277
  assign spsr[5:4] = 2'b00;
278
  assign spsr[3]   = wffull;
279
  assign spsr[2]   = wfempty;
280
  assign spsr[1]   = rffull;
281
  assign spsr[0]   = rfempty;
282
 
283
 
284
  // generate IRQ output (inta_o)
285
  always @(posedge clk_i)
286
    inta_o <=  spif & spie;
287
 
288
 
289
   wire [7:0] wfifo_dat_i;
290
   assign wfifo_dat_i = startup_busy ? {6'd0, startup_state_wdf} : dat_i;
291
 
292
   wire       wfifo_wfwe;
293
   assign wfifo_wfwe =  wfwe | startup_wfwe;
294
 
295
   wire       rfifo_rfre = rfre | startup_rfre;
296
 
297
  //
298
  // hookup read/write buffer fifo
299
  fifo4 #(8)
300
  rfifo(
301
        .clk   ( clk_i   ),
302
        .rst   ( ~rst_i   ),
303
        .clr   ( ~spe    ),
304
        .din   ( treg    ),
305
        .we    ( rfwe    ),
306
        .dout  ( rfdout  ),
307
        .re    ( rfifo_rfre    ),
308
        .full  ( rffull  ),
309
        .empty ( rfempty )
310
  ),
311
  wfifo(
312
        .clk   ( clk_i   ),
313
        .rst   ( ~rst_i   ),
314
        .clr   ( ~spe    ),
315
        .din   ( wfifo_dat_i   ),
316
        .we    ( wfifo_wfwe    ),
317
        .dout  ( wfdout  ),
318
        .re    ( wfre    ),
319
        .full  ( wffull  ),
320
        .empty ( wfempty )
321
  );
322
 
323
  //
324
  // generate clk divider
325
  reg [11:0] clkcnt;
326
  always @(posedge clk_i)
327
    if(spe & (|clkcnt & |state))
328
      clkcnt <=  clkcnt - 11'h1;
329
    else
330
      case (espr) // synopsys full_case parallel_case
331
        4'b0000: clkcnt <=  12'h0;   // 2   -- original M68HC11 coding
332
        4'b0001: clkcnt <=  12'h1;   // 4   -- original M68HC11 coding
333
        4'b0010: clkcnt <=  12'h3;   // 16  -- original M68HC11 coding
334
        4'b0011: clkcnt <=  12'hf;   // 32  -- original M68HC11 coding
335
        4'b0100: clkcnt <=  12'h1f;  // 8
336
        4'b0101: clkcnt <=  12'h7;   // 64
337
        4'b0110: clkcnt <=  12'h3f;  // 128
338
        4'b0111: clkcnt <=  12'h7f;  // 256
339
        4'b1000: clkcnt <=  12'hff;  // 512
340
        4'b1001: clkcnt <=  12'h1ff; // 1024
341
        4'b1010: clkcnt <=  12'h3ff; // 2048
342
        4'b1011: clkcnt <=  12'h7ff; // 4096
343
      endcase
344
 
345
  // generate clock enable signal
346
  wire ena = ~|clkcnt;
347
 
348
  // transfer statemachine
349
  always @(posedge clk_i)
350
    if (~spe | rst_i)
351
      begin
352
          state <=  2'b00; // idle
353
          bcnt  <=  3'h0;
354
          treg  <=  8'h00;
355
          wfre  <=  1'b0;
356
          rfwe  <=  1'b0;
357
          sck_o <=  1'b0;
358
      end
359
    else
360
      begin
361
         wfre <=  1'b0;
362
         rfwe <=  1'b0;
363
 
364
         case (state) //synopsys full_case parallel_case
365
           2'b00: // idle state
366
              begin
367
                  bcnt  <=  3'h7;   // set transfer counter
368
                  treg  <=  wfdout; // load transfer register
369
                  sck_o <=  cpol;   // set sck
370
 
371
                  if (~wfempty) begin
372
                    wfre  <=  1'b1;
373
                    state <=  2'b01;
374
                    if (cpha) sck_o <=  ~sck_o;
375
                  end
376
              end
377
 
378
           2'b01: // clock-phase2, next data
379
              if (ena) begin
380
                sck_o   <=  ~sck_o;
381
                state   <=  2'b11;
382
              end
383
 
384
           2'b11: // clock phase1
385
              if (ena) begin
386
                treg <=  {treg[6:0], miso_i};
387
                bcnt <=  bcnt -3'h1;
388
 
389
                if (~|bcnt) begin
390
                  state <=  2'b00;
391
                  sck_o <=  cpol;
392
                  rfwe  <=  1'b1;
393
                end else begin
394
                  state <=  2'b01;
395
                  sck_o <=  ~sck_o;
396
                end
397
              end
398
 
399
           2'b10: state <=  2'b00;
400
         endcase
401
      end
402
 
403
  assign mosi_o = treg[7];
404
 
405
 
406
  // count number of transfers (for interrupt generation)
407
  reg [1:0] tcnt; // transfer count
408
  always @(posedge clk_i)
409
    if (~spe)
410
      tcnt <=  icnt;
411
    else if (rfwe) // rfwe gets asserted when all bits have been transfered
412
      if (|tcnt)
413
        tcnt <=  tcnt - 2'h1;
414
      else
415
        tcnt <=  icnt;
416
 
417
  assign tirq = ~|tcnt & rfwe;
418
 
419
endmodule
420
 

powered by: WebSVN 2.1.0

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