Refactor picosoc code

This commit is contained in:
Clifford Wolf 2017-08-07 15:13:27 +02:00
parent caef4e3753
commit db2222ec02
9 changed files with 316 additions and 171 deletions

10
picosoc/.gitignore vendored
View File

@ -6,8 +6,8 @@
/firmware_vma.elf
/firmware.hex
/firmware.bin
/design.asc
/design.bin
/design.blif
/design.log
/design.rpt
/hx8kdemo.asc
/hx8kdemo.bin
/hx8kdemo.blif
/hx8kdemo.log
/hx8kdemo.rpt

View File

@ -1,4 +1,6 @@
# ---- Generic Testbenches ----
testbench: testbench.vvp firmware.hex
vvp -N $<
@ -11,10 +13,24 @@ spiflash_tb: spiflash_tb.vvp firmware.hex
spiflash_tb.vvp: spiflash.v spiflash_tb.v
iverilog -s testbench -o $@ $^
prog: design.bin firmware.bin
iceprog design.bin
# ---- iCE40 HX8K Breakout Board ----
hx8kprog: hx8kdemo.bin firmware.bin
iceprog hx8kdemo.bin
iceprog -o 1M firmware.bin
hx8kdemo.blif: hx8kdemo.v spimemio.v picosoc.v ../picorv32.v
yosys -ql hx8kdemo.log -p 'synth_ice40 -top hx8kdemo -blif hx8kdemo.blif' $^
hx8kdemo.asc: hx8kdemo.pcf hx8kdemo.blif
arachne-pnr -d 8k -o hx8kdemo.asc -p hx8kdemo.pcf hx8kdemo.blif
hx8kdemo.bin: hx8kdemo.asc
icetime -d hx8k -c 12 -mtr hx8kdemo.rpt hx8kdemo.asc
icepack hx8kdemo.asc hx8kdemo.bin
# ---- Example Firmware ----
firmware.elf: firmware.s
riscv32-unknown-elf-gcc -c -o firmware.elf firmware.s
@ -27,20 +43,12 @@ firmware.hex: firmware_vma.elf
firmware.bin: firmware.elf
riscv32-unknown-elf-objcopy -O binary firmware.elf firmware.bin
design.blif: spimemio.v picosoc.v ../picorv32.v
yosys -ql design.log -p 'synth_ice40 -top picosoc -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 ----
clean:
rm -f testbench.vvp testbench.vcd spiflash_tb.vvp spiflash_tb.vcd
rm -f firmware.elf firmware_vma.elf firmware.hex firmware.bin
rm -f design.blif design.log design.asc design.rpt design.bin
rm -f hx8kdemo.blif hx8kdemo.log hx8kdemo.asc hx8kdemo.rpt hx8kdemo.bin
.PHONY: testbench spiflash_tb prog clean
.PHONY: testbench spiflash_tb hx8kprog clean

View File

@ -5,23 +5,25 @@ PicoSoC - A simple example SoC using PicoRV32
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.
The flash is mapped to the memory region starting at 0x01000000. The reset
vector is set to 0x01100000, 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.
0x00000000.
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.
| File | Description |
| --------------------------- | --------------------------------------------------------------- |
| [picosoc.v](picosoc.v) | Top-level Verilog module for the design |
| [spimemio.v](spimemio.v) | Memory controller that interfaces to external SPI flash |
| [spiflash.v](spiflash.v) | Simulation model of an SPI flash (used by testbench.v) |
| [testbench.v](testbench.v) | Simple test bench for the design (requires firmware.hex). |
| [firmware.s](firmware.s) | Assembler source for firmware.hex/firmware.bin. |
| [pinout.pcf](pinout.pcf) | Pin constraints for implementation on iCE40-HX8K Breakout Board |
| File | Description |
| ----------------------------- | --------------------------------------------------------------- |
| [picosoc.v](picosoc.v) | Top-level PicoSoC Verilog module |
| [picosoc.v](picosoc.v) | Top-level PicoSoC Verilog module |
| [spimemio.v](spimemio.v) | Memory controller that interfaces to external SPI flash |
| [spiflash.v](spiflash.v) | Simulation model of an SPI flash (used by testbench.v) |
| [testbench.v](testbench.v) | Simple test bench for the design (requires firmware.hex). |
| [firmware.s](firmware.s) | Assembler source for firmware.hex/firmware.bin. |
| [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 |

View File

@ -23,7 +23,7 @@ li x5,0x00008067 # ret
sw x5,80(x0)
# setup gpio address in x5
li x5,0xc0000000
li x5,0x02000000
sw x0,0(x5)
# initial entry point into RAM code

24
picosoc/hx8kdemo.pcf Normal file
View File

@ -0,0 +1,24 @@
# Pinout for the iCE40-HX8K Breakout Board
set_io clk J3
set_io flash_csb R12
set_io flash_clk R11
set_io flash_io0 P12
set_io flash_io1 P11
set_io flash_io2 T9 # center on J3
set_io flash_io3 P8 # center on J3
set_io ser_tx B12
set_io ser_rx B10
set_io leds[0] B5 # LED0
set_io leds[1] B4 # LED1
set_io leds[2] A2 # LED2
set_io leds[3] A1 # LED3
set_io leds[4] C5 # LED4
set_io leds[5] C4 # LED5
set_io leds[6] B3 # LED6
set_io leds[7] C3 # LED7

109
picosoc/hx8kdemo.v Normal file
View File

@ -0,0 +1,109 @@
/*
* PicoSoC - A simple example SoC using PicoRV32
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
module hx8kdemo (
input clk,
input ser_tx,
input ser_rx,
output [7:0] leds,
output flash_csb,
output flash_clk,
inout flash_io0,
inout flash_io1,
inout flash_io2,
inout flash_io3
);
reg [5:0] reset_cnt = 0;
wire resetn = &reset_cnt;
always @(posedge clk) begin
reset_cnt <= reset_cnt + !resetn;
end
wire flash_io0_oe, flash_io0_do, flash_io0_di;
wire flash_io1_oe, flash_io1_do, flash_io1_di;
wire flash_io2_oe, flash_io2_do, flash_io2_di;
wire flash_io3_oe, flash_io3_do, flash_io3_di;
SB_IO #(
.PIN_TYPE(6'b 1010_01),
.PULLUP(1'b 0)
) flash_io_buf [3:0] (
.PACKAGE_PIN({flash_io3, flash_io2, flash_io1, flash_io0}),
.OUTPUT_ENABLE({flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}),
.D_OUT_0({flash_io3_do, flash_io2_do, flash_io1_do, flash_io0_do}),
.D_IN_0({flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di})
);
wire iomem_valid;
reg iomem_ready;
wire [3:0] iomem_wstrb;
wire [31:0] iomem_addr;
wire [31:0] iomem_wdata;
reg [31:0] iomem_rdata;
reg [31:0] gpio;
assign leds = gpio >> 12;
always @(posedge clk) begin
iomem_ready <= 0;
if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 02) begin
iomem_ready <= 1;
iomem_rdata <= gpio;
if (iomem_wstrb[0]) gpio[ 7: 0] <= iomem_wdata[ 7: 0];
if (iomem_wstrb[1]) gpio[15: 8] <= iomem_wdata[15: 8];
if (iomem_wstrb[2]) gpio[23:16] <= iomem_wdata[23:16];
if (iomem_wstrb[3]) gpio[31:24] <= iomem_wdata[31:24];
end
end
picosoc uut (
.clk (clk ),
.resetn (resetn ),
.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_di (flash_io0_di),
.flash_io1_di (flash_io1_di),
.flash_io2_di (flash_io2_di),
.flash_io3_di (flash_io3_di),
.iomem_valid (iomem_valid ),
.iomem_ready (iomem_ready ),
.iomem_wstrb (iomem_wstrb ),
.iomem_addr (iomem_addr ),
.iomem_wdata (iomem_wdata ),
.iomem_rdata (iomem_rdata )
);
endmodule

View File

@ -19,93 +19,111 @@
module picosoc (
input clk,
output trap,
input resetn,
input [31:0] gpio_i,
output reg [31:0] gpio_o,
output iomem_valid,
input iomem_ready,
output [ 3:0] iomem_wstrb,
output [31:0] iomem_addr,
output [31:0] iomem_wdata,
input [31:0] iomem_rdata,
output flash_csb,
output flash_clk,
output flash_io0,
input flash_io1,
input flash_io2,
input flash_io3
output flash_io0_oe,
output flash_io1_oe,
output flash_io2_oe,
output flash_io3_oe,
output flash_io0_do,
output flash_io1_do,
output flash_io2_do,
output flash_io3_do,
input flash_io0_di,
input flash_io1_di,
input flash_io2_di,
input flash_io3_di
);
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
parameter [31:0] PROGADDR_RESET = 32'h 0110_0000; // 1 MB into flash
wire mem_valid;
wire mem_instr;
reg mem_ready;
wire mem_ready;
wire [31:0] mem_addr;
wire [31:0] mem_wdata;
wire [3:0] mem_wstrb;
reg [31:0] mem_rdata;
wire [31:0] mem_rdata;
wire spimem_ready;
wire [31:0] spimem_rdata;
reg ram_ready;
reg [31:0] ram_rdata;
assign iomem_valid = mem_valid && (mem_addr[31:24] > 8'h 01);
assign iomem_wstrb = mem_wstrb;
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;
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_ready (mem_ready ),
.mem_addr (mem_addr ),
.mem_wdata (mem_wdata ),
.mem_wstrb (mem_wstrb ),
.mem_rdata (spimem_ready ? spimem_rdata : mem_rdata )
.mem_rdata (mem_rdata )
);
spimemio spimemio (
.clk(clk),
.resetn(resetn),
.valid (mem_valid && mem_addr[31:30] == 2'b10),
.valid (mem_valid && mem_addr[31:24] == 8'h 01),
.ready (spimem_ready),
.addr (mem_addr[23:0]),
.rdata (spimem_rdata),
.flash_csb (flash_csb),
.flash_clk (flash_clk),
.flash_io0 (flash_io0),
.flash_io1 (flash_io1),
.flash_io2 (flash_io2),
.flash_io3 (flash_io3)
.flash_io0 (flash_io0_do),
.flash_io1 (flash_io1_di),
.flash_io2 (flash_io2_di),
.flash_io3 (flash_io3_di)
);
assign flash_io0_oe = 1;
assign flash_io1_oe = 0;
assign flash_io2_oe = 0;
assign flash_io3_oe = 0;
assign flash_io1_do = 0;
assign flash_io2_do = 0;
assign flash_io3_do = 0;
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
ram_ready <= 0;
if (mem_valid && !mem_ready && mem_addr[31:24] == 8'h 00) begin
ram_ready <= 1;
ram_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
end
endmodule

View File

@ -1,83 +0,0 @@
# Pinout for the iCE40-HX8K Breakout Board
set_io clk J3
set_io flash_csb R12
set_io flash_clk R11
set_io flash_io0 P12
set_io flash_io1 P11
set_io flash_io2 T9 # center on J3
set_io flash_io3 P8 # center on J3
# 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

View File

@ -18,13 +18,20 @@
*/
module testbench;
reg clk = 1;
always #5 clk = ~clk;
reg clk;
always #5 clk = (clk === 1'b0);
reg resetn = 0;
initial begin
$dumpfile("testbench.vcd");
$dumpvars(0, testbench);
repeat (100) @(posedge clk);
resetn <= 1;
repeat (100000) @(posedge clk);
$display("");
$display("[TIMEOUT]");
$stop;
@ -35,32 +42,92 @@ module testbench;
wire flash_csb;
wire flash_clk;
wire flash_io0;
wire flash_io1;
wire flash_io2;
wire flash_io3;
always @(gpio_o) begin
$write("<GPIO:%02x>", gpio_o[7:0]);
if (gpio_o == 63) begin
wire flash_io0_oe;
wire flash_io1_oe;
wire flash_io2_oe;
wire flash_io3_oe;
wire flash_io0_do;
wire flash_io1_do;
wire flash_io2_do;
wire flash_io3_do;
wire flash_io0_di = flash_io0;
wire flash_io1_di = flash_io1;
wire flash_io2_di = flash_io2;
wire flash_io3_di = flash_io3;
assign flash_io0 = flash_io0_oe ? flash_io0_do : 1'bz;
assign flash_io1 = flash_io1_oe ? flash_io1_do : 1'bz;
assign flash_io2 = flash_io2_oe ? flash_io2_do : 1'bz;
assign flash_io3 = flash_io3_oe ? flash_io3_do : 1'bz;
wire iomem_valid;
reg iomem_ready;
wire [3:0] iomem_wstrb;
wire [31:0] iomem_addr;
wire [31:0] iomem_wdata;
reg [31:0] iomem_rdata;
reg [31:0] gpio;
always @(posedge clk) begin
iomem_ready <= 0;
if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 02) begin
iomem_ready <= 1;
iomem_rdata <= gpio;
if (iomem_wstrb[0]) gpio[ 7: 0] <= iomem_wdata[ 7: 0];
if (iomem_wstrb[1]) gpio[15: 8] <= iomem_wdata[15: 8];
if (iomem_wstrb[2]) gpio[23:16] <= iomem_wdata[23:16];
if (iomem_wstrb[3]) gpio[31:24] <= iomem_wdata[31:24];
end
end
always @(gpio) begin
$write("<GPIO:%02x>", gpio[7:0]);
if (gpio == 63) begin
$display("[OK]");
$finish;
end
if (gpio_o % 8 == 7) begin
if (gpio % 8 == 7) begin
$display("");
end
end
picosoc uut (
.clk (clk ),
.gpio_i (gpio_i ),
.gpio_o (gpio_o ),
.flash_csb(flash_csb),
.flash_clk(flash_clk),
.flash_io0(flash_io0),
.flash_io1(flash_io1),
.flash_io2(flash_io2),
.flash_io3(flash_io3)
.clk (clk ),
.resetn (resetn ),
.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_di (flash_io0_di),
.flash_io1_di (flash_io1_di),
.flash_io2_di (flash_io2_di),
.flash_io3_di (flash_io3_di),
.iomem_valid (iomem_valid ),
.iomem_ready (iomem_ready ),
.iomem_wstrb (iomem_wstrb ),
.iomem_addr (iomem_addr ),
.iomem_wdata (iomem_wdata ),
.iomem_rdata (iomem_rdata )
);
spiflash spiflash (