From 53b175d0fb036e114ce28c38831d7756afb834f5 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 11 Aug 2017 15:02:31 +0200 Subject: [PATCH] Add spimemio QSPI support --- picosoc/spimemio.v | 174 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 133 insertions(+), 41 deletions(-) diff --git a/picosoc/spimemio.v b/picosoc/spimemio.v index 1535aea..91bbb2f 100644 --- a/picosoc/spimemio.v +++ b/picosoc/spimemio.v @@ -66,6 +66,11 @@ module spimemio ( assign ready = valid && (addr == rd_addr) && rd_valid; wire jump = valid && !ready && (addr != rd_addr+4) && rd_valid; + reg config_ddr = 0; + reg config_qspi = 0; + reg config_cont = 0; + reg [3:0] config_dummy = 1; + spimemio_xfer xfer ( .clk (clk ), .resetn (xfer_resetn ), @@ -99,7 +104,6 @@ module spimemio ( always @(posedge clk) begin xfer_resetn <= 1; din_valid <= 0; - din_data <= 8'h 00; if (!resetn) begin state <= 0; @@ -133,8 +137,10 @@ module spimemio ( 0: begin din_valid <= 1; din_data <= 8'h ff; - if (din_ready) + if (din_ready) begin + din_valid <= 0; state <= 1; + end end 1: begin if (dout_valid) begin @@ -145,8 +151,10 @@ module spimemio ( 2: begin din_valid <= 1; din_data <= 8'h ab; - if (din_ready) + if (din_ready) begin + din_valid <= 0; state <= 3; + end end 3: begin if (dout_valid) begin @@ -157,43 +165,60 @@ module spimemio ( 4: begin rd_inc <= 0; din_valid <= 1; - din_data <= 8'h 03; - if (din_ready) + case ({config_ddr, config_qspi}) + 2'b11: din_data <= 8'h ED; + 2'b01: din_data <= 8'h EB; + 2'b00: din_data <= 8'h 03; + endcase + if (din_ready) begin + din_valid <= 0; state <= 5; + end end 5: begin if (valid && !ready) begin din_valid <= 1; din_data <= addr[23:16]; - if (din_ready) + din_qspi <= config_qspi; + din_ddr <= config_ddr; + if (din_ready) begin + din_valid <= 0; state <= 6; + end end end 6: begin din_valid <= 1; din_data <= addr[15:8]; - if (din_ready) + if (din_ready) begin + din_valid <= 0; state <= 7; + end end 7: begin din_valid <= 1; din_data <= addr[7:0]; - if (din_ready) - state <= 8; + if (din_ready) begin + din_valid <= 0; + din_data <= 0; + state <= config_qspi ? 8 : 9; + end end 8: begin din_valid <= 1; - din_data <= 8'h 00; + din_data <= config_cont ? 8'h A5 : 8'h FF; if (din_ready) begin - buffer_wen <= 4'b 0001; + din_rd <= 1; + din_data <= config_dummy; + din_valid <= 0; state <= 9; end end 9: begin din_valid <= 1; - din_data <= 8'h 00; if (din_ready) begin - buffer_wen <= 4'b 0010; + buffer_wen <= 4'b 0001; + din_valid <= 0; state <= 10; end end @@ -201,17 +226,26 @@ module spimemio ( din_valid <= 1; din_data <= 8'h 00; if (din_ready) begin - buffer_wen <= 4'b 0100; + buffer_wen <= 4'b 0010; + din_valid <= 0; state <= 11; end end 11: begin + din_valid <= 1; + if (din_ready) begin + buffer_wen <= 4'b 0100; + din_valid <= 0; + state <= 12; + end + end + 12: begin if (!rd_wait || valid) begin din_valid <= 1; - din_data <= 8'h 00; if (din_ready) begin buffer_wen <= 4'b 1000; - state <= 8; + din_valid <= 0; + state <= 9; end end end @@ -222,7 +256,14 @@ module spimemio ( rd_valid <= 0; xfer_resetn <= 0; buffer_wen <= 0; - state <= 4; + if (config_cont) begin + state <= 5; + end else begin + state <= 4; + din_qspi <= 0; + din_ddr <= 0; + end + din_rd <= 0; end end end @@ -260,13 +301,12 @@ module spimemio_xfer ( input flash_io2_di, input flash_io3_di ); - localparam [3:0] mode_spi = 0; - reg [3:0] mode; - reg [7:0] obuffer; reg [7:0] ibuffer; reg [3:0] count; + reg [3:0] dummy_count; + reg xfer_cont; reg xfer_qspi; reg xfer_ddr; @@ -276,12 +316,13 @@ module spimemio_xfer ( reg [7:0] next_ibuffer; reg [3:0] next_count; - reg fetch_next; - reg last_fetch_next; + reg fetch; + reg next_fetch; + reg last_fetch; - assign din_ready = din_valid && resetn && fetch_next; + assign din_ready = din_valid && resetn && next_fetch; - assign dout_valid = fetch_next && !last_fetch_next; + assign dout_valid = xfer_ddr ? fetch && !last_fetch : next_fetch && !fetch; assign dout_data = ibuffer; always @* begin @@ -298,34 +339,83 @@ module spimemio_xfer ( next_obuffer = obuffer; next_ibuffer = ibuffer; next_count = count; - fetch_next = 0; + next_fetch = 0; - case (mode) - mode_spi: begin - flash_io0_oe = 1; - flash_io0_do = obuffer[7]; + if (dummy_count == 0) begin + case ({xfer_ddr, xfer_qspi}) + 2'b 00: begin + flash_io0_oe = 1; + flash_io0_do = obuffer[7]; - if (flash_clk) begin - next_obuffer = {obuffer[6:0], 1'b 0}; - next_count = count - |count; - end else begin - next_ibuffer = {ibuffer[6:0], flash_io1_di}; + if (flash_clk) begin + next_obuffer = {obuffer[6:0], 1'b 0}; + next_count = count - |count; + end else begin + next_ibuffer = {ibuffer[6:0], flash_io1_di}; + end + + next_fetch = (next_count == 0); end + 2'b 01: begin + flash_io0_oe = !xfer_rd; + flash_io1_oe = !xfer_rd; + flash_io2_oe = !xfer_rd; + flash_io3_oe = !xfer_rd; - fetch_next = (next_count == 0); - end - endcase + flash_io0_do = obuffer[4]; + flash_io1_do = obuffer[5]; + flash_io2_do = obuffer[6]; + flash_io3_do = obuffer[7]; + + if (flash_clk) begin + next_obuffer = {obuffer[3:0], 4'b 0000}; + next_count = count - {|count, 2'b00}; + end else begin + next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; + end + + next_fetch = (next_count == 0); + end + 2'b 11: begin + flash_io0_oe = !xfer_rd; + flash_io1_oe = !xfer_rd; + flash_io2_oe = !xfer_rd; + flash_io3_oe = !xfer_rd; + + flash_io0_do = obuffer[4]; + flash_io1_do = obuffer[5]; + flash_io2_do = obuffer[6]; + flash_io3_do = obuffer[7]; + + next_obuffer = {obuffer[3:0], 4'b 0000}; + 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 + endcase + end end always @(posedge clk) begin if (!resetn) begin - mode <= mode_spi; - last_fetch_next <= 1; + fetch <= 1; + last_fetch <= 1; flash_csb <= 1; flash_clk <= 0; count <= 0; + dummy_count <= 0; + xfer_cont <= 0; + xfer_qspi <= 0; + xfer_ddr <= 0; + xfer_rd <= 0; end else begin - last_fetch_next <= fetch_next; + fetch <= next_fetch; + last_fetch <= xfer_ddr ? fetch : 1; + if (dummy_count) begin + flash_clk <= !flash_clk && !flash_csb; + dummy_count <= dummy_count - flash_clk; + end else if (count) begin flash_clk <= !flash_clk && !flash_csb; obuffer <= next_obuffer; @@ -337,8 +427,10 @@ module spimemio_xfer ( flash_clk <= 0; obuffer <= din_data; - ibuffer <= 8'h 00; + // ibuffer <= 8'h 00; + count <= 8; + dummy_count <= din_rd ? din_data : 0; xfer_cont <= din_cont; xfer_qspi <= din_qspi;