blob: 45769253bf78ec4865ec760198d7671e73c23d77 [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;
Tim Edwards581068f2020-11-19 12:45:25 -0500105 wire reg_dat_wait;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400106
107 wire [31:0] mem_wdata = wb_dat_i;
108 wire reg_dat_re = simple_spi_master_reg_dat_sel && !wb_sel_i && ~wb_we_i;
109
110 assign wb_dat_o = (simple_spi_master_reg_cfg_sel) ? simple_spi_master_reg_cfg_do :
111 simple_spi_master_reg_dat_do;
112 assign wb_ack_o = (simple_spi_master_reg_cfg_sel || simple_spi_master_reg_dat_sel)
113 && (!reg_dat_wait);
114
115 simple_spi_master spi_master (
116 .resetn(resetn),
117 .clk(wb_clk_i),
118 .reg_cfg_we(reg_cfg_we),
119 .reg_cfg_di(mem_wdata),
120 .reg_cfg_do(simple_spi_master_reg_cfg_do),
121 .reg_dat_we(reg_dat_we),
122 .reg_dat_re(reg_dat_re),
123 .reg_dat_di(mem_wdata),
124 .reg_dat_do(simple_spi_master_reg_dat_do),
125 .reg_dat_wait(reg_dat_wait),
126
Tim Edwards81153202020-10-09 19:57:04 -0400127 .hk_connect(hk_connect), // Attach to housekeeping SPI slave
Tim Edwards04ba17f2020-10-02 22:27:50 -0400128 .sdi(sdi), // SPI input
129 .csb(csb), // SPI chip select
130 .sck(sck), // SPI clock
131 .sdo(sdo), // SPI output
132 .irq_out(irq) // interrupt
133 );
134endmodule
135
136module simple_spi_master (
137 input resetn,
138 input clk, // master clock (assume 100MHz)
139
140 input [1:0] reg_cfg_we,
141 input [31:0] reg_cfg_di,
142 output [31:0] reg_cfg_do,
143
144 input reg_dat_we,
145 input reg_dat_re,
146 input [31:0] reg_dat_di,
147 output [31:0] reg_dat_do,
148 output reg_dat_wait,
149 output irq_out,
150 output err_out,
151
Tim Edwards81153202020-10-09 19:57:04 -0400152 output hk_connect, // Connect to housekeeping SPI
Tim Edwards04ba17f2020-10-02 22:27:50 -0400153 input sdi, // SPI input
154 output csb, // SPI chip select
155 output sck, // SPI clock
156 output sdo // SPI output
157);
158
159 parameter IDLE = 2'b00;
160 parameter SENDL = 2'b01;
161 parameter SENDH = 2'b10;
162 parameter FINISH = 2'b11;
163
164 reg done;
165 reg isdo, hsck, icsb;
166 reg [1:0] state;
167 reg isck;
168 reg err_out;
169
170 reg [7:0] treg, rreg, d_latched;
171 reg [2:0] nbit;
172
173 reg [7:0] prescaler;
174 reg [7:0] count;
175 reg invsck;
176 reg invcsb;
177 reg mlb;
178 reg irqena;
179 reg stream;
180 reg mode;
181 reg enable;
Tim Edwards81153202020-10-09 19:57:04 -0400182 reg hkconn;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400183
184 wire csb;
185 wire irq_out;
186 wire sck;
187 wire sdo;
Tim Edwards44bab472020-10-04 22:09:54 -0400188 wire sdoenb;
Tim Edwards81153202020-10-09 19:57:04 -0400189 wire hk_connect;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400190
191 // Define behavior for inverted SCK and inverted CSB
Tim Edwards44bab472020-10-04 22:09:54 -0400192 assign csb = (enable == 1'b0) ? 1'bz : (invcsb) ? ~icsb : icsb;
193 assign sck = (enable == 1'b0) ? 1'bz : (invsck) ? ~isck : isck;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400194
195 // No bidirectional 3-pin mode defined, so SDO is enabled whenever CSB is low.
Tim Edwards44bab472020-10-04 22:09:54 -0400196 assign sdoenb = icsb;
197 // assign sdo = (enable == 1'b0) ? 1'bz : icsb ? 1'bz : isdo;
Tim Edwardsca2f3182020-10-06 10:05:11 -0400198 assign sdo = (enable == 1'b0) ? 1'bz : isdo;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400199
200 assign irq_out = irqena & done;
Tim Edwards81153202020-10-09 19:57:04 -0400201 assign hk_connect = (enable == 1'b1) ? hkconn : 1'b0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400202
203 // Read configuration and data registers
Tim Edwards81153202020-10-09 19:57:04 -0400204 assign reg_cfg_do = {16'd0, hkconn, irqena, enable, stream, mode,
205 invsck, invcsb, mlb, prescaler};
Tim Edwards04ba17f2020-10-02 22:27:50 -0400206 assign reg_dat_wait = ~done;
207 assign reg_dat_do = done ? rreg : ~0;
208
209 // Write configuration register
210 always @(posedge clk or negedge resetn) begin
211 if (resetn == 1'b0) begin
212 prescaler <= 8'd2;
213 invcsb <= 1'b0;
214 invsck <= 1'b0;
215 mlb <= 1'b0;
216 enable <= 1'b0;
217 irqena <= 1'b0;
218 stream <= 1'b0;
219 mode <= 1'b0;
Tim Edwards81153202020-10-09 19:57:04 -0400220 hkconn <= 1'b0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400221 end else begin
222 if (reg_cfg_we[0]) prescaler <= reg_cfg_di[7:0];
223 if (reg_cfg_we[1]) begin
224 mlb <= reg_cfg_di[8];
225 invcsb <= reg_cfg_di[9];
226 invsck <= reg_cfg_di[10];
227 mode <= reg_cfg_di[11];
228 stream <= reg_cfg_di[12];
229 enable <= reg_cfg_di[13];
230 irqena <= reg_cfg_di[14];
Tim Edwards81153202020-10-09 19:57:04 -0400231 hkconn <= reg_cfg_di[15];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400232 end //reg_cfg_we[1]
233 end //resetn
234 end //always
235
236 // Watch for read and write enables on clk, not hsck, so as not to
237 // miss them.
238
239 reg w_latched, r_latched;
240
241 always @(posedge clk or negedge resetn) begin
242 if (resetn == 1'b0) begin
243 err_out <= 1'b0;
244 w_latched <= 1'b0;
245 r_latched <= 1'b0;
246 d_latched <= 8'd0;
247 end else begin
248 // Clear latches on SEND, otherwise latch when seen
249 if (state == SENDL || state == SENDH) begin
250 if (reg_dat_we == 1'b0) begin
251 w_latched <= 1'b0;
252 end
253 end else begin
254 if (reg_dat_we == 1'b1) begin
255 if (done == 1'b0 && w_latched == 1'b1) begin
256 err_out <= 1'b1;
257 end else begin
258 w_latched <= 1'b1;
259 d_latched <= reg_dat_di[7:0];
260 err_out <= 1'b0;
261 end
262 end
263 end
264
265 if (reg_dat_re == 1'b1) begin
266 if (r_latched == 1'b1) begin
267 r_latched <= 1'b0;
268 end else begin
269 err_out <= 1'b1; // byte not available
270 end
271 end else if (state == FINISH) begin
272 r_latched <= 1'b1;
273 end if (state == SENDL || state == SENDH) begin
274 if (r_latched == 1'b1) begin
275 err_out <= 1'b1; // last byte was never read
276 end else begin
277 r_latched <= 1'b0;
278 end
279 end
280 end
281 end
282
283 // State transition.
284
285 always @(posedge hsck or negedge resetn) begin
286 if (resetn == 1'b0) begin
287 state <= IDLE;
288 nbit <= 3'd0;
289 icsb <= 1'b1;
290 done <= 1'b1;
291 end else begin
292 if (state == IDLE) begin
293 if (w_latched == 1'b1) begin
294 state <= SENDL;
295 nbit <= 3'd0;
296 icsb <= 1'b0;
297 done <= 1'b0;
298 end else begin
299 icsb <= ~stream;
300 end
301 end else if (state == SENDL) begin
302 state <= SENDH;
303 end else if (state == SENDH) begin
304 nbit <= nbit + 1;
305 if (nbit == 3'd7) begin
306 state <= FINISH;
307 end else begin
308 state <= SENDL;
309 end
310 end else if (state == FINISH) begin
311 icsb <= ~stream;
312 done <= 1'b1;
313 state <= IDLE;
314 end
315 end
316 end
317
318 // Set up internal clock. The enable bit gates the internal clock
319 // to shut down the master SPI when disabled.
320
321 always @(posedge clk or negedge resetn) begin
322 if (resetn == 1'b0) begin
323 count <= 8'd0;
324 hsck <= 1'b0;
325 end else begin
326 if (enable == 1'b0) begin
327 count <= 8'd0;
328 end else begin
329 count <= count + 1;
330 if (count == prescaler) begin
331 hsck <= ~hsck;
332 count <= 8'd0;
333 end // count
334 end // enable
335 end // resetn
336 end // always
337
338 // sck is half the rate of hsck
339
340 always @(posedge hsck or negedge resetn) begin
341 if (resetn == 1'b0) begin
342 isck <= 1'b0;
343 end else begin
344 if (state == IDLE || state == FINISH)
345 isck <= 1'b0;
346 else
347 isck <= ~isck;
348 end // resetn
349 end // always
350
351 // Main procedure: read, write, shift data
352
353 always @(posedge hsck or negedge resetn) begin
354 if (resetn == 1'b0) begin
355 rreg <= 8'hff;
356 treg <= 8'hff;
357 isdo <= 1'b0;
358 end else begin
359 if (isck == 1'b0 && (state == SENDL || state == SENDH)) begin
360 if (mlb == 1'b1) begin
361 // LSB first, sdi@msb -> right shift
362 rreg <= {sdi, rreg[7:1]};
363 end else begin
364 // MSB first, sdi@lsb -> left shift
365 rreg <= {rreg[6:0], sdi};
366 end
367 end // read on ~isck
368
369 if (w_latched == 1'b1) begin
370 if (mlb == 1'b1) begin
371 treg <= {1'b1, d_latched[7:1]};
372 isdo <= d_latched[0];
373 end else begin
374 treg <= {d_latched[6:0], 1'b1};
375 isdo <= d_latched[7];
376 end // mlb
377 end else if ((mode ^ isck) == 1'b1) begin
378 if (mlb == 1'b1) begin
379 // LSB first, shift right
380 treg <= {1'b1, treg[7:1]};
381 isdo <= treg[0];
382 end else begin
383 // MSB first shift LEFT
384 treg <= {treg[6:0], 1'b1};
385 isdo <= treg[7];
386 end // mlb
387 end // write on mode ^ isck
388 end // resetn
389 end // always
390
391endmodule
Tim Edwards581068f2020-11-19 12:45:25 -0500392`default_nettype wire