aboutsummaryrefslogtreecommitdiffstats
path: root/picosoc/spiflash.v
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2017-08-07 13:38:07 +0200
committerClifford Wolf <clifford@clifford.at>2017-08-07 13:38:07 +0200
commitcaef4e3753d2c76de5d7030fcc2e3a1c331c64c6 (patch)
tree57162c7dd5d90c5b18e0ecd3380d9fd67f6771ff /picosoc/spiflash.v
parent571f5d5df742b3168d1e8c26e8ef0b8247960666 (diff)
downloadpicorv32-caef4e3753d2c76de5d7030fcc2e3a1c331c64c6.tar.gz
picorv32-caef4e3753d2c76de5d7030fcc2e3a1c331c64c6.zip
Rename "spiflash" example to "picosoc"
Diffstat (limited to 'picosoc/spiflash.v')
-rw-r--r--picosoc/spiflash.v344
1 files changed, 344 insertions, 0 deletions
diff --git a/picosoc/spiflash.v b/picosoc/spiflash.v
new file mode 100644
index 0000000..c1e9615
--- /dev/null
+++ b/picosoc/spiflash.v
@@ -0,0 +1,344 @@
+/*
+ * PicoSoC - A simple example SoC using PicoRV32
+ *
+ * Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *
+ * Supported commands:
+ * AB, B9, FF, 03, EB, ED
+ *
+ * Well written SPI flash data sheets:
+ * Cypress S25FL064L http://www.cypress.com/file/316661/download
+ *
+ */
+
+module spiflash (
+ input csb,
+ input clk,
+ inout io0, // MOSI
+ inout io1, // MISO
+ inout io2,
+ inout io3
+);
+ localparam verbose = 0;
+
+ reg [7:0] buffer;
+ integer bitcount = 0;
+ integer bytecount = 0;
+ integer dummycount = 0;
+
+ reg [7:0] spi_cmd;
+ reg [7:0] xip_cmd = 0;
+ reg [23:0] spi_addr;
+
+ reg [7:0] spi_in;
+ reg [7:0] spi_out;
+ reg spi_io_vld;
+
+ reg qspi_active = 0;
+ reg powered_up = 0;
+
+ localparam [3:0] mode_spi = 1;
+ localparam [3:0] mode_qspi_rd = 2;
+ localparam [3:0] mode_qspi_wr = 3;
+ localparam [3:0] mode_qspi_ddr_rd = 4;
+ localparam [3:0] mode_qspi_ddr_wr = 5;
+
+ reg [3:0] mode = 0;
+ reg [3:0] next_mode = 0;
+
+ reg io0_oe = 0;
+ reg io1_oe = 0;
+ reg io2_oe = 0;
+ reg io3_oe = 0;
+
+ reg io0_dout = 0;
+ reg io1_dout = 0;
+ reg io2_dout = 0;
+ reg io3_dout = 0;
+
+ assign io0 = io0_oe ? io0_dout : 1'bz;
+ assign io1 = io1_oe ? io1_dout : 1'bz;
+ assign io2 = io2_oe ? io2_dout : 1'bz;
+ assign io3 = io3_oe ? io3_dout : 1'bz;
+
+ wire io0_delayed;
+ wire io1_delayed;
+ wire io2_delayed;
+ wire io3_delayed;
+
+ assign #1 io0_delayed = io0;
+ assign #1 io1_delayed = io1;
+ assign #1 io2_delayed = io2;
+ assign #1 io3_delayed = io3;
+
+ // 16 MB (128Mb) Flash
+ reg [7:0] memory [0:16*1024*1024-1];
+
+ initial begin
+ $readmemh("firmware.hex", memory);
+ end
+
+ task spi_action;
+ begin
+ spi_in = buffer;
+
+ if (bytecount == 1) begin
+ spi_cmd = buffer;
+
+ if (spi_cmd == 8'h ab)
+ powered_up = 1;
+
+ if (spi_cmd == 8'h b9)
+ powered_up = 0;
+
+ if (spi_cmd == 8'h ff)
+ qspi_active = 0;
+ end
+
+ if (powered_up && spi_cmd == 'h 03) begin
+ if (bytecount == 2)
+ spi_addr[23:16] = buffer;
+
+ if (bytecount == 3)
+ spi_addr[15:8] = buffer;
+
+ if (bytecount == 4)
+ spi_addr[7:0] = buffer;
+
+ if (bytecount >= 4) begin
+ buffer = memory[spi_addr];
+ spi_addr = spi_addr + 1;
+ end
+ end
+
+ if (powered_up && spi_cmd == 'h eb) begin
+ if (bytecount == 1)
+ mode = mode_qspi_rd;
+
+ if (bytecount == 2)
+ spi_addr[23:16] = buffer;
+
+ if (bytecount == 3)
+ spi_addr[15:8] = buffer;
+
+ if (bytecount == 4)
+ spi_addr[7:0] = buffer;
+
+ if (bytecount == 5) begin
+ xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
+ mode = mode_qspi_wr;
+ dummycount = 1;
+ end
+
+ if (bytecount >= 5) begin
+ buffer = memory[spi_addr];
+ spi_addr = spi_addr + 1;
+ end
+ end
+
+ if (powered_up && spi_cmd == 'h ed) begin
+ if (bytecount == 1)
+ next_mode = mode_qspi_ddr_rd;
+
+ if (bytecount == 2)
+ spi_addr[23:16] = buffer;
+
+ if (bytecount == 3)
+ spi_addr[15:8] = buffer;
+
+ if (bytecount == 4)
+ spi_addr[7:0] = buffer;
+
+ if (bytecount == 5) begin
+ xip_cmd = (buffer == 8'h a5) ? spi_cmd : 8'h 00;
+ mode = mode_qspi_ddr_wr;
+ dummycount = 1;
+ end
+
+ if (bytecount >= 5) begin
+ buffer = memory[spi_addr];
+ spi_addr = spi_addr + 1;
+ end
+ end
+
+ spi_out = buffer;
+ spi_io_vld = 1;
+
+ if (verbose) begin
+ if (bytecount == 1)
+ $write("<SPI-START>");
+ $write("<SPI:%02x:%02x>", spi_in, spi_out);
+ end
+
+ end
+ endtask
+
+ task ddr_rd_edge;
+ begin
+ buffer = {buffer, io3_delayed, io2_delayed, io1_delayed, io0_delayed};
+ bitcount = bitcount + 4;
+ if (bitcount == 8) begin
+ bitcount = 0;
+ bytecount = bytecount + 1;
+ spi_action;
+ end
+ end
+ endtask
+
+ task ddr_wr_edge;
+ begin
+ io0_oe = 1;
+ io1_oe = 1;
+ io2_oe = 1;
+ io3_oe = 1;
+
+ io0_dout = buffer[4];
+ io1_dout = buffer[5];
+ io2_dout = buffer[6];
+ io3_dout = buffer[7];
+
+ buffer = {buffer, 4'h 0};
+ bitcount = bitcount + 4;
+ if (bitcount == 8) begin
+ bitcount = 0;
+ bytecount = bytecount + 1;
+ spi_action;
+ end
+ end
+ endtask
+
+ always @(csb) begin
+ if (csb) begin
+ if (verbose) begin
+ $display("");
+ $fflush;
+ end
+ buffer = 0;
+ bitcount = 0;
+ bytecount = 0;
+ mode = mode_spi;
+ io0_oe = 0;
+ io1_oe = 0;
+ io2_oe = 0;
+ io3_oe = 0;
+ end else
+ if (xip_cmd) begin
+ buffer = xip_cmd;
+ bitcount = 0;
+ bytecount = 1;
+ spi_action;
+ end
+ end
+
+ always @(csb, clk) begin
+ spi_io_vld = 0;
+ if (!csb && !clk) begin
+ if (dummycount > 0) begin
+ io0_oe = 0;
+ io1_oe = 0;
+ io2_oe = 0;
+ io3_oe = 0;
+ end else
+ case (mode)
+ mode_spi: begin
+ io0_oe = 0;
+ io1_oe = 1;
+ io2_oe = 0;
+ io3_oe = 0;
+ io1_dout = buffer[7];
+ end
+ mode_qspi_rd: begin
+ io0_oe = 0;
+ io1_oe = 0;
+ io2_oe = 0;
+ io3_oe = 0;
+ end
+ mode_qspi_wr: begin
+ io0_oe = 1;
+ io1_oe = 1;
+ io2_oe = 1;
+ io3_oe = 1;
+ io0_dout = buffer[4];
+ io1_dout = buffer[5];
+ io2_dout = buffer[6];
+ io3_dout = buffer[7];
+ end
+ mode_qspi_ddr_rd: begin
+ ddr_rd_edge;
+ end
+ mode_qspi_ddr_wr: begin
+ ddr_wr_edge;
+ end
+ endcase
+ if (next_mode) begin
+ case (next_mode)
+ mode_qspi_ddr_rd: begin
+ io0_oe = 0;
+ io1_oe = 0;
+ io2_oe = 0;
+ io3_oe = 0;
+ end
+ mode_qspi_ddr_wr: begin
+ io0_oe = 1;
+ io1_oe = 1;
+ io2_oe = 1;
+ io3_oe = 1;
+ io0_dout = buffer[4];
+ io1_dout = buffer[5];
+ io2_dout = buffer[6];
+ io3_dout = buffer[7];
+ end
+ endcase
+ mode = next_mode;
+ next_mode = 0;
+ end
+ end
+ end
+
+ always @(posedge clk) begin
+ if (!csb) begin
+ if (dummycount > 0) begin
+ dummycount = dummycount - 1;
+ end else
+ case (mode)
+ mode_spi: begin
+ buffer = {buffer, io0};
+ bitcount = bitcount + 1;
+ if (bitcount == 8) begin
+ bitcount = 0;
+ bytecount = bytecount + 1;
+ spi_action;
+ end
+ end
+ mode_qspi_rd, mode_qspi_wr: begin
+ buffer = {buffer, io3, io2, io1, io0};
+ bitcount = bitcount + 4;
+ if (bitcount == 8) begin
+ bitcount = 0;
+ bytecount = bytecount + 1;
+ spi_action;
+ end
+ end
+ mode_qspi_ddr_rd: begin
+ ddr_rd_edge;
+ end
+ mode_qspi_ddr_wr: begin
+ ddr_wr_edge;
+ end
+ endcase
+ end
+ end
+endmodule