Add spiflash example project
This commit is contained in:
parent
4ce36a87d1
commit
098829e579
|
@ -0,0 +1,11 @@
|
||||||
|
/testbench.vcd
|
||||||
|
/testbench.vvp
|
||||||
|
/firmware.elf
|
||||||
|
/firmware_vma.elf
|
||||||
|
/firmware.hex
|
||||||
|
/firmware.bin
|
||||||
|
/design.asc
|
||||||
|
/design.bin
|
||||||
|
/design.blif
|
||||||
|
/design.log
|
||||||
|
/design.rpt
|
|
@ -0,0 +1,40 @@
|
||||||
|
|
||||||
|
test: testbench.vvp firmware.hex
|
||||||
|
vvp -N $<
|
||||||
|
|
||||||
|
prog: design.bin firmware.bin
|
||||||
|
iceprog design.bin
|
||||||
|
iceprog -o 1M firmware.bin
|
||||||
|
|
||||||
|
testbench.vvp: spiflash.v spimemio.v testbench.v top.v ../picorv32.v
|
||||||
|
iverilog -s testbench -o $@ $^
|
||||||
|
|
||||||
|
firmware.elf: firmware.s
|
||||||
|
riscv32-unknown-elf-gcc -c -o firmware.elf firmware.s
|
||||||
|
|
||||||
|
firmware_vma.elf: firmware.elf
|
||||||
|
riscv32-unknown-elf-objcopy --change-section-vma .text=0x00100000 firmware.elf firmware_vma.elf
|
||||||
|
|
||||||
|
firmware.hex: firmware_vma.elf
|
||||||
|
riscv32-unknown-elf-objcopy -O verilog firmware_vma.elf firmware.hex
|
||||||
|
|
||||||
|
firmware.bin: firmware.elf
|
||||||
|
riscv32-unknown-elf-objcopy -O binary firmware.elf firmware.bin
|
||||||
|
|
||||||
|
design.blif: spimemio.v top.v ../picorv32.v
|
||||||
|
yosys -ql design.log -p 'synth_ice40 -top top -blif design.blif' $^
|
||||||
|
|
||||||
|
design.asc: pinout.pcf design.blif
|
||||||
|
arachne-pnr -d 8k -o design.asc -p pinout.pcf design.blif
|
||||||
|
|
||||||
|
design.bin: design.asc
|
||||||
|
icetime -d hx8k -c 12 -mtr design.rpt design.asc
|
||||||
|
icepack design.asc design.bin
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f testbench.vvp testbench.vcd
|
||||||
|
rm -f firmware.elf firmware_vma.elf firmware.hex firmware.bin
|
||||||
|
rm -f design.blif design.log design.asc design.rpt design.bin
|
||||||
|
|
||||||
|
.PHONY: test prog clean
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
PicoRV32 SPI-Flash Demo
|
||||||
|
=======================
|
||||||
|
|
||||||
|
This is a simple PicoRV32 example design that can run code directly from an SPI
|
||||||
|
flash chip. This example design uses the Lattice iCE40-HX8K Breakout Board.
|
||||||
|
|
||||||
|
The flash is mapped to the memory region starting at 0x80000000. The reset
|
||||||
|
vector is set to 0x80100000, i.e. at the 1MB offset inside the flash memory.
|
||||||
|
|
||||||
|
A small scratchpad memory (default 256 words, i.e. 1 kB) is mapped to address
|
||||||
|
0x00000000. A simple GPIO controller is mapped to address 0xC0000000.
|
||||||
|
|
||||||
|
Run "make test" to run the test bench (and create testbench.vcd).
|
||||||
|
|
||||||
|
Run "make prog" to build the configuration bit-stream and firmware images
|
||||||
|
and upload them to a connected iCE40-HX8K Breakout Board.
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
start:
|
||||||
|
li x1,0xc0000000
|
||||||
|
sw x0,0(x0)
|
||||||
|
loop: lw x2,0(x0)
|
||||||
|
addi x2,x2,1
|
||||||
|
sw x2,0(x1)
|
||||||
|
sw x2,0(x0)
|
||||||
|
j loop
|
|
@ -0,0 +1,81 @@
|
||||||
|
|
||||||
|
# Pinout for the iCE40-HX8K Breakout Board
|
||||||
|
|
||||||
|
set_io clk J3
|
||||||
|
|
||||||
|
set_io spi_cs R12
|
||||||
|
set_io spi_sclk R11
|
||||||
|
set_io spi_miso P11
|
||||||
|
set_io spi_mosi P12
|
||||||
|
|
||||||
|
# All the GPIO pins below are connected to pins that are floating
|
||||||
|
# on the iCE40-HX8K Breakout Board, expect the marked LED pins.
|
||||||
|
|
||||||
|
set_io trap C3 # LED7
|
||||||
|
|
||||||
|
set_io gpio_o[0] C14
|
||||||
|
set_io gpio_o[1] D13
|
||||||
|
set_io gpio_o[2] C12
|
||||||
|
set_io gpio_o[3] E11
|
||||||
|
set_io gpio_o[4] C13
|
||||||
|
set_io gpio_o[5] E10
|
||||||
|
set_io gpio_o[6] C11
|
||||||
|
set_io gpio_o[7] D11
|
||||||
|
set_io gpio_o[8] C10
|
||||||
|
set_io gpio_o[9] D10
|
||||||
|
set_io gpio_o[10] L10
|
||||||
|
set_io gpio_o[11] E9
|
||||||
|
set_io gpio_o[12] B5 # LED0
|
||||||
|
set_io gpio_o[13] B4 # LED1
|
||||||
|
set_io gpio_o[14] A2 # LED2
|
||||||
|
set_io gpio_o[15] A1 # LED3
|
||||||
|
set_io gpio_o[16] C5 # LED4
|
||||||
|
set_io gpio_o[17] C4 # LED5
|
||||||
|
set_io gpio_o[18] B3 # LED6
|
||||||
|
set_io gpio_o[19] D9
|
||||||
|
set_io gpio_o[20] F9
|
||||||
|
set_io gpio_o[21] D8
|
||||||
|
set_io gpio_o[22] D7
|
||||||
|
set_io gpio_o[23] D6
|
||||||
|
set_io gpio_o[24] E6
|
||||||
|
set_io gpio_o[25] D5
|
||||||
|
set_io gpio_o[26] D4
|
||||||
|
set_io gpio_o[27] E5
|
||||||
|
set_io gpio_o[28] D3
|
||||||
|
set_io gpio_o[29] M13
|
||||||
|
set_io gpio_o[30] M14
|
||||||
|
set_io gpio_o[31] L12
|
||||||
|
|
||||||
|
set_io gpio_i[0] L13
|
||||||
|
set_io gpio_i[1] L14
|
||||||
|
set_io gpio_i[2] K12
|
||||||
|
set_io gpio_i[3] J10
|
||||||
|
set_io gpio_i[4] J11
|
||||||
|
set_io gpio_i[5] K13
|
||||||
|
set_io gpio_i[6] J12
|
||||||
|
set_io gpio_i[7] J13
|
||||||
|
set_io gpio_i[8] J16
|
||||||
|
set_io gpio_i[9] H13
|
||||||
|
set_io gpio_i[10] H12
|
||||||
|
set_io gpio_i[11] G10
|
||||||
|
set_io gpio_i[12] G11
|
||||||
|
set_io gpio_i[13] G13
|
||||||
|
set_io gpio_i[14] G12
|
||||||
|
set_io gpio_i[15] F12
|
||||||
|
set_io gpio_i[16] F11
|
||||||
|
set_io gpio_i[17] E14
|
||||||
|
set_io gpio_i[18] F13
|
||||||
|
set_io gpio_i[19] E13
|
||||||
|
set_io gpio_i[20] N6
|
||||||
|
set_io gpio_i[21] P4
|
||||||
|
set_io gpio_i[22] N5
|
||||||
|
set_io gpio_i[23] P5
|
||||||
|
set_io gpio_i[24] M7
|
||||||
|
set_io gpio_i[25] N7
|
||||||
|
set_io gpio_i[26] P6
|
||||||
|
set_io gpio_i[27] M8
|
||||||
|
set_io gpio_i[28] L9
|
||||||
|
set_io gpio_i[29] P7
|
||||||
|
set_io gpio_i[30] N9
|
||||||
|
set_io gpio_i[31] M9
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
module spiflash (
|
||||||
|
input spi_cs,
|
||||||
|
output reg spi_miso,
|
||||||
|
input spi_mosi,
|
||||||
|
input spi_sclk
|
||||||
|
);
|
||||||
|
localparam verbose = 1;
|
||||||
|
|
||||||
|
reg [7:0] buffer;
|
||||||
|
integer bitcount = 0;
|
||||||
|
integer bytecount = 0;
|
||||||
|
|
||||||
|
reg [7:0] spi_cmd;
|
||||||
|
reg [23:0] spi_addr;
|
||||||
|
|
||||||
|
reg [7:0] spi_in;
|
||||||
|
reg [7:0] spi_out;
|
||||||
|
reg spi_io_vld;
|
||||||
|
|
||||||
|
reg powered_up = 0;
|
||||||
|
reg in_xfer = 0;
|
||||||
|
|
||||||
|
// 16 MB (128Mb) Flash
|
||||||
|
reg [7:0] memory [0:16*1024*1024-1];
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$readmemh("firmware.hex", memory);
|
||||||
|
end
|
||||||
|
|
||||||
|
task spi_action;
|
||||||
|
begin
|
||||||
|
if (verbose) begin
|
||||||
|
if (bytecount == 1)
|
||||||
|
$write("<SPI>");
|
||||||
|
$write("<SPI:%02x", buffer);
|
||||||
|
spi_in = buffer;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (bytecount == 1) begin
|
||||||
|
spi_cmd = buffer;
|
||||||
|
if (spi_cmd == 8'hAB)
|
||||||
|
powered_up = 1;
|
||||||
|
if (spi_cmd == 8'hB9)
|
||||||
|
powered_up = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (powered_up && spi_cmd == 'h03) begin
|
||||||
|
if (bytecount == 2)
|
||||||
|
spi_addr[23:16] = buffer;
|
||||||
|
|
||||||
|
if (bytecount == 3)
|
||||||
|
spi_addr[15:8] = buffer;
|
||||||
|
|
||||||
|
if (bytecount == 4)
|
||||||
|
spi_addr[7:0] = buffer;
|
||||||
|
|
||||||
|
if (bytecount >= 4) begin
|
||||||
|
buffer = memory[spi_addr];
|
||||||
|
spi_addr = spi_addr + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (verbose) begin
|
||||||
|
$write(":%02x>", buffer);
|
||||||
|
spi_out = buffer;
|
||||||
|
spi_io_vld = 1;
|
||||||
|
$fflush;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
always @(spi_cs) begin
|
||||||
|
if (spi_cs) begin
|
||||||
|
if (verbose && in_xfer) begin
|
||||||
|
$display("");
|
||||||
|
$fflush;
|
||||||
|
end
|
||||||
|
buffer = 0;
|
||||||
|
in_xfer = 0;
|
||||||
|
bitcount = 0;
|
||||||
|
bytecount = 0;
|
||||||
|
spi_miso = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(spi_cs, spi_sclk) begin
|
||||||
|
spi_io_vld = 0;
|
||||||
|
if (!spi_cs && !spi_sclk) begin
|
||||||
|
spi_miso = buffer[7];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge spi_sclk) begin
|
||||||
|
if (!spi_cs) begin
|
||||||
|
buffer = {buffer, spi_mosi};
|
||||||
|
bitcount = bitcount + 1;
|
||||||
|
if (bitcount == 8) begin
|
||||||
|
in_xfer = 1;
|
||||||
|
bitcount = 0;
|
||||||
|
bytecount = bytecount + 1;
|
||||||
|
spi_action;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
|
@ -0,0 +1,65 @@
|
||||||
|
module spimemio (
|
||||||
|
input clk, resetn,
|
||||||
|
|
||||||
|
input valid,
|
||||||
|
output reg ready,
|
||||||
|
input [23:0] addr,
|
||||||
|
output reg [31:0] rdata,
|
||||||
|
|
||||||
|
output reg spi_cs,
|
||||||
|
output reg spi_sclk,
|
||||||
|
output reg spi_mosi,
|
||||||
|
input spi_miso
|
||||||
|
);
|
||||||
|
reg [23:0] addr_q;
|
||||||
|
reg addr_q_vld;
|
||||||
|
|
||||||
|
reg [31:0] buffer;
|
||||||
|
reg [6:0] xfer_cnt;
|
||||||
|
reg xfer_wait;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
ready <= 0;
|
||||||
|
if (!resetn) begin
|
||||||
|
spi_cs <= 1;
|
||||||
|
spi_sclk <= 1;
|
||||||
|
xfer_cnt <= 8;
|
||||||
|
buffer <= 8'hAB << 24;
|
||||||
|
addr_q_vld <= 0;
|
||||||
|
xfer_wait <= 0;
|
||||||
|
end else
|
||||||
|
if (xfer_cnt) begin
|
||||||
|
if (spi_cs) begin
|
||||||
|
spi_cs <= 0;
|
||||||
|
end else
|
||||||
|
if (spi_sclk) begin
|
||||||
|
spi_sclk <= 0;
|
||||||
|
spi_mosi <= buffer[31];
|
||||||
|
end else begin
|
||||||
|
spi_sclk <= 1;
|
||||||
|
buffer <= {buffer, spi_miso};
|
||||||
|
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;
|
||||||
|
xfer_cnt <= 32;
|
||||||
|
xfer_wait <= 1;
|
||||||
|
end else begin
|
||||||
|
spi_cs <= 1;
|
||||||
|
buffer <= {8'h 03, addr};
|
||||||
|
addr_q <= addr + 4;
|
||||||
|
addr_q_vld <= 1;
|
||||||
|
xfer_cnt <= 64;
|
||||||
|
xfer_wait <= 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
|
@ -0,0 +1,37 @@
|
||||||
|
module testbench;
|
||||||
|
reg clk = 1;
|
||||||
|
always #5 clk = ~clk;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$dumpfile("testbench.vcd");
|
||||||
|
$dumpvars(0, testbench);
|
||||||
|
repeat (10000) @(posedge clk);
|
||||||
|
$display("<END>");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
wire [31:0] gpio_i = 0;
|
||||||
|
wire [31:0] gpio_o;
|
||||||
|
|
||||||
|
wire spi_cs;
|
||||||
|
wire spi_sclk;
|
||||||
|
wire spi_mosi;
|
||||||
|
wire spi_miso;
|
||||||
|
|
||||||
|
top uut (
|
||||||
|
.clk (clk ),
|
||||||
|
.gpio_i (gpio_i ),
|
||||||
|
.gpio_o (gpio_o ),
|
||||||
|
.spi_cs (spi_cs ),
|
||||||
|
.spi_sclk(spi_sclk),
|
||||||
|
.spi_mosi(spi_mosi),
|
||||||
|
.spi_miso(spi_miso)
|
||||||
|
);
|
||||||
|
|
||||||
|
spiflash spiflash (
|
||||||
|
.spi_cs (spi_cs ),
|
||||||
|
.spi_sclk(spi_sclk),
|
||||||
|
.spi_mosi(spi_mosi),
|
||||||
|
.spi_miso(spi_miso)
|
||||||
|
);
|
||||||
|
endmodule
|
|
@ -0,0 +1,89 @@
|
||||||
|
module top (
|
||||||
|
input clk,
|
||||||
|
output trap,
|
||||||
|
|
||||||
|
input [31:0] gpio_i,
|
||||||
|
output reg [31:0] gpio_o,
|
||||||
|
|
||||||
|
output spi_cs,
|
||||||
|
output spi_sclk,
|
||||||
|
output spi_mosi,
|
||||||
|
input spi_miso
|
||||||
|
);
|
||||||
|
parameter integer MEM_WORDS = 256;
|
||||||
|
parameter [31:0] STACKADDR = (4*MEM_WORDS); // end of memory
|
||||||
|
parameter [31:0] PROGADDR_RESET = 32'h 8010_0000; // 1 MB into flash
|
||||||
|
|
||||||
|
reg [5:0] reset_cnt = 0;
|
||||||
|
wire resetn = &reset_cnt;
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
reset_cnt <= reset_cnt + !resetn;
|
||||||
|
end
|
||||||
|
|
||||||
|
wire mem_valid;
|
||||||
|
wire mem_instr;
|
||||||
|
reg mem_ready;
|
||||||
|
wire [31:0] mem_addr;
|
||||||
|
wire [31:0] mem_wdata;
|
||||||
|
wire [3:0] mem_wstrb;
|
||||||
|
reg [31:0] mem_rdata;
|
||||||
|
|
||||||
|
wire spimem_ready;
|
||||||
|
wire [31:0] spimem_rdata;
|
||||||
|
|
||||||
|
picorv32 #(
|
||||||
|
.STACKADDR(STACKADDR),
|
||||||
|
.PROGADDR_RESET(PROGADDR_RESET)
|
||||||
|
) cpu (
|
||||||
|
.clk (clk ),
|
||||||
|
.resetn (resetn ),
|
||||||
|
.trap (trap ),
|
||||||
|
.mem_valid (mem_valid ),
|
||||||
|
.mem_instr (mem_instr ),
|
||||||
|
.mem_ready (mem_ready || spimem_ready),
|
||||||
|
.mem_addr (mem_addr ),
|
||||||
|
.mem_wdata (mem_wdata ),
|
||||||
|
.mem_wstrb (mem_wstrb ),
|
||||||
|
.mem_rdata (spimem_ready ? spimem_rdata : mem_rdata )
|
||||||
|
);
|
||||||
|
|
||||||
|
spimemio spimemio (
|
||||||
|
.clk(clk),
|
||||||
|
.resetn(resetn),
|
||||||
|
|
||||||
|
.valid (mem_valid && mem_addr[31:30] == 2'b10),
|
||||||
|
.ready (spimem_ready),
|
||||||
|
.addr (mem_addr[23:0]),
|
||||||
|
.rdata (spimem_rdata),
|
||||||
|
|
||||||
|
.spi_cs (spi_cs ),
|
||||||
|
.spi_sclk (spi_sclk),
|
||||||
|
.spi_mosi (spi_mosi),
|
||||||
|
.spi_miso (spi_miso)
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [31:0] memory [0:MEM_WORDS-1];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
mem_ready <= 0;
|
||||||
|
if (mem_valid && !mem_ready) begin
|
||||||
|
if (mem_addr < 4*MEM_WORDS) begin
|
||||||
|
mem_ready <= 1;
|
||||||
|
mem_rdata <= memory[mem_addr >> 2];
|
||||||
|
if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
|
||||||
|
if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
|
||||||
|
if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
|
||||||
|
if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
|
||||||
|
end
|
||||||
|
if (mem_addr == 32'h c000_0000) begin
|
||||||
|
mem_ready <= 1;
|
||||||
|
mem_rdata <= gpio_i;
|
||||||
|
if (mem_wstrb[0]) gpio_o[ 7: 0] <= mem_wdata[ 7: 0];
|
||||||
|
if (mem_wstrb[1]) gpio_o[15: 8] <= mem_wdata[15: 8];
|
||||||
|
if (mem_wstrb[2]) gpio_o[23:16] <= mem_wdata[23:16];
|
||||||
|
if (mem_wstrb[3]) gpio_o[31:24] <= mem_wdata[31:24];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
Loading…
Reference in New Issue