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 408

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
//
36
// Motorola MC68HC11E based SPI interface
37
//
38
// Currently only MASTER mode is supported
39
//
40
 
41
// synopsys translate_off
42
`include "timescale.v"
43
// synopsys translate_on
44
 
45
`define SIMPLE_SPI_RST_SENS rst_i
46
 
47
//module simple_spi_top(
48
module simple_spi ( // renamed by Julius
49
                    // 8bit WISHBONE bus slave interface
50
                    clk_i,         // clock
51
                    rst_i,         // reset (asynchronous active low)
52
                    cyc_i,         // cycle
53
                    stb_i,         // strobe
54
                    adr_i,         // address
55
                    we_i,          // write enable
56
                    dat_i,         // data input
57
                    dat_o,         // data output
58
                    ack_o,         // normal bus termination
59
                    inta_o,        // interrupt output
60
 
61
 
62
                    sck_o,         // serial clock output
63
                    ss_o, //slave select
64
                    mosi_o,        // MasterOut SlaveIN
65
                    miso_i         // MasterIn SlaveOut             
66
                    );
67
 
68
   parameter slave_select_width = 1;
69
 
70
   input  wire      clk_i;         // clock
71
   input  wire      rst_i;         // reset (asynchronous active low)
72
   input  wire      cyc_i;         // cycle
73
   input  wire      stb_i;         // strobe
74
   input  wire [2:0] adr_i;         // address
75
   input  wire       we_i;          // write enable
76
   input  wire [7:0] dat_i;         // data input
77
   output reg [7:0]  dat_o;         // data output
78
   output reg        ack_o;         // normal bus termination
79
   output reg        inta_o;        // interrupt output
80
 
81
   // SPI port
82
   output reg        sck_o;         // serial clock output
83
   output [slave_select_width-1:0] ss_o;
84
   output wire                         mosi_o;        // MasterOut SlaveIN
85
   input  wire                         miso_i;         // MasterIn SlaveOut     
86
 
87
 
88
   reg [slave_select_width-1:0]        ss_r;
89
 
90
  //
91
  // Module body
92
  //
93
  reg  [7:0] spcr;       // Serial Peripheral Control Register ('HC11 naming)
94
  wire [7:0] spsr;       // Serial Peripheral Status register ('HC11 naming)
95
  reg  [7:0] sper;       // Serial Peripheral Extension register
96
  reg  [7:0] treg; // Transmit/Receive register
97
 
98
  // fifo signals
99
  wire [7:0] rfdout;
100
  reg        wfre, rfwe;
101
  wire       rfre, rffull, rfempty;
102
  wire [7:0] wfdout;
103
  wire       wfwe, wffull, wfempty;
104
 
105
  // misc signals
106
  wire      tirq;     // transfer interrupt (selected number of transfers done)
107
  wire      wfov;     // write fifo overrun (writing while fifo full)
108
  reg [1:0] state;    // statemachine state
109
  reg [2:0] bcnt;
110
 
111
 
112
  //
113
  // Wishbone interface
114 408 julius
  wire wb_acc = cyc_i & stb_i;       // WISHBONE access
115 361 julius
  wire wb_wr  = wb_acc & we_i;       // WISHBONE write access
116
 
117
  // dat_i
118
  always @(posedge clk_i)
119
    if (`SIMPLE_SPI_RST_SENS)
120
      begin
121 408 julius
         spcr <=  8'h10;  // set master bit
122 361 julius
         sper <=  8'h00;
123
         ss_r <=  0;
124
      end
125
    else if (wb_wr)
126
      begin
127
        if (adr_i == 3'b000)
128
          spcr <=  dat_i | 8'h10; // always set master bit
129
 
130
        if (adr_i == 3'b011)
131
          sper <=  dat_i;
132
 
133
         if (adr_i == 3'b100)
134
           ss_r <=  dat_i[slave_select_width-1:0];
135
      end // if (wb_wr)
136
 
137
   // Slave select output
138
   // SPI slave select is active low   
139
   assign ss_o = ~ss_r;
140
 
141
  // write fifo
142
  assign wfwe = wb_acc & (adr_i == 3'b010) & ack_o &  we_i;
143
  assign wfov = wfwe & wffull;
144
 
145
  // dat_o
146
  always @(posedge clk_i)
147
    case(adr_i) // synopsys full_case parallel_case
148
      3'b000: dat_o <=  spcr;
149
      3'b001: dat_o <=  spsr;
150
      3'b010: dat_o <=  rfdout;
151
      3'b011: dat_o <=  sper;
152
      3'b100: dat_o <=  {{(8-slave_select_width){1'b0}},ss_r};
153
      default:
154
        dat_o <= 0;
155
    endcase
156
 
157
  // read fifo
158
  assign rfre = wb_acc & (adr_i == 3'b010) & ack_o & ~we_i;
159
 
160
  // ack_o
161
  always @(posedge clk_i)
162
    if (`SIMPLE_SPI_RST_SENS)
163
      ack_o <=  1'b0;
164
    else
165
      ack_o <=  wb_acc & !ack_o;
166
 
167
  // decode Serial Peripheral Control Register
168
  wire       spie = spcr[7];   // Interrupt enable bit
169
  wire       spe  = spcr[6];   // System Enable bit
170
  wire       dwom = spcr[5];   // Port D Wired-OR Mode Bit
171
  wire       mstr = spcr[4];   // Master Mode Select Bit
172
  wire       cpol = spcr[3];   // Clock Polarity Bit
173
  wire       cpha = spcr[2];   // Clock Phase Bit
174
  wire [1:0] spr  = spcr[1:0]; // Clock Rate Select Bits
175
 
176
  // decode Serial Peripheral Extension Register
177
  wire [1:0] icnt = sper[7:6]; // interrupt on transfer count
178
  wire [1:0] spre = sper[1:0]; // extended clock rate select
179
 
180
  wire [3:0] espr = {spre, spr};
181
 
182
  // generate status register
183
  wire wr_spsr = wb_wr & (adr_i == 3'b001);
184
 
185
  reg spif;
186
  always @(posedge clk_i)
187
    if (~spe | rst_i)
188
      spif <=  1'b0;
189
    else
190
      spif <=  (tirq | spif) & ~(wr_spsr & dat_i[7]);
191
 
192
  reg wcol;
193
  always @(posedge clk_i)
194
    if (~spe | rst_i)
195
      wcol <=  1'b0;
196
    else
197
      wcol <=  (wfov | wcol) & ~(wr_spsr & dat_i[6]);
198
 
199
  assign spsr[7]   = spif;
200
  assign spsr[6]   = wcol;
201
  assign spsr[5:4] = 2'b00;
202
  assign spsr[3]   = wffull;
203
  assign spsr[2]   = wfempty;
204
  assign spsr[1]   = rffull;
205
  assign spsr[0]   = rfempty;
206
 
207
 
208
  // generate IRQ output (inta_o)
209
  always @(posedge clk_i)
210
    inta_o <=  spif & spie;
211
 
212
 
213
   wire [7:0] wfifo_dat_i;
214 408 julius
   assign wfifo_dat_i = dat_i;
215 361 julius
 
216
   wire       wfifo_wfwe;
217 408 julius
   assign wfifo_wfwe =  wfwe;
218 361 julius
 
219 408 julius
   wire       rfifo_rfre = rfre;
220 361 julius
 
221
  //
222
  // hookup read/write buffer fifo
223
  fifo4 #(8)
224
  rfifo(
225
        .clk   ( clk_i   ),
226
        .rst   ( ~rst_i   ),
227
        .clr   ( ~spe    ),
228
        .din   ( treg    ),
229
        .we    ( rfwe    ),
230
        .dout  ( rfdout  ),
231
        .re    ( rfifo_rfre    ),
232
        .full  ( rffull  ),
233
        .empty ( rfempty )
234
  ),
235
  wfifo(
236
        .clk   ( clk_i   ),
237
        .rst   ( ~rst_i   ),
238
        .clr   ( ~spe    ),
239
        .din   ( wfifo_dat_i   ),
240
        .we    ( wfifo_wfwe    ),
241
        .dout  ( wfdout  ),
242
        .re    ( wfre    ),
243
        .full  ( wffull  ),
244
        .empty ( wfempty )
245
  );
246
 
247
  //
248
  // generate clk divider
249
  reg [11:0] clkcnt;
250
  always @(posedge clk_i)
251
    if(spe & (|clkcnt & |state))
252
      clkcnt <=  clkcnt - 11'h1;
253
    else
254
      case (espr) // synopsys full_case parallel_case
255
        4'b0000: clkcnt <=  12'h0;   // 2   -- original M68HC11 coding
256
        4'b0001: clkcnt <=  12'h1;   // 4   -- original M68HC11 coding
257
        4'b0010: clkcnt <=  12'h3;   // 16  -- original M68HC11 coding
258
        4'b0011: clkcnt <=  12'hf;   // 32  -- original M68HC11 coding
259
        4'b0100: clkcnt <=  12'h1f;  // 8
260
        4'b0101: clkcnt <=  12'h7;   // 64
261
        4'b0110: clkcnt <=  12'h3f;  // 128
262
        4'b0111: clkcnt <=  12'h7f;  // 256
263
        4'b1000: clkcnt <=  12'hff;  // 512
264
        4'b1001: clkcnt <=  12'h1ff; // 1024
265
        4'b1010: clkcnt <=  12'h3ff; // 2048
266
        4'b1011: clkcnt <=  12'h7ff; // 4096
267
      endcase
268
 
269
  // generate clock enable signal
270
  wire ena = ~|clkcnt;
271
 
272
  // transfer statemachine
273
  always @(posedge clk_i)
274
    if (~spe | rst_i)
275
      begin
276
          state <=  2'b00; // idle
277
          bcnt  <=  3'h0;
278
          treg  <=  8'h00;
279
          wfre  <=  1'b0;
280
          rfwe  <=  1'b0;
281
          sck_o <=  1'b0;
282
      end
283
    else
284
      begin
285
         wfre <=  1'b0;
286
         rfwe <=  1'b0;
287
 
288
         case (state) //synopsys full_case parallel_case
289
           2'b00: // idle state
290
              begin
291
                  bcnt  <=  3'h7;   // set transfer counter
292
                  treg  <=  wfdout; // load transfer register
293
                  sck_o <=  cpol;   // set sck
294
 
295
                  if (~wfempty) begin
296
                    wfre  <=  1'b1;
297
                    state <=  2'b01;
298
                    if (cpha) sck_o <=  ~sck_o;
299
                  end
300
              end
301
 
302
           2'b01: // clock-phase2, next data
303
              if (ena) begin
304
                sck_o   <=  ~sck_o;
305
                state   <=  2'b11;
306
              end
307
 
308
           2'b11: // clock phase1
309
              if (ena) begin
310
                treg <=  {treg[6:0], miso_i};
311
                bcnt <=  bcnt -3'h1;
312
 
313
                if (~|bcnt) begin
314
                  state <=  2'b00;
315
                  sck_o <=  cpol;
316
                  rfwe  <=  1'b1;
317
                end else begin
318
                  state <=  2'b01;
319
                  sck_o <=  ~sck_o;
320
                end
321
              end
322
 
323
           2'b10: state <=  2'b00;
324
         endcase
325
      end
326
 
327
  assign mosi_o = treg[7];
328
 
329
 
330
  // count number of transfers (for interrupt generation)
331
  reg [1:0] tcnt; // transfer count
332
  always @(posedge clk_i)
333
    if (~spe)
334
      tcnt <=  icnt;
335
    else if (rfwe) // rfwe gets asserted when all bits have been transfered
336
      if (|tcnt)
337
        tcnt <=  tcnt - 2'h1;
338
      else
339
        tcnt <=  icnt;
340
 
341
  assign tirq = ~|tcnt & rfwe;
342
 
343
endmodule
344
 

powered by: WebSVN 2.1.0

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