diff --git a/src/iosys/iosys.v b/src/iosys/iosys.v index 2e63a3e..5888e56 100644 --- a/src/iosys/iosys.v +++ b/src/iosys/iosys.v @@ -99,20 +99,12 @@ reg flash_start; wire [7:0] flash_dout; wire flash_out_strb; assign flash_spi_hold_n = 1; -assign flash_spi_wp_n = 0; +assign flash_spi_wp_n = 1; // disable write protection reg [7:0] flash_d; reg [3:0] flash_wstrb; reg flash_wr; - -// Load 256KB of ROM from flash address 0x500000 into SDRAM at address 0x0 -spiflash #(.ADDR(24'h500000), .LEN(FIRMWARE_SIZE)) flash ( - .clk(clk), .resetn(resetn), - .ncs(flash_spi_cs_n), .miso(flash_spi_miso), .mosi(flash_spi_mosi), - .sck(flash_spi_clk), - - .start(flash_start), .dout(flash_dout), .dout_strb(flash_out_strb), - .busy() -); +wire [31:0] spiflash_reg_do; +wire spiflash_reg_wait; always @(posedge clk) begin if (~resetn) begin @@ -183,21 +175,30 @@ wire romload_reg_data_sel /* synthesis syn_keep=1 */ = mem_valid && (mem_ wire joystick_reg_sel = mem_valid && (mem_addr == 32'h 0200_0040); wire time_reg_sel = mem_valid && (mem_addr == 32'h0200_0050); // milli-seconds since start-up (overflows in 49 days) +wire cycle_reg_sel = mem_valid && (mem_addr == 32'h0200_0054); // cycles counter (overflows every 200 seconds) wire id_reg_sel = mem_valid && (mem_addr == 32'h0200_0060); +wire spiflash_reg_byte_sel = mem_valid && (mem_addr == 32'h0200_0070); +wire spiflash_reg_word_sel = mem_valid && (mem_addr == 32'h0200_0074); +wire spiflash_reg_ctrl_sel = mem_valid && (mem_addr == 32'h0200_0078); + assign mem_ready = ram_ready || textdisp_reg_char_sel || simpleuart_reg_div_sel || - romload_reg_ctrl_sel || romload_reg_data_sel || joystick_reg_sel || time_reg_sel || id_reg_sel || + romload_reg_ctrl_sel || romload_reg_data_sel || joystick_reg_sel || time_reg_sel || cycle_reg_sel || id_reg_sel || (simpleuart_reg_dat_sel && !simpleuart_reg_dat_wait) || - ((simplespimaster_reg_byte_sel || simplespimaster_reg_word_sel) && !simplespimaster_reg_wait); + ((simplespimaster_reg_byte_sel || simplespimaster_reg_word_sel) && !simplespimaster_reg_wait) || + (spiflash_reg_byte_sel || spiflash_reg_word_sel) && !spiflash_reg_wait || + spiflash_reg_ctrl_sel; assign mem_rdata = ram_ready ? ram_rdata : joystick_reg_sel ? {4'b0, joy2, 4'b0, joy1} : simpleuart_reg_div_sel ? simpleuart_reg_div_do : simpleuart_reg_dat_sel ? simpleuart_reg_dat_do : time_reg_sel ? time_reg : + cycle_reg_sel ? cycle_reg : id_reg_sel ? {16'b0, CORE_ID} : (simplespimaster_reg_byte_sel | simplespimaster_reg_word_sel) ? simplespimaster_reg_do : + (spiflash_reg_byte_sel | spiflash_reg_word_sel) ? spiflash_reg_do : 32'h 0000_0000; picorv32 #( @@ -240,7 +241,7 @@ always @(posedge clk) begin end end -// uart @ 0x0200_0004 & 0x200_0008 +// uart @ 0x0200_0010 simpleuart simpleuart ( .clk (clk ), .resetn (resetn ), @@ -259,7 +260,7 @@ simpleuart simpleuart ( .reg_dat_wait(simpleuart_reg_dat_wait) ); -// spi sd card @ 0x0200_000c +// spi sd card @ 0x0200_0020 assign sd_dat1 = 1; assign sd_dat2 = 1; assign sd_dat3 = 0; @@ -293,7 +294,6 @@ always @(posedge clk) begin rom_do_valid <= 1; end end - always @(posedge clk) begin if (romload_reg_ctrl_sel && mem_wstrb) begin // control register @@ -304,6 +304,21 @@ always @(posedge clk) begin end end +// SPI flash @ 0x02000_0070 +// Load 256KB of ROM from flash address 0x500000 into SDRAM at address 0x0 +spiflash #(.ADDR(24'h500000), .LEN(FIRMWARE_SIZE)) flash ( + .clk(clk), .resetn(resetn), + .ncs(flash_spi_cs_n), .miso(flash_spi_miso), .mosi(flash_spi_mosi), + .sck(flash_spi_clk), + + .start(flash_start), .dout(flash_dout), .dout_strb(flash_out_strb), .busy(), + + .reg_byte_we(spiflash_reg_byte_sel ? mem_wstrb[0] : 1'b0), + .reg_word_we(spiflash_reg_word_sel ? mem_wstrb[0] : 1'b0), + .reg_ctrl_we(spiflash_reg_ctrl_sel ? mem_wstrb[0] : 1'b0), + .reg_di(mem_wdata), .reg_do(spiflash_reg_do), .reg_wait(spiflash_reg_wait) +); + // RV memory access assign rv_addr = flash_loading ? flash_addr : mem_addr; assign rv_wdata = flash_loading ? {flash_d, flash_d, flash_d, flash_d} : mem_wdata; @@ -313,13 +328,14 @@ assign rv_valid = flash_loading ? flash_wr : (mem_valid & ram_sel); assign ram_ready = rv_ready; // Time counter register -reg [31:0] time_reg; +reg [31:0] time_reg, cycle_reg; reg [$clog2(FREQ/1000)-1:0] time_cnt; always @(posedge clk) begin if (~resetn) begin time_reg <= 0; time_cnt <= 0; end else begin + cycle_reg <= cycle_reg + 1; time_cnt <= time_cnt + 1; if (time_cnt == FREQ/1000-1) begin time_cnt <= 0; diff --git a/src/iosys/spiflash.v b/src/iosys/spiflash.v index 04b303a..78e676c 100644 --- a/src/iosys/spiflash.v +++ b/src/iosys/spiflash.v @@ -1,4 +1,15 @@ -// read a block of content from spi flash +// Spi flash module with two functions, +// 1. Inital program loading from flash +// 2. MMIO interface for R/W accesses to the flash +// +// MMIO Registers: +// 0x200_0070: Byte reg. Write to initiate a byte transfer. +// The lowest byte is transfered over SPI. +// Then a read will return the received byte. +// 0x200_0074: Word transfer. Writes and reads 4 bytes. +// 0x200_0078: Control register (write-only). [0]=CS_N +// +// Chip is Winbond W25Q64 module spiflash #( parameter CLK_DIV = 2, parameter [23:0] ADDR = 1024*1024, @@ -12,10 +23,19 @@ module spiflash #( output mosi, // mster out slave in output sck, // spi clock - input start, // pulse to start reading from flash + // program loading at ADDR for LEN bytes + input start, // pulse to start loading from flash output reg busy, output reg [7:0] dout, - output reg dout_strb + output reg dout_strb, + + // RV MMIO interface + input reg_byte_we, // 1: write-read a byte + input reg_word_we, // 1: write-read a word + input reg_ctrl_we, // 1: write control register + input [31:0] reg_di, + output reg [31:0] reg_do, + output reg_wait ); reg [1:0] state; @@ -29,11 +49,10 @@ wire spi_ready; reg [20:0] cnt; // transfer byte count, max 2MB -// spi #(.CLK_DIV(CLK_DIV)) spi ( -// .clk(clk), .resetn(resetn), .miso(miso), .mosi(mosi), -// .sck(sck), .start(spi_start), .data_in(data_in), .data_out(data_out), -// .busy(spi_busy), .new_data(new_data) -// ); +assign reg_wait = wait_buf & (reg_byte_we | reg_word_we); +reg wait_buf = 1; +reg reg_byte_we_r, reg_word_we_r; +reg active, new_request; SPI_Master #(.CLKS_PER_HALF_BIT(CLK_DIV)) spi ( .i_Clk(clk), .i_Rst_L(resetn), @@ -47,7 +66,17 @@ always @(posedge clk) begin state <= 0; ncs_buf <= 1'b1; end else begin + reg new_request_t = reg_byte_we && ~reg_byte_we_r || reg_word_we && ~reg_word_we_r; + reg_byte_we_r <= reg_byte_we; + reg_word_we_r <= reg_word_we; + if (new_request_t) + new_request <= 1; + + if (reg_ctrl_we) + ncs_buf <= reg_di[0]; + spi_start <= 0; + wait_buf <= 1; dout_strb <= 0; case (state) 2'd0: @@ -79,13 +108,34 @@ always @(posedge clk) begin if (cnt == LEN) begin state <= 2'd3; busy <= 0; + ncs_buf <= 1'b1; end spi_start <= 1; dout <= data_out; dout_strb <= 1'b1; end - 2'd3: begin // finish - ncs_buf <= 1'b1; + 2'd3: begin // MMIO + if (spi_ready && ~spi_start && (new_request_t || new_request || active)) begin + // send + if (new_request || new_request_t) begin + data_in <= reg_di[7:0]; + spi_start <= 1; + active <= 1; + new_request <= 0; + end else if (reg_word_we && cnt != 2'd3) begin + data_in <= reg_di[(cnt+1)*8 +: 8]; + spi_start <= 1; + cnt <= cnt + 2'd1; + end else begin // last byte is transmitted, let CPU continue + wait_buf <= 0; + cnt <= 0; + active <= 0; + end + + // receive + if (~new_request) + reg_do[cnt*8 +: 8] <= data_out; + end end endcase end