aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2019-02-13 14:13:58 +0100
committerGitHub <noreply@github.com>2019-02-13 14:13:58 +0100
commit5c081c3291f8ce93d6d194be5861401a0263b636 (patch)
tree31940468d44a19d508936ae6d24cf27cc6945eec
parent0886cc7562788cd339045d964610c4c9d6881c7a (diff)
parent358dde2376d101f198f204607138a1e39c562342 (diff)
downloadpicorv32-5c081c3291f8ce93d6d194be5861401a0263b636.tar.gz
picorv32-5c081c3291f8ce93d6d194be5861401a0263b636.zip
Merge pull request #111 from stv0g/icebreaker-spram
Use SPRAM on ICE40UP5K based boards
-rw-r--r--picosoc/.gitignore3
-rw-r--r--picosoc/Makefile20
-rw-r--r--picosoc/firmware.c154
-rw-r--r--picosoc/ice40up5k_spram.v91
-rw-r--r--picosoc/icebreaker.v11
-rw-r--r--picosoc/icebreaker_tb.v7
-rw-r--r--picosoc/picosoc.core6
-rw-r--r--picosoc/picosoc.v12
-rw-r--r--picosoc/sections.lds10
9 files changed, 274 insertions, 40 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 aee1195..ab01df4 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' $^
@@ -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
@@ -50,10 +53,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
@@ -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 b53fa0e..19de4e0 100644
--- a/picosoc/firmware.c
+++ b/picosoc/firmware.c
@@ -20,7 +20,11 @@
#include <stdint.h>
#include <stdbool.h>
-#if !defined(ICEBREAKER) && !defined(HX8KDEMO)
+#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
@@ -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()
@@ -578,36 +681,23 @@ void main()
print(" | |_) | |/ __/ _ \\___ \\ / _ \\| |\n");
print(" | __/| | (_| (_) |__) | (_) | |___\n");
print(" |_| |_|\\___\\___/____/ \\___/ \\____|\n");
+ 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("Total memory: ");
+ print_dec(MEM_TOTAL / 1024);
+ print(" KiB\n");
+ print("\n");
- print(" QSPI ");
- if ((reg_spictrl & (1 << 21)) != 0)
- print("ON\n");
- else
- print("OFF\n");
+ cmd_memtest();
+ print("\n");
- print(" CRM ");
- if ((reg_spictrl & (1 << 20)) != 0)
- print("ON\n");
- else
- print("OFF\n");
+ cmd_print_spi_state();
+ print("\n");
+ while (1)
+ {
print("\n");
+
print("Select an action:\n");
print("\n");
print(" [1] Read SPI Flash ID\n");
@@ -619,6 +709,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(" [e] Echo UART\n");
print("\n");
@@ -659,6 +751,12 @@ void main()
case '0':
cmd_benchmark_all();
break;
+ case 'M':
+ cmd_memtest();
+ break;
+ case 'P':
+ cmd_print_spi_state();
+ break;
case 'e':
cmd_echo();
break;
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 <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 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..342f346 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,
@@ -39,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;
@@ -100,7 +108,8 @@ module icebreaker (
picosoc #(
.BARREL_SHIFTER(0),
- .ENABLE_MULDIV(0)
+ .ENABLE_MULDIV(0),
+ .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 ),
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]),
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 {