mirror of https://github.com/YosysHQ/picorv32.git
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