blob: d4a82d9d95768e0a68fa41577280e1f090add068 [file] [log] [blame]
Matt Venn08cd6eb2020-11-16 12:01:14 +01001`default_nettype none
Tim Edwardscd64af52020-08-07 11:11:58 -04002/*
3 * PicoSoC - A simple example SoC using PicoRV32
4 *
5 * Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21`timescale 1 ns / 1 ps
22
23//
24// Simple SPI flash simulation model
25//
26// This model samples io input signals 1ns before the SPI clock edge and
27// updates output signals 1ns after the SPI clock edge.
28//
29// Supported commands:
30// AB, B9, FF, 03, BB, EB, ED
31//
32// Well written SPI flash data sheets:
33// Cypress S25FL064L http://www.cypress.com/file/316661/download
34// Cypress S25FL128L http://www.cypress.com/file/316171/download
35//
36
37module spiflash #(
38 parameter FILENAME = "firmware.hex"
39)(
40 input csb,
41 input clk,
42 inout io0, // MOSI
43 inout io1, // MISO
44 inout io2,
45 inout io3
46);
47 localparam verbose = 0;
48 localparam integer latency = 8;
49
50 reg [7:0] buffer;
51 integer bitcount = 0;
52 integer bytecount = 0;
53 integer dummycount = 0;
54
55 reg [7:0] spi_cmd;
56 reg [7:0] xip_cmd = 0;
57 reg [23:0] spi_addr;
58
59 reg [7:0] spi_in;
60 reg [7:0] spi_out;
61 reg spi_io_vld;
62
63 reg powered_up = 0;
64
65 localparam [3:0] mode_spi = 1;
66 localparam [3:0] mode_dspi_rd = 2;
67 localparam [3:0] mode_dspi_wr = 3;
68 localparam [3:0] mode_qspi_rd = 4;
69 localparam [3:0] mode_qspi_wr = 5;
70 localparam [3:0] mode_qspi_ddr_rd = 6;
71 localparam [3:0] mode_qspi_ddr_wr = 7;
72
73 reg [3:0] mode = 0;
74 reg [3:0] next_mode = 0;
75
76 reg io0_oe = 0;
77 reg io1_oe = 0;
78 reg io2_oe = 0;
79 reg io3_oe = 0;
80
81 reg io0_dout = 0;
82 reg io1_dout = 0;
83 reg io2_dout = 0;
84 reg io3_dout = 0;
85
86 assign #1 io0 = io0_oe ? io0_dout : 1'bz;
87 assign #1 io1 = io1_oe ? io1_dout : 1'bz;
88 assign #1 io2 = io2_oe ? io2_dout : 1'bz;
89 assign #1 io3 = io3_oe ? io3_dout : 1'bz;
90
91 wire io0_delayed;
92 wire io1_delayed;
93 wire io2_delayed;
94 wire io3_delayed;
95
96 assign #1 io0_delayed = io0;
97 assign #1 io1_delayed = io1;
98 assign #1 io2_delayed = io2;
99 assign #1 io3_delayed = io3;
100
101 // 16 MB (128Mb) Flash
102 reg [7:0] memory [0:16*1024*1024-1];
103
104 initial begin
105 $display("Memory 5 bytes = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
106 memory[1048576], memory[1048577], memory[1048578],
107 memory[1048579], memory[1048580]);
108 $display("Reading %s", FILENAME);
109 $readmemh(FILENAME, memory);
110 $display("%s loaded into memory", FILENAME);
111 $display("Memory 5 bytes = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
112 memory[1048576], memory[1048577], memory[1048578],
113 memory[1048579], memory[1048580]);
114 end
115
116 task spi_action;
117 begin
118 spi_in = buffer;
119
120 if (bytecount == 1) begin
121 spi_cmd = buffer;
122
123 if (spi_cmd == 8'h ab)
124 powered_up = 1;
125
126 if (spi_cmd == 8'h b9)
127 powered_up = 0;
128
129 if (spi_cmd == 8'h ff)
130 xip_cmd = 0;
131 end
132
133 if (powered_up && spi_cmd == 'h 03) begin
134 if (bytecount == 2)
135 spi_addr[23:16] = buffer;
136
137 if (bytecount == 3)
138 spi_addr[15:8] = buffer;
139
140 if (bytecount == 4)
141 spi_addr[7:0] = buffer;
142
143 if (bytecount >= 4) begin
144 buffer = memory[spi_addr];
145 spi_addr = spi_addr + 1;
146 end
147 end
148
149 if (powered_up && spi_cmd == 'h bb) begin
150 if (bytecount == 1)
151 mode = mode_dspi_rd;
152
153 if (bytecount == 2)
154 spi_addr[23:16] = buffer;
155
156 if (bytecount == 3)
157 spi_addr[15:8] = buffer;
158
159 if (bytecount == 4)
160 spi_addr[7:0] = buffer;
161
162 if (bytecount == 5) begin
163 xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
164 mode = mode_dspi_wr;
165 dummycount = latency;
166 end
167
168 if (bytecount >= 5) begin
169 buffer = memory[spi_addr];
170 spi_addr = spi_addr + 1;
171 end
172 end
173
174 if (powered_up && spi_cmd == 'h eb) begin
175 if (bytecount == 1)
176 mode = mode_qspi_rd;
177
178 if (bytecount == 2)
179 spi_addr[23:16] = buffer;
180
181 if (bytecount == 3)
182 spi_addr[15:8] = buffer;
183
184 if (bytecount == 4)
185 spi_addr[7:0] = buffer;
186
187 if (bytecount == 5) begin
188 xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
189 mode = mode_qspi_wr;
190 dummycount = latency;
191 end
192
193 if (bytecount >= 5) begin
194 buffer = memory[spi_addr];
195 spi_addr = spi_addr + 1;
196 end
197 end
198
199 if (powered_up && spi_cmd == 'h ed) begin
200 if (bytecount == 1)
201 next_mode = mode_qspi_ddr_rd;
202
203 if (bytecount == 2)
204 spi_addr[23:16] = buffer;
205
206 if (bytecount == 3)
207 spi_addr[15:8] = buffer;
208
209 if (bytecount == 4)
210 spi_addr[7:0] = buffer;
211
212 if (bytecount == 5) begin
213 xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
214 mode = mode_qspi_ddr_wr;
215 dummycount = latency;
216 end
217
218 if (bytecount >= 5) begin
219 buffer = memory[spi_addr];
220 spi_addr = spi_addr + 1;
221 end
222 end
223
224 spi_out = buffer;
225 spi_io_vld = 1;
226
227 if (verbose) begin
228 if (bytecount == 1)
229 $write("<SPI-START>");
230 $write("<SPI:%02x:%02x>", spi_in, spi_out);
231 end
232
233 end
234 endtask
235
236 task ddr_rd_edge;
237 begin
238 buffer = {buffer, io3_delayed, io2_delayed, io1_delayed, io0_delayed};
239 bitcount = bitcount + 4;
240 if (bitcount == 8) begin
241 bitcount = 0;
242 bytecount = bytecount + 1;
243 spi_action;
244 end
245 end
246 endtask
247
248 task ddr_wr_edge;
249 begin
250 io0_oe = 1;
251 io1_oe = 1;
252 io2_oe = 1;
253 io3_oe = 1;
254
255 io0_dout = buffer[4];
256 io1_dout = buffer[5];
257 io2_dout = buffer[6];
258 io3_dout = buffer[7];
259
260 buffer = {buffer, 4'h 0};
261 bitcount = bitcount + 4;
262 if (bitcount == 8) begin
263 bitcount = 0;
264 bytecount = bytecount + 1;
265 spi_action;
266 end
267 end
268 endtask
269
270 always @(csb) begin
271 if (csb) begin
272 if (verbose) begin
273 $display("");
274 $fflush;
275 end
276 buffer = 0;
277 bitcount = 0;
278 bytecount = 0;
279 mode = mode_spi;
280 io0_oe = 0;
281 io1_oe = 0;
282 io2_oe = 0;
283 io3_oe = 0;
284 end else
285 if (xip_cmd) begin
286 buffer = xip_cmd;
287 bitcount = 0;
288 bytecount = 1;
289 spi_action;
290 end
291 end
292
293 always @(csb, clk) begin
294 spi_io_vld = 0;
295 if (!csb && !clk) begin
296 if (dummycount > 0) begin
297 io0_oe = 0;
298 io1_oe = 0;
299 io2_oe = 0;
300 io3_oe = 0;
301 end else
302 case (mode)
303 mode_spi: begin
304 io0_oe = 0;
305 io1_oe = 1;
306 io2_oe = 0;
307 io3_oe = 0;
308 io1_dout = buffer[7];
309 end
310 mode_dspi_rd: begin
311 io0_oe = 0;
312 io1_oe = 0;
313 io2_oe = 0;
314 io3_oe = 0;
315 end
316 mode_dspi_wr: begin
317 io0_oe = 1;
318 io1_oe = 1;
319 io2_oe = 0;
320 io3_oe = 0;
321 io0_dout = buffer[6];
322 io1_dout = buffer[7];
323 end
324 mode_qspi_rd: begin
325 io0_oe = 0;
326 io1_oe = 0;
327 io2_oe = 0;
328 io3_oe = 0;
329 end
330 mode_qspi_wr: begin
331 io0_oe = 1;
332 io1_oe = 1;
333 io2_oe = 1;
334 io3_oe = 1;
335 io0_dout = buffer[4];
336 io1_dout = buffer[5];
337 io2_dout = buffer[6];
338 io3_dout = buffer[7];
339 end
340 mode_qspi_ddr_rd: begin
341 ddr_rd_edge;
342 end
343 mode_qspi_ddr_wr: begin
344 ddr_wr_edge;
345 end
346 endcase
347 if (next_mode) begin
348 case (next_mode)
349 mode_qspi_ddr_rd: begin
350 io0_oe = 0;
351 io1_oe = 0;
352 io2_oe = 0;
353 io3_oe = 0;
354 end
355 mode_qspi_ddr_wr: begin
356 io0_oe = 1;
357 io1_oe = 1;
358 io2_oe = 1;
359 io3_oe = 1;
360 io0_dout = buffer[4];
361 io1_dout = buffer[5];
362 io2_dout = buffer[6];
363 io3_dout = buffer[7];
364 end
365 endcase
366 mode = next_mode;
367 next_mode = 0;
368 end
369 end
370 end
371
372 always @(posedge clk) begin
373 if (!csb) begin
374 if (dummycount > 0) begin
375 dummycount = dummycount - 1;
376 end else
377 case (mode)
378 mode_spi: begin
379 buffer = {buffer, io0};
380 bitcount = bitcount + 1;
381 if (bitcount == 8) begin
382 bitcount = 0;
383 bytecount = bytecount + 1;
384 spi_action;
385 end
386 end
387 mode_dspi_rd, mode_dspi_wr: begin
388 buffer = {buffer, io1, io0};
389 bitcount = bitcount + 2;
390 if (bitcount == 8) begin
391 bitcount = 0;
392 bytecount = bytecount + 1;
393 spi_action;
394 end
395 end
396 mode_qspi_rd, mode_qspi_wr: begin
397 buffer = {buffer, io3, io2, io1, io0};
398 bitcount = bitcount + 4;
399 if (bitcount == 8) begin
400 bitcount = 0;
401 bytecount = bytecount + 1;
402 spi_action;
403 end
404 end
405 mode_qspi_ddr_rd: begin
406 ddr_rd_edge;
407 end
408 mode_qspi_ddr_wr: begin
409 ddr_wr_edge;
410 end
411 endcase
412 end
413 end
414endmodule