blob: 447f0f11aa5397624c5a8bde5500150a3463a4a3 [file] [log] [blame]
Tim Edwards04ba17f2020-10-02 22:27:50 -04001//----------------------------------------------------------------------------
2// Module: simple_spi_master
3//
4//----------------------------------------------------------------------------
5// Copyright (C) 2019 efabless, inc.
6//
7// This source file may be used and distributed without
8// restriction provided that this copyright statement is not
9// removed from the file and that any derivative work contains
10// the original copyright notice and the associated disclaimer.
11//
12// This source file is free software; you can redistribute it
13// and/or modify it under the terms of the GNU Lesser General
14// Public License as published by the Free Software Foundation;
15// either version 2.1 of the License, or (at your option) any
16// later version.
17//
18// This source is distributed in the hope that it will be
19// useful, but WITHOUT ANY WARRANTY; without even the implied
20// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
21// PURPOSE. See the GNU Lesser General Public License for more
22// details.
23//
24//--------------------------------------------------------------------
25//
26// resetn: active low async reset
27// clk: master clock (before prescaler)
28// stream:
29// 0 = apply/release CSB separately for each byte
30// 1 = apply CSB until stream bit is cleared
31// mlb:
32// 0 = msb 1st
33// 1 = lsb 1st
34// invsck:
35// 0 = normal SCK
36// 1 = inverted SCK
37// invcsb:
38// 0 = normal CSB (active low)
39// 1 = inverted CSB (active high)
40// mode:
41// 0 = read and change data on opposite SCK edges
42// 1 = read and change data on the same SCK edge
43// enable:
44// 0 = disable the SPI master
45// 1 = enable the SPI master
46// irqena:
47// 0 = disable interrupt
48// 1 = enable interrupt
Tim Edwards81153202020-10-09 19:57:04 -040049// hkconn:
50// 0 = housekeeping SPI disconnected
51// 1 = housekeeping SPI connected (when SPI master enabled)
Tim Edwards04ba17f2020-10-02 22:27:50 -040052// prescaler: count (in master clock cycles) of 1/2 SCK cycle.
53//
54// reg_dat_we:
55// 1 = data write enable
56// reg_dat_re:
57// 1 = data read enable
58// reg_cfg_*: Signaling for read/write of configuration register
59// reg_dat_*: Signaling for read/write of data register
60//
61// err_out: Indicates attempt to read/write before data ready
62// (failure to wait for reg_dat_wait to clear)
63//
64// Between "mode" and "invsck", all four standard SPI modes are supported
65//
66//--------------------------------------------------------------------
67
68module simple_spi_master_wb #(
69 parameter BASE_ADR = 32'h2100_0000,
70 parameter CONFIG = 8'h00,
71 parameter DATA = 8'h04
72) (
73 input wb_clk_i,
74 input wb_rst_i,
75 input [31:0] wb_adr_i,
76 input [31:0] wb_dat_i,
77 input [3:0] wb_sel_i,
78 input wb_we_i,
79 input wb_cyc_i,
80 input wb_stb_i,
81 output wb_ack_o,
82 output [31:0] wb_dat_o,
83
Tim Edwards81153202020-10-09 19:57:04 -040084 output hk_connect, // Connect to housekeeping SPI
Tim Edwards04ba17f2020-10-02 22:27:50 -040085 input sdi, // SPI input
86 output csb, // SPI chip select
87 output sck, // SPI clock
88 output sdo, // SPI output
Tim Edwards44bab472020-10-04 22:09:54 -040089 output sdoenb, // SPI output enable
Tim Edwards04ba17f2020-10-02 22:27:50 -040090 output irq // interrupt output
91);
92
93 wire [31:0] simple_spi_master_reg_cfg_do;
94 wire [31:0] simple_spi_master_reg_dat_do;
95
96 wire resetn = ~wb_rst_i;
97 wire valid = wb_stb_i && wb_cyc_i;
98 wire simple_spi_master_reg_cfg_sel = valid && (wb_adr_i == (BASE_ADR | CONFIG));
99 wire simple_spi_master_reg_dat_sel = valid && (wb_adr_i == (BASE_ADR | DATA));
100
101 wire [1:0] reg_cfg_we = (simple_spi_master_reg_cfg_sel) ?
102 (wb_sel_i[1:0] & {2{wb_we_i}}): 2'b00;
103 wire reg_dat_we = (simple_spi_master_reg_dat_sel) ? (wb_sel_i[0] & wb_we_i): 1'b0;
104
105 wire [31:0] mem_wdata = wb_dat_i;
106 wire reg_dat_re = simple_spi_master_reg_dat_sel && !wb_sel_i && ~wb_we_i;
107
108 assign wb_dat_o = (simple_spi_master_reg_cfg_sel) ? simple_spi_master_reg_cfg_do :
109 simple_spi_master_reg_dat_do;
110 assign wb_ack_o = (simple_spi_master_reg_cfg_sel || simple_spi_master_reg_dat_sel)
111 && (!reg_dat_wait);
112
113 simple_spi_master spi_master (
114 .resetn(resetn),
115 .clk(wb_clk_i),
116 .reg_cfg_we(reg_cfg_we),
117 .reg_cfg_di(mem_wdata),
118 .reg_cfg_do(simple_spi_master_reg_cfg_do),
119 .reg_dat_we(reg_dat_we),
120 .reg_dat_re(reg_dat_re),
121 .reg_dat_di(mem_wdata),
122 .reg_dat_do(simple_spi_master_reg_dat_do),
123 .reg_dat_wait(reg_dat_wait),
124
Tim Edwards81153202020-10-09 19:57:04 -0400125 .hk_connect(hk_connect), // Attach to housekeeping SPI slave
Tim Edwards04ba17f2020-10-02 22:27:50 -0400126 .sdi(sdi), // SPI input
127 .csb(csb), // SPI chip select
128 .sck(sck), // SPI clock
129 .sdo(sdo), // SPI output
130 .irq_out(irq) // interrupt
131 );
132endmodule
133
134module simple_spi_master (
135 input resetn,
136 input clk, // master clock (assume 100MHz)
137
138 input [1:0] reg_cfg_we,
139 input [31:0] reg_cfg_di,
140 output [31:0] reg_cfg_do,
141
142 input reg_dat_we,
143 input reg_dat_re,
144 input [31:0] reg_dat_di,
145 output [31:0] reg_dat_do,
146 output reg_dat_wait,
147 output irq_out,
148 output err_out,
149
Tim Edwards81153202020-10-09 19:57:04 -0400150 output hk_connect, // Connect to housekeeping SPI
Tim Edwards04ba17f2020-10-02 22:27:50 -0400151 input sdi, // SPI input
152 output csb, // SPI chip select
153 output sck, // SPI clock
154 output sdo // SPI output
155);
156
157 parameter IDLE = 2'b00;
158 parameter SENDL = 2'b01;
159 parameter SENDH = 2'b10;
160 parameter FINISH = 2'b11;
161
162 reg done;
163 reg isdo, hsck, icsb;
164 reg [1:0] state;
165 reg isck;
166 reg err_out;
167
168 reg [7:0] treg, rreg, d_latched;
169 reg [2:0] nbit;
170
171 reg [7:0] prescaler;
172 reg [7:0] count;
173 reg invsck;
174 reg invcsb;
175 reg mlb;
176 reg irqena;
177 reg stream;
178 reg mode;
179 reg enable;
Tim Edwards81153202020-10-09 19:57:04 -0400180 reg hkconn;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400181
182 wire csb;
183 wire irq_out;
184 wire sck;
185 wire sdo;
Tim Edwards44bab472020-10-04 22:09:54 -0400186 wire sdoenb;
Tim Edwards81153202020-10-09 19:57:04 -0400187 wire hk_connect;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400188
189 // Define behavior for inverted SCK and inverted CSB
Tim Edwards44bab472020-10-04 22:09:54 -0400190 assign csb = (enable == 1'b0) ? 1'bz : (invcsb) ? ~icsb : icsb;
191 assign sck = (enable == 1'b0) ? 1'bz : (invsck) ? ~isck : isck;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400192
193 // No bidirectional 3-pin mode defined, so SDO is enabled whenever CSB is low.
Tim Edwards44bab472020-10-04 22:09:54 -0400194 assign sdoenb = icsb;
195 // assign sdo = (enable == 1'b0) ? 1'bz : icsb ? 1'bz : isdo;
Tim Edwardsca2f3182020-10-06 10:05:11 -0400196 assign sdo = (enable == 1'b0) ? 1'bz : isdo;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400197
198 assign irq_out = irqena & done;
Tim Edwards81153202020-10-09 19:57:04 -0400199 assign hk_connect = (enable == 1'b1) ? hkconn : 1'b0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400200
201 // Read configuration and data registers
Tim Edwards81153202020-10-09 19:57:04 -0400202 assign reg_cfg_do = {16'd0, hkconn, irqena, enable, stream, mode,
203 invsck, invcsb, mlb, prescaler};
Tim Edwards04ba17f2020-10-02 22:27:50 -0400204 assign reg_dat_wait = ~done;
205 assign reg_dat_do = done ? rreg : ~0;
206
207 // Write configuration register
208 always @(posedge clk or negedge resetn) begin
209 if (resetn == 1'b0) begin
210 prescaler <= 8'd2;
211 invcsb <= 1'b0;
212 invsck <= 1'b0;
213 mlb <= 1'b0;
214 enable <= 1'b0;
215 irqena <= 1'b0;
216 stream <= 1'b0;
217 mode <= 1'b0;
Tim Edwards81153202020-10-09 19:57:04 -0400218 hkconn <= 1'b0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400219 end else begin
220 if (reg_cfg_we[0]) prescaler <= reg_cfg_di[7:0];
221 if (reg_cfg_we[1]) begin
222 mlb <= reg_cfg_di[8];
223 invcsb <= reg_cfg_di[9];
224 invsck <= reg_cfg_di[10];
225 mode <= reg_cfg_di[11];
226 stream <= reg_cfg_di[12];
227 enable <= reg_cfg_di[13];
228 irqena <= reg_cfg_di[14];
Tim Edwards81153202020-10-09 19:57:04 -0400229 hkconn <= reg_cfg_di[15];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400230 end //reg_cfg_we[1]
231 end //resetn
232 end //always
233
234 // Watch for read and write enables on clk, not hsck, so as not to
235 // miss them.
236
237 reg w_latched, r_latched;
238
239 always @(posedge clk or negedge resetn) begin
240 if (resetn == 1'b0) begin
241 err_out <= 1'b0;
242 w_latched <= 1'b0;
243 r_latched <= 1'b0;
244 d_latched <= 8'd0;
245 end else begin
246 // Clear latches on SEND, otherwise latch when seen
247 if (state == SENDL || state == SENDH) begin
248 if (reg_dat_we == 1'b0) begin
249 w_latched <= 1'b0;
250 end
251 end else begin
252 if (reg_dat_we == 1'b1) begin
253 if (done == 1'b0 && w_latched == 1'b1) begin
254 err_out <= 1'b1;
255 end else begin
256 w_latched <= 1'b1;
257 d_latched <= reg_dat_di[7:0];
258 err_out <= 1'b0;
259 end
260 end
261 end
262
263 if (reg_dat_re == 1'b1) begin
264 if (r_latched == 1'b1) begin
265 r_latched <= 1'b0;
266 end else begin
267 err_out <= 1'b1; // byte not available
268 end
269 end else if (state == FINISH) begin
270 r_latched <= 1'b1;
271 end if (state == SENDL || state == SENDH) begin
272 if (r_latched == 1'b1) begin
273 err_out <= 1'b1; // last byte was never read
274 end else begin
275 r_latched <= 1'b0;
276 end
277 end
278 end
279 end
280
281 // State transition.
282
283 always @(posedge hsck or negedge resetn) begin
284 if (resetn == 1'b0) begin
285 state <= IDLE;
286 nbit <= 3'd0;
287 icsb <= 1'b1;
288 done <= 1'b1;
289 end else begin
290 if (state == IDLE) begin
291 if (w_latched == 1'b1) begin
292 state <= SENDL;
293 nbit <= 3'd0;
294 icsb <= 1'b0;
295 done <= 1'b0;
296 end else begin
297 icsb <= ~stream;
298 end
299 end else if (state == SENDL) begin
300 state <= SENDH;
301 end else if (state == SENDH) begin
302 nbit <= nbit + 1;
303 if (nbit == 3'd7) begin
304 state <= FINISH;
305 end else begin
306 state <= SENDL;
307 end
308 end else if (state == FINISH) begin
309 icsb <= ~stream;
310 done <= 1'b1;
311 state <= IDLE;
312 end
313 end
314 end
315
316 // Set up internal clock. The enable bit gates the internal clock
317 // to shut down the master SPI when disabled.
318
319 always @(posedge clk or negedge resetn) begin
320 if (resetn == 1'b0) begin
321 count <= 8'd0;
322 hsck <= 1'b0;
323 end else begin
324 if (enable == 1'b0) begin
325 count <= 8'd0;
326 end else begin
327 count <= count + 1;
328 if (count == prescaler) begin
329 hsck <= ~hsck;
330 count <= 8'd0;
331 end // count
332 end // enable
333 end // resetn
334 end // always
335
336 // sck is half the rate of hsck
337
338 always @(posedge hsck or negedge resetn) begin
339 if (resetn == 1'b0) begin
340 isck <= 1'b0;
341 end else begin
342 if (state == IDLE || state == FINISH)
343 isck <= 1'b0;
344 else
345 isck <= ~isck;
346 end // resetn
347 end // always
348
349 // Main procedure: read, write, shift data
350
351 always @(posedge hsck or negedge resetn) begin
352 if (resetn == 1'b0) begin
353 rreg <= 8'hff;
354 treg <= 8'hff;
355 isdo <= 1'b0;
356 end else begin
357 if (isck == 1'b0 && (state == SENDL || state == SENDH)) begin
358 if (mlb == 1'b1) begin
359 // LSB first, sdi@msb -> right shift
360 rreg <= {sdi, rreg[7:1]};
361 end else begin
362 // MSB first, sdi@lsb -> left shift
363 rreg <= {rreg[6:0], sdi};
364 end
365 end // read on ~isck
366
367 if (w_latched == 1'b1) begin
368 if (mlb == 1'b1) begin
369 treg <= {1'b1, d_latched[7:1]};
370 isdo <= d_latched[0];
371 end else begin
372 treg <= {d_latched[6:0], 1'b1};
373 isdo <= d_latched[7];
374 end // mlb
375 end else if ((mode ^ isck) == 1'b1) begin
376 if (mlb == 1'b1) begin
377 // LSB first, shift right
378 treg <= {1'b1, treg[7:1]};
379 isdo <= treg[0];
380 end else begin
381 // MSB first shift LEFT
382 treg <= {treg[6:0], 1'b1};
383 isdo <= treg[7];
384 end // mlb
385 end // write on mode ^ isck
386 end // resetn
387 end // always
388
389endmodule