1
2// Modified 2010 by Matt Ettus to remove old verilog style
3
4//////////////////////////////////////////////////////////////////////
5////                                                              ////
6////  spi_top.v                                                   ////
7////                                                              ////
8////  This file is part of the SPI IP core project                ////
9////  http://www.opencores.org/projects/spi/                      ////
10////                                                              ////
11////  Author(s):                                                  ////
12////      - Simon Srot (simons@opencores.org)                     ////
13////                                                              ////
14////  All additional information is avaliable in the Readme.txt   ////
15////  file.                                                       ////
16////                                                              ////
17//////////////////////////////////////////////////////////////////////
18////                                                              ////
19//// Copyright (C) 2002 Authors                                   ////
20////                                                              ////
21//// This source file may be used and distributed without         ////
22//// restriction provided that this copyright statement is not    ////
23//// removed from the file and that any derivative work contains  ////
24//// the original copyright notice and the associated disclaimer. ////
25////                                                              ////
26//// This source file is free software; you can redistribute it   ////
27//// and/or modify it under the terms of the GNU Lesser General   ////
28//// Public License as published by the Free Software Foundation; ////
29//// either version 2.1 of the License, or (at your option) any   ////
30//// later version.                                               ////
31////                                                              ////
32//// This source is distributed in the hope that it will be       ////
33//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
34//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
35//// PURPOSE.  See the GNU Lesser General Public License for more ////
36//// details.                                                     ////
37////                                                              ////
38//// You should have received a copy of the GNU Lesser General    ////
39//// Public License along with this source; if not, download it   ////
40//// from http://www.opencores.org/lgpl.shtml                     ////
41////                                                              ////
42//////////////////////////////////////////////////////////////////////
43
44
45`include "spi_defines.v"
46
47module spi_top
48(
49  // Wishbone signals
50  wb_clk_i, wb_rst_i, wb_adr_i, wb_dat_i, wb_dat_o, wb_sel_i,
51  wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_err_o, wb_int_o,
52
53  // SPI signals
54  ss_pad_o, sclk_pad_o, mosi_pad_o, miso_pad_i
55);
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  input                   [32-1:0] wb_dat_i;         // databus input
62  output                  [32-1:0] wb_dat_o;         // databus output
63  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  reg                     [32-1:0] wb_dat_o;
78  reg                              wb_ack_o;
79  reg                              wb_int_o;
80
81  // Internal signals
82  reg       [`SPI_DIVIDER_LEN-1:0] divider;          // Divider register
83  reg       [`SPI_CTRL_BIT_NB-1:0] ctrl;             // Control and status register
84  reg             [`SPI_SS_NB-1:0] ss;               // Slave select register
85  reg                     [32-1:0] wb_dat;           // wb data out
86  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  wire                             ass;              // automatic slave select
94  wire                             spi_divider_sel;  // divider register select
95  wire                             spi_ctrl_sel;     // ctrl register select
96  wire                       [3:0] spi_tx_sel;       // tx_l register select
97  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_DIVIDE);
105  assign spi_ctrl_sel    = wb_cyc_i & wb_stb_i & (wb_adr_i[`SPI_OFS_BITS] == `SPI_CTRL);
106  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  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`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      `SPI_RX_3:    wb_dat = {{128-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:96]};
121`else
122`ifdef SPI_MAX_CHAR_64
123      `SPI_RX_0:    wb_dat = rx[31:0];
124      `SPI_RX_1:    wb_dat = {{64-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:32]};
125      `SPI_RX_2:    wb_dat = 32'b0;
126      `SPI_RX_3:    wb_dat = 32'b0;
127`else
128      `SPI_RX_0:    wb_dat = {{32-`SPI_MAX_CHAR{1'b0}}, rx[`SPI_MAX_CHAR-1:0]};
129      `SPI_RX_1:    wb_dat = 32'b0;
130      `SPI_RX_2:    wb_dat = 32'b0;
131      `SPI_RX_3:    wb_dat = 32'b0;
132`endif
133`endif
134      `SPI_CTRL:    wb_dat = {{32-`SPI_CTRL_BIT_NB{1'b0}}, ctrl};
135      `SPI_DIVIDE:  wb_dat = {{32-`SPI_DIVIDER_LEN{1'b0}}, divider};
136      `SPI_SS:      wb_dat = {{32-`SPI_SS_NB{1'b0}}, ss};
137      default:      wb_dat = 32'bx;
138    endcase
139  end
140
141  // Wb data out
142  always @(posedge wb_clk_i)
143  begin
144    if (wb_rst_i)
145      wb_dat_o <= 32'b0;
146    else
147      wb_dat_o <= wb_dat;
148  end
149
150  // Wb acknowledge
151  always @(posedge wb_clk_i)
152  begin
153    if (wb_rst_i)
154      wb_ack_o <= 1'b0;
155    else
156      wb_ack_o <= wb_cyc_i & wb_stb_i & ~wb_ack_o;
157  end
158
159  // Wb error
160  assign wb_err_o = 1'b0;
161
162  // Interrupt
163  always @(posedge wb_clk_i)
164  begin
165    if (wb_rst_i)
166      wb_int_o <= 1'b0;
167    else if (ie && tip && last_bit && pos_edge)
168      wb_int_o <= 1'b1;
169    else if (wb_ack_o)
170      wb_int_o <= 1'b0;
171  end
172
173  // Divider register
174  always @(posedge wb_clk_i)
175  begin
176    if (wb_rst_i)
177        divider <= {`SPI_DIVIDER_LEN{1'b0}};
178    else if (spi_divider_sel && wb_we_i && !tip)
179      begin
180      `ifdef SPI_DIVIDER_LEN_8
181        if (wb_sel_i[0])
182          divider <= wb_dat_i[`SPI_DIVIDER_LEN-1:0];
183      `endif
184      `ifdef SPI_DIVIDER_LEN_16
185        if (wb_sel_i[0])
186          divider[7:0] <= wb_dat_i[7:0];
187        if (wb_sel_i[1])
188          divider[`SPI_DIVIDER_LEN-1:8] <= wb_dat_i[`SPI_DIVIDER_LEN-1:8];
189      `endif
190      `ifdef SPI_DIVIDER_LEN_24
191        if (wb_sel_i[0])
192          divider[7:0] <= wb_dat_i[7:0];
193        if (wb_sel_i[1])
194          divider[15:8] <= wb_dat_i[15:8];
195        if (wb_sel_i[2])
196          divider[`SPI_DIVIDER_LEN-1:16] <= wb_dat_i[`SPI_DIVIDER_LEN-1:16];
197      `endif
198      `ifdef SPI_DIVIDER_LEN_32
199        if (wb_sel_i[0])
200          divider[7:0] <= wb_dat_i[7:0];
201        if (wb_sel_i[1])
202          divider[15:8] <= wb_dat_i[15:8];
203        if (wb_sel_i[2])
204          divider[23:16] <= wb_dat_i[23:16];
205        if (wb_sel_i[3])
206          divider[`SPI_DIVIDER_LEN-1:24] <= wb_dat_i[`SPI_DIVIDER_LEN-1:24];
207      `endif
208      end
209  end
210
211  // Ctrl register
212  always @(posedge wb_clk_i)
213  begin
214    if (wb_rst_i)
215      ctrl <= {`SPI_CTRL_BIT_NB{1'b0}};
216    else if(spi_ctrl_sel && wb_we_i && !tip)
217      begin
218        if (wb_sel_i[0])
219          ctrl[7:0] <= wb_dat_i[7:0] | {7'b0, ctrl[0]};
220        if (wb_sel_i[1])
221          ctrl[`SPI_CTRL_BIT_NB-1:8] <= wb_dat_i[`SPI_CTRL_BIT_NB-1:8];
222      end
223    else if(tip && last_bit && pos_edge)
224      ctrl[`SPI_CTRL_GO] <= 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  assign ass        = ctrl[`SPI_CTRL_ASS];
234
235  // Slave select register
236  always @(posedge wb_clk_i)
237  begin
238    if (wb_rst_i)
239      ss <= {`SPI_SS_NB{1'b0}};
240    else if(spi_ss_sel && wb_we_i && !tip)
241      begin
242      `ifdef SPI_SS_NB_8
243        if (wb_sel_i[0])
244          ss <= wb_dat_i[`SPI_SS_NB-1:0];
245      `endif
246      `ifdef SPI_SS_NB_16
247        if (wb_sel_i[0])
248          ss[7:0] <= wb_dat_i[7:0];
249        if (wb_sel_i[1])
250          ss[`SPI_SS_NB-1:8] <= wb_dat_i[`SPI_SS_NB-1:8];
251      `endif
252      `ifdef SPI_SS_NB_24
253        if (wb_sel_i[0])
254          ss[7:0] <= wb_dat_i[7:0];
255        if (wb_sel_i[1])
256          ss[15:8] <= wb_dat_i[15:8];
257        if (wb_sel_i[2])
258          ss[`SPI_SS_NB-1:16] <= wb_dat_i[`SPI_SS_NB-1:16];
259      `endif
260      `ifdef SPI_SS_NB_32
261        if (wb_sel_i[0])
262          ss[7:0] <= wb_dat_i[7:0];
263        if (wb_sel_i[1])
264          ss[15:8] <= wb_dat_i[15:8];
265        if (wb_sel_i[2])
266          ss[23:16] <= wb_dat_i[23:16];
267        if (wb_sel_i[3])
268          ss[`SPI_SS_NB-1:24] <= wb_dat_i[`SPI_SS_NB-1:24];
269      `endif
270      end
271  end
272
273  assign ss_pad_o = ~((ss & {`SPI_SS_NB{tip & ass}}) | (ss & {`SPI_SS_NB{!ass}}));
274
275  spi_clgen clgen (.clk_in(wb_clk_i), .rst(wb_rst_i), .go(go), .enable(tip), .last_clk(last_bit),
276                   .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                   .latch(spi_tx_sel[3:0] & {4{wb_we_i}}), .byte_sel(wb_sel_i), .lsb(lsb),
281                   .go(go), .pos_edge(pos_edge), .neg_edge(neg_edge),
282                   .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));
286endmodule
287
288