diff --git a/picosoc/README.md b/picosoc/README.md index e70f87c..5d7e2d3 100644 --- a/picosoc/README.md +++ b/picosoc/README.md @@ -27,3 +27,32 @@ and upload them to a connected iCE40-HX8K Breakout Board. | [hx8kdemo.v](hx8kdemo.v) | FPGA-based example implementation on iCE40-HX8K Breakout Board | | [hx8kdemo.pcf](hx8kdemo.pcf) | Pin constraints for implementation on iCE40-HX8K Breakout Board | +### Memory map: + +| Address Range | Description | +| ------------------------ | --------------------------------------- | +| 0x00000000 .. 0x00FFFFFF | Internal SRAM | +| 0x01000000 .. 0x01FFFFFF | External Serial Flash | +| 0x02000000 .. 0x02000003 | SPI Flash Controller Config Register | +| 0x03000000 .. 0x00FFFFFF | Memory mapped user peripherals | + +The example design (hx8kdemo.v) and generic test bench (testbench.v) have 32 +GPIO pins mapped to the 32 bit word at address 0x03000000. + +### SPI Flash Controller Config Register: + +| Bit(s) | Description | +| -----: | --------------------------------------------------------- | +| 31 | MEMIO Enable (reset=1, set to 0 to bit bang SPI commands) | +| 30:20 | Reserved (read 0) | +| 19:16 | IO Output enable bits in bit bang mode | +| 15:14 | Reserved (read 0) | +| 13 | Chip select (CS) line in bit bang mode | +| 12 | Serial clock line in bit bang mode | +| 11:8 | IO data bits in bit bang mode | +| 7 | Reserved (read 0) | +| 6 | DDR Enable bit (reset=0) | +| 5 | QSPI Enable bit (reset=0) | +| 4 | Continous Read Enable bit (reset=0) | +| 3:0 | Number of QSPI dummy cycles (reset=0) | + diff --git a/picosoc/firmware.s b/picosoc/firmware.s index 1b8900f..d7cb3f9 100644 --- a/picosoc/firmware.s +++ b/picosoc/firmware.s @@ -52,7 +52,7 @@ li x5,0x00008067 # ret sw x5,196(x0) # setup gpio address in x5 -li x5,0x02000000 +li x5,0x03000000 sw x0,0(x5) # initial entry point into RAM code diff --git a/picosoc/hx8kdemo.v b/picosoc/hx8kdemo.v index db4d9a8..a3ae35b 100644 --- a/picosoc/hx8kdemo.v +++ b/picosoc/hx8kdemo.v @@ -72,7 +72,7 @@ module hx8kdemo ( gpio_shr <= 0; end else begin iomem_ready <= 0; - if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 02) begin + if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 03) begin iomem_ready <= 1; iomem_rdata <= gpio; if (iomem_wstrb[0]) gpio[ 7: 0] <= iomem_wdata[ 7: 0]; diff --git a/picosoc/picosoc.v b/picosoc/picosoc.v index 23260c9..da9b9a9 100644 --- a/picosoc/picosoc.v +++ b/picosoc/picosoc.v @@ -69,8 +69,12 @@ module picosoc ( assign iomem_addr = mem_addr; assign iomem_wdata = mem_wdata; - assign mem_ready = (iomem_valid && iomem_ready) || spimem_ready || ram_ready; - assign mem_rdata = (iomem_valid && iomem_ready) ? iomem_rdata : spimem_ready ? spimem_rdata : ram_ready ? ram_rdata : 32'h xxxx_xxxx; + wire spimemio_cfgreg_sel = (mem_addr == 32'h 0200_0000); + wire [31:0] spimemio_cfgreg_do; + + assign mem_ready = (iomem_valid && iomem_ready) || spimem_ready || ram_ready || spimemio_cfgreg_sel; + assign mem_rdata = (iomem_valid && iomem_ready) ? iomem_rdata : spimem_ready ? spimem_rdata : ram_ready ? ram_rdata : + spimemio_cfgreg_sel ? spimemio_cfgreg_do : 32'h xxxx_xxxx; picorv32 #( .STACKADDR(STACKADDR), @@ -111,7 +115,11 @@ module picosoc ( .flash_io0_di (flash_io0_di), .flash_io1_di (flash_io1_di), .flash_io2_di (flash_io2_di), - .flash_io3_di (flash_io3_di) + .flash_io3_di (flash_io3_di), + + .cfgreg_we(spimemio_cfgreg_sel ? mem_wstrb : 4'b 0000), + .cfgreg_di(mem_wdata), + .cfgreg_do(spimemio_cfgreg_do) ); reg [31:0] memory [0:MEM_WORDS-1]; diff --git a/picosoc/spimemio.v b/picosoc/spimemio.v index 91bbb2f..c7d8cb6 100644 --- a/picosoc/spimemio.v +++ b/picosoc/spimemio.v @@ -41,12 +41,17 @@ module spimemio ( input flash_io0_di, input flash_io1_di, input flash_io2_di, - input flash_io3_di + input flash_io3_di, + + input [3:0] cfgreg_we, + input [31:0] cfgreg_di, + output [31:0] cfgreg_do ); reg xfer_resetn; reg din_valid; wire din_ready; reg [7:0] din_data; + reg [3:0] din_tag; reg din_cont; reg din_qspi; reg din_ddr; @@ -54,9 +59,9 @@ module spimemio ( wire dout_valid; wire [7:0] dout_data; + wire [3:0] dout_tag; reg [23:0] buffer; - reg [3:0] buffer_wen; reg [23:0] rd_addr; reg rd_valid; @@ -66,10 +71,84 @@ 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; + reg softreset; + + reg config_en; // cfgreg[31] + reg [3:0] config_oe; // cfgreg[19:16] + reg config_csb; // cfgreg[13] + reg config_clk; // cfgref[12] + reg [3:0] config_do; // cfgreg[11:8] + reg config_ddr; // cfgreg[6] + reg config_qspi; // cfgreg[5] + reg config_cont; // cfgreg[4] + reg [3:0] config_dummy; // cfgreg[3:0] + + assign cfgreg_do[31] = config_en; + assign cfgreg_do[30:20] = 0; + assign cfgreg_do[19:16] = {flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}; + assign cfgreg_do[15:14] = 0; + assign cfgreg_do[13] = flash_csb; + assign cfgreg_do[12] = flash_clk; + assign cfgreg_do[11:8] = {flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; + assign cfgreg_do[7] = 0; + assign cfgreg_do[6] = config_ddr; + assign cfgreg_do[5] = config_qspi; + assign cfgreg_do[4] = config_cont; + assign cfgreg_do[3:0] = config_dummy; + + always @(posedge clk) begin + softreset <= !config_en || cfgreg_we; + if (!resetn) begin + softreset <= 1; + config_en <= 1; + config_csb <= 0; + config_clk <= 0; + config_oe <= 0; + config_do <= 0; + config_ddr <= 0; + config_qspi <= 0; + config_cont <= 0; + config_dummy <= 0; + end else begin + if (cfgreg_we[0]) begin + config_ddr <= cfgreg_di[6]; + config_qspi <= cfgreg_di[5]; + config_cont <= cfgreg_di[4]; + config_dummy <= cfgreg_di[3:0]; + end + if (cfgreg_we[1]) begin + config_csb <= cfgreg_di[13]; + config_clk <= cfgreg_di[12]; + config_do <= cfgreg_di[11:8]; + end + if (cfgreg_we[2]) begin + config_oe <= cfgreg_di[19:16]; + end + if (cfgreg_we[3]) begin + config_en <= cfgreg_di[31]; + end + end + end + + wire xfer_io0_oe; + wire xfer_io1_oe; + wire xfer_io2_oe; + wire xfer_io3_oe; + + wire xfer_io0_do; + wire xfer_io1_do; + wire xfer_io2_do; + wire xfer_io3_do; + + assign flash_io0_oe = config_en ? xfer_io0_oe : config_oe[0]; + assign flash_io1_oe = config_en ? xfer_io1_oe : config_oe[1]; + assign flash_io2_oe = config_en ? xfer_io2_oe : config_oe[2]; + assign flash_io3_oe = config_en ? xfer_io3_oe : config_oe[3]; + + assign flash_io0_do = config_en ? xfer_io0_do : config_do[0]; + assign flash_io1_do = config_en ? xfer_io1_do : config_do[1]; + assign flash_io2_do = config_en ? xfer_io2_do : config_do[2]; + assign flash_io3_do = config_en ? xfer_io3_do : config_do[3]; spimemio_xfer xfer ( .clk (clk ), @@ -77,22 +156,24 @@ module spimemio ( .din_valid (din_valid ), .din_ready (din_ready ), .din_data (din_data ), + .din_tag (din_tag ), .din_cont (din_cont ), .din_qspi (din_qspi ), .din_ddr (din_ddr ), .din_rd (din_rd ), .dout_valid (dout_valid ), .dout_data (dout_data ), + .dout_tag (dout_tag ), .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_oe (xfer_io0_oe), + .flash_io1_oe (xfer_io1_oe), + .flash_io2_oe (xfer_io2_oe), + .flash_io3_oe (xfer_io3_oe), + .flash_io0_do (xfer_io0_do), + .flash_io1_do (xfer_io1_do), + .flash_io2_do (xfer_io2_do), + .flash_io3_do (xfer_io3_do), .flash_io0_di (flash_io0_di), .flash_io1_di (flash_io1_di), .flash_io2_di (flash_io2_di), @@ -105,20 +186,20 @@ module spimemio ( xfer_resetn <= 1; din_valid <= 0; - if (!resetn) begin + if (!resetn || softreset) begin state <= 0; xfer_resetn <= 0; rd_valid <= 0; - buffer_wen <= 0; + din_tag <= 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 + if (dout_valid && dout_tag == 1) buffer[ 7: 0] <= dout_data; + if (dout_valid && dout_tag == 2) buffer[15: 8] <= dout_data; + if (dout_valid && dout_tag == 3) buffer[23:16] <= dout_data; + if (dout_valid && dout_tag == 4) begin rdata <= {dout_data, buffer}; rd_addr <= rd_inc ? rd_addr + 4 : addr; rd_valid <= 1; @@ -126,10 +207,6 @@ module spimemio ( rd_inc <= 1; end - if (dout_valid && buffer_wen) begin - buffer_wen <= 0; - end - if (valid) rd_wait <= 0; @@ -137,6 +214,7 @@ module spimemio ( 0: begin din_valid <= 1; din_data <= 8'h ff; + din_tag <= 0; if (din_ready) begin din_valid <= 0; state <= 1; @@ -151,6 +229,7 @@ module spimemio ( 2: begin din_valid <= 1; din_data <= 8'h ab; + din_tag <= 0; if (din_ready) begin din_valid <= 0; state <= 3; @@ -165,6 +244,7 @@ module spimemio ( 4: begin rd_inc <= 0; din_valid <= 1; + din_tag <= 0; case ({config_ddr, config_qspi}) 2'b11: din_data <= 8'h ED; 2'b01: din_data <= 8'h EB; @@ -178,6 +258,7 @@ module spimemio ( 5: begin if (valid && !ready) begin din_valid <= 1; + din_tag <= 0; din_data <= addr[23:16]; din_qspi <= config_qspi; din_ddr <= config_ddr; @@ -189,6 +270,7 @@ module spimemio ( end 6: begin din_valid <= 1; + din_tag <= 0; din_data <= addr[15:8]; if (din_ready) begin din_valid <= 0; @@ -197,6 +279,7 @@ module spimemio ( end 7: begin din_valid <= 1; + din_tag <= 0; din_data <= addr[7:0]; if (din_ready) begin din_valid <= 0; @@ -206,6 +289,7 @@ module spimemio ( end 8: begin din_valid <= 1; + din_tag <= 0; din_data <= config_cont ? 8'h A5 : 8'h FF; if (din_ready) begin din_rd <= 1; @@ -216,8 +300,8 @@ module spimemio ( end 9: begin din_valid <= 1; + din_tag <= 1; if (din_ready) begin - buffer_wen <= 4'b 0001; din_valid <= 0; state <= 10; end @@ -225,16 +309,16 @@ module spimemio ( 10: begin din_valid <= 1; din_data <= 8'h 00; + din_tag <= 2; if (din_ready) begin - buffer_wen <= 4'b 0010; din_valid <= 0; state <= 11; end end 11: begin din_valid <= 1; + din_tag <= 3; if (din_ready) begin - buffer_wen <= 4'b 0100; din_valid <= 0; state <= 12; end @@ -242,8 +326,8 @@ module spimemio ( 12: begin if (!rd_wait || valid) begin din_valid <= 1; + din_tag <= 4; if (din_ready) begin - buffer_wen <= 4'b 1000; din_valid <= 0; state <= 9; end @@ -255,7 +339,6 @@ module spimemio ( rd_inc <= 0; rd_valid <= 0; xfer_resetn <= 0; - buffer_wen <= 0; if (config_cont) begin state <= 5; end else begin @@ -275,6 +358,7 @@ module spimemio_xfer ( input din_valid, output din_ready, input [7:0] din_data, + input [3:0] din_tag, input din_cont, input din_qspi, input din_ddr, @@ -282,6 +366,7 @@ module spimemio_xfer ( output dout_valid, output [7:0] dout_data, + output [3:0] dout_tag, output reg flash_csb, output reg flash_clk, @@ -310,7 +395,10 @@ module spimemio_xfer ( reg xfer_cont; reg xfer_qspi; reg xfer_ddr; + reg xfer_ddr_q; reg xfer_rd; + reg [3:0] xfer_tag; + reg [3:0] xfer_tag_q; reg [7:0] next_obuffer; reg [7:0] next_ibuffer; @@ -320,10 +408,16 @@ module spimemio_xfer ( reg next_fetch; reg last_fetch; + always @(posedge clk) begin + xfer_ddr_q <= xfer_ddr; + xfer_tag_q <= xfer_tag; + end + assign din_ready = din_valid && resetn && next_fetch; - assign dout_valid = xfer_ddr ? fetch && !last_fetch : next_fetch && !fetch; + assign dout_valid = xfer_ddr_q ? fetch && !last_fetch : next_fetch && !fetch; assign dout_data = ibuffer; + assign dout_tag = xfer_tag_q; always @* begin flash_io0_oe = 0; @@ -405,6 +499,7 @@ module spimemio_xfer ( flash_clk <= 0; count <= 0; dummy_count <= 0; + xfer_tag <= 0; xfer_cont <= 0; xfer_qspi <= 0; xfer_ddr <= 0; @@ -426,12 +521,11 @@ module spimemio_xfer ( flash_csb <= 0; flash_clk <= 0; - obuffer <= din_data; - // ibuffer <= 8'h 00; - count <= 8; dummy_count <= din_rd ? din_data : 0; + obuffer <= din_data; + xfer_tag <= din_tag; xfer_cont <= din_cont; xfer_qspi <= din_qspi; xfer_ddr <= din_ddr; diff --git a/picosoc/testbench.v b/picosoc/testbench.v index 6b1cae2..af5b121 100644 --- a/picosoc/testbench.v +++ b/picosoc/testbench.v @@ -78,7 +78,7 @@ module testbench; always @(posedge clk) begin iomem_ready <= 0; - if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 02) begin + if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 03) begin iomem_ready <= 1; iomem_rdata <= gpio; if (iomem_wstrb[0]) gpio[ 7: 0] <= iomem_wdata[ 7: 0];