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

Subversion Repositories spi

[/] [spi/] [trunk/] [rtl/] [verilog/] [spi_top.v] - Blame information for rev 27

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 simons
//////////////////////////////////////////////////////////////////////
2
////                                                              ////
3
////  spi_top.v                                                   ////
4
////                                                              ////
5
////  This file is part of the SPI IP core project                ////
6
////  http://www.opencores.org/projects/spi/                      ////
7
////                                                              ////
8
////  Author(s):                                                  ////
9
////      - Simon Srot (simons@opencores.org)                     ////
10
////                                                              ////
11
////  All additional information is avaliable in the Readme.txt   ////
12
////  file.                                                       ////
13
////                                                              ////
14
//////////////////////////////////////////////////////////////////////
15
////                                                              ////
16
//// Copyright (C) 2002 Authors                                   ////
17
////                                                              ////
18
//// This source file may be used and distributed without         ////
19
//// restriction provided that this copyright statement is not    ////
20
//// removed from the file and that any derivative work contains  ////
21
//// the original copyright notice and the associated disclaimer. ////
22
////                                                              ////
23
//// This source file is free software; you can redistribute it   ////
24
//// and/or modify it under the terms of the GNU Lesser General   ////
25
//// Public License as published by the Free Software Foundation; ////
26
//// either version 2.1 of the License, or (at your option) any   ////
27
//// later version.                                               ////
28
////                                                              ////
29
//// This source is distributed in the hope that it will be       ////
30
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
31
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
32
//// PURPOSE.  See the GNU Lesser General Public License for more ////
33
//// details.                                                     ////
34
////                                                              ////
35
//// You should have received a copy of the GNU Lesser General    ////
36
//// Public License along with this source; if not, download it   ////
37
//// from http://www.opencores.org/lgpl.shtml                     ////
38
////                                                              ////
39
//////////////////////////////////////////////////////////////////////
40
 
41
 
42
`include "spi_defines.v"
43
`include "timescale.v"
44
 
45
module spi_top
46
(
47
  // Wishbone signals
48
  wb_clk_i, wb_rst_i, wb_adr_i, wb_dat_i, wb_dat_o, wb_sel_i,
49
  wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_err_o, wb_int_o,
50
 
51
  // SPI signals
52
  ss_pad_o, sclk_pad_o, mosi_pad_o, miso_pad_i
53
);
54
 
55
  parameter Tp = 1;
56
 
57
  // Wishbone signals
58
  input                            wb_clk_i;         // master clock input
59
  input                            wb_rst_i;         // synchronous active high reset
60
  input                      [4:0] wb_adr_i;         // lower address bits
61 7 simons
  input                   [32-1:0] wb_dat_i;         // databus input
62
  output                  [32-1:0] wb_dat_o;         // databus output
63 2 simons
  input                      [3:0] wb_sel_i;         // byte select inputs
64
  input                            wb_we_i;          // write enable input
65
  input                            wb_stb_i;         // stobe/core select signal
66
  input                            wb_cyc_i;         // valid bus cycle input
67
  output                           wb_ack_o;         // bus cycle acknowledge output
68
  output                           wb_err_o;         // termination w/ error
69
  output                           wb_int_o;         // interrupt request signal output
70
 
71
  // SPI signals                                     
72
  output          [`SPI_SS_NB-1:0] ss_pad_o;         // slave select
73
  output                           sclk_pad_o;       // serial clock
74
  output                           mosi_pad_o;       // master out slave in
75
  input                            miso_pad_i;       // master in slave out
76
 
77 7 simons
  reg                     [32-1:0] wb_dat_o;
78 2 simons
  reg                              wb_ack_o;
79
  reg                              wb_int_o;
80
 
81
  // Internal signals
82 13 simons
  reg       [`SPI_DIVIDER_LEN-1:0] divider;          // Divider register
83 2 simons
  reg       [`SPI_CTRL_BIT_NB-1:0] ctrl;             // Control and status register
84
  reg             [`SPI_SS_NB-1:0] ss;               // Slave select register
85 7 simons
  reg                     [32-1:0] wb_dat;           // wb data out
86 2 simons
  wire         [`SPI_MAX_CHAR-1:0] rx;               // Rx register
87
  wire                             rx_negedge;       // miso is sampled on negative edge
88
  wire                             tx_negedge;       // mosi is driven on negative edge
89
  wire    [`SPI_CHAR_LEN_BITS-1:0] char_len;         // char len
90
  wire                             go;               // go
91
  wire                             lsb;              // lsb first on line
92
  wire                             ie;               // interrupt enable
93 8 simons
  wire                             ass;              // automatic slave select
94 2 simons
  wire                             spi_divider_sel;  // divider register select
95
  wire                             spi_ctrl_sel;     // ctrl register select
96 9 simons
  wire                       [3:0] spi_tx_sel;       // tx_l register select
97 2 simons
  wire                             spi_ss_sel;       // ss register select
98
  wire                             tip;              // transfer in progress
99
  wire                             pos_edge;         // recognize posedge of sclk
100
  wire                             neg_edge;         // recognize negedge of sclk
101
  wire                             last_bit;         // marks last character bit
102
 
103
  // Address decoder
104
  assign spi_divider_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_DEVIDE);
105
  assign spi_ctrl_sel    = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_CTRL);
106 9 simons
  assign spi_tx_sel[0]   = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_0);
107
  assign spi_tx_sel[1]   = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_1);
108
  assign spi_tx_sel[2]   = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_2);
109
  assign spi_tx_sel[3]   = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_TX_3);
110 2 simons
  assign spi_ss_sel      = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_SS);
111
 
112
  // Read from registers
113
  always @(wb_adr_i or rx or ctrl or divider or ss)
114
  begin
115
    case (wb_adr_i[`SPI_OFS_BITS])
116 9 simons
`ifdef SPI_MAX_CHAR_128
117
      `SPI_RX_0:    wb_dat = rx[31:0];
118
      `SPI_RX_1:    wb_dat = rx[63:32];
119
      `SPI_RX_2:    wb_dat = rx[95:64];
120 15 simons
      `SPI_RX_3:    wb_dat = {{128-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:96]};
121 9 simons
`else
122 7 simons
`ifdef SPI_MAX_CHAR_64
123 9 simons
      `SPI_RX_0:    wb_dat = rx[31:0];
124 15 simons
      `SPI_RX_1:    wb_dat = {{64-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:32]};
125 9 simons
      `SPI_RX_2:    wb_dat = 32'b0;
126
      `SPI_RX_3:    wb_dat = 32'b0;
127 7 simons
`else
128 15 simons
      `SPI_RX_0:    wb_dat = {{32-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:0]};
129 9 simons
      `SPI_RX_1:    wb_dat = 32'b0;
130 13 simons
      `SPI_RX_2:    wb_dat = 32'b0;
131
      `SPI_RX_3:    wb_dat = 32'b0;
132 7 simons
`endif
133 9 simons
`endif
134 7 simons
      `SPI_CTRL:    wb_dat = {{32-`SPI_CTRL_BIT_NB{1'b0}}, ctrl};
135 13 simons
      `SPI_DEVIDE:  wb_dat = {{32-`SPI_DIVIDER_LEN{1'b0}}, divider};
136 7 simons
      `SPI_SS:      wb_dat = {{32-`SPI_SS_NB{1'b0}}, ss};
137 10 simons
      default:      wb_dat = 32'bx;
138 2 simons
    endcase
139
  end
140
 
141
  // Wb data out
142
  always @(posedge wb_clk_i or posedge wb_rst_i)
143
  begin
144
    if (wb_rst_i)
145 7 simons
      wb_dat_o <= #Tp 32'b0;
146 2 simons
    else
147
      wb_dat_o <= #Tp wb_dat;
148
  end
149
 
150
  // Wb acknowledge
151
  always @(posedge wb_clk_i or posedge wb_rst_i)
152
  begin
153
    if (wb_rst_i)
154
      wb_ack_o <= #Tp 1'b0;
155
    else
156
      wb_ack_o <= #Tp wb_cyc_i & wb_stb_i & ~wb_ack_o;
157
  end
158
 
159
  // Wb error
160 13 simons
  assign wb_err_o = 1'b0;
161 2 simons
 
162
  // Interrupt
163
  always @(posedge wb_clk_i or posedge wb_rst_i)
164
  begin
165
    if (wb_rst_i)
166
      wb_int_o <= #Tp 1'b0;
167
    else if (ie && tip && last_bit && pos_edge)
168
      wb_int_o <= #Tp 1'b1;
169
    else if (wb_ack_o)
170
      wb_int_o <= #Tp 1'b0;
171
  end
172
 
173
  // Divider register
174
  always @(posedge wb_clk_i or posedge wb_rst_i)
175
  begin
176
    if (wb_rst_i)
177 13 simons
        divider <= #Tp {`SPI_DIVIDER_LEN{1'b0}};
178 2 simons
    else if (spi_divider_sel && wb_we_i && !tip)
179 13 simons
      begin
180
      `ifdef SPI_DIVIDER_LEN_8
181 21 simons
        if (wb_sel_i[0])
182 15 simons
          divider <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:0];
183 13 simons
      `endif
184
      `ifdef SPI_DIVIDER_LEN_16
185 21 simons
        if (wb_sel_i[0])
186 13 simons
          divider[7:0] <= #Tp wb_dat_i[7:0];
187 21 simons
        if (wb_sel_i[1])
188 15 simons
          divider[`SPI_DIVIDER_LEN-1:8] <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:8];
189
      `endif
190
      `ifdef SPI_DIVIDER_LEN_24
191 21 simons
        if (wb_sel_i[0])
192 15 simons
          divider[7:0] <= #Tp wb_dat_i[7:0];
193 21 simons
        if (wb_sel_i[1])
194
          divider[15:8] <= #Tp wb_dat_i[15:8];
195 15 simons
        if (wb_sel_i[2])
196
          divider[`SPI_DIVIDER_LEN-1:16] <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:16];
197 13 simons
      `endif
198
      `ifdef SPI_DIVIDER_LEN_32
199 21 simons
        if (wb_sel_i[0])
200 13 simons
          divider[7:0] <= #Tp wb_dat_i[7:0];
201 21 simons
        if (wb_sel_i[1])
202
          divider[15:8] <= #Tp wb_dat_i[15:8];
203 13 simons
        if (wb_sel_i[2])
204
          divider[23:16] <= #Tp wb_dat_i[23:16];
205 21 simons
        if (wb_sel_i[3])
206 15 simons
          divider[`SPI_DIVIDER_LEN-1:24] <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:24];
207 13 simons
      `endif
208
      end
209 2 simons
  end
210
 
211
  // Ctrl register
212
  always @(posedge wb_clk_i or posedge wb_rst_i)
213
  begin
214
    if (wb_rst_i)
215
      ctrl <= #Tp {`SPI_CTRL_BIT_NB{1'b0}};
216
    else if(spi_ctrl_sel && wb_we_i && !tip)
217
      begin
218 21 simons
        if (wb_sel_i[0])
219 13 simons
          ctrl[7:0] <= #Tp wb_dat_i[7:0] | {7'b0, ctrl[0]};
220 21 simons
        if (wb_sel_i[1])
221 13 simons
          ctrl[`SPI_CTRL_BIT_NB-1:8] <= #Tp wb_dat_i[`SPI_CTRL_BIT_NB-1:8];
222 2 simons
      end
223
    else if(tip && last_bit && pos_edge)
224
      ctrl[`SPI_CTRL_GO] <= #Tp 1'b0;
225
  end
226
 
227
  assign rx_negedge = ctrl[`SPI_CTRL_RX_NEGEDGE];
228
  assign tx_negedge = ctrl[`SPI_CTRL_TX_NEGEDGE];
229
  assign go         = ctrl[`SPI_CTRL_GO];
230
  assign char_len   = ctrl[`SPI_CTRL_CHAR_LEN];
231
  assign lsb        = ctrl[`SPI_CTRL_LSB];
232
  assign ie         = ctrl[`SPI_CTRL_IE];
233 8 simons
  assign ass        = ctrl[`SPI_CTRL_ASS];
234 2 simons
 
235
  // Slave select register
236
  always @(posedge wb_clk_i or posedge wb_rst_i)
237
  begin
238
    if (wb_rst_i)
239
      ss <= #Tp {`SPI_SS_NB{1'b0}};
240
    else if(spi_ss_sel && wb_we_i && !tip)
241 13 simons
      begin
242
      `ifdef SPI_SS_NB_8
243 21 simons
        if (wb_sel_i[0])
244 15 simons
          ss <= #Tp wb_dat_i[`SPI_SS_NB-1:0];
245 13 simons
      `endif
246
      `ifdef SPI_SS_NB_16
247 21 simons
        if (wb_sel_i[0])
248 13 simons
          ss[7:0] <= #Tp wb_dat_i[7:0];
249 21 simons
        if (wb_sel_i[1])
250 15 simons
          ss[`SPI_SS_NB-1:8] <= #Tp wb_dat_i[`SPI_SS_NB-1:8];
251
      `endif
252
      `ifdef SPI_SS_NB_24
253 21 simons
        if (wb_sel_i[0])
254 15 simons
          ss[7:0] <= #Tp wb_dat_i[7:0];
255 21 simons
        if (wb_sel_i[1])
256
          ss[15:8] <= #Tp wb_dat_i[15:8];
257 15 simons
        if (wb_sel_i[2])
258
          ss[`SPI_SS_NB-1:16] <= #Tp wb_dat_i[`SPI_SS_NB-1:16];
259 13 simons
      `endif
260
      `ifdef SPI_SS_NB_32
261 21 simons
        if (wb_sel_i[0])
262 13 simons
          ss[7:0] <= #Tp wb_dat_i[7:0];
263 21 simons
        if (wb_sel_i[1])
264
          ss[15:8] <= #Tp wb_dat_i[15:8];
265 13 simons
        if (wb_sel_i[2])
266
          ss[23:16] <= #Tp wb_dat_i[23:16];
267 21 simons
        if (wb_sel_i[3])
268 15 simons
          ss[`SPI_SS_NB-1:24] <= #Tp wb_dat_i[`SPI_SS_NB-1:24];
269 13 simons
      `endif
270
      end
271 2 simons
  end
272
 
273 10 simons
  assign ss_pad_o = ~((ss & {`SPI_SS_NB{tip & ass}}) | (ss & {`SPI_SS_NB{!ass}}));
274 2 simons
 
275 9 simons
  spi_clgen clgen (.clk_in(wb_clk_i), .rst(wb_rst_i), .go(go), .enable(tip), .last_clk(last_bit),
276 2 simons
                   .divider(divider), .clk_out(sclk_pad_o), .pos_edge(pos_edge),
277
                   .neg_edge(neg_edge));
278
 
279
  spi_shift shift (.clk(wb_clk_i), .rst(wb_rst_i), .len(char_len[`SPI_CHAR_LEN_BITS-1:0]),
280 13 simons
                   .latch(spi_tx_sel[3:0] & {4{wb_we_i}}), .byte_sel(wb_sel_i), .lsb(lsb),
281 7 simons
                   .go(go), .pos_edge(pos_edge), .neg_edge(neg_edge),
282 2 simons
                   .rx_negedge(rx_negedge), .tx_negedge(tx_negedge),
283
                   .tip(tip), .last(last_bit),
284
                   .p_in(wb_dat_i), .p_out(rx),
285
                   .s_clk(sclk_pad_o), .s_in(miso_pad_i), .s_out(mosi_pad_o));
286
endmodule
287
 

powered by: WebSVN 2.1.0

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