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