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