updated wiki url
[debian/gnuradio] / usrp2 / fpga / opencores / spi / rtl / verilog / spi_top.v
1 //////////////////////////////////////////////////////////////////////
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   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_DEVIDE);
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_DEVIDE:  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 or posedge wb_rst_i)
143   begin
144     if (wb_rst_i)
145       wb_dat_o <= #Tp 32'b0;
146     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   assign wb_err_o = 1'b0;
161   
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         divider <= #Tp {`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 <= #Tp 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] <= #Tp wb_dat_i[7:0];
187         if (wb_sel_i[1])
188           divider[`SPI_DIVIDER_LEN-1:8] <= #Tp 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] <= #Tp wb_dat_i[7:0];
193         if (wb_sel_i[1])
194           divider[15:8] <= #Tp wb_dat_i[15:8];
195         if (wb_sel_i[2])
196           divider[`SPI_DIVIDER_LEN-1:16] <= #Tp 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] <= #Tp wb_dat_i[7:0];
201         if (wb_sel_i[1])
202           divider[15:8] <= #Tp wb_dat_i[15:8];
203         if (wb_sel_i[2])
204           divider[23:16] <= #Tp wb_dat_i[23:16];
205         if (wb_sel_i[3])
206           divider[`SPI_DIVIDER_LEN-1:24] <= #Tp wb_dat_i[`SPI_DIVIDER_LEN-1:24];
207       `endif
208       end
209   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         if (wb_sel_i[0])
219           ctrl[7:0] <= #Tp wb_dat_i[7:0] | {7'b0, ctrl[0]};
220         if (wb_sel_i[1])
221           ctrl[`SPI_CTRL_BIT_NB-1:8] <= #Tp wb_dat_i[`SPI_CTRL_BIT_NB-1:8];
222       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   assign ass        = ctrl[`SPI_CTRL_ASS];
234   
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       begin
242       `ifdef SPI_SS_NB_8
243         if (wb_sel_i[0])
244           ss <= #Tp 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] <= #Tp wb_dat_i[7:0];
249         if (wb_sel_i[1])
250           ss[`SPI_SS_NB-1:8] <= #Tp 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] <= #Tp wb_dat_i[7:0];
255         if (wb_sel_i[1])
256           ss[15:8] <= #Tp wb_dat_i[15:8];
257         if (wb_sel_i[2])
258           ss[`SPI_SS_NB-1:16] <= #Tp 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] <= #Tp wb_dat_i[7:0];
263         if (wb_sel_i[1])
264           ss[15:8] <= #Tp wb_dat_i[15:8];
265         if (wb_sel_i[2])
266           ss[23:16] <= #Tp wb_dat_i[23:16];
267         if (wb_sel_i[3])
268           ss[`SPI_SS_NB-1:24] <= #Tp 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));
286 endmodule
287