From d21937bafc77e9f7d81c2f50d2ad825a39fb644c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 11 Feb 2019 23:13:05 +0100 Subject: [PATCH 1/4] picosoc: increase available memory by using SPRAM instead of BRAM for the Icebreaker example --- picosoc/Makefile | 6 +-- picosoc/ice40up5k_spram.v | 91 +++++++++++++++++++++++++++++++++++++++ picosoc/icebreaker.v | 9 +++- picosoc/picosoc.core | 6 ++- picosoc/picosoc.v | 12 +++++- 5 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 picosoc/ice40up5k_spram.v diff --git a/picosoc/Makefile b/picosoc/Makefile index aee1195..29a3b07 100644 --- a/picosoc/Makefile +++ b/picosoc/Makefile @@ -5,7 +5,7 @@ hx8ksim: hx8kdemo_tb.vvp hx8kdemo_fw.hex vvp -N $< +firmware=hx8kdemo_fw.hex hx8ksynsim: hx8kdemo_syn_tb.vvp hx8kdemo_fw.hex - vvp -N $< +firmware=hx8kdemo_fw.hex + vvp -N $< +firmware=hx8kdemo_fw.hex hx8kdemo.blif: hx8kdemo.v spimemio.v simpleuart.v picosoc.v ../picorv32.v yosys -ql hx8kdemo.log -p 'synth_ice40 -top hx8kdemo -blif hx8kdemo.blif' $^ @@ -50,10 +50,10 @@ icebsim: icebreaker_tb.vvp icebreaker_fw.hex icebsynsim: icebreaker_syn_tb.vvp icebreaker_fw.hex vvp -N $< +firmware=icebreaker_fw.hex -icebreaker.json: icebreaker.v spimemio.v simpleuart.v picosoc.v ../picorv32.v +icebreaker.json: icebreaker.v ice40up5k_spram.v spimemio.v simpleuart.v picosoc.v ../picorv32.v yosys -ql icebreaker.log -p 'synth_ice40 -top icebreaker -json icebreaker.json' $^ -icebreaker_tb.vvp: icebreaker_tb.v icebreaker.v spimemio.v simpleuart.v picosoc.v ../picorv32.v spiflash.v +icebreaker_tb.vvp: icebreaker_tb.v icebreaker.v ice40up5k_spram.v spimemio.v simpleuart.v picosoc.v ../picorv32.v spiflash.v iverilog -s testbench -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v` icebreaker_syn_tb.vvp: icebreaker_tb.v icebreaker_syn.v spiflash.v diff --git a/picosoc/ice40up5k_spram.v b/picosoc/ice40up5k_spram.v new file mode 100644 index 0000000..6edb23b --- /dev/null +++ b/picosoc/ice40up5k_spram.v @@ -0,0 +1,91 @@ + +/* + * PicoSoC - A simple example SoC using PicoRV32 + * + * Copyright (C) 2017 Clifford Wolf + * + * 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 ice40up5k_spram #( + // We current always use the whole SPRAM (128 kB) + parameter integer WORDS = 32768 +) ( + input clk, + input [3:0] wen, + input [21:0] addr, + input [31:0] wdata, + output [31:0] rdata +); + + wire cs_0, cs_1; + wire [31:0] rdata_0, rdata_1; + + assign cs_0 = !addr[14]; + assign cs_1 = addr[14]; + assign rdata = addr[14] ? rdata_1 : rdata_0; + + SB_SPRAM256KA ram00 ( + .ADDRESS(addr[13:0]), + .DATAIN(wdata[15:0]), + .MASKWREN({wen[1], wen[1], wen[0], wen[0]}), + .WREN(wen[1]|wen[0]), + .CHIPSELECT(cs_0), + .CLOCK(clk), + .STANDBY(1'b0), + .SLEEP(1'b0), + .POWEROFF(1'b1), + .DATAOUT(rdata_0[15:0]) + ); + + SB_SPRAM256KA ram01 ( + .ADDRESS(addr[13:0]), + .DATAIN(wdata[31:16]), + .MASKWREN({wen[3], wen[3], wen[2], wen[2]}), + .WREN(wen[3]|wen[2]), + .CHIPSELECT(cs_0), + .CLOCK(clk), + .STANDBY(1'b0), + .SLEEP(1'b0), + .POWEROFF(1'b1), + .DATAOUT(rdata_0[31:16]) + ); + + SB_SPRAM256KA ram10 ( + .ADDRESS(addr[13:0]), + .DATAIN(wdata[15:0]), + .MASKWREN({wen[1], wen[1], wen[0], wen[0]}), + .WREN(wen[1]|wen[0]), + .CHIPSELECT(cs_1), + .CLOCK(clk), + .STANDBY(1'b0), + .SLEEP(1'b0), + .POWEROFF(1'b1), + .DATAOUT(rdata_1[15:0]) + ); + + SB_SPRAM256KA ram11 ( + .ADDRESS(addr[13:0]), + .DATAIN(wdata[31:16]), + .MASKWREN({wen[3], wen[3], wen[2], wen[2]}), + .WREN(wen[3]|wen[2]), + .CHIPSELECT(cs_1), + .CLOCK(clk), + .STANDBY(1'b0), + .SLEEP(1'b0), + .POWEROFF(1'b1), + .DATAOUT(rdata_1[31:16]) + ); + +endmodule diff --git a/picosoc/icebreaker.v b/picosoc/icebreaker.v index ef9b9ac..00da2d7 100644 --- a/picosoc/icebreaker.v +++ b/picosoc/icebreaker.v @@ -17,6 +17,12 @@ * */ +`ifdef PICOSOC_V +`error "icebreaker.v must be read before icebreaker.v!" +`endif + +`define PICOSOC_MEM ice40up5k_spram + module icebreaker ( input clk, @@ -100,7 +106,8 @@ module icebreaker ( picosoc #( .BARREL_SHIFTER(0), - .ENABLE_MULDIV(0) + .ENABLE_MULDIV(0), + .MEM_WORDS(32768) ) soc ( .clk (clk ), .resetn (resetn ), diff --git a/picosoc/picosoc.core b/picosoc/picosoc.core index a6eae08..eb0988a 100644 --- a/picosoc/picosoc.core +++ b/picosoc/picosoc.core @@ -14,10 +14,14 @@ filesets: targets: default: filesets : [picosoc] - parameters : [PICORV32_REGS] + parameters : [PICORV32_REGS, PICOSOC_MEM] parameters: PICORV32_REGS: datatype : str default : picosoc_regs paramtype : vlogdefine + PICOSOC_MEM: + datatype : str + default : picosoc_mem + paramtype : vlogdefine diff --git a/picosoc/picosoc.v b/picosoc/picosoc.v index 353f2ef..9c5981e 100644 --- a/picosoc/picosoc.v +++ b/picosoc/picosoc.v @@ -25,6 +25,14 @@ `define PICORV32_REGS picosoc_regs `endif +`ifndef PICOSOC_MEM +`define PICOSOC_MEM picosoc_mem +`endif + +// this macro can be used to check if the verilog files in your +// design are read in the correct order. +`define PICOSOC_V + module picosoc ( input clk, input resetn, @@ -197,7 +205,9 @@ module picosoc ( always @(posedge clk) ram_ready <= mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS; - picosoc_mem #(.WORDS(MEM_WORDS)) memory ( + `PICOSOC_MEM #( + .WORDS(MEM_WORDS) + ) memory ( .clk(clk), .wen((mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS) ? mem_wstrb : 4'b0), .addr(mem_addr[23:2]), From f3b1246c862c37108f2a472816e2ed2e5b37e269 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 11 Feb 2019 23:14:56 +0100 Subject: [PATCH 2/4] picosoc: added memtest --- picosoc/firmware.c | 154 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 126 insertions(+), 28 deletions(-) diff --git a/picosoc/firmware.c b/picosoc/firmware.c index e3eed76..4a86615 100644 --- a/picosoc/firmware.c +++ b/picosoc/firmware.c @@ -20,7 +20,11 @@ #include #include -#if !defined(ICEBREAKER) && !defined(HX8KDEMO) +#ifdef ICEBREAKER + #define MEM_TOTAL 0x20000 +#elif HX8KDEMO + #define MEM_TOTAL 0x200 +#else # error "Set -DICEBREAKER or -DHX8KDEMO when compiling firmware.c" #endif @@ -176,11 +180,21 @@ void print_hex(uint32_t v, int digits) void print_dec(uint32_t v) { - if (v >= 100) { - print(">=100"); + if (v >= 1000) { + print(">=1000"); return; } + if (v >= 900) { putchar('9'); v -= 900; } + else if (v >= 800) { putchar('8'); v -= 800; } + else if (v >= 700) { putchar('7'); v -= 700; } + else if (v >= 600) { putchar('6'); v -= 600; } + else if (v >= 500) { putchar('5'); v -= 500; } + else if (v >= 400) { putchar('4'); v -= 400; } + else if (v >= 300) { putchar('3'); v -= 300; } + else if (v >= 200) { putchar('2'); v -= 200; } + else if (v >= 100) { putchar('1'); v -= 100; } + if (v >= 90) { putchar('9'); v -= 90; } else if (v >= 80) { putchar('8'); v -= 80; } else if (v >= 70) { putchar('7'); v -= 70; } @@ -236,6 +250,95 @@ char getchar() return getchar_prompt(0); } +void cmd_print_spi_state() +{ + print("SPI State:\n"); + + print(" LATENCY "); + print_dec((reg_spictrl >> 16) & 15); + print("\n"); + + print(" DDR "); + if ((reg_spictrl & (1 << 22)) != 0) + print("ON\n"); + else + print("OFF\n"); + + print(" QSPI "); + if ((reg_spictrl & (1 << 21)) != 0) + print("ON\n"); + else + print("OFF\n"); + + print(" CRM "); + if ((reg_spictrl & (1 << 20)) != 0) + print("ON\n"); + else + print("OFF\n"); +} + +uint32_t xorshift32(uint32_t *state) +{ + /* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */ + uint32_t x = *state; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + *state = x; + + return x; +} + +void cmd_memtest() +{ + int cyc_count = 5; + int stride = 256; + uint32_t state; + + volatile uint32_t *base_word = (uint32_t *) 0; + volatile uint8_t *base_byte = (uint8_t *) 0; + + print("Running memtest "); + + // Walk in stride increments, word access + for (int i = 1; i <= cyc_count; i++) { + state = i; + + for (int word = 0; word < MEM_TOTAL / sizeof(int); word += stride) { + *(base_word + word) = xorshift32(&state); + } + + state = i; + + for (int word = 0; word < MEM_TOTAL / sizeof(int); word += stride) { + if (*(base_word + word) != xorshift32(&state)) { + print(" ***FAILED WORD*** at "); + print_hex(4*word, 4); + print("\n"); + return; + } + } + + print("."); + } + + // Byte access + for (int byte = 0; byte < 128; byte++) { + *(base_byte + byte) = (uint8_t) byte; + } + + for (int byte = 0; byte < 128; byte++) { + if (*(base_byte + byte) != (uint8_t) byte) { + print(" ***FAILED BYTE*** at "); + print_hex(byte, 4); + print("\n"); + return; + } + } + + print(" passed\n"); +} + // -------------------------------------------------------- void cmd_read_flash_id() @@ -570,36 +673,23 @@ void main() print(" | |_) | |/ __/ _ \\___ \\ / _ \\| |\n"); print(" | __/| | (_| (_) |__) | (_) | |___\n"); print(" |_| |_|\\___\\___/____/ \\___/ \\____|\n"); + print("\n"); + + print("Total memory: "); + print_dec(MEM_TOTAL / 1024); + print(" KiB\n"); + print("\n"); + + cmd_memtest(); + print("\n"); + + cmd_print_spi_state(); + print("\n"); while (1) { print("\n"); - print("\n"); - print("SPI State:\n"); - print(" LATENCY "); - print_dec((reg_spictrl >> 16) & 15); - print("\n"); - - print(" DDR "); - if ((reg_spictrl & (1 << 22)) != 0) - print("ON\n"); - else - print("OFF\n"); - - print(" QSPI "); - if ((reg_spictrl & (1 << 21)) != 0) - print("ON\n"); - else - print("OFF\n"); - - print(" CRM "); - if ((reg_spictrl & (1 << 20)) != 0) - print("ON\n"); - else - print("OFF\n"); - - print("\n"); print("Select an action:\n"); print("\n"); print(" [1] Read SPI Flash ID\n"); @@ -611,6 +701,8 @@ void main() print(" [7] Toggle continuous read mode\n"); print(" [9] Run simplistic benchmark\n"); print(" [0] Benchmark all configs\n"); + print(" [M] Run Memtest\n"); + print(" [S] Print SPI state\n"); print("\n"); for (int rep = 10; rep > 0; rep--) @@ -650,6 +742,12 @@ void main() case '0': cmd_benchmark_all(); break; + case 'M': + cmd_memtest(); + break; + case 'P': + cmd_print_spi_state(); + break; default: continue; } From eb64df6c3e5184ee982bb57c8828b80c798ce1b6 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 11 Feb 2019 23:44:47 +0100 Subject: [PATCH 3/4] picosoc: use preprocessor for generating target-specific linker script --- picosoc/.gitignore | 3 +++ picosoc/Makefile | 14 ++++++++++---- picosoc/firmware.c | 4 ++-- picosoc/sections.lds | 10 +++++++++- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/picosoc/.gitignore b/picosoc/.gitignore index 1817f7d..08067d3 100644 --- a/picosoc/.gitignore +++ b/picosoc/.gitignore @@ -11,6 +11,7 @@ /hx8kdemo_fw.elf /hx8kdemo_fw.hex /hx8kdemo_fw.bin +/hx8kdemo_sections.lds /icebreaker.asc /icebreaker.bin /icebreaker.json @@ -22,5 +23,7 @@ /icebreaker_fw.elf /icebreaker_fw.hex /icebreaker_fw.bin +/icebreaker_sections.lds /testbench.vcd /cmos.log + diff --git a/picosoc/Makefile b/picosoc/Makefile index 29a3b07..ab01df4 100644 --- a/picosoc/Makefile +++ b/picosoc/Makefile @@ -33,8 +33,11 @@ hx8kprog: hx8kdemo.bin hx8kdemo_fw.bin hx8kprog_fw: hx8kdemo_fw.bin iceprog -o 1M hx8kdemo_fw.bin -hx8kdemo_fw.elf: sections.lds start.s firmware.c - riscv32-unknown-elf-gcc -DHX8KDEMO -march=rv32imc -Wl,-Bstatic,-T,sections.lds,--strip-debug -ffreestanding -nostdlib -o hx8kdemo_fw.elf start.s firmware.c +hx8kprog_sections.lds: sections.lds + riscv32-unknown-elf-cpp -P -DHX8KDEMO -o $@ $^ + +hx8kdemo_fw.elf: hx8kdemo_sections.lds start.s firmware.c + riscv32-unknown-elf-gcc -DHX8KDEMO -march=rv32imc -Wl,-Bstatic,-T,hx8kdemo_sections.lds,--strip-debug -ffreestanding -nostdlib -o hx8kdemo_fw.elf start.s firmware.c hx8kdemo_fw.hex: hx8kdemo_fw.elf riscv32-unknown-elf-objcopy -O verilog hx8kdemo_fw.elf hx8kdemo_fw.hex @@ -76,8 +79,11 @@ icebprog: icebreaker.bin icebreaker_fw.bin icebprog_fw: icebreaker_fw.bin iceprog -o 1M icebreaker_fw.bin -icebreaker_fw.elf: sections.lds start.s firmware.c - riscv32-unknown-elf-gcc -DICEBREAKER -march=rv32ic -Wl,-Bstatic,-T,sections.lds,--strip-debug -ffreestanding -nostdlib -o icebreaker_fw.elf start.s firmware.c +icebreaker_sections.lds: sections.lds + riscv32-unknown-elf-cpp -P -DICEBREAKER -o $@ $^ + +icebreaker_fw.elf: icebreaker_sections.lds start.s firmware.c + riscv32-unknown-elf-gcc -DICEBREAKER -march=rv32ic -Wl,-Bstatic,-T,icebreaker_sections.lds,--strip-debug -ffreestanding -nostdlib -o icebreaker_fw.elf start.s firmware.c icebreaker_fw.hex: icebreaker_fw.elf riscv32-unknown-elf-objcopy -O verilog icebreaker_fw.elf icebreaker_fw.hex diff --git a/picosoc/firmware.c b/picosoc/firmware.c index 4a86615..6a498fe 100644 --- a/picosoc/firmware.c +++ b/picosoc/firmware.c @@ -21,9 +21,9 @@ #include #ifdef ICEBREAKER - #define MEM_TOTAL 0x20000 +# define MEM_TOTAL 0x20000 /* 128 KB */ #elif HX8KDEMO - #define MEM_TOTAL 0x200 +# define MEM_TOTAL 0x200 /* 2 KB */ #else # error "Set -DICEBREAKER or -DHX8KDEMO when compiling firmware.c" #endif diff --git a/picosoc/sections.lds b/picosoc/sections.lds index 5f74459..f38d813 100644 --- a/picosoc/sections.lds +++ b/picosoc/sections.lds @@ -1,7 +1,15 @@ +#ifdef ICEBREAKER +# define MEM_TOTAL 0x20000 /* 128 KB */ +#elif HX8KDEMO +# define MEM_TOTAL 0x200 /* 2 KB */ +#else +# error "Set -DICEBREAKER or -DHX8KDEMO when compiling firmware.c" +#endif + MEMORY { FLASH (rx) : ORIGIN = 0x00100000, LENGTH = 0x400000 /* entire flash, 4 MiB */ - RAM (xrw) : ORIGIN = 0x00000000, LENGTH = 0x000400 /* 1 KB */ + RAM (xrw) : ORIGIN = 0x00000000, LENGTH = MEM_TOTAL } SECTIONS { From 3710a86b81e4e8e5426c2941e9edf1d40f686370 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Tue, 12 Feb 2019 00:13:33 +0100 Subject: [PATCH 4/4] icebreaker: artificially limit available RAM to speed-up simulation --- picosoc/icebreaker.v | 4 +++- picosoc/icebreaker_tb.v | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/picosoc/icebreaker.v b/picosoc/icebreaker.v index 00da2d7..342f346 100644 --- a/picosoc/icebreaker.v +++ b/picosoc/icebreaker.v @@ -45,6 +45,8 @@ module icebreaker ( inout flash_io2, inout flash_io3 ); + parameter integer MEM_WORDS = 32768; + reg [5:0] reset_cnt = 0; wire resetn = &reset_cnt; @@ -107,7 +109,7 @@ module icebreaker ( picosoc #( .BARREL_SHIFTER(0), .ENABLE_MULDIV(0), - .MEM_WORDS(32768) + .MEM_WORDS(MEM_WORDS) ) soc ( .clk (clk ), .resetn (resetn ), diff --git a/picosoc/icebreaker_tb.v b/picosoc/icebreaker_tb.v index 2126ca2..209d165 100644 --- a/picosoc/icebreaker_tb.v +++ b/picosoc/icebreaker_tb.v @@ -62,7 +62,12 @@ module testbench; #1 $display("%b", leds); end - icebreaker uut ( + icebreaker #( + // We limit the amount of memory in simulation + // in order to avoid reduce simulation time + // required for intialization of RAM + .MEM_WORDS(256) + ) uut ( .clk (clk ), .led1 (led1 ), .led2 (led2 ),