From c06ba38113b98b4996aed6d523667444a5d83bf6 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Sep 2017 15:50:50 +0200 Subject: [PATCH] Add PicoSoC spimem Dual I/O support --- picosoc/README.md | 22 +++++++++-------- picosoc/spiflash.v | 60 ++++++++++++++++++++++++++++++++++++++++++---- picosoc/spimemio.v | 37 +++++++++++++++++++++++----- 3 files changed, 98 insertions(+), 21 deletions(-) diff --git a/picosoc/README.md b/picosoc/README.md index c112835..aec6142 100644 --- a/picosoc/README.md +++ b/picosoc/README.md @@ -55,8 +55,8 @@ GPIO pins mapped to the 32 bit word at address 0x03000000. | 30:23 | Reserved (read 0) | | 22 | DDR Enable bit (reset=0) | | 21 | QSPI Enable bit (reset=0) | -| 20 | XIP Enable bit (reset=0) | -| 19:16 | Number of QSPI dummy cycles (reset=0) | +| 20 | CRM Enable bit (reset=0) | +| 19:16 | Read latency (dummy) cycles (reset=0) | | 15:12 | Reserved (read 0) | | 11:8 | IO Output enable bits in bit bang mode | | 7:6 | Reserved (read 0) | @@ -64,13 +64,15 @@ GPIO pins mapped to the 32 bit word at address 0x03000000. | 4 | Serial clock line in bit bang mode | | 3:0 | IO data bits in bit bang mode | -The following settings for XIP/DDR/QSPI modes are valid: +The following settings for CRM/DDR/QSPI modes are valid: -| XIP | DDR | QSPI | Read Command Byte | Mode Byte | -| :-: | :-: | :--: | :-------------------- | :-------: | -| 0 | 0 | 0 | 03h Read | N/A | -| 0 | 0 | 1 | EBh Quad I/O Read | FFh | -| 1 | 0 | 1 | EBh Quad I/O Read | A5h / FFh | -| 0 | 1 | 1 | EDh DDR Quad I/O Read | FFh | -| 1 | 1 | 1 | EDh DDR Quad I/O Read | A5h / FFh | +| CRM | QSPI | DDR | Read Command Byte | Mode Byte | +| :-: | :--: | :-: | :-------------------- | :-------: | +| 0 | 0 | 0 | 03h Read | N/A | +| 0 | 0 | 1 | BBh Dual I/O Read | FFh | +| 1 | 0 | 1 | BBh Dual I/O Read | A5h | +| 0 | 1 | 0 | EBh Quad I/O Read | FFh | +| 1 | 1 | 0 | EBh Quad I/O Read | A5h | +| 0 | 1 | 1 | EDh DDR Quad I/O Read | FFh | +| 1 | 1 | 1 | EDh DDR Quad I/O Read | A5h | diff --git a/picosoc/spiflash.v b/picosoc/spiflash.v index 18cd68d..63d21dc 100644 --- a/picosoc/spiflash.v +++ b/picosoc/spiflash.v @@ -26,7 +26,7 @@ // updates output signals 1ns after the SPI clock edge. // // Supported commands: -// AB, B9, FF, 03, EB, ED +// AB, B9, FF, 03, BB, EB, ED // // Well written SPI flash data sheets: // Cypress S25FL064L http://www.cypress.com/file/316661/download @@ -60,10 +60,12 @@ module spiflash ( 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; + localparam [3:0] mode_dspi_rd = 2; + localparam [3:0] mode_dspi_wr = 3; + localparam [3:0] mode_qspi_rd = 4; + localparam [3:0] mode_qspi_wr = 5; + localparam [3:0] mode_qspi_ddr_rd = 6; + localparam [3:0] mode_qspi_ddr_wr = 7; reg [3:0] mode = 0; reg [3:0] next_mode = 0; @@ -133,6 +135,31 @@ module spiflash ( end end + if (powered_up && spi_cmd == 'h bb) begin + if (bytecount == 1) + mode = mode_dspi_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_dspi_wr; + dummycount = latency; + end + + if (bytecount >= 5) 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; @@ -269,6 +296,20 @@ module spiflash ( io3_oe = 0; io1_dout = buffer[7]; end + mode_dspi_rd: begin + io0_oe = 0; + io1_oe = 0; + io2_oe = 0; + io3_oe = 0; + end + mode_dspi_wr: begin + io0_oe = 1; + io1_oe = 1; + io2_oe = 0; + io3_oe = 0; + io0_dout = buffer[6]; + io1_dout = buffer[7]; + end mode_qspi_rd: begin io0_oe = 0; io1_oe = 0; @@ -332,6 +373,15 @@ module spiflash ( spi_action; end end + mode_dspi_rd, mode_dspi_wr: begin + buffer = {buffer, io1, io0}; + bitcount = bitcount + 2; + 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; diff --git a/picosoc/spimemio.v b/picosoc/spimemio.v index 311edcd..0bbf532 100644 --- a/picosoc/spimemio.v +++ b/picosoc/spimemio.v @@ -168,6 +168,9 @@ module spimemio ( assign flash_io2_do = config_en ? (config_ddr ? xfer_io2_90 : xfer_io2_do) : config_do[2]; assign flash_io3_do = config_en ? (config_ddr ? xfer_io3_90 : xfer_io3_do) : config_do[3]; + wire xfer_dspi = din_ddr && !din_qspi; + wire xfer_ddr = din_ddr && din_qspi; + spimemio_xfer xfer ( .clk (clk ), .resetn (xfer_resetn ), @@ -176,8 +179,9 @@ module spimemio ( .din_data (din_data ), .din_tag (din_tag ), .din_cont (din_cont ), + .din_dspi (xfer_dspi ), .din_qspi (din_qspi ), - .din_ddr (din_ddr ), + .din_ddr (xfer_ddr ), .din_rd (din_rd ), .dout_valid (dout_valid ), .dout_data (dout_data ), @@ -266,6 +270,7 @@ module spimemio ( case ({config_ddr, config_qspi}) 2'b11: din_data <= 8'h ED; 2'b01: din_data <= 8'h EB; + 2'b10: din_data <= 8'h BB; 2'b00: din_data <= 8'h 03; endcase if (din_ready) begin @@ -302,7 +307,7 @@ module spimemio ( if (din_ready) begin din_valid <= 0; din_data <= 0; - state <= config_qspi ? 8 : 9; + state <= config_qspi || config_ddr ? 8 : 9; end end 8: begin @@ -378,6 +383,7 @@ module spimemio_xfer ( input [7:0] din_data, input [3:0] din_tag, input din_cont, + input din_dspi, input din_qspi, input din_ddr, input din_rd, @@ -411,6 +417,7 @@ module spimemio_xfer ( reg [3:0] dummy_count; reg xfer_cont; + reg xfer_dspi; reg xfer_qspi; reg xfer_ddr; reg xfer_ddr_q; @@ -454,8 +461,8 @@ module spimemio_xfer ( next_fetch = 0; if (dummy_count == 0) begin - case ({xfer_ddr, xfer_qspi}) - 2'b 00: begin + casez ({xfer_ddr, xfer_qspi, xfer_dspi}) + 3'b 000: begin flash_io0_oe = 1; flash_io0_do = obuffer[7]; @@ -468,7 +475,7 @@ module spimemio_xfer ( next_fetch = (next_count == 0); end - 2'b 01: begin + 3'b 01?: begin flash_io0_oe = !xfer_rd; flash_io1_oe = !xfer_rd; flash_io2_oe = !xfer_rd; @@ -488,7 +495,7 @@ module spimemio_xfer ( next_fetch = (next_count == 0); end - 2'b 11: begin + 3'b 11?: begin flash_io0_oe = !xfer_rd; flash_io1_oe = !xfer_rd; flash_io2_oe = !xfer_rd; @@ -503,6 +510,22 @@ module spimemio_xfer ( next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; next_count = count - {|count, 2'b00}; + next_fetch = (next_count == 0); + end + 3'b ??1: begin + flash_io0_oe = !xfer_rd; + flash_io1_oe = !xfer_rd; + + flash_io0_do = obuffer[6]; + flash_io1_do = obuffer[7]; + + if (flash_clk) begin + next_obuffer = {obuffer[5:0], 2'b 00}; + next_count = count - {|count, 1'b0}; + end else begin + next_ibuffer = {ibuffer[5:0], flash_io1_di, flash_io0_di}; + end + next_fetch = (next_count == 0); end endcase @@ -519,6 +542,7 @@ module spimemio_xfer ( dummy_count <= 0; xfer_tag <= 0; xfer_cont <= 0; + xfer_dspi <= 0; xfer_qspi <= 0; xfer_ddr <= 0; xfer_rd <= 0; @@ -545,6 +569,7 @@ module spimemio_xfer ( xfer_tag <= din_tag; xfer_cont <= din_cont; + xfer_dspi <= din_dspi; xfer_qspi <= din_qspi; xfer_ddr <= din_ddr; xfer_rd <= din_rd;