1
2// Modified 2010 by Matt Ettus to remove old verilog style and
3// allow 16-bit operation
4
5//////////////////////////////////////////////////////////////////////
6////                                                              ////
7////  spi_top.v                                                   ////
8////                                                              ////
9////  This file is part of the SPI IP core project                ////
10////  http://www.opencores.org/projects/spi/                      ////
11////                                                              ////
12////  Author(s):                                                  ////
13////      - Simon Srot (simons@opencores.org)                     ////
14////                                                              ////
15////  All additional information is avaliable in the Readme.txt   ////
16////  file.                                                       ////
17////                                                              ////
18//////////////////////////////////////////////////////////////////////
19////                                                              ////
20//// Copyright (C) 2002 Authors                                   ////
21////                                                              ////
22//// This source file may be used and distributed without         ////
23//// restriction provided that this copyright statement is not    ////
24//// removed from the file and that any derivative work contains  ////
25//// the original copyright notice and the associated disclaimer. ////
26////                                                              ////
27//// This source file is free software; you can redistribute it   ////
28//// and/or modify it under the terms of the GNU Lesser General   ////
29//// Public License as published by the Free Software Foundation; ////
30//// either version 2.1 of the License, or (at your option) any   ////
31//// later version.                                               ////
32////                                                              ////
33//// This source is distributed in the hope that it will be       ////
34//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
35//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
36//// PURPOSE.  See the GNU Lesser General Public License for more ////
37//// details.                                                     ////
38////                                                              ////
39//// You should have received a copy of the GNU Lesser General    ////
40//// Public License along with this source; if not, download it   ////
41//// from http://www.opencores.org/lgpl.shtml                     ////
42////                                                              ////
43//////////////////////////////////////////////////////////////////////
44
45
46`include "spi_defines.v"
47
48module spi_top16
49  (input wb_clk_i, input wb_rst_i,
50   input [4:0] wb_adr_i,
51   input [15:0] wb_dat_i,
52   output reg [15:0] wb_dat_o,
53   input [1:0] wb_sel_i,
54   input wb_we_i, input wb_stb_i, input wb_cyc_i,
55   output reg wb_ack_o, output wb_err_o, output reg wb_int_o,
56
57   // SPI signals
58   output [15:0] ss_pad_o, output sclk_pad_o, output mosi_pad_o, input miso_pad_i);
59
60   // Internal signals
61   reg [15:0] divider;          // Divider register
62   reg [`SPI_CTRL_BIT_NB-1:0] ctrl;             // Control and status register
63   reg [15:0] 		      ss;               // Slave select register
64   reg [31:0] 		      wb_dat;           // wb data out
65   wire [31:0] 		      rx;               // Rx register
66   wire 		      rx_negedge;       // miso is sampled on negative edge
67   wire 		      tx_negedge;       // mosi is driven on negative edge
68   wire [`SPI_CHAR_LEN_BITS-1:0] char_len;         // char len
69   wire 			 go;               // go
70   wire 			 lsb;              // lsb first on line
71   wire 			 ie;               // interrupt enable
72   wire 			 ass;              // automatic slave select
73   wire 			 spi_divider_sel;  // divider register select
74   wire 			 spi_ctrl_sel;     // ctrl register select
75   wire [3:0] 			 spi_tx_sel;       // tx_l register select
76   wire 			 spi_ss_sel;       // ss register select
77   wire 			 tip;              // transfer in progress
78   wire 			 pos_edge;         // recognize posedge of sclk
79   wire 			 neg_edge;         // recognize negedge of sclk
80   wire 			 last_bit;         // marks last character bit
81
82   // Address decoder
83   assign spi_divider_sel = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_DIVIDE);
84   assign spi_ctrl_sel    = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_CTRL);
85   assign spi_tx_sel[0]   = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_TX_0);
86   assign spi_tx_sel[1]   = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_TX_1);
87   assign spi_tx_sel[2]   = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_TX_2);
88   assign spi_tx_sel[3]   = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_TX_3);
89   assign spi_ss_sel      = wb_cyc_i & wb_stb_i & (wb_adr_i[4:2] == `SPI_SS);
90
91   always @(wb_adr_i or rx or ctrl or divider or ss)
92     case (wb_adr_i[4:2])
93       `SPI_RX_0:    wb_dat = rx[31:0];
94       `SPI_CTRL:    wb_dat = {{32-`SPI_CTRL_BIT_NB{1'b0}}, ctrl};
95       `SPI_DIVIDE:  wb_dat = {16'b0, divider};
96       `SPI_SS:      wb_dat = {16'b0, ss};
97       default : wb_dat = 32'd0;
98     endcase // case (wb_adr_i[4:2])
99
100   always @(posedge wb_clk_i)
101     if (wb_rst_i)
102       wb_dat_o <= 32'b0;
103     else
104       wb_dat_o <= wb_adr_i[1] ? wb_dat[31:16] : wb_dat[15:0];
105
106   always @(posedge wb_clk_i)
107     if (wb_rst_i)
108       wb_ack_o <= 1'b0;
109     else
110       wb_ack_o <= wb_cyc_i & wb_stb_i & ~wb_ack_o;
111
112   assign wb_err_o = 1'b0;
113
114   // Interrupt
115   always @(posedge wb_clk_i)
116     if (wb_rst_i)
117       wb_int_o <= 1'b0;
118     else if (ie && tip && last_bit && pos_edge)
119       wb_int_o <= 1'b1;
120     else if (wb_ack_o)
121       wb_int_o <= 1'b0;
122
123   // Divider register
124   always @(posedge wb_clk_i)
125     if (wb_rst_i)
126       divider <= 16'b0;
127     else if (spi_divider_sel && wb_we_i && !tip && ~wb_adr_i[1])
128       divider <= wb_dat_i;
129
130   // Ctrl register
131   always @(posedge wb_clk_i)
132     if (wb_rst_i)
133       ctrl <= {`SPI_CTRL_BIT_NB{1'b0}};
134     else if(spi_ctrl_sel && wb_we_i && !tip && ~wb_adr_i[1])
135       begin
136          if (wb_sel_i[0])
137            ctrl[7:0] <= wb_dat_i[7:0] | {7'b0, ctrl[0]};
138          if (wb_sel_i[1])
139            ctrl[`SPI_CTRL_BIT_NB-1:8] <= wb_dat_i[`SPI_CTRL_BIT_NB-1:8];
140       end
141     else if(tip && last_bit && pos_edge)
142       ctrl[`SPI_CTRL_GO] <= 1'b0;
143
144   assign rx_negedge = ctrl[`SPI_CTRL_RX_NEGEDGE];
145   assign tx_negedge = ctrl[`SPI_CTRL_TX_NEGEDGE];
146   assign go         = ctrl[`SPI_CTRL_GO];
147   assign char_len   = ctrl[`SPI_CTRL_CHAR_LEN];
148   assign lsb        = ctrl[`SPI_CTRL_LSB];
149   assign ie         = ctrl[`SPI_CTRL_IE];
150   assign ass        = ctrl[`SPI_CTRL_ASS];
151
152   // Slave select register
153   always @(posedge wb_clk_i)
154     if (wb_rst_i)
155       ss <= 16'b0;
156     else if(spi_ss_sel && wb_we_i && !tip & ~wb_adr_i[1])
157       begin
158          if (wb_sel_i[0])
159            ss[7:0] <= wb_dat_i[7:0];
160          if (wb_sel_i[1])
161            ss[15:8] <= wb_dat_i[15:8];
162       end
163
164   assign ss_pad_o = ~((ss & {16{tip & ass}}) | (ss & {16{!ass}}));
165
166   spi_clgen clgen (.clk_in(wb_clk_i), .rst(wb_rst_i), .go(go), .enable(tip), .last_clk(last_bit),
167                    .divider(divider[`SPI_DIVIDER_LEN-1:0]), .clk_out(sclk_pad_o), .pos_edge(pos_edge),
168                    .neg_edge(neg_edge));
169
170   wire [3:0] new_sels = { (wb_adr_i[1] & wb_sel_i[1]), (wb_adr_i[1] & wb_sel_i[0]),
171			   (~wb_adr_i[1] & wb_sel_i[1]), (~wb_adr_i[1] & wb_sel_i[0]) };
172
173
174   spi_shift shift (.clk(wb_clk_i), .rst(wb_rst_i), .len(char_len[`SPI_CHAR_LEN_BITS-1:0]),
175                    .latch(spi_tx_sel[3:0] & {4{wb_we_i}}), .byte_sel(new_sels), .lsb(lsb),
176                    .go(go), .pos_edge(pos_edge), .neg_edge(neg_edge),
177                    .rx_negedge(rx_negedge), .tx_negedge(tx_negedge),
178                    .tip(tip), .last(last_bit),
179                    .p_in({wb_dat_i,wb_dat_i}), .p_out(rx),
180                    .s_clk(sclk_pad_o), .s_in(miso_pad_i), .s_out(mosi_pad_o));
181
182endmodule // spi_top16
183