aboutsummaryrefslogtreecommitdiffstats
path: root/picosoc/spimemio.v
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2017-08-07 22:36:58 +0200
committerClifford Wolf <clifford@clifford.at>2017-08-07 22:36:58 +0200
commit8821696748afe0dab113c845910be9db9d772438 (patch)
treeba7b55cefc5386a911c9b75a994bf29b9e3f431a /picosoc/spimemio.v
parentff7855900d4f4b8d3ccd840e54f5d9c940c4f7e4 (diff)
downloadpicorv32-8821696748afe0dab113c845910be9db9d772438.tar.gz
picorv32-8821696748afe0dab113c845910be9db9d772438.zip
Major rewrite of picosoc spimemio core
Diffstat (limited to 'picosoc/spimemio.v')
-rw-r--r--picosoc/spimemio.v369
1 files changed, 292 insertions, 77 deletions
diff --git a/picosoc/spimemio.v b/picosoc/spimemio.v
index 57347cc..93227cb 100644
--- a/picosoc/spimemio.v
+++ b/picosoc/spimemio.v
@@ -21,10 +21,225 @@ module spimemio (
input clk, resetn,
input valid,
- output reg ready,
+ output ready,
input [23:0] addr,
output reg [31:0] rdata,
+ output flash_csb,
+ output flash_clk,
+
+ output flash_io0_oe,
+ output flash_io1_oe,
+ output flash_io2_oe,
+ output flash_io3_oe,
+
+ output flash_io0_do,
+ output flash_io1_do,
+ output flash_io2_do,
+ output flash_io3_do,
+
+ input flash_io0_di,
+ input flash_io1_di,
+ input flash_io2_di,
+ input flash_io3_di
+);
+ reg xfer_resetn;
+ reg din_valid;
+ wire din_ready;
+ reg [7:0] din_data;
+ reg din_cont;
+ reg din_qspi;
+ reg din_ddr;
+ reg din_rd;
+
+ wire dout_valid;
+ wire [7:0] dout_data;
+
+ reg [23:0] buffer;
+ reg [3:0] buffer_wen;
+
+ reg [23:0] rd_addr;
+ reg rd_valid;
+ reg rd_wait;
+ reg rd_inc;
+
+ assign ready = valid && (addr == rd_addr) && rd_valid;
+ wire jump = valid && !ready && (addr != rd_addr+4) && rd_valid;
+
+ spimemio_xfer xfer (
+ .clk (clk ),
+ .resetn (xfer_resetn ),
+ .din_valid (din_valid ),
+ .din_ready (din_ready ),
+ .din_data (din_data ),
+ .din_cont (din_cont ),
+ .din_qspi (din_qspi ),
+ .din_ddr (din_ddr ),
+ .din_rd (din_rd ),
+ .dout_valid (dout_valid ),
+ .dout_data (dout_data ),
+ .flash_csb (flash_csb ),
+ .flash_clk (flash_clk ),
+ .flash_io0_oe (flash_io0_oe),
+ .flash_io1_oe (flash_io1_oe),
+ .flash_io2_oe (flash_io2_oe),
+ .flash_io3_oe (flash_io3_oe),
+ .flash_io0_do (flash_io0_do),
+ .flash_io1_do (flash_io1_do),
+ .flash_io2_do (flash_io2_do),
+ .flash_io3_do (flash_io3_do),
+ .flash_io0_di (flash_io0_di),
+ .flash_io1_di (flash_io1_di),
+ .flash_io2_di (flash_io2_di),
+ .flash_io3_di (flash_io3_di)
+ );
+
+ reg [3:0] state;
+
+ always @(posedge clk) begin
+ xfer_resetn <= 1;
+ din_valid <= 0;
+ din_data <= 8'h 00;
+
+ if (!resetn) begin
+ state <= 0;
+ xfer_resetn <= 0;
+ rd_valid <= 0;
+ din_cont <= 0;
+ din_qspi <= 0;
+ din_ddr <= 0;
+ din_rd <= 0;
+ end else begin
+ if (dout_valid && buffer_wen[0]) buffer[ 7: 0] <= dout_data;
+ if (dout_valid && buffer_wen[1]) buffer[15: 8] <= dout_data;
+ if (dout_valid && buffer_wen[2]) buffer[23:16] <= dout_data;
+ if (dout_valid && buffer_wen[3]) begin
+ rdata <= {dout_data, buffer};
+ rd_addr <= rd_inc ? rd_addr + 4 : addr;
+ rd_valid <= 1;
+ rd_wait <= rd_inc;
+ rd_inc <= 1;
+ end
+
+ if (dout_valid && buffer_wen) begin
+ buffer_wen <= 0;
+ end
+
+ if (valid)
+ rd_wait <= 0;
+
+ case (state)
+ 0: begin
+ din_valid <= 1;
+ din_data <= 8'h ff;
+ if (din_ready)
+ state <= 1;
+ end
+ 1: begin
+ if (dout_valid) begin
+ xfer_resetn <= 0;
+ state <= 2;
+ end
+ end
+ 2: begin
+ din_valid <= 1;
+ din_data <= 8'h ab;
+ if (din_ready)
+ state <= 3;
+ end
+ 3: begin
+ if (dout_valid) begin
+ xfer_resetn <= 0;
+ state <= 4;
+ end
+ end
+ 4: begin
+ rd_inc <= 0;
+ din_valid <= 1;
+ din_data <= 8'h 03;
+ if (din_ready)
+ state <= 5;
+ end
+ 5: begin
+ if (valid && !ready) begin
+ din_valid <= 1;
+ din_data <= addr[23:16];
+ if (din_ready)
+ state <= 6;
+ end
+ end
+ 6: begin
+ din_valid <= 1;
+ din_data <= addr[15:8];
+ if (din_ready)
+ state <= 7;
+ end
+ 7: begin
+ din_valid <= 1;
+ din_data <= addr[7:0];
+ if (din_ready)
+ state <= 8;
+ end
+ 8: begin
+ din_valid <= 1;
+ din_data <= 8'h 00;
+ if (din_ready) begin
+ buffer_wen <= 4'b 0001;
+ state <= 9;
+ end
+ end
+ 9: begin
+ din_valid <= 1;
+ din_data <= 8'h 00;
+ if (din_ready) begin
+ buffer_wen <= 4'b 0010;
+ state <= 10;
+ end
+ end
+ 10: begin
+ din_valid <= 1;
+ din_data <= 8'h 00;
+ if (din_ready) begin
+ buffer_wen <= 4'b 0100;
+ state <= 11;
+ end
+ end
+ 11: 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;
+ end
+ end
+ end
+ endcase
+
+ if (jump) begin
+ rd_inc <= 0;
+ rd_valid <= 0;
+ xfer_resetn <= 0;
+ state <= 4;
+ end
+ end
+ end
+endmodule
+
+module spimemio_xfer (
+ input clk, resetn,
+
+ input din_valid,
+ output din_ready,
+ input [7:0] din_data,
+ input din_cont,
+ input din_qspi,
+ input din_ddr,
+ input din_rd,
+
+ output dout_valid,
+ output [7:0] dout_data,
+
output reg flash_csb,
output reg flash_clk,
@@ -43,91 +258,91 @@ module spimemio (
input flash_io2_di,
input flash_io3_di
);
- parameter ENABLE_PREFETCH = 1;
+ localparam [3:0] mode_spi = 0;
+ reg [3:0] mode;
- reg [23:0] addr_q;
- reg addr_q_vld;
+ reg [7:0] obuffer;
+ reg [7:0] ibuffer;
- reg [31:0] buffer;
- reg [6:0] xfer_cnt;
- reg pulse_csb_8;
- reg xfer_wait;
- reg prefetch;
+ reg [3:0] count;
+ reg xfer_cont;
+ reg xfer_qspi;
+ reg xfer_ddr;
+ reg xfer_rd;
- always @(posedge clk) begin
- ready <= 0;
- if (!resetn) begin
- addr_q_vld <= 0;
- xfer_wait <= 0;
- prefetch <= 0;
+ reg [7:0] next_obuffer;
+ reg [7:0] next_ibuffer;
+ reg [3:0] next_count;
+
+ reg fetch_next;
+ reg last_fetch_next;
+
+ assign din_ready = din_valid && resetn && fetch_next;
+
+ assign dout_valid = fetch_next && !last_fetch_next;
+ assign dout_data = ibuffer;
+
+ always @* begin
+ flash_io0_oe = 0;
+ flash_io1_oe = 0;
+ flash_io2_oe = 0;
+ flash_io3_oe = 0;
+
+ flash_io0_do = 0;
+ flash_io1_do = 0;
+ flash_io2_do = 0;
+ flash_io3_do = 0;
+
+ next_obuffer = obuffer;
+ next_ibuffer = ibuffer;
+ next_count = count;
+ fetch_next = 0;
- xfer_cnt <= 16;
- pulse_csb_8 <= 1;
- buffer <= {8'h FF, 8'h AB, 16'h 0000};
+ case (mode)
+ mode_spi: 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};
+ end
+
+ fetch_next = (next_count == 0);
+ end
+ endcase
+ end
+
+ always @(posedge clk) begin
+ if (!resetn) begin
+ mode <= mode_spi;
+ last_fetch_next <= 1;
flash_csb <= 1;
- flash_clk <= 1;
-
- flash_io0_oe <= 0;
- flash_io1_oe <= 0;
- flash_io2_oe <= 0;
- flash_io3_oe <= 0;
-
- flash_io0_do <= 0;
- flash_io1_do <= 0;
- flash_io2_do <= 0;
- flash_io3_do <= 0;
- end else
- if (xfer_cnt) begin
- if (xfer_cnt == 8 && pulse_csb_8) begin
- pulse_csb_8 <= 0;
- flash_csb <= 1;
- end else
- if (flash_csb) begin
+ flash_clk <= 0;
+ count <= 0;
+ end else begin
+ last_fetch_next <= fetch_next;
+ if (count) begin
+ flash_clk <= !flash_clk && !flash_csb;
+ obuffer <= next_obuffer;
+ ibuffer <= next_ibuffer;
+ count <= next_count;
+ end
+ if (din_valid && din_ready) begin
flash_csb <= 0;
- end else
- if (flash_clk) begin
flash_clk <= 0;
- flash_io0_oe <= 1;
- flash_io0_do <= buffer[31];
- end else begin
- flash_clk <= 1;
- buffer <= {buffer, flash_io1_di};
- xfer_cnt <= xfer_cnt - 1;
- end
- end else
- if (xfer_wait) begin
- ready <= 1;
- rdata <= {buffer[7:0], buffer[15:8], buffer[23:16], buffer[31:24]};
- xfer_wait <= 0;
- end else
- if (valid && !ready) begin
- if (addr_q_vld && addr_q == addr) begin
- addr_q <= addr + 4;
- addr_q_vld <= 1;
- if (!prefetch)
- xfer_cnt <= 32;
- xfer_wait <= 1;
- prefetch <= 0;
- end else begin
- flash_csb <= 1;
- buffer <= {8'h 03, addr};
- addr_q <= addr + 4;
- addr_q_vld <= 1;
- xfer_cnt <= 64;
- xfer_wait <= 1;
- prefetch <= 0;
- end
- end else if (ENABLE_PREFETCH && !prefetch) begin
- prefetch <= 1;
- xfer_cnt <= 32;
- end
- if (ENABLE_PREFETCH && resetn && prefetch && valid && !ready && addr_q != addr) begin
- prefetch <= 0;
- xfer_cnt <= 0;
- xfer_wait <= 0;
- flash_clk <= 1;
+ obuffer <= din_data;
+ ibuffer <= 8'h 00;
+ count <= 8;
+
+ xfer_cont <= din_cont;
+ xfer_qspi <= din_qspi;
+ xfer_ddr <= din_ddr;
+ xfer_rd <= din_rd;
+ end
end
end
endmodule