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