Skip to content

Commit

Permalink
Iosys spi flash mmio for core switching
Browse files Browse the repository at this point in the history
  • Loading branch information
nand2mario committed Jun 2, 2024
1 parent ceebc8b commit f06aaf8
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 27 deletions.
50 changes: 33 additions & 17 deletions src/iosys/iosys.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 #(
Expand Down Expand Up @@ -240,7 +241,7 @@ always @(posedge clk) begin
end
end

// uart @ 0x0200_0004 & 0x200_0008
// uart @ 0x0200_0010
simpleuart simpleuart (
.clk (clk ),
.resetn (resetn ),
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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;
Expand Down
70 changes: 60 additions & 10 deletions src/iosys/spiflash.v
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;
Expand All @@ -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),
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit f06aaf8

Please sign in to comment.